[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