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):
"""