Merge "Use pip instead of easy_install for installation."
This commit is contained in:
commit
6c91a6f0f0
@ -45,4 +45,4 @@ class CommandsConfig(base.BaseConfig):
|
|||||||
self.pbr_config, 'use-egg', 'PBR_USE_EGG')
|
self.pbr_config, 'use-egg', 'PBR_USE_EGG')
|
||||||
# We always want non-egg install unless explicitly requested
|
# We always want non-egg install unless explicitly requested
|
||||||
if 'manpages' in self.pbr_config or not use_egg:
|
if 'manpages' in self.pbr_config or not use_egg:
|
||||||
self.add_command('pbr.packaging.DistutilsInstall')
|
self.add_command('pbr.packaging.LocalInstall')
|
||||||
|
128
pbr/packaging.py
128
pbr/packaging.py
@ -28,14 +28,15 @@ import sys
|
|||||||
|
|
||||||
from d2to1.extern import six
|
from d2to1.extern import six
|
||||||
from distutils.command import install as du_install
|
from distutils.command import install as du_install
|
||||||
|
import distutils.errors
|
||||||
from distutils import log
|
from distutils import log
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
from setuptools.command import easy_install
|
|
||||||
from setuptools.command import install
|
from setuptools.command import install
|
||||||
from setuptools.command import sdist
|
from setuptools.command import sdist
|
||||||
|
|
||||||
log.set_verbosity(log.INFO)
|
log.set_verbosity(log.INFO)
|
||||||
TRUE_VALUES = ['true', '1', 'yes']
|
TRUE_VALUES = ('true', '1', 'yes')
|
||||||
|
REQUIREMENTS_FILES = ('requirements.txt', 'tools/pip-requires')
|
||||||
|
|
||||||
|
|
||||||
def append_text_list(config, key, text_list):
|
def append_text_list(config, key, text_list):
|
||||||
@ -60,6 +61,41 @@ def _parse_mailmap(mailmap_info):
|
|||||||
return mapping
|
return mapping
|
||||||
|
|
||||||
|
|
||||||
|
def _wrap_in_quotes(values):
|
||||||
|
return ["'%s'" % value for value in values]
|
||||||
|
|
||||||
|
|
||||||
|
def _make_links_args(links):
|
||||||
|
return ["-f '%s'" % link for link in links]
|
||||||
|
|
||||||
|
|
||||||
|
def _missing_requires(requires):
|
||||||
|
"""Return the list of requirements that are not already installed.
|
||||||
|
|
||||||
|
Do this check explicitly, because it's very easy to see if a package
|
||||||
|
is in the current working set, to avoid shelling out to pip and attempting
|
||||||
|
an install. pip will do the right thing, but we don't need to do the
|
||||||
|
excess work on everyone's machines all the time (especially since tox
|
||||||
|
likes re-installing things a lot)
|
||||||
|
"""
|
||||||
|
return [r for r in requires
|
||||||
|
if not pkg_resources.working_set.find(
|
||||||
|
pkg_resources.Requirement.parse(r))]
|
||||||
|
|
||||||
|
|
||||||
|
def _pip_install(links, requires, root=None):
|
||||||
|
root_cmd = ""
|
||||||
|
if root:
|
||||||
|
root_cmd = "--root=%s" % root
|
||||||
|
_run_shell_command(
|
||||||
|
"%s -m pip install %s %s %s" % (
|
||||||
|
sys.executable,
|
||||||
|
root_cmd,
|
||||||
|
" ".join(links),
|
||||||
|
" ".join(_wrap_in_quotes(_missing_requires(requires)))),
|
||||||
|
throw_on_error=True, buffer=False)
|
||||||
|
|
||||||
|
|
||||||
def read_git_mailmap(git_dir, mailmap='.mailmap'):
|
def read_git_mailmap(git_dir, mailmap='.mailmap'):
|
||||||
mailmap = os.path.join(git_dir, mailmap)
|
mailmap = os.path.join(git_dir, mailmap)
|
||||||
if os.path.exists(mailmap):
|
if os.path.exists(mailmap):
|
||||||
@ -85,8 +121,7 @@ def get_reqs_from_files(requirements_files):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def parse_requirements(requirements_files=['requirements.txt',
|
def parse_requirements(requirements_files=REQUIREMENTS_FILES):
|
||||||
'tools/pip-requires']):
|
|
||||||
|
|
||||||
def egg_fragment(match):
|
def egg_fragment(match):
|
||||||
# take a versioned egg fragment and return a
|
# take a versioned egg fragment and return a
|
||||||
@ -127,8 +162,7 @@ def parse_requirements(requirements_files=['requirements.txt',
|
|||||||
return requirements
|
return requirements
|
||||||
|
|
||||||
|
|
||||||
def parse_dependency_links(requirements_files=['requirements.txt',
|
def parse_dependency_links(requirements_files=REQUIREMENTS_FILES):
|
||||||
'tools/pip-requires']):
|
|
||||||
dependency_links = []
|
dependency_links = []
|
||||||
# dependency_links inject alternate locations to find packages listed
|
# dependency_links inject alternate locations to find packages listed
|
||||||
# in requirements
|
# in requirements
|
||||||
@ -145,21 +179,27 @@ def parse_dependency_links(requirements_files=['requirements.txt',
|
|||||||
return dependency_links
|
return dependency_links
|
||||||
|
|
||||||
|
|
||||||
def _run_shell_command(cmd, throw_on_error=False):
|
def _run_shell_command(cmd, throw_on_error=False, buffer=True):
|
||||||
|
if buffer:
|
||||||
|
out_location = subprocess.PIPE
|
||||||
|
err_location = subprocess.PIPE
|
||||||
|
else:
|
||||||
|
out_location = None
|
||||||
|
err_location = None
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
output = subprocess.Popen(["cmd.exe", "/C", cmd],
|
output = subprocess.Popen(["cmd.exe", "/C", cmd],
|
||||||
stdout=subprocess.PIPE,
|
stdout=out_location,
|
||||||
stderr=subprocess.PIPE)
|
stderr=err_location)
|
||||||
else:
|
else:
|
||||||
output = subprocess.Popen(["/bin/sh", "-c", cmd],
|
output = subprocess.Popen(["/bin/sh", "-c", cmd],
|
||||||
stdout=subprocess.PIPE,
|
stdout=out_location,
|
||||||
stderr=subprocess.PIPE)
|
stderr=err_location)
|
||||||
out = output.communicate()
|
out = output.communicate()
|
||||||
if output.returncode and throw_on_error:
|
if output.returncode and throw_on_error:
|
||||||
raise Exception("%s returned %d" % cmd, output.returncode)
|
raise distutils.errors.DistutilsError(
|
||||||
if len(out) == 0:
|
"%s returned %d" % (cmd, output.returncode))
|
||||||
return None
|
if len(out) == 0 or not out[0] or not out[0].strip():
|
||||||
if len(out[0].strip()) == 0:
|
|
||||||
return None
|
return None
|
||||||
return out[0].strip().decode('utf-8')
|
return out[0].strip().decode('utf-8')
|
||||||
|
|
||||||
@ -245,48 +285,30 @@ def _find_modules(arg, dirname, files):
|
|||||||
filename[:-3])] = True
|
filename[:-3])] = True
|
||||||
|
|
||||||
|
|
||||||
class DistutilsInstall(install.install):
|
class LocalInstall(install.install):
|
||||||
"""Forces single-version-externally-managed."""
|
"""Runs python setup.py install in a sensible manner.
|
||||||
|
|
||||||
|
Force a non-egg installed in the manner of
|
||||||
|
single-version-externally-managed, which allows us to install manpages
|
||||||
|
and config files.
|
||||||
|
|
||||||
|
Because non-egg installs bypass the depend processing machinery, we
|
||||||
|
need to do our own. Because easy_install is evil, just use pip to
|
||||||
|
process our requirements files directly, which means we don't have to
|
||||||
|
do crazy extra processing.
|
||||||
|
|
||||||
|
Bypass installation if --single-version-externally-managed is given,
|
||||||
|
so that behavior for packagers remains the same.
|
||||||
|
"""
|
||||||
|
|
||||||
command_name = 'install'
|
command_name = 'install'
|
||||||
|
|
||||||
def fetch_build_egg(self, req):
|
|
||||||
"""Fetch an egg needed for building."""
|
|
||||||
try:
|
|
||||||
cmd = self._egg_fetcher
|
|
||||||
cmd.package_index.to_scan = []
|
|
||||||
except AttributeError:
|
|
||||||
dist = self.distribution.__class__(
|
|
||||||
{'script_args': ['easy_install']})
|
|
||||||
dist.parse_config_files()
|
|
||||||
opts = dist.get_option_dict('easy_install')
|
|
||||||
keep = (
|
|
||||||
'find_links', 'site_dirs', 'index_url', 'optimize',
|
|
||||||
'site_dirs', 'allow_hosts'
|
|
||||||
)
|
|
||||||
for key in opts.keys():
|
|
||||||
if key not in keep:
|
|
||||||
del opts[key] # don't use any other settings
|
|
||||||
if self.distribution.dependency_links:
|
|
||||||
links = self.distribution.dependency_links[:]
|
|
||||||
if 'find_links' in opts:
|
|
||||||
links = opts['find_links'][1].split() + links
|
|
||||||
opts['find_links'] = ('setup', links)
|
|
||||||
cmd = easy_install.easy_install(
|
|
||||||
dist, args=["x"],
|
|
||||||
always_copy=False, build_directory=None, editable=False,
|
|
||||||
upgrade=False, multi_version=True, no_report=True
|
|
||||||
)
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
self._egg_fetcher = cmd
|
|
||||||
return cmd.easy_install(req)
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
for dist in pkg_resources.working_set.resolve(
|
if (not self.single_version_externally_managed
|
||||||
pkg_resources.parse_requirements(
|
and self.distribution.install_requires):
|
||||||
self.distribution.install_requires),
|
links = _make_links_args(self.distribution.dependency_links)
|
||||||
installer=self.fetch_build_egg):
|
_pip_install(links, self.distribution.install_requires, self.root)
|
||||||
pkg_resources.working_set.add(dist)
|
|
||||||
return du_install.install.run(self)
|
return du_install.install.run(self)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
d2to1>=0.2.10,<0.3
|
d2to1>=0.2.10,<0.3
|
||||||
distribute
|
distribute<0.7
|
||||||
setuptools_git>=0.4
|
setuptools_git>=0.4
|
||||||
|
13
setup.py
13
setup.py
@ -14,6 +14,19 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
sys.path += [x for x in os.listdir(".") if x.endswith(".egg")]
|
||||||
|
import d2to1 # flake8: noqa
|
||||||
|
except ImportError:
|
||||||
|
import subprocess
|
||||||
|
if not subprocess.call(
|
||||||
|
[sys.executable] +
|
||||||
|
"-m pip.__init__ install distribute<0.7 d2to1>=0.2.10,<0.3".split()
|
||||||
|
):
|
||||||
|
sys.exit(subprocess.call([sys.executable] + sys.argv))
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
|
Loading…
Reference in New Issue
Block a user