Blame SOURCES/nodejs.prov

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