Blame SOURCES/nodejs.prov

27913e
#!/usr/bin/python
27913e
# -*- coding: utf-8 -*-
27913e
# Copyright 2012 T.C. Hollingsworth <tchollingsworth@gmail.com>
27913e
# Copyright 2017 Tomas Tomecek <ttomecek@redhat.com>
27913e
# Copyright 2019 Jan Stanek <jstanek@redhat.com>
27913e
#
27913e
# Permission is hereby granted, free of charge, to any person obtaining a copy
27913e
# of this software and associated documentation files (the "Software"), to
27913e
# deal in the Software without restriction, including without limitation the
27913e
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
27913e
# sell copies of the Software, and to permit persons to whom the Software is
27913e
# furnished to do so, subject to the following conditions:
27913e
#
27913e
# The above copyright notice and this permission notice shall be included in
27913e
# all copies or substantial portions of the Software.
27913e
#
27913e
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27913e
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27913e
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27913e
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27913e
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27913e
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27913e
# IN THE SOFTWARE.
27913e
27913e
"""Automatic provides generator for Node.js libraries.
27913e
27913e
Metadata taken from package.json.  See `man npm-json` for details.
27913e
"""
27913e
27913e
from __future__ import print_function, with_statement
27913e
27913e
import json
27913e
import os
27913e
import sys
27913e
from itertools import chain, groupby
27913e
27913e
DEPENDENCY_TEMPLATE = "rh-nodejs12-npm(%(name)s) = %(version)s"
27913e
BUNDLED_TEMPLATE = "bundled(nodejs-%(name)s) = %(version)s"
27913e
NODE_MODULES = {"node_modules", "node_modules.bundled"}
27913e
27913e
27913e
class PrivatePackage(RuntimeError):
27913e
    """Private package metadata that should not be listed."""
27913e
27913e
27913e
#: Something is wrong with the ``package.json`` file
27913e
_INVALID_METADATA_FILE = (IOError, PrivatePackage, KeyError)
27913e
27913e
27913e
def format_metadata(metadata, bundled=False):
27913e
    """Format ``package.json``-like metadata into RPM dependency.
27913e
27913e
    Arguments:
27913e
        metadata (dict): Package metadata, presumably read from ``package.json``.
27913e
        bundled (bool): Should the bundled dependency format be used?
27913e
27913e
    Returns:
27913e
        str: RPM dependency (i.e. ``npm(example) = 1.0.0``)
27913e
27913e
    Raises:
27913e
        KeyError: Expected key (i.e. ``name``, ``version``) missing in metadata.
27913e
        PrivatePackage: The metadata indicate private (unlisted) package.
27913e
    """
27913e
27913e
    # Skip private packages
27913e
    if metadata.get("private", False):
27913e
        raise PrivatePackage(metadata)
27913e
27913e
    template = BUNDLED_TEMPLATE if bundled else DEPENDENCY_TEMPLATE
27913e
    return template % metadata
27913e
27913e
27913e
def generate_dependencies(module_path, module_dir_set=NODE_MODULES):
27913e
    """Generate RPM dependency for a module and all it's dependencies.
27913e
27913e
    Arguments:
27913e
        module_path (str): Path to a module directory or it's ``package.json``
27913e
        module_dir_set (set): Base names of directories to look into
27913e
            for bundled dependencies.
27913e
27913e
    Yields:
27913e
        str: RPM dependency for the module and each of it's (public) bundled dependencies.
27913e
27913e
    Raises:
27913e
        ValueError: module_path is not valid module or ``package.json`` file
27913e
    """
27913e
27913e
    # Determine paths to root module directory and package.json
27913e
    if os.path.isdir(module_path):
27913e
        root_dir = module_path
27913e
    elif os.path.basename(module_path) == "package.json":
27913e
        root_dir = os.path.dirname(module_path)
27913e
    else:  # Invalid metadata path
27913e
        raise ValueError("Invalid module path '%s'" % module_path)
27913e
27913e
    for dir_path, subdir_list, __ in os.walk(root_dir):
27913e
        # Currently in node_modules (or similar), continue to subdirs
27913e
        if os.path.basename(dir_path) in module_dir_set:
27913e
            continue
27913e
27913e
        # Read and format metadata
27913e
        metadata_path = os.path.join(dir_path, "package.json")
27913e
        bundled = dir_path != root_dir
27913e
        try:
27913e
            with open(metadata_path, mode="r") as metadata_file:
27913e
                metadata = json.load(metadata_file)
27913e
            yield format_metadata(metadata, bundled=bundled)
27913e
        except _INVALID_METADATA_FILE:
27913e
            pass  # Ignore
27913e
27913e
        # Only visit subdirectories in module_dir_set
27913e
        subdir_list[:] = list(module_dir_set & set(subdir_list))
27913e
27913e
27913e
if __name__ == "__main__":
27913e
    module_paths = (path.strip() for path in sys.stdin)
27913e
    provides = chain.from_iterable(generate_dependencies(m) for m in module_paths)
27913e
27913e
    # sort|uniq
27913e
    for provide, __ in groupby(sorted(provides)):
27913e
        print(provide)