diff --git a/docs/news.txt b/docs/news.txt index fae899c657a..b088a724b2e 100644 --- a/docs/news.txt +++ b/docs/news.txt @@ -5,7 +5,7 @@ News Next Release ============ -Beta and final releases of 1.3 are planned for the end of 2012. +Beta and final releases of 1.3 are planned for Feb 2013. .. include:: ../CHANGES.txt diff --git a/pip/locations.py b/pip/locations.py index d378dd73997..36efdcaa9e5 100644 --- a/pip/locations.py +++ b/pip/locations.py @@ -4,7 +4,9 @@ import site import os import tempfile +import getpass from pip.backwardcompat import get_python_lib +import pip.exceptions def running_under_virtualenv(): @@ -25,6 +27,31 @@ def virtualenv_no_global(): if running_under_virtualenv() and os.path.isfile(no_global_file): return True +def _get_build_prefix(): + """ Returns a safe build_prefix """ + path = os.path.join(tempfile.gettempdir(), 'pip-build-%s' % \ + getpass.getuser()) + if sys.platform == 'win32': + """ on windows(tested on 7) temp dirs are isolated """ + return path + try: + os.mkdir(path) + except OSError: + file_uid = None + try: + fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) + file_uid = os.fstat(fd).st_uid + os.close(fd) + except OSError: + file_uid = None + if file_uid != os.getuid(): + msg = "The temporary folder for building (%s) is not owned by your user!" \ + % path + print (msg) + print("pip will not work until the temporary folder is " + \ + "either deleted or owned by your user account.") + raise pip.exceptions.InstallationError(msg) + return path if running_under_virtualenv(): build_prefix = os.path.join(sys.prefix, 'build') @@ -33,7 +60,7 @@ def virtualenv_no_global(): # Use tempfile to create a temporary folder for build # Note: we are NOT using mkdtemp so we can have a consistent build dir # Note: using realpath due to tmp dirs on OSX being symlinks - build_prefix = os.path.realpath(os.path.join(tempfile.gettempdir(), 'pip-build')) + build_prefix = os.path.realpath(_get_build_prefix()) ## FIXME: keep src in cwd for now (it is not a temporary folder) try: diff --git a/tests/test_locations.py b/tests/test_locations.py new file mode 100644 index 00000000000..50b9cdf0a82 --- /dev/null +++ b/tests/test_locations.py @@ -0,0 +1,81 @@ +""" +locations.py tests + +""" +import os +import sys +import shutil +import tempfile +import getpass +from mock import Mock +import pip + +class TestLocations: + def setup(self): + self.tempdir = tempfile.mkdtemp() + self.st_uid = 9999 + self.username = "example" + self.patch() + + def tearDown(self): + self.revert_patch() + shutil.rmtree(self.tempdir, ignore_errors=True) + + def patch(self): + """ first store and then patch python methods pythons """ + self.tempfile_gettempdir = tempfile.gettempdir + self.old_os_fstat = os.fstat + self.old_os_getuid = os.getuid + self.old_getpass_getuser = getpass.getuser + + # now patch + tempfile.gettempdir = lambda : self.tempdir + getpass.getuser = lambda : self.username + os.getuid = lambda : self.st_uid + os.fstat = lambda fd : self.get_mock_fstat(fd) + + def revert_patch(self): + """ revert the patches to python methods """ + tempfile.gettempdir = self.tempfile_gettempdir + getpass.getuser = self.old_getpass_getuser + os.getuid = self.old_os_getuid + os.fstat = self.old_os_fstat + + def get_mock_fstat(self, fd): + """ returns a basic mock fstat call result. + Currently only the st_uid attribute has been set. + """ + result = Mock() + result.st_uid = self.st_uid + return result + + def get_build_dir_location(self): + """ returns a string pointing to the + current build_prefix. + """ + return os.path.join(self.tempdir, 'pip-build-%s' % self.username) + + def test_dir_created(self): + """ test that the build_prefix directory is generated when + _get_build_prefix is called. + """ + + assert not os.path.exists(self.get_build_dir_location() ), \ + "the build_prefix directory should not exist yet!" + from pip import locations + locations._get_build_prefix() + assert os.path.exists(self.get_build_dir_location() ), \ + "the build_prefix directory should now exist!" + + def test_error_raised_when_owned_by_another(self): + """ test calling _get_build_prefix when there is a temporary + directory owned by another user raises an InstallationError. + """ + from pip import locations + os.getuid = lambda : 1111 + os.mkdir(self.get_build_dir_location() ) + try: + locations._get_build_prefix() + raise AssertionError("An InstallationError should have been raised!") + except pip.exceptions.InstallationError: + pass