[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/github/codeql/codeql-cli-2.19.2/python/extractor/convert_setup.py [Back]  [Original]

#!/usr/bin/env python

import os.path
import imp
import sys
import traceback
import re

SETUP_TAG = "LGTM_PYTHON_SETUP_SETUP_PY"

setup_file_path = ""
requirements_file_path = ""

if sys.version_info >= (3,):
    basestring = str

def setup_interceptor(**args):
    requirements = make_requirements(**args)
    write_requirements_file(requirements)

def make_requirements(requires=(), install_requires=(), extras_require={}, dependency_links=[], **other_args):
    # Install main requirements.
    requirements = list(requires) + list(install_requires)
    # Install requirements for all features.
    for feature, feature_requirements in extras_require.items():
        if isinstance(feature_requirements, basestring):
            requirements += [feature_requirements]
        else:
            requirements += list(feature_requirements)

    # Attempt to use dependency_links to find requirements first.
    for link in dependency_links:
        split_link = link.rsplit("#egg=", 1)
        if len(split_link) != 2:
            print("Invalid dependency link \"%s\" was ignored." % link)
            continue
        if not link.startswith("http"):
            print("Dependency link \"%s\" is not an HTTP link so is being ignored." % link)
            continue
        package_name = split_link[1].rsplit("-", 1)[0]
        for index, requirement in enumerate(requirements):
            if requirement_name(requirement) == package_name:
                print("Using %s to install %s." % (link, requirement))
                requirements[index] = package_name + " @ " + link

    print("Creating %s file from %s." % (requirements_file_path, setup_file_path))
    requirements = [requirement.encode("ascii", "ignore").strip().decode("ascii") for requirement in requirements]
    print("Requirements extracted from setup.py: %s" % requirements)
    return requirements

REQUIREMENT = re.compile(r"^([\w-]+)")

def requirement_name(req_string):
    req_string = req_string.strip()
    if req_string[0] == '#':
        return None
    match = REQUIREMENT.match(req_string)
    if match:
        return match.group(1)
    return None


def write_requirements_file(requirements):
    if os.path.exists(requirements_file_path):
        # Only overwrite the existing requirements if the new requirements are not empty.
        if requirements:
            print("%s already exists. It will be overwritten." % requirements_file_path)
        else:
            print("%s already exists and it will not be overwritten because the new requirements list is empty." % requirements_file_path)
            return
    elif not requirements:
        print("%s will not be written because the new requirements list is empty." % requirements_file_path)
        return
    with open(requirements_file_path, "w") as requirements_file:
        for requirement in requirements:
            requirements_file.write(requirement + "\n")
    print("Requirements have been written to " + requirements_file_path)

def convert_setup_to_requirements(root):
    global setup_file_path
    if SETUP_TAG in os.environ:
        setup_file_path = os.environ[SETUP_TAG]
        if setup_file_path == "false":
            print("setup.py explicitly ignored")
            return 0
    else:
        setup_file_path = os.path.join(root, "setup.py")
    if not os.path.exists(setup_file_path):
        print("%s does not exist. Not generating requirements.txt." % setup_file_path)
        return 0
    # Override the setuptools and distutils.core implementation of setup with our own.
    import setuptools
    setattr(setuptools, "setup", setup_interceptor)
    import distutils.core
    setattr(distutils.core, "setup", setup_interceptor)

    # TODO: WHY are we inserting at index 1?
    # >>> l = [1,2,3]; l.insert(1, 'x'); print(l)
    # [1, 'x', 2, 3]

    # Ensure the current directory is on path since setup.py might try and include some files in it.
    sys.path.insert(1, root)

    # Modify the arguments since the setup file sometimes checks them.
    sys.argv = [setup_file_path, "build"]

    # Run the setup.py file.
    try:
        imp.load_source("__main__", setup_file_path)
    except BaseException as ex:
        # We don't really care about errors so long as a requirements.txt exists in the next build step.
        print("Running %s failed." % setup_file_path)
        traceback.print_exc(file=sys.stdout)
        if not os.path.exists(requirements_file_path):
            print("%s failed, and a %s file does not exist. Exiting with error." % (setup_file_path, requirements_file_path))
            return 1
    return 0

def main():
    global requirements_file_path
    requirements_file_path = sys.argv[2]
    sys.path.extend(sys.argv[3:])
    sys.exit(convert_setup_to_requirements(sys.argv[1]))

if __name__ == "__main__":
    main()

Web Proxy Viewer  |  New URL  |  Original Page