diff --git a/pip/commands/install.py b/pip/commands/install.py index 52062c32c64..07d0efa77ee 100644 --- a/pip/commands/install.py +++ b/pip/commands/install.py @@ -15,6 +15,7 @@ InstallationError, CommandError, PreviousBuildDirError, ) from pip import cmdoptions +from pip.utils import default_user_site from pip.utils.build import BuildDirectory from pip.utils.deprecation import RemovedInPip7Warning, RemovedInPip8Warning @@ -126,6 +127,12 @@ def __init__(self, *args, **kw): action='store_true', help='Install using the user scheme.') + cmd_opts.add_option( + '--global', + dest='use_user_site', + action='store_false', + help='Install into the global site packages.') + cmd_opts.add_option( '--egg', dest='as_egg', @@ -224,6 +231,13 @@ def run(self, options, args): options.src_dir = os.path.abspath(options.src_dir) install_options = options.install_options or [] + + # If we don't have an explicitly selected --user or --global then we + # want to execute our fallback code to determine what we're going to + # use. + if options.use_user_site is None: + options.use_user_site = default_user_site() + if options.use_user_site: if virtualenv_no_global(): raise InstallationError( diff --git a/pip/utils/__init__.py b/pip/utils/__init__.py index 164e54c7522..ec52c8a2bf6 100644 --- a/pip/utils/__init__.py +++ b/pip/utils/__init__.py @@ -7,6 +7,7 @@ import os import posixpath import shutil +import site import stat import subprocess import sys @@ -39,7 +40,7 @@ 'make_path_relative', 'normalize_path', 'renames', 'get_terminal_size', 'get_prog', 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess', - 'captured_stdout', 'remove_tracebacks'] + 'captured_stdout', 'remove_tracebacks', 'default_user_site'] logger = logging.getLogger(__name__) @@ -54,6 +55,37 @@ def get_prog(): return 'pip' +def default_user_site(): + # Avoid circular import, the running_under_virtualenv should probably be + # in pip.utils anyways TBH. + from pip.locations import running_under_virtualenv, distutils_scheme + + # If we're running inside of a virtual environment, we do not want to + # install to the --user directory. + if running_under_virtualenv(): + return False + + # If the Python we're running under does not have their user packages + # enabled then we do not want to install to the user directory since it + # may or may not work or exist. + if not site.ENABLE_USER_SITE: + return False + + # If any of our potentional locations for writing files is not writable by + # us then we want to use the --user scheme instead of the --global scheme. + # TODO: We should figure out a way to make this work for --root and + # --isolated and such options as well. + # TODO: Figure out if this works when the directories don't exist. + for path in distutils_scheme("").values(): + if not os.access(path, os.W_OK): + return True + + # If we get to this point, then we will assume that we want to use + # --global, as that is the most backwards compatible policy and it will + # mean that ``sudo pip install`` continues to work as it had previously. + return False + + # Retry every half second for up to 3 seconds @retry(stop_max_delay=3000, wait_fixed=500) def rmtree(dir, ignore_errors=False):