From 061954f29de70ed9bc9e58845f73acd2d5637e67 Mon Sep 17 00:00:00 2001 From: hetmankp Date: Mon, 1 Oct 2012 18:27:35 +1000 Subject: [PATCH 1/4] Added --root command line option, works the same as for distutils --- pip/commands/install.py | 9 ++++++++- pip/req.py | 20 +++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/pip/commands/install.py b/pip/commands/install.py index 9900c434a..99947bdff 100644 --- a/pip/commands/install.py +++ b/pip/commands/install.py @@ -172,6 +172,13 @@ class InstallCommand(Command): action='store_true', help="Install as self contained egg file, like easy_install does.") + self.parser.add_option( + '--root', + dest='root_path', + metavar='DIR', + default=None, + help="Install everything relative to this alternate root directory") + def _build_package_finder(self, options, index_urls): """ Create a package finder appropriate to this install command. @@ -258,7 +265,7 @@ class InstallCommand(Command): requirement_set.locate_files() if not options.no_install and not self.bundle: - requirement_set.install(install_options, global_options) + requirement_set.install(install_options, global_options, root=options.root_path) installed = ' '.join([req.name for req in requirement_set.successfully_installed]) if installed: diff --git a/pip/req.py b/pip/req.py index e814d3990..fe6747837 100644 --- a/pip/req.py +++ b/pip/req.py @@ -8,6 +8,7 @@ import shutil import tempfile import zipfile +from distutils.util import change_root from pip.locations import bin_py, running_under_virtualenv from pip.exceptions import (InstallationError, UninstallationError, BestVersionAlreadyInstalled, @@ -557,7 +558,7 @@ exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec')) name = name.replace(os.path.sep, '/') return name - def install(self, install_options, global_options=()): + def install(self, install_options, global_options=(), root=None): if self.editable: self.install_editable(install_options, global_options) return @@ -576,6 +577,9 @@ exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec')) if not self.as_egg: install_args += ['--single-version-externally-managed'] + if root is not None: + install_args += ['--root', root] + if running_under_virtualenv(): ## FIXME: I'm not sure if this is a reasonable location; probably not ## but we can't put it in the default location, as that is a virtualenv symlink that isn't writable @@ -598,11 +602,17 @@ exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec')) # so we unable to save the installed-files.txt return + def prepend_root(path): + if root is None or not os.path.isabs(path): + return path + else: + return change_root(root, path) + f = open(record_filename) for line in f: line = line.strip() if line.endswith('.egg-info'): - egg_info_dir = line + egg_info_dir = prepend_root(line) break else: logger.warn('Could not find .egg-info directory in install record for %s' % self) @@ -616,7 +626,7 @@ exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec')) filename = line.strip() if os.path.isdir(filename): filename += os.path.sep - new_lines.append(make_path_relative(filename, egg_info_dir)) + new_lines.append(make_path_relative(prepend_root(filename), egg_info_dir)) f.close() f = open(os.path.join(egg_info_dir, 'installed-files.txt'), 'w') f.write('\n'.join(new_lines)+'\n') @@ -1145,7 +1155,7 @@ class RequirementSet(object): _write_delete_marker_message(os.path.join(location, PIP_DELETE_MARKER_FILENAME)) return retval - def install(self, install_options, global_options=()): + def install(self, install_options, global_options=(), *args, **kwargs): """Install everything in this set (after having downloaded and unpacked the packages)""" to_install = [r for r in self.requirements.values() if not r.satisfied_by] @@ -1164,7 +1174,7 @@ class RequirementSet(object): finally: logger.indent -= 2 try: - requirement.install(install_options, global_options) + requirement.install(install_options, global_options, *args, **kwargs) except: # if install did not succeed, rollback previous uninstall if requirement.conflicts_with and not requirement.install_succeeded: From 1faa0c1876a0cd1ea64e975134c0e935b1f48602 Mon Sep 17 00:00:00 2001 From: hetmankp Date: Tue, 2 Oct 2012 13:55:56 +1000 Subject: [PATCH 2/4] Simple test to check --root option functionality --- tests/test_basic.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_basic.py b/tests/test_basic.py index e1b990a35..4478941fb 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -491,6 +491,17 @@ def test_install_package_with_target(): assert Path('scratch')/'target'/'initools' in result.files_created, str(result) +def test_install_package_with_root(): + """ + Test installing a package using pip install --root + """ + env = reset_env() + root_dir = env.scratch_path/'root' + result = run_pip('install', '--root', root_dir, '--install-option=--home=', "initools==0.1") + + assert Path('scratch')/'root'/'lib'/'python'/'initools' in result.files_created, str(result) + + def test_find_command_folder_in_path(): """ If a folder named e.g. 'git' is in PATH, and find_command is looking for From 294d4aefbc61c219f05c67d9a147bed91d53e5ce Mon Sep 17 00:00:00 2001 From: hetmankp Date: Wed, 3 Oct 2012 16:07:21 +1000 Subject: [PATCH 3/4] PyPy is special and overrides default distutils directory scheme, alter test to suit --- tests/test_basic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index 4478941fb..d5a054b14 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -497,7 +497,8 @@ def test_install_package_with_root(): """ env = reset_env() root_dir = env.scratch_path/'root' - result = run_pip('install', '--root', root_dir, '--install-option=--home=', "initools==0.1") + result = run_pip('install', '--root', root_dir, '--install-option=--home=', + '--install-option=--install-lib=/lib/python', "initools==0.1") assert Path('scratch')/'root'/'lib'/'python'/'initools' in result.files_created, str(result) From 0b2a01bb46923e5a9138237b2cc47b6ed22bc9ca Mon Sep 17 00:00:00 2001 From: hetmankp Date: Mon, 29 Oct 2012 12:59:52 +1100 Subject: [PATCH 4/4] Added author name and description of changes --- AUTHORS.txt | 1 + docs/news.txt | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index b567d7ee1..636fcd254 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -47,6 +47,7 @@ Paul van der Linden Peter Waller Phil Whelan Piet Delport +Przemek Wrzos Qiangning Hong Rafael Caricio Rene Dudfield diff --git a/docs/news.txt b/docs/news.txt index d512783b5..1f92adecb 100644 --- a/docs/news.txt +++ b/docs/news.txt @@ -25,6 +25,10 @@ develop (unreleased) * Added "pip show" command to get information about an installed package. Fixes #131. Thanks Kelsey Hightower and Rafael Caricio. +* Added `--root` option for "pip install" to specify root directory. Behaves + like the same option in distutils but also plays nice with pip's egg-info. + (Issue #253) + 1.2.1 (2012-09-06) ------------------