Repository: pypa/pip

Issue:
pip --root=... doesn't work with wheel
The pip --root=... flag should move install paths to the named directory, but when installing from wheel pip ignores it.



Discussion:
```
$ pip install --use-wheel --no-deps python-fedora --root test/
Downloading/unpacking python-fedora
  Downloading python_fedora-0.3.32.3-py27-none-any.whl (128kB): 128kB downloaded
  Storing download in cache at /Users/dstufft/.pip/cache/https%3A%2F%2Fpypi.python.org%2Fpackages%2F2.7%2Fp%2Fpython-fedora%2Fpython_fedora-0.3.32.3-py27-none-any.whl
Installing collected packages: python-fedora
Successfully installed python-fedora
Cleaning up...
$ ls test/
$ ls ls $VIRTUAL_ENV/lib/python2.7/site-packages/fedora*
__init__.py  client       django       release.py   tg           urlutils.py
accounts     compat25     iterutils.py textutils.py tg2          wsgi
```

This needs to be fixed for pip 1.5.


Resolving patch:
diff --git a/pip/locations.py b/pip/locations.py
--- a/pip/locations.py
+++ b/pip/locations.py
@@ -127,7 +127,7 @@ def _get_build_prefix():
         default_log_file = os.path.join(user_dir, 'Library/Logs/pip.log')
 
 
-def distutils_scheme(dist_name, user=False, home=None):
+def distutils_scheme(dist_name, user=False, home=None, root=None):
     """
     Return a distutils install scheme
     """
@@ -141,6 +141,7 @@ def distutils_scheme(dist_name, user=False, home=None):
     # ideally, we'd prefer a scheme class that has no side-effects.
     i.user = user or i.user
     i.home = home or i.home
+    i.root = root or i.root
     i.finalize_options()
     for key in SCHEME_KEYS:
         scheme[key] = getattr(i, 'install_'+key)
@@ -152,4 +153,10 @@ def distutils_scheme(dist_name, user=False, home=None):
                                     'python' + sys.version[:3],
                                     dist_name)
 
+        if root is not None:
+            scheme["headers"] = os.path.join(
+                root,
+                os.path.abspath(scheme["headers"])[1:],
+            )
+
     return scheme
diff --git a/pip/req.py b/pip/req.py
--- a/pip/req.py
+++ b/pip/req.py
@@ -612,7 +612,7 @@ def install(self, install_options, global_options=(), root=None):
             self.install_editable(install_options, global_options)
             return
         if self.is_wheel:
-            self.move_wheel_files(self.source_dir)
+            self.move_wheel_files(self.source_dir, root=root)
             self.install_succeeded = True
             return
 
@@ -831,8 +831,13 @@ def move_bundle_files(self, dest_build_dir, dest_src_dir):
         self._bundle_build_dirs = bundle_build_dirs
         self._bundle_editable_dirs = bundle_editable_dirs
 
-    def move_wheel_files(self, wheeldir):
-        move_wheel_files(self.name, self.req, wheeldir, user=self.use_user_site, home=self.target_dir)
+    def move_wheel_files(self, wheeldir, root=None):
+        move_wheel_files(
+            self.name, self.req, wheeldir,
+            user=self.use_user_site,
+            home=self.target_dir,
+            root=root,
+        )
 
     @property
     def delete_marker_filename(self):
diff --git a/pip/wheel.py b/pip/wheel.py
--- a/pip/wheel.py
+++ b/pip/wheel.py
@@ -103,10 +103,10 @@ def root_is_purelib(name, wheeldir):
                         return True
     return False
 
-def move_wheel_files(name, req, wheeldir, user=False, home=None):
+def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None):
     """Install a wheel"""
 
-    scheme = distutils_scheme(name, user=user, home=home)
+    scheme = distutils_scheme(name, user=user, home=home, root=root)
 
     if root_is_purelib(name, wheeldir):
         lib_dir = scheme['purelib']


Test patch:
diff --git a/tests/functional/test_install_wheel.py b/tests/functional/test_install_wheel.py
--- a/tests/functional/test_install_wheel.py
+++ b/tests/functional/test_install_wheel.py
@@ -57,6 +57,16 @@ def test_install_wheel_with_target(script, data):
     assert Path('scratch')/'target'/'simpledist' in result.files_created, str(result)
 
 
+def test_install_wheel_with_root(script, data):
+    """
+    Test installing a wheel using pip install --root
+    """
+    root_dir = script.scratch_path/'root'
+    result = script.pip('install', 'simple.dist==0.1', '--root', root_dir, '--use-wheel',
+                     '--no-index', '--find-links='+data.find_links)
+    assert Path('scratch')/'root' in result.files_created
+
+
 def test_install_from_wheel_installs_deps(script, data):
     """
     Test can install dependencies of wheels
diff --git a/tests/unit/test_locations.py b/tests/unit/test_locations.py
--- a/tests/unit/test_locations.py
+++ b/tests/unit/test_locations.py
@@ -13,6 +13,8 @@
 from mock import Mock
 import pip
 
+from pip.locations import distutils_scheme
+
 if sys.platform == 'win32':
    pwd = Mock()
 else:
@@ -120,3 +122,14 @@ def test_no_error_raised_when_owned_by_you(self):
         from pip import locations
         os.mkdir(self.get_build_dir_location())
         locations._get_build_prefix()
+
+
+class TestDisutilsScheme:
+
+    def test_root_modifies_appropiately(self):
+        norm_scheme = distutils_scheme("example")
+        root_scheme = distutils_scheme("example", root="/test/root/")
+
+        for key, value in norm_scheme.items():
+            expected = os.path.join("/test/root/", os.path.abspath(value)[1:])
+            assert root_scheme[key] == expected