codekingpro/portable-devtools
114k
1import glob2import os3import subprocess4import sys5import tempfile6from distutils import log7from distutils.errors import DistutilsError8from functools import partial9 10from . import _reqs11from .wheel import Wheel12from .warnings import SetuptoolsDeprecationWarning13 14 15def _fixup_find_links(find_links):16 """Ensure find-links option end-up being a list of strings."""17 if isinstance(find_links, str):18 return find_links.split()19 assert isinstance(find_links, (tuple, list))20 return find_links21 22 23def fetch_build_egg(dist, req):24 """Fetch an egg needed for building.25 26 Use pip/wheel to fetch/build a wheel."""27 _DeprecatedInstaller.emit()28 _warn_wheel_not_available(dist)29 return _fetch_build_egg_no_warn(dist, req)30 31 32def _fetch_build_eggs(dist, requires):33 import pkg_resources # Delay import to avoid unnecessary side-effects34 35 _DeprecatedInstaller.emit(stacklevel=3)36 _warn_wheel_not_available(dist)37 38 resolved_dists = pkg_resources.working_set.resolve(39 _reqs.parse(requires, pkg_resources.Requirement), # required for compatibility40 installer=partial(_fetch_build_egg_no_warn, dist), # avoid warning twice41 replace_conflicting=True,42 )43 for dist in resolved_dists:44 pkg_resources.working_set.add(dist, replace=True)45 return resolved_dists46 47 48def _fetch_build_egg_no_warn(dist, req): # noqa: C901 # is too complex (16) # FIXME49 import pkg_resources # Delay import to avoid unnecessary side-effects50 51 # Ignore environment markers; if supplied, it is required.52 req = strip_marker(req)53 # Take easy_install options into account, but do not override relevant54 # pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll55 # take precedence.56 opts = dist.get_option_dict('easy_install')57 if 'allow_hosts' in opts:58 raise DistutilsError(59 'the `allow-hosts` option is not supported '60 'when using pip to install requirements.'61 )62 quiet = 'PIP_QUIET' not in os.environ and 'PIP_VERBOSE' not in os.environ63 if 'PIP_INDEX_URL' in os.environ:64 index_url = None65 elif 'index_url' in opts:66 index_url = opts['index_url'][1]67 else:68 index_url = None69 find_links = (70 _fixup_find_links(opts['find_links'][1])[:] if 'find_links' in opts else []71 )72 if dist.dependency_links:73 find_links.extend(dist.dependency_links)74 eggs_dir = os.path.realpath(dist.get_egg_cache_dir())75 environment = pkg_resources.Environment()76 for egg_dist in pkg_resources.find_distributions(eggs_dir):77 if egg_dist in req and environment.can_add(egg_dist):78 return egg_dist79 with tempfile.TemporaryDirectory() as tmpdir:80 cmd = [81 sys.executable,82 '-m',83 'pip',84 '--disable-pip-version-check',85 'wheel',86 '--no-deps',87 '-w',88 tmpdir,89 ]90 if quiet:91 cmd.append('--quiet')92 if index_url is not None:93 cmd.extend(('--index-url', index_url))94 for link in find_links or []:95 cmd.extend(('--find-links', link))96 # If requirement is a PEP 508 direct URL, directly pass97 # the URL to pip, as `req @ url` does not work on the98 # command line.99 cmd.append(req.url or str(req))100 try:101 subprocess.check_call(cmd)102 except subprocess.CalledProcessError as e:103 raise DistutilsError(str(e)) from e104 wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0])105 dist_location = os.path.join(eggs_dir, wheel.egg_name())106 wheel.install_as_egg(dist_location)107 dist_metadata = pkg_resources.PathMetadata(108 dist_location, os.path.join(dist_location, 'EGG-INFO')109 )110 return pkg_resources.Distribution.from_filename(111 dist_location, metadata=dist_metadata112 )113 114 115def strip_marker(req):116 """117 Return a new requirement without the environment marker to avoid118 calling pip with something like `babel; extra == "i18n"`, which119 would always be ignored.120 """121 import pkg_resources # Delay import to avoid unnecessary side-effects122 123 # create a copy to avoid mutating the input124 req = pkg_resources.Requirement.parse(str(req))125 req.marker = None126 return req127 128 129def _warn_wheel_not_available(dist):130 import pkg_resources # Delay import to avoid unnecessary side-effects131 132 try:133 pkg_resources.get_distribution('wheel')134 except pkg_resources.DistributionNotFound:135 dist.announce('WARNING: The wheel package is not available.', log.WARN)136 137 138class _DeprecatedInstaller(SetuptoolsDeprecationWarning):139 _SUMMARY = "setuptools.installer and fetch_build_eggs are deprecated."140 _DETAILS = """141 Requirements should be satisfied by a PEP 517 installer.142 If you are using pip, you can try `pip install --use-pep517`.143 """144 # _DUE_DATE not decided yet145 