diff --git a/pip/commands/install.py b/pip/commands/install.py index c95594ff846..d126e64a2a5 100644 --- a/pip/commands/install.py +++ b/pip/commands/install.py @@ -51,7 +51,11 @@ def __init__(self, *args, **kw): dest='target_dir', metavar='dir', default=None, - help='Install packages into .') + help='Install packages into . ' + 'By default this will not replace existing files/folders in ' + '. Use --upgrade to replace existing packages in ' + 'with new versions.' + ) cmd_opts.add_option( '-d', '--download', '--download-dir', '--download-directory', @@ -344,9 +348,32 @@ def run(self, options, args): os.makedirs(options.target_dir) lib_dir = distutils_scheme('', home=temp_target_dir)['purelib'] for item in os.listdir(lib_dir): + target_item_dir = os.path.join(options.target_dir, item) + if os.path.exists(target_item_dir): + if not options.upgrade: + logger.warn( + 'Target directory %s already exists. Specify ' + '--upgrade to force replacement.' + % target_item_dir + ) + continue + if os.path.islink(target_item_dir): + logger.warn( + 'Target directory %s already exists and is ' + 'a link. Pip will not automatically replace ' + 'links, please remove if replacement is ' + 'desired.' + % target_item_dir + ) + continue + if os.path.isdir(target_item_dir): + shutil.rmtree(target_item_dir) + else: + os.remove(target_item_dir) + shutil.move( os.path.join(lib_dir, item), - os.path.join(options.target_dir, item), + target_item_dir ) shutil.rmtree(temp_target_dir) return requirement_set diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py index 07f6a6f5b98..8a0a5b19781 100644 --- a/tests/functional/test_install.py +++ b/tests/functional/test_install.py @@ -527,6 +527,33 @@ def test_install_package_with_target(script): str(result) ) + # Test repeated call without --upgrade, no files should have changed + result = script.pip('install', '-t', target_dir, "initools==0.1") + assert not Path('scratch') / 'target' / 'initools' in result.files_updated + + # Test upgrade call, check that new version is installed + result = script.pip('install', '--upgrade', '-t', + target_dir, "initools==0.2") + assert Path('scratch') / 'target' / 'initools' in result.files_updated, ( + str(result) + ) + egg_folder = ( + Path('scratch') / 'target' / 'INITools-0.2-py%s.egg-info' % pyversion) + assert egg_folder in result.files_created, ( + str(result) + ) + + # Test install and upgrade of single-module package + result = script.pip('install', '-t', target_dir, 'six') + assert Path('scratch') / 'target' / 'six.py' in result.files_created, ( + str(result) + ) + + result = script.pip('install', '-t', target_dir, '--upgrade', 'six') + assert Path('scratch') / 'target' / 'six.py' in result.files_updated, ( + str(result) + ) + def test_install_package_with_root(script, data): """