summaryrefslogtreecommitdiff
path: root/setuptools/command/easy_install.py
diff options
context:
space:
mode:
authorPJ Eby <distutils-sig@python.org>2006-02-13 18:09:47 +0000
committerPJ Eby <distutils-sig@python.org>2006-02-13 18:09:47 +0000
commitcef2b2986e6c3cfc7606c7f774c43f3189eb35ff (patch)
treebb6d6460af591e9a05ec28cac5534a02c966b884 /setuptools/command/easy_install.py
parent49c03612e7eb1a75ec836c574f6d1711fb6ecebf (diff)
downloadpython-setuptools-git-cef2b2986e6c3cfc7606c7f774c43f3189eb35ff.tar.gz
Added exhaustive testing of the install directory, including a spawn test
for ``.pth`` file support, and directory writability/existence checks. This should virtually eliminate the need to set or configure ``--site-dirs``. --HG-- branch : setuptools extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4042346
Diffstat (limited to 'setuptools/command/easy_install.py')
-rwxr-xr-xsetuptools/command/easy_install.py171
1 files changed, 147 insertions, 24 deletions
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index 45b204a5..34d362ab 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -155,22 +155,7 @@ class easy_install(Command):
)
else:
self.all_site_dirs.append(normalize_path(d))
- instdir = normalize_path(self.install_dir)
- if instdir in self.all_site_dirs:
- if self.pth_file is None:
- self.pth_file = PthDistributions(
- os.path.join(instdir,'easy-install.pth')
- )
-
- elif not self.multi_version:
- # Can't install non-multi to non-site dir
- raise DistutilsError(self.no_default_version_msg())
-
- if instdir in map(normalize_path, self.site_dirs or []):
- # don't install site.py if install target is already a site dir
- self.sitepy_installed = True
-
- self.install_dir = instdir
+ self.check_site_dir()
self.index_url = self.index_url or "http://www.python.org/pypi"
self.shadow_path = self.all_site_dirs[:]
for path_item in self.install_dir, normalize_path(self.script_dir):
@@ -212,14 +197,12 @@ class easy_install(Command):
raise DistutilsArgError(
"Must specify a build directory (-b) when using --editable"
)
-
if not self.args:
raise DistutilsArgError(
"No urls, filenames, or requirements specified (see --help)")
self.outputs = []
-
def run(self):
if self.verbose<>self.distribution.verbose:
log.set_verbosity(self.verbose)
@@ -242,7 +225,147 @@ class easy_install(Command):
log.set_verbosity(self.distribution.verbose)
+ def pseudo_tempname(self):
+ """Return a pseudo-tempname base in the install directory.
+
+ This code is intentionally naive; if a malicious party can write to
+ the target directory you're already in deep doodoo.
+ """
+ try:
+ pid = os.getpid()
+ except:
+ import random
+ pid = random.randint(0,sys.maxint)
+ return os.path.join(self.install_dir, "test-easy-install-%s" % pid)
+
+
+
+
+
+
+
+ def check_site_dir(self):
+ """Verify that self.install_dir is .pth-capable dir, if needed"""
+
+ instdir = normalize_path(self.install_dir)
+ pth_file = os.path.join(instdir,'easy-install.pth')
+
+ # Is it a configured, PYTHONPATH, implicit, or explicit site dir?
+ is_site_dir = instdir in self.all_site_dirs
+
+ if not is_site_dir:
+ # No? Then directly test whether it does .pth file processing
+ is_site_dir = self.check_pth_processing()
+ else:
+ # make sure we can write to target dir
+ testfile = self.pseudo_tempname()+'.write-test'
+ test_exists = os.path.exists(testfile)
+ try:
+ if test_exists: os.unlink(testfile)
+ open(testfile,'w').close()
+ os.unlink(testfile)
+ except (OSError,IOError):
+ self.cant_write_to_target()
+
+ if not is_site_dir and not self.multi_version:
+ # Can't install non-multi to non-site dir
+ raise DistutilsError(self.no_default_version_msg())
+
+ if is_site_dir:
+ if self.pth_file is None:
+ self.pth_file = PthDistributions(pth_file)
+ else:
+ self.pth_file = None
+
+ PYTHONPATH = os.environ.get('PYTHONPATH','').split(os.pathsep)
+ if instdir not in map(normalize_path, filter(None,PYTHONPATH)):
+ # only PYTHONPATH dirs need a site.py, so pretend it's there
+ self.sitepy_installed = True
+
+ self.install_dir = instdir
+
+
+ def cant_write_to_target(self):
+ msg = """can't create or remove files in install directory
+
+The following error occurred while trying to add or remove files in the
+installation directory:
+
+ %s
+
+The installation directory you specified (via --install-dir, --prefix, or
+the distutils default setting) was:
+
+ %s
+""" % (sys.exc_info()[1], self.install_dir,)
+
+ if not os.path.exists(self.install_dir):
+ msg += """
+This directory does not currently exist. Please create it and try again, or
+choose a different installation directory (using the -d or --install-dir
+option).
+"""
+ else:
+ msg += """
+Perhaps your account does not have write access to this directory? If the
+installation directory is a system-owned directory, you may need to sign in
+as the administrator or "root" account. If you do not have administrative
+access to this machine, you may wish to choose a different installation
+directory, preferably one that is listed in your PYTHONPATH environment
+variable.
+
+For information on other options, you may wish to consult the
+documentation at:
+
+ http://peak.telecommunity.com/EasyInstall.html
+
+Please make the appropriate changes for your system and try again.
+"""
+ raise DistutilsError(msg)
+
+
+
+ def check_pth_processing(self):
+ """Empirically verify whether .pth files are supported in inst. dir"""
+ instdir = self.install_dir
+ log.info("Checking .pth file support in %s", instdir)
+ pth_file = self.pseudo_tempname()+".pth"
+ ok_file = pth_file+'.ok'
+ ok_exists = os.path.exists(ok_file)
+ try:
+ if ok_exists: os.unlink(ok_file)
+ f = open(pth_file,'w')
+ except (OSError,IOError):
+ self.cant_write_to_target()
+ else:
+ try:
+ f.write("import os;open(%r,'w').write('OK')\n" % (ok_file,))
+ f.close(); f=None
+ executable = sys.executable
+ if os.name=='nt':
+ dirname,basename = os.path.split(executable)
+ alt = os.path.join(dirname,'pythonw.exe')
+ if basename.lower()=='python.exe' and os.path.exists(alt):
+ # use pythonw.exe to avoid opening a console window
+ executable = alt
+
+ from distutils.spawn import spawn
+ spawn([executable,'-E','-c','pass'],0)
+
+ if os.path.exists(ok_file):
+ log.info(
+ "TEST PASSED: %s appears to support .pth files",
+ instdir
+ )
+ return True
+ finally:
+ if f: f.close()
+ if os.path.exists(ok_file): os.unlink(ok_file)
+ if os.path.exists(pth_file): os.unlink(pth_file)
+
+ log.warn("TEST FAILED: %s does NOT support .pth files", instdir)
+ return False
def install_egg_scripts(self, dist):
"""Write all the scripts for `dist`, unless scripts are excluded"""
@@ -904,9 +1027,9 @@ See the setuptools documentation for the "develop" command for more info.
return """bad install directory or PYTHONPATH
You are attempting to install a package to a directory that is not
-on PYTHONPATH and is not registered as supporting Python ".pth" files
-by default. The installation directory you specified (via --install-dir,
---prefix, or the distutils default setting) was:
+on PYTHONPATH and which Python does not read ".pth" files from. The
+installation directory you specified (via --install-dir, --prefix, or
+the distutils default setting) was:
%s
@@ -923,9 +1046,8 @@ Here are some of your options for correcting the problem:
variable. (It must then also be on PYTHONPATH whenever you run
Python and want to use the package(s) you are installing.)
-* You can set up the installation directory to support ".pth" files,
- and configure EasyInstall to recognize this, by using one of the
- approaches described here:
+* You can set up the installation directory to support ".pth" files by
+ using one of the approaches described here:
http://peak.telecommunity.com/EasyInstall.html#custom-installation-locations
@@ -941,6 +1063,7 @@ Please make the appropriate changes for your system and try again.""" % (
+
def install_site_py(self):
"""Make sure there's a site.py in the target dir, if needed"""