From 3bef6462fa8117dde2f55a3ff06dbf1b1a8e02a8 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sun, 30 Nov 2008 06:19:04 +0000 Subject: Big thandy installation refactoring. Things should be saner now: we recognize that checking an item is sometimes orthogonal to installing it; we do not carry around big bits of unimplemented machinery; we actually document what stuff does in thandy-spec.txt; we do more OO in the places that make sense and less in the places that do not; and almost as an afterthought, we support the command installer type internally. Now all we need is a frontend to make command installers. git-svn-id: file:///home/or/svnrepo/updater/trunk@17414 55e972cd-5a19-0410-ae62-a4d7a52db4cd --- lib/thandy/packagesys/PackageDB.py | 153 +++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 49 deletions(-) (limited to 'lib/thandy/packagesys/PackageDB.py') diff --git a/lib/thandy/packagesys/PackageDB.py b/lib/thandy/packagesys/PackageDB.py index a81507d..94a5ad9 100644 --- a/lib/thandy/packagesys/PackageDB.py +++ b/lib/thandy/packagesys/PackageDB.py @@ -2,13 +2,18 @@ import atexit import shelve +import logging import thandy.util import thandy.formats -import thandy.packagesys.PackageSystem +import thandy.packagesys.PackageSystem as PS class SimplePackageDB: + """Trivial wrapper around Python's shelve module to provide storage for + installation information for package items that don't automatically + record their presence. + """ def __init__(self, filename): thandy.util.ensureParentDir(filename) self._db = shelve.open(filename, 'c') @@ -23,71 +28,121 @@ class SimplePackageDB: def setInstallParameters(self, package, params): self._db['ip_%s'%str(package)] = params + def setManifest(self, package, fnameToDigest): + self._db['mf_%s'%str(package)] = fnameToDigest + def getCurVersion(self, package): v = self._db.get('pv_%s'%str(package)) if v != None: return v[0] + else: + return None def getInstallParameters(self, package): return self._db.get('pi_%s'%str(package)) -class DBBackedPackageSystem(thandy.packagesys.PackageSystem.PackageSystem): - def __init__(self): - self._packageDB = None + def getManifest(self, package): + return self._db.get('mf_%'%str(package), {}) - def getDB(self): - if self._packageDB is None: - fname = thandy.util.userFilename("db/packages") - self._packageDB = SimplePackageDB(fname) - return self._packageDB - -class DBBackedPackageHandle(thandy.packagesys.PackageSystem.PackageHandle): - def __init__(self, packageDB, name, version, filelist): - thandy.packagesys.PackageSystem.PackageHandle.__init__(self) - self._packageDB = packageDB - self._name = name - self._version = version - self._filelist = filelist + def removeAll(self, package): + for template in ["pv_%s", "ip_%s", "mf_%s"]: + try: + del self._db[template % str(package)] + except KeyError: + pass + +_DB_INSTANCE = None - self._metaData = None +def getPackageDBInstance(): + global _DB_INSTANCE + if _DB_INSTANCE == None: + fname = thandy.util.userFilename("db/packages") + logging.info("Opening package database in %s", fname) + _DB_INSTANCE = SimplePackageDB(fname) + return _DB_INSTANCEx - def _getInstallBase(self): - raise NotImplemented() +class _DBMixin: + def setDB(self, db): + self._db = db - def anyVersionInstalled(self, transaction=None): - return self.getInstalledVersion(transaction) != None + def getDB(self): + if self._db is None: + self._db = getPackageDBInstance() + return self._db + +class DBChecker(PS.Checker, _DBMixin): + def __init__(self, name, version): + PS.Checker.__init__(self) + self._name = name + self._version = version + self._db = None + + def __repr__(self): + return "DBChecker(%r, %r)"%(self._name, self._version) + +# def checkInstall(self): +# if not self.isInstalled(): +# return False +# else: +# return self._checkManifest() +# +# def _getInstallRoot(self): +# return "/" +# +# def _checkManifest(self): +# manifest = self.getDB().getManifest(self._name) +# root = self._getInstallRoot() +# all_ok = True +# for fname, digest_want in manifest: +# real_fname = os.path.join(self._getInstallRoot(), fname) +# logging.info("Checking digest on %s", fname) +# try: +# digest = thandy.formats.getFileDigest(real_fname): +# if digest != digest_want: +# logging.warn("Digest on %s not as expected", real_fname) +# all_ok = False +# except OSError: +# logging.warn("File %s not found.", real_fname) +# all_ok = False +# return all_ok +# + def getInstalledVersions(self): + return [ self.getDB().getCurVersion(self._name) ] + + def isInstalled(self): + return self._version in self.getInstalledVersions(transaction) + +class DBInstaller(PS.Installer, _DBMixin): + def __init__(self, name, version, relPath, installer): + PS.Installer.__init__(self, relPath) + self._name = name + self._version = version + self._installer = installer - def getInstalledVersion(self, transaction=None): - return self._packageDB.getCurVersion(self._name) + def __repr__(self): + return "DBInstaller(%r, %r, %r, %r)"%(self._name, + self._version, + self._relPath, + self._installer) - def install(self, transaction=None): - params = self._doInstall() - self._packageDB.setVersion( - self._name, self._version, self._filelist) - self._packageDB.setInstallParameters(self._name, params) + def setTransaction(self, transaction): + self._installer.setTransaction(transaction) - def _doInstall(self): - raise NotImplemented() + def setCacheRoot(self, cacheRoot): + self._installer.setCacheRoot(cacheRoot) - def isInstalled(self, transaction=None): - return self.getInstalledVersion(transaction) == self._version + def install(self): + self._installer.install() - def checkInstall(self, transaction=None): - base = self._getInstallBase() + params, manifest = self._installer.getInstallResult() + self.getDB().setCurVersion(self._name, self._version) + if params != None: + self.getDB().getInstallParameters(self._name, params) + if manifest != None: + self.getDB().setManifest(self._name, manifest) - all_ok = True - for fn, hash in self._filelist: - fn = os.path.join(base, fn) - if not os.path.exists(fn): - all_ok = False - else: - try: - d = thandy.formats.getFileDigest(fn) - if d != hash: - all_ok = False - except OSError: - all_ok = False - break + def remove(self): + self._installer.remove() + self.getDB().removeAll(self._name) - return all_ok -- cgit v1.2.3