Archived
172 lines
5.4 KiB
Python
172 lines
5.4 KiB
Python
import glob
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from distutils import log
|
|
from distutils.errors import DistutilsError
|
|
|
|
import pkg_resources
|
|
from setuptools.command.easy_install import easy_install
|
|
from setuptools.extern import six
|
|
from setuptools.wheel import Wheel
|
|
|
|
from .py31compat import TemporaryDirectory
|
|
|
|
|
|
def _fixup_find_links(find_links):
|
|
"""Ensure find-links option end-up being a list of strings."""
|
|
if isinstance(find_links, six.string_types):
|
|
return find_links.split()
|
|
assert isinstance(find_links, (tuple, list))
|
|
return find_links
|
|
|
|
|
|
def _legacy_fetch_build_egg(dist, req):
|
|
"""Fetch an egg needed for building.
|
|
|
|
Legacy path using EasyInstall.
|
|
"""
|
|
tmp_dist = dist.__class__({"script_args": ["easy_install"]})
|
|
opts = tmp_dist.get_option_dict("easy_install")
|
|
opts.clear()
|
|
opts.update(
|
|
(k, v)
|
|
for k, v in dist.get_option_dict("easy_install").items()
|
|
if k
|
|
in (
|
|
# don't use any other settings
|
|
"find_links",
|
|
"site_dirs",
|
|
"index_url",
|
|
"optimize",
|
|
"site_dirs",
|
|
"allow_hosts",
|
|
)
|
|
)
|
|
if dist.dependency_links:
|
|
links = dist.dependency_links[:]
|
|
if "find_links" in opts:
|
|
links = _fixup_find_links(opts["find_links"][1]) + links
|
|
opts["find_links"] = ("setup", links)
|
|
install_dir = dist.get_egg_cache_dir()
|
|
cmd = easy_install(
|
|
tmp_dist,
|
|
args=["x"],
|
|
install_dir=install_dir,
|
|
exclude_scripts=True,
|
|
always_copy=False,
|
|
build_directory=None,
|
|
editable=False,
|
|
upgrade=False,
|
|
multi_version=True,
|
|
no_report=True,
|
|
user=False,
|
|
)
|
|
cmd.ensure_finalized()
|
|
return cmd.easy_install(req)
|
|
|
|
|
|
def fetch_build_egg(dist, req):
|
|
"""Fetch an egg needed for building.
|
|
|
|
Use pip/wheel to fetch/build a wheel."""
|
|
# Check pip is available.
|
|
try:
|
|
pkg_resources.get_distribution("pip")
|
|
except pkg_resources.DistributionNotFound:
|
|
dist.announce(
|
|
"WARNING: The pip package is not available, falling back "
|
|
"to EasyInstall for handling setup_requires/test_requires; "
|
|
"this is deprecated and will be removed in a future version.",
|
|
log.WARN,
|
|
)
|
|
return _legacy_fetch_build_egg(dist, req)
|
|
# Warn if wheel is not.
|
|
try:
|
|
pkg_resources.get_distribution("wheel")
|
|
except pkg_resources.DistributionNotFound:
|
|
dist.announce("WARNING: The wheel package is not available.", log.WARN)
|
|
# Ignore environment markers; if supplied, it is required.
|
|
req = strip_marker(req)
|
|
# Take easy_install options into account, but do not override relevant
|
|
# pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll
|
|
# take precedence.
|
|
opts = dist.get_option_dict("easy_install")
|
|
if "allow_hosts" in opts:
|
|
raise DistutilsError(
|
|
"the `allow-hosts` option is not supported "
|
|
"when using pip to install requirements."
|
|
)
|
|
if "PIP_QUIET" in os.environ or "PIP_VERBOSE" in os.environ:
|
|
quiet = False
|
|
else:
|
|
quiet = True
|
|
if "PIP_INDEX_URL" in os.environ:
|
|
index_url = None
|
|
elif "index_url" in opts:
|
|
index_url = opts["index_url"][1]
|
|
else:
|
|
index_url = None
|
|
if "find_links" in opts:
|
|
find_links = _fixup_find_links(opts["find_links"][1])[:]
|
|
else:
|
|
find_links = []
|
|
if dist.dependency_links:
|
|
find_links.extend(dist.dependency_links)
|
|
eggs_dir = os.path.realpath(dist.get_egg_cache_dir())
|
|
environment = pkg_resources.Environment()
|
|
for egg_dist in pkg_resources.find_distributions(eggs_dir):
|
|
if egg_dist in req and environment.can_add(egg_dist):
|
|
return egg_dist
|
|
with TemporaryDirectory() as tmpdir:
|
|
cmd = [
|
|
sys.executable,
|
|
"-m",
|
|
"pip",
|
|
"--disable-pip-version-check",
|
|
"wheel",
|
|
"--no-deps",
|
|
"-w",
|
|
tmpdir,
|
|
]
|
|
if quiet:
|
|
cmd.append("--quiet")
|
|
if index_url is not None:
|
|
cmd.extend(("--index-url", index_url))
|
|
if find_links is not None:
|
|
for link in find_links:
|
|
cmd.extend(("--find-links", link))
|
|
# If requirement is a PEP 508 direct URL, directly pass
|
|
# the URL to pip, as `req @ url` does not work on the
|
|
# command line.
|
|
if req.url:
|
|
cmd.append(req.url)
|
|
else:
|
|
cmd.append(str(req))
|
|
try:
|
|
subprocess.check_call(cmd)
|
|
except subprocess.CalledProcessError as e:
|
|
raise DistutilsError(str(e))
|
|
wheel = Wheel(glob.glob(os.path.join(tmpdir, "*.whl"))[0])
|
|
dist_location = os.path.join(eggs_dir, wheel.egg_name())
|
|
wheel.install_as_egg(dist_location)
|
|
dist_metadata = pkg_resources.PathMetadata(
|
|
dist_location, os.path.join(dist_location, "EGG-INFO")
|
|
)
|
|
dist = pkg_resources.Distribution.from_filename(
|
|
dist_location, metadata=dist_metadata
|
|
)
|
|
return dist
|
|
|
|
|
|
def strip_marker(req):
|
|
"""
|
|
Return a new requirement without the environment marker to avoid
|
|
calling pip with something like `babel; extra == "i18n"`, which
|
|
would always be ignored.
|
|
"""
|
|
# create a copy to avoid mutating the input
|
|
req = pkg_resources.Requirement.parse(str(req))
|
|
req.marker = None
|
|
return req
|