Skip to content

Commit acf8634

Browse files
committed
Fixing issues with install's --target option.
1. Check for the existence of a directory before copying from temporary directory to final target. If it exists, warn the user. 2. If the user specifies the --upgrade option and the directory exists, delete it and continue with installation. 3. Adding tests for above cases. This resolves pypa#1489, pypa#1710 completely and parts of pypa#1833.
1 parent 4b6b7c7 commit acf8634

File tree

2 files changed

+28
-2
lines changed

2 files changed

+28
-2
lines changed

pip/commands/install.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ def __init__(self, *args, **kw):
5151
dest='target_dir',
5252
metavar='dir',
5353
default=None,
54-
help='Install packages into <dir>.')
54+
help='Install packages into <dir>. '
55+
'By default this will not replace existing files/folders in <dir>.'
56+
'Use --upgrade to replace existing packages in <dir> with new versions.'
57+
)
5558

5659
cmd_opts.add_option(
5760
'-d', '--download', '--download-dir', '--download-directory',
@@ -344,9 +347,19 @@ def run(self, options, args):
344347
os.makedirs(options.target_dir)
345348
lib_dir = distutils_scheme('', home=temp_target_dir)['purelib']
346349
for item in os.listdir(lib_dir):
350+
target_item_dir = os.path.join(options.target_dir, item)
351+
if os.path.exists(target_item_dir):
352+
if not options.upgrade:
353+
logger.warn('Target directory %s already exists. Specify --upgrade to force replacement.' % target_item_dir)
354+
continue
355+
if not os.path.isdir(target_item_dir):
356+
logger.warn('Target directory %s already exists and is not a directory. Please remove in order for replacement.' % target_item_dir)
357+
continue
358+
shutil.rmtree(target_item_dir)
359+
347360
shutil.move(
348361
os.path.join(lib_dir, item),
349-
os.path.join(options.target_dir, item),
362+
target_item_dir
350363
)
351364
shutil.rmtree(temp_target_dir)
352365
return requirement_set

tests/functional/test_install.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,19 @@ def test_install_package_with_target(script):
527527
str(result)
528528
)
529529

530+
# Test repeated call without --upgrade, no files should have changed
531+
result = script.pip('install', '-t', target_dir, "initools==0.1")
532+
assert not Path('scratch') / 'target' / 'initools' in result.files_updated
533+
534+
# Test upgrade call, check that new version is installed
535+
result = script.pip('install', '--upgrade', '-t', target_dir, "initools==0.2")
536+
assert Path('scratch') / 'target' / 'initools' in result.files_updated, (
537+
str(result)
538+
)
539+
assert Path('scratch') / 'target' / 'INITools-0.2-py%s.egg-info' % pyversion in result.files_created, (
540+
str(result)
541+
)
542+
530543

531544
def test_install_package_with_root(script, data):
532545
"""

0 commit comments

Comments
 (0)