Commit c8ebbe36 authored by PJ Eby's avatar PJ Eby

Added ``--site-dirs`` option to allow adding custom "site" directories.

Made ``easy-install.pth`` work in platform-specific alternate site
directories (e.g. ``~/Library/Python/2.x/site-packages``).

--HG--
branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4041131
parent 8fffda12
......@@ -575,6 +575,31 @@ Command-Line Options
is included for compatibility with tools that expect to pass this option
to "setup.py install".
``--site-dirs=DIRLIST, -S DIRLIST`` (New in 0.6a1)
Specify one or more custom "site" directories (separated by commas).
"Site" directories are directories where ``.pth`` files are processed, such
as the main Python ``site-packages`` directory. By default, EasyInstall
only knows about Python-defined "site" directories, not those that may be
added by an OS distribution or site administrator calling
``site.addsitedir()``. You should not normally need to use this option
directly, as your system administrator should configure it in the
``distutils.cfg`` file of the Python installation. For example, if the
administrator wants to make each user's ``~/lib/python2.3`` directory be a
"site" directory, he or she should create an ``altinstall.pth`` file in the
normal site-packages directory, containing this::
import os; addsitedir(os.path.expanduser('~/lib/python2.3'))
and a ``distutils.cfg`` file inside the ``distutils`` package directory,
containing this::
[easy_install]
site_dirs = ~/lib/python23
This will ensure that EasyInstall knows about the additional "site"
directory, thereby allowing individual users to install their own
Python packages via EasyInstall.
Release Notes/Change History
============================
......@@ -593,6 +618,11 @@ Known Issues
in Exemaker. So, don't use Exemaker to wrap ``easy_install.py``, or at any
rate don't expect it to work with all packages.
0.6a1
* Added ``--site-dirs`` option to allow adding custom "site" directories.
Made ``easy-install.pth`` work in platform-specific alternate site
directories (e.g. ``~/Library/Python/2.x/site-packages``).
0.5a12
* Fix ``python -m easy_install`` not working due to setuptools being installed
as a zipfile. Update safety scanner to check for modules that might be used
......
......@@ -67,7 +67,8 @@ class easy_install(Command):
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
('record=', None,
"filename in which to record list of installed files"),
('always-unzip', 'Z', "don't install as a zipfile, no matter what")
('always-unzip', 'Z', "don't install as a zipfile, no matter what"),
('site-dirs=','S',"list of directories where .pth files work"),
]
boolean_options = [
......@@ -79,7 +80,6 @@ class easy_install(Command):
create_index = PackageIndex
def initialize_options(self):
self.zip_ok = None
self.install_dir = self.script_dir = self.exclude_scripts = None
......@@ -94,7 +94,7 @@ class easy_install(Command):
self.pth_file = None
self.delete_conflicting = None
self.ignore_conflicts_at_my_risk = None
self.site_dirs = None
def delete_blockers(self, blockers):
for filename in blockers:
......@@ -139,17 +139,28 @@ class easy_install(Command):
)
# default --record from the install command
self.set_undefined_options('install', ('record', 'record'))
normpath = map(normalize,sys.path)
self.all_site_dirs = get_site_dirs()
if self.site_dirs is not None:
site_dirs = [
os.path.expanduser(s.strip()) for s in self.site_dirs.split(',')
]
for d in site_dirs:
if not os.path.isdir(d):
log.warn("%s (in --site-dirs) does not exist", d)
elif normalize(d) not in normpath:
raise DistutilsOptionError(
d+" (in --site-dirs) is not on sys.path"
)
else:
self.all_site_dirs.append(normalize(d))
site_packages = get_python_lib()
instdir = self.install_dir
if instdir is None or samefile(site_packages,instdir):
instdir = site_packages
instdir = self.install_dir or self.all_site_dirs[-1]
if normalize(instdir) in self.all_site_dirs:
if self.pth_file is None:
self.pth_file = PthDistributions(
os.path.join(instdir,'easy-install.pth')
)
self.install_dir = instdir
elif self.multi_version is None:
self.multi_version = True
......@@ -157,15 +168,15 @@ class easy_install(Command):
elif not self.multi_version:
# explicit false set from Python code; raise an error
raise DistutilsArgError(
"Can't do single-version installs outside site-packages"
"Can't do single-version installs outside 'site-package' dirs"
)
self.install_dir = normalize(instdir)
self.index_url = self.index_url or "http://www.python.org/pypi"
self.shadow_path = sys.path[:]
self.shadow_path = map(normalize,sys.path)
for path_item in self.install_dir, self.script_dir:
if path_item not in self.shadow_path:
self.shadow_path.insert(0, self.install_dir)
if normalize(path_item) not in self.shadow_path:
self.shadow_path.insert(0, normalize(path_item))
if self.package_index is None:
self.package_index = self.create_index(
self.index_url, search_path = self.shadow_path
......@@ -179,7 +190,6 @@ class easy_install(Command):
self.find_links = []
self.set_undefined_options('install_lib', ('optimize','optimize'))
if not isinstance(self.optimize,int):
try:
self.optimize = int(self.optimize)
......@@ -192,6 +202,7 @@ class easy_install(Command):
"Can't use both --delete-conflicting and "
"--ignore-conflicts-at-my-risk at the same time"
)
if not self.args:
raise DistutilsArgError(
"No urls, filenames, or requirements specified (see --help)")
......@@ -203,6 +214,7 @@ class easy_install(Command):
self.outputs = []
def alloc_tmp(self):
if self.build_directory is None:
return tempfile.mkdtemp(prefix="easy_install-")
......@@ -231,6 +243,7 @@ class easy_install(Command):
log.set_verbosity(self.distribution.verbose)
def add_output(self, path):
if os.path.isdir(path):
for base, dirs, files in os.walk(path):
......@@ -244,6 +257,34 @@ class easy_install(Command):
def easy_install(self, spec):
tmpdir = self.alloc_tmp()
download = None
......@@ -591,7 +632,7 @@ class easy_install(Command):
for ext,mode,typ in get_suffixes():
exts[ext] = 1
for path,files in expand_paths([self.install_dir, get_python_lib()]):
for path,files in expand_paths([self.install_dir]+self.all_site_dirs):
for filename in files:
base,ext = os.path.splitext(filename)
if base in names:
......@@ -670,7 +711,7 @@ similar to one of these examples, in order to select the desired version:
pkg_resources.require("%(name)s==%(version)s") # this exact version
pkg_resources.require("%(name)s>=%(version)s") # this version or higher
"""
if not samefile(get_python_lib(),self.install_dir):
if self.install_dir not in map(normalize,sys.path):
msg += """
Note also that the installation directory must be on sys.path at runtime for
......@@ -741,14 +782,14 @@ PYTHONPATH, or by being added to sys.path by your code.)
return
for d in self.pth_file.get(dist.key,()): # drop old entries
if self.multi_version or d.path != dist.path:
if self.multi_version or normalize(d.path) != normalize(dist.path):
log.info("Removing %s from easy-install.pth file", d)
self.pth_file.remove(d)
if d.path in self.shadow_path:
if normalize(d.path) in self.shadow_path:
self.shadow_path.remove(d.path)
if not self.multi_version:
if dist.path in self.pth_file.paths:
if normalize(dist.path) in map(normalize,self.pth_file.paths):
log.info(
"%s is already the active version in easy-install.pth",
dist
......@@ -756,8 +797,8 @@ PYTHONPATH, or by being added to sys.path by your code.)
else:
log.info("Adding %s to easy-install.pth file", dist)
self.pth_file.add(dist) # add new entry
if dist.path not in self.shadow_path:
self.shadow_path.append(dist.path)
if normalize(dist.path) not in self.shadow_path:
self.shadow_path.append(normalize(dist.path))
self.pth_file.save()
......@@ -818,12 +859,54 @@ PYTHONPATH, or by being added to sys.path by your code.)
def get_site_dirs():
# return a list of 'site' dirs, based on 'site' module's code to do this
sitedirs = []
prefixes = [sys.prefix]
if sys.exec_prefix != sys.prefix:
prefixes.append(sys.exec_prefix)
for prefix in prefixes:
if prefix:
if sys.platform in ('os2emx', 'riscos'):
sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
elif os.sep == '/':
sitedirs.extend([os.path.join(prefix,
"lib",
"python" + sys.version[:3],
"site-packages"),
os.path.join(prefix, "lib", "site-python")])
else:
sitedirs.extend(
[prefix, os.path.join(prefix, "lib", "site-packages")]
)
if sys.platform == 'darwin':
# for framework builds *only* we add the standard Apple
# locations. Currently only per-user, but /Library and
# /Network/Library could be added too
if 'Python.framework' in prefix:
home = os.environ.get('HOME')
if home:
sitedirs.append(
os.path.join(home,
'Library',
'Python',
sys.version[:3],
'site-packages'))
sitedirs = filter(os.path.isdir, sitedirs)
sitedirs = map(normalize, sitedirs)
return sitedirs or [normalize(get_python_lib())] # ensure at least one
def expand_paths(inputs):
"""Yield sys.path directories that might contain "old-style" packages"""
seen = {}
for dirname in inputs:
dirname = normalize(dirname)
if dirname in seen:
continue
......@@ -850,7 +933,7 @@ def expand_paths(inputs):
# Yield existing non-dupe, non-import directory lines from it
for line in lines:
if not line.startswith("import"):
line = line.rstrip()
line = normalize(line.rstrip())
if line not in seen:
seen[line] = 1
if not os.path.isdir(line):
......@@ -858,7 +941,6 @@ def expand_paths(inputs):
yield line, os.listdir(line)
def extract_wininst_cfg(dist_filename):
"""Extract configuration data from a bdist_wininst .exe
......@@ -987,8 +1069,8 @@ def main(argv, **kw):
setup(script_args = ['-q','easy_install', '-v']+argv, **kw)
def normalize(path):
return os.path.normcase(os.path.realpath(path))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment