[Python-checkins] r42965 - in sandbox/trunk/setuptools: EasyInstall.txt setuptools/command/develop.py setuptools/command/easy_install.py site.py
phillip.eby
python-checkins at python.org
Sat Mar 11 01:39:13 CET 2006
Author: phillip.eby
Date: Sat Mar 11 01:39:09 2006
New Revision: 42965
Modified:
sandbox/trunk/setuptools/EasyInstall.txt
sandbox/trunk/setuptools/setuptools/command/develop.py
sandbox/trunk/setuptools/setuptools/command/easy_install.py
sandbox/trunk/setuptools/site.py
Log:
Added automatic handling of installation conflicts. Eggs are now shifted to
the front of sys.path, in an order consistent with where they came from,
making EasyInstall seamlessly co-operate with system package managers.
The ``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk`` options
are now no longer necessary, and will generate warnings at the end of a
run if you use them.
Modified: sandbox/trunk/setuptools/EasyInstall.txt
==============================================================================
--- sandbox/trunk/setuptools/EasyInstall.txt (original)
+++ sandbox/trunk/setuptools/EasyInstall.txt Sat Mar 11 01:39:09 2006
@@ -465,6 +465,15 @@
Dealing with Installation Conflicts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(NOTE: As of 0.6a11, this section is obsolete; it is retained here only so that
+people using older versions of EasyInstall can consult it. As of version
+0.6a11, installation conflicts are handled automatically without deleting the
+old or system-installed packages, and without ignoring the issue. Instead,
+eggs are automatically shifted to the front of ``sys.path`` using special
+code added to the ``easy-install.pth`` file. So, if you are using version
+0.6a11 or better of setuptools, you do not need to worry about conflicts,
+and the following issues do not apply to you.)
+
EasyInstall installs distributions in a "managed" way, such that each
distribution can be independently activated or deactivated on ``sys.path``.
However, packages that were not installed by EasyInstall are "unmanaged",
@@ -715,7 +724,9 @@
package not being available locally, or due to the use of the ``--update``
or ``-U`` option.
-``--delete-conflicting, -D`` (New in 0.5a9)
+``--delete-conflicting, -D`` (Removed in 0.6a11)
+ (As of 0.6a11, this option is no longer necessary; please do not use it!)
+
If you are replacing a package that was previously installed *without*
using EasyInstall, the old version may end up on ``sys.path`` before the
version being installed with EasyInstall. EasyInstall will normally abort
@@ -724,7 +735,9 @@
option, however, EasyInstall will attempt to delete the files or
directories itself, and then proceed with the installation.
-``--ignore-conflicts-at-my-risk`` (New in 0.5a9)
+``--ignore-conflicts-at-my-risk`` (Removed in 0.6a11)
+ (As of 0.6a11, this option is no longer necessary; please do not use it!)
+
Ignore conflicting packages and proceed with installation anyway, even
though it means the package probably won't work properly. If the
conflicting package is in a directory you can't write to, this may be your
@@ -1066,6 +1079,14 @@
time out or be missing a file.
0.6a11
+ * Added automatic handling of installation conflicts. Eggs are now shifted to
+ the front of sys.path, in an order consistent with where they came from,
+ making EasyInstall seamlessly co-operate with system package managers.
+
+ The ``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk`` options
+ are now no longer necessary, and will generate warnings at the end of a
+ run if you use them.
+
* Don't recursively traverse subdirectories given to ``--find-links``.
0.6a10
Modified: sandbox/trunk/setuptools/setuptools/command/develop.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/develop.py (original)
+++ sandbox/trunk/setuptools/setuptools/command/develop.py Sat Mar 11 01:39:09 2006
@@ -24,6 +24,7 @@
self.uninstall_link()
else:
self.install_for_development()
+ self.warn_deprecated_options()
def initialize_options(self):
self.uninstall = None
@@ -38,7 +39,6 @@
-
def finalize_options(self):
ei = self.get_finalized_command("egg_info")
if ei.broken_egg_info:
Modified: sandbox/trunk/setuptools/setuptools/command/easy_install.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/easy_install.py (original)
+++ sandbox/trunk/setuptools/setuptools/command/easy_install.py Sat Mar 11 01:39:09 2006
@@ -9,7 +9,7 @@
__ http://peak.telecommunity.com/DevCenter/EasyInstall
"""
-import sys, os.path, zipimport, shutil, tempfile, zipfile, re, stat
+import sys, os.path, zipimport, shutil, tempfile, zipfile, re, stat, random
from glob import glob
from setuptools import Command
from setuptools.sandbox import run_setup
@@ -55,10 +55,9 @@
("always-copy", "a", "Copy all needed packages to install dir"),
("index-url=", "i", "base URL of Python Package Index"),
("find-links=", "f", "additional URL(s) to search for packages"),
- ("delete-conflicting", "D", "delete old packages that get in the way"),
+ ("delete-conflicting", "D", "no longer needed; don't use this"),
("ignore-conflicts-at-my-risk", None,
- "install even if old packages are in the way, even though it "
- "most likely means the new package won't work."),
+ "no longer needed; don't use this"),
("build-directory=", "b",
"download/extract/build in DIR; keep the results"),
('optimize=', 'O',
@@ -80,6 +79,7 @@
negative_opt = {'always-unzip': 'zip-ok'}
create_index = PackageIndex
+
def initialize_options(self):
self.zip_ok = None
self.install_dir = self.script_dir = self.exclude_scripts = None
@@ -221,28 +221,28 @@
"writing list of installed files to '%s'" %
self.record
)
+ self.warn_deprecated_options()
finally:
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 warn_deprecated_options(self):
+ if self.delete_conflicting or self.ignore_conflicts_at_my_risk:
+ log.warn(
+ "Note: The -D, --delete-conflicting and"
+ " --ignore-conflicts-at-my-risk no longer have any purpose"
+ " and should not be used."
+ )
def check_site_dir(self):
"""Verify that self.install_dir is .pth-capable dir, if needed"""
@@ -786,6 +786,7 @@
def check_conflicts(self, dist):
"""Verify that there are no conflicting "old-style" packages"""
+ return dist # XXX temporarily disable until new strategy is stable
from imp import find_module, get_suffixes
from glob import glob
@@ -812,7 +813,6 @@
blockers.append(filename)
elif ext in exts and base!='site': # XXX ugh
blockers.append(os.path.join(path,filename))
-
if blockers:
self.found_conflicts(dist, blockers)
@@ -1072,16 +1072,18 @@
sitepy = os.path.join(self.install_dir, "site.py")
source = resource_string(Requirement.parse("setuptools"), "site.py")
+ current = ""
if os.path.exists(sitepy):
log.debug("Checking existing site.py in %s", self.install_dir)
current = open(sitepy,'rb').read()
- if current != source:
+ if not current.startswith('def __boot():'):
raise DistutilsError(
"%s is not a setuptools-generated site.py; please"
" remove it." % sitepy
)
- else:
+
+ if current != source:
log.info("Creating %s", sitepy)
if not self.dry_run:
ensure_directory(sitepy)
@@ -1103,8 +1105,6 @@
-
-
INSTALL_SCHEMES = dict(
posix = dict(
install_dir = '$base/lib/python$py_version_short/site-packages',
@@ -1323,9 +1323,13 @@
def _load(self):
self.paths = []
+ saw_import = False
seen = {}
if os.path.isfile(self.filename):
for line in open(self.filename,'rt'):
+ if line.startswith('import'):
+ saw_import = True
+ continue
path = line.rstrip()
self.paths.append(path)
if not path.strip() or path.strip().startswith('#'):
@@ -1339,17 +1343,41 @@
continue
seen[path] = 1
- while self.paths and not self.paths[-1].strip(): self.paths.pop()
+ if self.paths and not saw_import:
+ self.dirty = True # ensure anything we touch has import wrappers
+
+ while self.paths and not self.paths[-1].strip():
+ self.paths.pop()
+
+
def save(self):
"""Write changed .pth file back to disk"""
- if self.dirty:
+ if not self.dirty:
+ return
+
+ data = '\n'.join(self.paths)
+ if data:
log.debug("Saving %s", self.filename)
- data = '\n'.join(self.paths+[''])
+ data = (
+ "import sys; sys.__plen = len(sys.path)\n"
+ "%s\n"
+ "import sys; new=sys.path[sys.__plen:];"
+ " del sys.path[sys.__plen:];"
+ " p=getattr(sys,'__egginsert',0); sys.path[p:p]=new;"
+ " sys.__egginsert = p+len(new)\n"
+ ) % data
+
if os.path.islink(self.filename):
os.unlink(self.filename)
- f = open(self.filename,'wt'); f.write(data); f.close()
- self.dirty = False
+ f = open(self.filename,'wb')
+ f.write(data); f.close()
+
+ elif os.path.exists(self.filename):
+ log.debug("Deleting empty %s", self.filename)
+ os.unlink(self.filename)
+
+ self.dirty = False
def add(self,dist):
"""Add `dist` to the distribution map"""
@@ -1392,6 +1420,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
def get_script_args(dist, executable=sys_executable):
"""Yield write_script() argument tuples for a distribution's entrypoints"""
spec = str(dist.as_requirement())
Modified: sandbox/trunk/setuptools/site.py
==============================================================================
--- sandbox/trunk/setuptools/site.py (original)
+++ sandbox/trunk/setuptools/site.py Sat Mar 11 01:39:09 2006
@@ -41,12 +41,16 @@
known_paths = dict([(makepath(item)[1],1) for item in sys.path]) # 2.2 comp
+ oldpos = getattr(sys,'__egginsert',0) # save old insertion position
+ sys.__egginsert = 0 # and reset the current one
+
for item in PYTHONPATH:
addsitedir(item)
+
+ sys.__egginsert += oldpos # restore effective old position
d,nd = makepath(stdpath[0])
insert_at = None
- skipped = []
new_path = []
for item in sys.path:
@@ -54,22 +58,15 @@
if np==nd and insert_at is None:
# We've hit the first 'system' path entry, so added entries go here
- new_path.extend(skipped)
insert_at = len(new_path)
- skipped = []
- if np in known_paths:
- # Old path, just copy
+ if np in known_paths or insert_at is None:
new_path.append(item)
- elif insert_at is None:
- # New path before the insert point, buffer it
- skipped.append(item)
else:
# new path after the insert point, back-insert it
new_path.insert(insert_at, item)
insert_at += 1
- new_path.extend(skipped)
sys.path[:] = new_path
if __name__=='site':
@@ -80,3 +77,6 @@
+
+
+
More information about the Python-checkins
mailing list