Blame SOURCES/nodejs.prov

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