Blame SOURCES/list_bundled_nodejs_packages.py

5bde66
#!/usr/bin/env python3
5bde66
#
5bde66
# generates Provides: bundled(npm(...)) = ... lines for each declared dependency and devDependency of package.json
5bde66
#
2e7f84
import os
5bde66
import sys
5bde66
import json
5bde66
import re
5bde66
from packaging import version
5bde66
5bde66
2e7f84
def scan_package_json(package_dir):
2e7f84
    for root, dirs, files in os.walk(package_dir, topdown=True):
2e7f84
        dirs[:] = [d for d in dirs if d not in ["node_modules", "vendor"]]
2e7f84
        if "package.json" in files:
2e7f84
            yield os.path.join(root, "package.json")
2e7f84
2e7f84
5bde66
def read_declared_pkgs(package_json_path):
5bde66
    with open(package_json_path) as f:
5bde66
        package_json = json.load(f)
2e7f84
        return list(package_json.get("dependencies", {}).keys()) + list(
2e7f84
            package_json.get("devDependencies", {}).keys()
2e7f84
        )
5bde66
5bde66
5bde66
def read_installed_pkgs(yarn_lock_path):
5bde66
    with open(yarn_lock_path) as f:
5bde66
        lockfile = f.read()
2e7f84
        return re.findall(
2e7f84
            r'^"?'  # can start with a "
2e7f84
            r"(.+?)@.+(?:,.*)?:\n"  # characters up to @
2e7f84
            r'  version "(.+)"',  # and the version
2e7f84
            lockfile,
2e7f84
            re.MULTILINE,
2e7f84
        )
5bde66
5bde66
5bde66
def list_provides(declared_pkgs, installed_pkgs):
5bde66
    for declared_pkg in declared_pkgs:
5bde66
        # there can be multiple versions installed of one package (transitive dependencies)
5bde66
        # but rpm doesn't support Provides: with a single package and multiple versions
5bde66
        # so let's declare the oldest version here
2e7f84
        versions = [
2e7f84
            version.parse(pkg_version)
2e7f84
            for pkg_name, pkg_version in installed_pkgs
2e7f84
            if pkg_name == declared_pkg
2e7f84
        ]
2e7f84
2e7f84
        if not versions:
2e7f84
            print(f"warning: {declared_pkg} missing in yarn.lock", file=sys.stderr)
2e7f84
            continue
2e7f84
5bde66
        oldest_version = sorted(versions)[0]
5bde66
        yield f"Provides: bundled(npm({declared_pkg})) = {oldest_version}"
5bde66
5bde66
5bde66
if __name__ == "__main__":
5bde66
    if len(sys.argv) != 2:
5bde66
        print(f"usage: {sys.argv[0]} package-X.Y.Z/", file=sys.stdout)
5bde66
        sys.exit(1)
5bde66
5bde66
    package_dir = sys.argv[1]
2e7f84
    declared_pkgs = []
2e7f84
    for package_json_path in scan_package_json(package_dir):
2e7f84
        declared_pkgs.extend(read_declared_pkgs(package_json_path))
5bde66
    installed_pkgs = read_installed_pkgs(f"{package_dir}/yarn.lock")
5bde66
    provides = list_provides(declared_pkgs, installed_pkgs)
5bde66
    for provide in sorted(provides):
5bde66
        print(provide)