[Python-checkins] python/dist/src/Lib/plat-mac pimp.py, 1.27.4.4, 1.27.4.5

jackjansen at users.sourceforge.net jackjansen at users.sourceforge.net
Fri Jan 7 14:48:56 CET 2005


Update of /cvsroot/python/python/dist/src/Lib/plat-mac
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6279
Modified Files:
 Tag: release23-maint
	pimp.py 
Log Message:
Backport of 1.38:
Allow relative URLs for included databases and packages.
Index: pimp.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/pimp.py,v
retrieving revision 1.27.4.4
retrieving revision 1.27.4.5
diff -u -d -r1.27.4.4 -r1.27.4.5
--- pimp.py	3 Jan 2005 15:46:30 -0000	1.27.4.4
+++ pimp.py	7 Jan 2005 13:48:53 -0000	1.27.4.5
@@ -1,6 +1,6 @@
 """Package Install Manager for Python.
 
-This is currently a MacOSX-only strawman implementation. 
+This is currently a MacOSX-only strawman implementation.
 Despite other rumours the name stands for "Packman IMPlementation".
 
 Tools to allow easy installation of packages. The idea is that there is
@@ -27,7 +27,7 @@
 import shutil
 import time
 
-__all__ = ["PimpPreferences", "PimpDatabase", "PimpPackage", "main", 
+__all__ = ["PimpPreferences", "PimpDatabase", "PimpPackage", "main",
 "getDefaultDatabase", "PIMP_VERSION", "main"]
 
 _scriptExc_NotInstalled = "pimp._scriptExc_NotInstalled"
@@ -53,12 +53,12 @@
 status = "exp"
 else:
 status = "prod"
- 
+
 major, minor, micro, state, extra = sys.version_info
 pyvers = '%d.%d' % (major, minor)
 if micro == 0 and state != 'final':
 pyvers = pyvers + '%s%d' % (state, extra)
- 
+
 longplatform = distutils.util.get_platform()
 osname, release, machine = longplatform.split('-')
 # For some platforms we may want to differentiate between
@@ -95,7 +95,7 @@
 
 def _cmd(output, dir, *cmditems):
 """Internal routine to run a shell command in a given directory."""
- 
+
 cmd = ("cd \"%s\"; " % dir) + " ".join(cmditems)
 if output:
 output.write("+ %s\n" % cmd)
@@ -113,22 +113,22 @@
 
 class PimpDownloader:
 """Abstract base class - Downloader for archives"""
- 
+
 def __init__(self, argument,
 dir="",
 watcher=None):
 self.argument = argument
 self._dir = dir
 self._watcher = watcher
- 
+
 def download(self, url, filename, output=None):
 return None
- 
+
 def update(self, str):
 if self._watcher:
 return self._watcher.update(str)
 return True
- 
+
 class PimpCurlDownloader(PimpDownloader):
 
 def download(self, url, filename, output=None):
@@ -139,7 +139,7 @@
 url)
 self.update("Downloading %s: finished" % url)
 return (not exitstatus)
- 
+
 class PimpUrllibDownloader(PimpDownloader):
 
 def download(self, url, filename, output=None):
@@ -151,13 +151,13 @@
 length = long(download.headers['content-length'])
 else:
 length = -1
- 
+
 data = download.read(4096) #read 4K at a time
 dlsize = 0
 lasttime = 0
 while keepgoing:
 dlsize = dlsize + len(data)
- if len(data) == 0: 
+ if len(data) == 0:
 #this is our exit condition
 break
 output.write(data)
@@ -172,12 +172,12 @@
 if keepgoing:
 self.update("Downloading %s: finished" % url)
 return keepgoing
- 
+
 class PimpUnpacker:
 """Abstract base class - Unpacker for archives"""
- 
+
 _can_rename = False
- 
+
 def __init__(self, argument,
 dir="",
 renames=[],
@@ -188,30 +188,30 @@
 self._dir = dir
 self._renames = renames
 self._watcher = watcher
- 
+
 def unpack(self, archive, output=None, package=None):
 return None
- 
+
 def update(self, str):
 if self._watcher:
 return self._watcher.update(str)
 return True
- 
+
 class PimpCommandUnpacker(PimpUnpacker):
 """Unpack archives by calling a Unix utility"""
- 
+
 _can_rename = False
- 
+
 def unpack(self, archive, output=None, package=None):
 cmd = self.argument % archive
 if _cmd(output, self._dir, cmd):
 return "unpack command failed"
- 
+
 class PimpTarUnpacker(PimpUnpacker):
 """Unpack tarfiles using the builtin tarfile module"""
- 
+
 _can_rename = True
- 
+
 def unpack(self, archive, output=None, package=None):
 tf = tarfile.open(archive, "r")
 members = tf.getmembers()
@@ -254,7 +254,7 @@
 names = package.filterExpectedSkips(names)
 if names:
 return "Not all files were unpacked: %s" % " ".join(names)
- 
+
 ARCHIVE_FORMATS = [
 (".tar.Z", PimpTarUnpacker, None),
 (".taz", PimpTarUnpacker, None),
@@ -267,8 +267,8 @@
 class PimpPreferences:
 """Container for per-user preferences, such as the database to use
 and where to install packages."""
- 
- def __init__(self, 
+
+ def __init__(self,
 flavorOrder=None,
 downloadDir=None,
 buildDir=None,
@@ -288,10 +288,10 @@
 self.buildDir = buildDir
 self.pimpDatabase = pimpDatabase
 self.watcher = None
- 
+
 def setWatcher(self, watcher):
 self.watcher = watcher
- 
+
 def setInstallDir(self, installDir=None):
 if installDir:
 # Installing to non-standard location.
@@ -304,14 +304,14 @@
 installDir = DEFAULT_INSTALLDIR
 self.installLocations = []
 self.installDir = installDir
- 
+
 def isUserInstall(self):
 return self.installDir != DEFAULT_INSTALLDIR
 
 def check(self):
 """Check that the preferences make sense: directories exist and are
 writable, the install directory is on sys.path, etc."""
- 
+
 rv = ""
 RWX_OK = os.R_OK|os.W_OK|os.X_OK
 if not os.path.exists(self.downloadDir):
@@ -338,7 +338,7 @@
 else:
 rv += "Warning: Install directory \"%s\" is not on sys.path\n" % self.installDir
 return rv
- 
+
 def compareFlavors(self, left, right):
 """Compare two flavor strings. This is part of your preferences
 because whether the user prefers installing from source or binary is."""
@@ -349,13 +349,13 @@
 if right in self.flavorOrder:
 return 1
 return cmp(left, right)
- 
+
 class PimpDatabase:
 """Class representing a pimp database. It can actually contain
 information from multiple databases through inclusion, but the
 toplevel database is considered the master, as its maintainer is
 "responsible" for the contents."""
- 
+
 def __init__(self, prefs):
 self._packages = []
 self.preferences = prefs
@@ -364,23 +364,23 @@
 self._version = ""
 self._maintainer = ""
 self._description = ""
- 
+
 # Accessor functions
 def url(self): return self._url
 def version(self): return self._version
 def maintainer(self): return self._maintainer
 def description(self): return self._description
- 
+
 def close(self):
 """Clean up"""
 self._packages = []
 self.preferences = None
- 
+
 def appendURL(self, url, included=0):
 """Append packages from the database with the given URL.
 Only the first database should specify included=0, so the
 global information (maintainer, description) get stored."""
- 
+
 if url in self._urllist:
 return
 self._urllist.append(url)
@@ -397,23 +397,26 @@
 if not self._version:
 sys.stderr.write("Warning: database has no Version information\n")
 elif self._version > PIMP_VERSION:
- sys.stderr.write("Warning: database version %s newer than pimp version %s\n" 
+ sys.stderr.write("Warning: database version %s newer than pimp version %s\n"
 % (self._version, PIMP_VERSION))
 self._maintainer = plistdata.get('Maintainer', '')
 self._description = plistdata.get('Description', '').strip()
 self._url = url
- self._appendPackages(plistdata['Packages'])
+ self._appendPackages(plistdata['Packages'], url)
 others = plistdata.get('Include', [])
- for url in others:
- self.appendURL(url, included=1)
- 
- def _appendPackages(self, packages):
+ for o in others:
+ o = urllib.basejoin(url, o)
+ self.appendURL(o, included=1)
+
+ def _appendPackages(self, packages, url):
 """Given a list of dictionaries containing package
 descriptions create the PimpPackage objects and append them
 to our internal storage."""
- 
+
 for p in packages:
 p = dict(p)
+ if p.has_key('Download-URL'):
+ p['Download-URL'] = urllib.basejoin(url, p['Download-URL'])
 flavor = p.get('Flavor')
 if flavor == 'source':
 pkg = PimpPackage_source(self, p)
@@ -426,27 +429,27 @@
 else:
 pkg = PimpPackage(self, dict(p))
 self._packages.append(pkg)
- 
+
 def list(self):
 """Return a list of all PimpPackage objects in the database."""
- 
+
 return self._packages
- 
+
 def listnames(self):
 """Return a list of names of all packages in the database."""
- 
+
 rv = []
 for pkg in self._packages:
 rv.append(pkg.fullname())
 rv.sort()
 return rv
- 
+
 def dump(self, pathOrFile):
 """Dump the contents of the database to an XML .plist file.
- 
+
 The file can be passed as either a file object or a pathname.
 All data, including included databases, is dumped."""
- 
+
 packages = []
 for pkg in self._packages:
 packages.append(pkg.dump())
@@ -458,15 +461,15 @@
 }
 plist = plistlib.Plist(**plistdata)
 plist.write(pathOrFile)
- 
+
 def find(self, ident):
 """Find a package. The package can be specified by name
 or as a dictionary with name, version and flavor entries.
- 
+
 Only name is obligatory. If there are multiple matches the
 best one (higher version number, flavors ordered according to
 users' preference) is returned."""
- 
+
 if type(ident) == str:
 # Remove ( and ) for pseudo-packages
 if ident[0] == '(' and ident[-1] == ')':
@@ -496,7 +499,7 @@
 if not found or found < p:
 found = p
 return found
- 
+
 ALLOWED_KEYS = [
 "Name",
 "Version",
@@ -516,7 +519,7 @@
 
 class PimpPackage:
 """Class representing a single package."""
- 
+
 def __init__(self, db, plistdata):
 self._db = db
 name = plistdata["Name"]
@@ -524,10 +527,10 @@
 if not k in ALLOWED_KEYS:
 sys.stderr.write("Warning: %s: unknown key %s\n" % (name, k))
 self._dict = plistdata
- 
+
 def __getitem__(self, key):
 return self._dict[key]
- 
+
 def name(self): return self._dict['Name']
 def version(self): return self._dict.get('Version')
 def flavor(self): return self._dict.get('Flavor')
@@ -536,13 +539,13 @@
 def homepage(self): return self._dict.get('Home-page')
 def downloadURL(self): return self._dict.get('Download-URL')
 def systemwideOnly(self): return self._dict.get('Systemwide-only')
- 
+
 def fullname(self):
 """Return the full name "name-version-flavor" of a package.
- 
+
 If the package is a pseudo-package, something that cannot be
 installed through pimp, return the name in (parentheses)."""
- 
+
 rv = self._dict['Name']
 if self._dict.has_key('Version'):
 rv = rv + '-%s' % self._dict['Version']
@@ -552,14 +555,14 @@
 # Pseudo-package, show in parentheses
 rv = '(%s)' % rv
 return rv
- 
+
 def dump(self):
 """Return a dict object containing the information on the package."""
 return self._dict
- 
+
 def __cmp__(self, other):
 """Compare two packages, where the "better" package sorts lower."""
- 
+
 if not isinstance(other, PimpPackage):
 return cmp(id(self), id(other))
 if self.name() != other.name():
@@ -567,15 +570,15 @@
 if self.version() != other.version():
 return -cmp(self.version(), other.version())
 return self._db.preferences.compareFlavors(self.flavor(), other.flavor())
- 
+
 def installed(self):
 """Test wheter the package is installed.
- 
+
 Returns two values: a status indicator which is one of
 "yes", "no", "old" (an older version is installed) or "bad"
 (something went wrong during the install test) and a human
 readable string which may contain more details."""
- 
+
 namespace = {
 "NotInstalled": _scriptExc_NotInstalled,
 "OldInstalled": _scriptExc_OldInstalled,
@@ -607,16 +610,16 @@
 sys.stderr.write("-------------------------------------\n")
 return "bad", "Package install test got exception"
 return "yes", ""
- 
+
 def prerequisites(self):
 """Return a list of prerequisites for this package.
- 
+
 The list contains 2-tuples, of which the first item is either
 a PimpPackage object or None, and the second is a descriptive
 string. The first item can be None if this package depends on
 something that isn't pimp-installable, in which case the descriptive
 string should tell the user what to do."""
- 
+
 rv = []
 if not self._dict.get('Download-URL'):
 # For pseudo-packages that are already installed we don't
@@ -624,7 +627,7 @@
 status, _ = self.installed()
 if status == "yes":
 return []
- return [(None, 
+ return [(None,
 "Package %s cannot be installed automatically, see the description" %
 self.fullname())]
 if self.systemwideOnly() and self._db.preferences.isUserInstall():
@@ -650,28 +653,28 @@
 descr = pkg.shortdescription()
 rv.append((pkg, descr))
 return rv
- 
- 
+
+
 def downloadPackageOnly(self, output=None):
 """Download a single package, if needed.
- 
+
 An MD5 signature is used to determine whether download is needed,
 and to test that we actually downloaded what we expected.
 If output is given it is a file-like object that will receive a log
 of what happens.
- 
+
 If anything unforeseen happened the method returns an error message
 string.
 """
- 
+
 scheme, loc, path, query, frag = urlparse.urlsplit(self._dict['Download-URL'])
 path = urllib.url2pathname(path)
 filename = os.path.split(path)[1]
- self.archiveFilename = os.path.join(self._db.preferences.downloadDir, filename) 
+ self.archiveFilename = os.path.join(self._db.preferences.downloadDir, filename)
 if not self._archiveOK():
 if scheme == 'manual':
 return "Please download package manually and save as %s" % self.archiveFilename
- downloader = PimpUrllibDownloader(None, self._db.preferences.downloadDir, 
+ downloader = PimpUrllibDownloader(None, self._db.preferences.downloadDir,
 watcher=self._db.preferences.watcher)
 if not downloader.download(self._dict['Download-URL'],
 self.archiveFilename, output):
@@ -680,10 +683,10 @@
 return "archive not found after download"
 if not self._archiveOK():
 return "archive does not have correct MD5 checksum"
- 
+
 def _archiveOK(self):
 """Test an archive. It should exist and the MD5 checksum should be correct."""
- 
+
 if not os.path.exists(self.archiveFilename):
 return 0
 if not self._dict.get('MD5Sum'):
@@ -692,10 +695,10 @@
 data = open(self.archiveFilename, 'rb').read()
 checksum = md5.new(data).hexdigest()
 return checksum == self._dict['MD5Sum']
- 
+
 def unpackPackageOnly(self, output=None):
 """Unpack a downloaded package archive."""
- 
+
 filename = os.path.split(self.archiveFilename)[1]
 for ext, unpackerClass, arg in ARCHIVE_FORMATS:
 if filename[-len(ext):] == ext:
@@ -703,43 +706,43 @@
 else:
 return "unknown extension for archive file: %s" % filename
 self.basename = filename[:-len(ext)]
- unpacker = unpackerClass(arg, dir=self._db.preferences.buildDir, 
+ unpacker = unpackerClass(arg, dir=self._db.preferences.buildDir,
 watcher=self._db.preferences.watcher)
 rv = unpacker.unpack(self.archiveFilename, output=output)
 if rv:
 return rv
- 
+
 def installPackageOnly(self, output=None):
 """Default install method, to be overridden by subclasses"""
 return "%s: This package needs to be installed manually (no support for flavor=\"%s\")" \
 % (self.fullname(), self._dict.get(flavor, ""))
- 
+
 def installSinglePackage(self, output=None):
 """Download, unpack and install a single package.
- 
+
 If output is given it should be a file-like object and it
 will receive a log of what happened."""
- 
+
 if not self._dict.get('Download-URL'):
 return "%s: This package needs to be installed manually (no Download-URL field)" % self.fullname()
 msg = self.downloadPackageOnly(output)
 if msg:
 return "%s: download: %s" % (self.fullname(), msg)
- 
+
 msg = self.unpackPackageOnly(output)
 if msg:
 return "%s: unpack: %s" % (self.fullname(), msg)
- 
+
 return self.installPackageOnly(output)
- 
+
 def beforeInstall(self):
 """Bookkeeping before installation: remember what we have in site-packages"""
 self._old_contents = os.listdir(self._db.preferences.installDir)
- 
+
 def afterInstall(self):
 """Bookkeeping after installation: interpret any new .pth files that have
 appeared"""
- 
+
 new_contents = os.listdir(self._db.preferences.installDir)
 for fn in new_contents:
 if fn in self._old_contents:
@@ -762,7 +765,7 @@
 line = os.path.join(self._db.preferences.installDir, line)
 line = os.path.realpath(line)
 if not line in sys.path:
- sys.path.append(line) 
+ sys.path.append(line)
 
 def filterExpectedSkips(self, names):
 """Return a list that contains only unpexpected skips"""
@@ -785,21 +788,21 @@
 def unpackPackageOnly(self, output=None):
 """We don't unpack binary packages until installing"""
 pass
- 
+
 def installPackageOnly(self, output=None):
 """Install a single source package.
- 
+
 If output is given it should be a file-like object and it
 will receive a log of what happened."""
- 
+
 if self._dict.has_key('Install-command'):
 return "%s: Binary package cannot have Install-command" % self.fullname()
- 
+
 if self._dict.has_key('Pre-install-command'):
 if _cmd(output, '/tmp', self._dict['Pre-install-command']):
 return "pre-install %s: running \"%s\" failed" % \
 (self.fullname(), self._dict['Pre-install-command'])
- 
+
 self.beforeInstall()
 
 # Install by unpacking
@@ -810,7 +813,7 @@
 else:
 return "%s: unknown extension for archive file: %s" % (self.fullname(), filename)
 self.basename = filename[:-len(ext)]
- 
+
 install_renames = []
 for k, newloc in self._db.preferences.installLocations:
 if not newloc:
@@ -820,22 +823,22 @@
 else:
 return "%s: Don't know installLocation %s" % (self.fullname(), k)
 install_renames.append((oldloc, newloc))
- 
+
 unpacker = unpackerClass(arg, dir="/", renames=install_renames)
 rv = unpacker.unpack(self.archiveFilename, output=output, package=self)
 if rv:
 return rv
- 
+
 self.afterInstall()
- 
+
 if self._dict.has_key('Post-install-command'):
 if _cmd(output, '/tmp', self._dict['Post-install-command']):
 return "%s: post-install: running \"%s\" failed" % \
 (self.fullname(), self._dict['Post-install-command'])
 
 return None
- 
- 
+
+
 class PimpPackage_source(PimpPackage):
 
 def unpackPackageOnly(self, output=None):
@@ -849,15 +852,15 @@
 
 def installPackageOnly(self, output=None):
 """Install a single source package.
- 
+
 If output is given it should be a file-like object and it
 will receive a log of what happened."""
- 
+
 if self._dict.has_key('Pre-install-command'):
 if _cmd(output, self._buildDirname, self._dict['Pre-install-command']):
 return "pre-install %s: running \"%s\" failed" % \
 (self.fullname(), self._dict['Pre-install-command'])
- 
+
 self.beforeInstall()
 installcmd = self._dict.get('Install-command')
 if installcmd and self._install_renames:
@@ -887,15 +890,15 @@
 rv = None
 shutil.rmtree(unwanted_install_dir)
 return rv
- 
+
 self.afterInstall()
- 
+
 if self._dict.has_key('Post-install-command'):
 if _cmd(output, self._buildDirname, self._dict['Post-install-command']):
 return "post-install %s: running \"%s\" failed" % \
 (self.fullname(), self._dict['Post-install-command'])
 return None
- 
+
 class PimpPackage_installer(PimpPackage):
 
 def unpackPackageOnly(self, output=None):
@@ -927,36 +930,36 @@
 if _cmd(output, "/tmp", installcmd):
 return '%s: install command failed (use verbose for details)' % self.fullname()
 return '%s: downloaded and opened. Install manually and restart Package Manager' % self.archiveFilename
- 
+
 class PimpInstaller:
 """Installer engine: computes dependencies and installs
 packages in the right order."""
- 
+
 def __init__(self, db):
 self._todo = []
 self._db = db
 self._curtodo = []
 self._curmessages = []
- 
+
 def __contains__(self, package):
 return package in self._todo
- 
+
 def _addPackages(self, packages):
 for package in packages:
 if not package in self._todo:
 self._todo.append(package)
- 
+
 def _prepareInstall(self, package, force=0, recursive=1):
 """Internal routine, recursive engine for prepareInstall.
- 
+
 Test whether the package is installed and (if not installed
 or if force==1) prepend it to the temporary todo list and
 call ourselves recursively on all prerequisites."""
- 
+
 if not force:
 status, message = package.installed()
 if status == "yes":
- return 
+ return
 if package in self._todo or package in self._curtodo:
 return
 self._curtodo.insert(0, package)
@@ -968,17 +971,17 @@
 self._prepareInstall(pkg, False, recursive)
 else:
 self._curmessages.append("Problem with dependency: %s" % descr)
- 
+
 def prepareInstall(self, package, force=0, recursive=1):
 """Prepare installation of a package.
- 
+
 If the package is already installed and force is false nothing
 is done. If recursive is true prerequisites are installed first.
- 
+
 Returns a list of packages (to be passed to install) and a list
 of messages of any problems encountered.
 """
- 
+
 self._curtodo = []
 self._curmessages = []
 self._prepareInstall(package, force, recursive)
@@ -986,10 +989,10 @@
 self._curtodo = []
 self._curmessages = []
 return rv
- 
+
 def install(self, packages, output):
 """Install a list of packages."""
- 
+
 self._addPackages(packages)
 status = []
 for pkg in self._todo:
@@ -997,12 +1000,12 @@
 if msg:
 status.append(msg)
 return status
- 
- 
- 
+
+
+
 def _run(mode, verbose, force, args, prefargs, watcher):
 """Engine for the main program"""
- 
+
 prefs = PimpPreferences(**prefargs)
 if watcher:
 prefs.setWatcher(watcher)
@@ -1011,7 +1014,7 @@
 sys.stdout.write(rv)
 db = PimpDatabase(prefs)
 db.appendURL(prefs.pimpDatabase)
- 
+
 if mode == 'dump':
 db.dump(sys.stdout)
 elif mode =='list':
@@ -1086,7 +1089,7 @@
 
 def main():
 """Minimal commandline tool to drive pimp."""
- 
+
 import getopt
 def _help():
 print "Usage: pimp [options] -s [package ...] List installed status"
@@ -1101,12 +1104,12 @@
 print " (default: %s)" % DEFAULT_INSTALLDIR
 print " -u url URL for database"
 sys.exit(1)
- 
+
 class _Watcher:
 def update(self, msg):
 sys.stderr.write(msg + '\r')
 return 1
- 
+
 try:
 opts, args = getopt.getopt(sys.argv[1:], "slifvdD:Vu:")
 except getopt.GetoptError:
@@ -1169,8 +1172,6 @@
 (pimp_update.PIMP_VERSION, PIMP_VERSION))
 else:
 from pimp_update import *
- 
+
 if __name__ == '__main__':
 main()
- 
- 


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /