summaryrefslogtreecommitdiff
path: root/lib/thandy/packagesys
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2008-11-16 20:15:34 +0000
committerNick Mathewson <nickm@torproject.org>2008-11-16 20:15:34 +0000
commitc5749895ab4f6893bdf1d398691d1dd33e81574c (patch)
tree4ee47c3c6c56e313c3074f04c77a3637cf0fe31d /lib/thandy/packagesys
parent02a2e5807f23ad0cad9a49b5febe08ec25fcc74c (diff)
have some more thandy. This update includes a working downloader with tor support, a package system framework, and more. Most of what's left is glue code.
git-svn-id: file:///home/or/svnrepo/updater/trunk@17288 55e972cd-5a19-0410-ae62-a4d7a52db4cd
Diffstat (limited to 'lib/thandy/packagesys')
-rw-r--r--lib/thandy/packagesys/ExePackages.py33
-rw-r--r--lib/thandy/packagesys/PackageDB.py81
-rw-r--r--lib/thandy/packagesys/PackageSystem.py58
-rw-r--r--lib/thandy/packagesys/RPMPackages.py156
-rw-r--r--lib/thandy/packagesys/__init__.py4
5 files changed, 332 insertions, 0 deletions
diff --git a/lib/thandy/packagesys/ExePackages.py b/lib/thandy/packagesys/ExePackages.py
new file mode 100644
index 0000000..1688da3
--- /dev/null
+++ b/lib/thandy/packagesys/ExePackages.py
@@ -0,0 +1,33 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
+
+import thandy.packagesys.PackageSystem as ps
+import thandy.packagesys.PackageDB as pdb
+
+class ExePackageSystem(pdb.DBBackedPackageSystem):
+
+ def getName(self):
+ return "executable"
+
+ def packageHandleFromJSON(self, json):
+ raise NotImplemented() #XXXX????
+
+ def canBeAutomatic(self):
+ return True
+
+ def canHaveUI(self):
+ return True
+
+class ExePackageHandle(pdb.DBBackedPackageHandle):
+ def __init__(self, packageDB, name, version, filelist, filename,
+ arguments):
+ pdb.DBBackedPackageHandle.__init__(packageDB, name, version, filelist)
+ self._filename = filename
+ self._arguments = arguments
+
+ def _doInstall(self):
+ commandline = [ self._filename ] + self._arguments
+ logging.info("Installing %s. Command line: %s", self._filename,
+ commandLine)
+ subprocess.call(commandline)
+
+
diff --git a/lib/thandy/packagesys/PackageDB.py b/lib/thandy/packagesys/PackageDB.py
new file mode 100644
index 0000000..bb218be
--- /dev/null
+++ b/lib/thandy/packagesys/PackageDB.py
@@ -0,0 +1,81 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
+
+import anydbm
+import shelve
+
+import thandy.util
+import thandy.formats
+
+class SimplePackageDB:
+
+ def __init__(self, filename):
+ self._db = anydbm.open(filename, 'c')
+
+ def setVersion(self, package, version, filelist):
+ pass
+
+ def setInstallParameters(self, package, params):
+ pass
+
+ def getCurVersion(self, package):
+ pass
+
+ def getInstallParameters(self, package):
+ pass
+
+
+class DBBackedPackageSystem(thandy.packagesys.PackageSystem):
+ def __init__(self, packageDB):
+ self._packageDB = packageDB
+
+class DBBackedPackageHandle(thandy.packagesys.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
+
+ self._metaData = None
+
+ def _getInstallBase(self):
+ raise NotImplemented()
+
+ def anyVersionInstalled(self, transaction=None):
+ return self._packageDB.getCurVersion(self._name) != None
+
+ def getInstalledVersion(self, transaction=None):
+ return self._packageDB.getCurVersion(self._name)
+
+ def install(self):
+ params = self._doInstall()
+ self._packageDB.setCurVersion(
+ self._name, self._version, self._filelist)
+ self._packageDB.setInstallParameters(self._name, params)
+
+ def _doInstall(self):
+ raise NotImplemented()
+
+ def isInstalled(self):
+ return self.getInstalledVersion(self, transaction) == self._version
+
+ def checkInstall(self):
+ base = self._getInstallBase()
+
+ 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:
+ f = open(fn, 'rb')
+ try:
+ try:
+ d = thandy.formats.getFileDigest(f)
+ except OSError:
+ all_ok = False
+ break
+ finally:
+ f.close()
+
+ return all_ok
diff --git a/lib/thandy/packagesys/PackageSystem.py b/lib/thandy/packagesys/PackageSystem.py
new file mode 100644
index 0000000..ad1e221
--- /dev/null
+++ b/lib/thandy/packagesys/PackageSystem.py
@@ -0,0 +1,58 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
+
+class PackageSystem:
+ def getName(self):
+ raise NotImplemented()
+
+ def packageHandleFromJSON(self, json):
+ raise NotImplemented()
+
+ def canBeAutomatic(self):
+ return True
+
+ def canHaveUI(self):
+ return False
+
+ def getTransaction(self):
+ return PackageTransaction()
+
+class PackageTransaction:
+ def __init__(self):
+ self._transactions = []
+
+ def _start(self):
+ pass
+
+ def _commit(self):
+ pass
+
+ def run(self):
+ self._start()
+ for cb in self._transactions:
+ cb(self)
+ self._commit()
+
+ def addInstall(self, packageHandle):
+ self._transactions.append(packageHandle.install)
+
+ def addRemove(self, packageHandle):
+ self._transactions.append(packageHandle.remove)
+
+class PackageHandle:
+ def isInstalled(self, transaction=None):
+ raise NotImplemented()
+
+ def anyVersionInstalled(self, transaction=None):
+ raise NotImplemented()
+
+ def getInstalledVersion(self, transaction=None):
+ raise NotImplemented()
+
+ def install(self, transaction):
+ raise NotImplemented()
+
+ def remove(self, transaction):
+ raise NotImplemented()
+
+ def checkInstall(self, transaction=None):
+ raise NotImplemented()
diff --git a/lib/thandy/packagesys/RPMPackages.py b/lib/thandy/packagesys/RPMPackages.py
new file mode 100644
index 0000000..5e4c960
--- /dev/null
+++ b/lib/thandy/packagesys/RPMPackages.py
@@ -0,0 +1,156 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
+
+import thandy.packagesys.PackageSystem
+
+import os
+import rpm
+import md5
+
+__all__ = [ 'RPMPackageSystem' ]
+
+class RPMPackageSystem(thandy.packagesys.PackageSystem.PackageSystem):
+ def getName(self):
+ return "RPM"
+
+ def packageHandleFromJSON(self, json):
+ raise NotImplemented() # XXXX
+
+ def getTransaction(self):
+ return RPMPackageTransaction()
+
+_CALLBACK_CODES = {}
+
+for name in dir(rpm):
+ if name.startswith("RPMCALLBACK_"):
+ _CALLBACK_CODES[getattr(rpm, name)] = name[12:]
+del name
+
+class RPMPackageTransaction(thandy.packagesys.PackageSystem.PackageTransaction):
+
+ def _start(self):
+ thandy.packagesys.PackageSystem.PackageTransaction.__init__(self)
+ self._tset = rpm.TransactionSet()
+
+ def _commit(self):
+ self._tset.run(self._callback, "")
+
+ def _callback(self, what, amount, total, mydata, _):
+ if what == rpm.RPMCALLBACK_INST_OPEN_FILE:
+ hdr, path = mydata
+ logging.info("Installing RPM for %s [%s]", hdr['name'], path)
+
+ elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
+ hdr, path = mydata
+ logging.info("Done installing RPM for %s", path)
+
+ elif what == rpm.RPMCALLBACK_INST_PROGRESS:
+ hdr, path = mydata
+ logging.info("%s: %.5s%% done", name, float(amount)/total*100)
+
+ else:
+ hdr, path = mydata
+ logging.info("RPM event %s on %s [%s/%s]",
+ _CALLBACK_CODES.get(what,str(what)),
+ hdr['name'], amount, total)
+
+def addRPMInstall(ts, path):
+ fd = os.open(path, os.O_RDONLY)
+ try:
+ hdr = ts.hdrFromFdno(fd)
+ finally:
+ os.close(fd)
+ ts.addInstall(hdr, (hdr, path), "u")
+
+def addRPMErase(ts, name):
+ ts.addErase(name)
+
+def getInstalledRPMVersions(name, ts=None):
+ if ts is None:
+ ts = rpm.TransactionSet()
+ #XXXX need to close?
+
+ versions = set()
+ for match in ts.dbMatch(rpm.RPMTAG_NAME, name):
+ versions.add(match['version'])
+
+ return versions
+
+def fileMD5(fname):
+ d = md5.new()
+ try:
+ f = open(fname, 'r')
+ try:
+ while 1:
+ s = f.read(4096)
+ if not s:
+ break
+ d.update(s)
+
+ finally:
+ f.close()
+ except OSError, e:
+ logging.warn("Couldn't get digest of %s: %s", fname, e)
+ return None
+
+ return d.hexdigest()
+
+def checkRPMInstall(name, version, ts=None):
+ if ts is None:
+ ts = rpm.TransactionSet()
+ #XXXX need to close?
+
+ found = False
+ all_ok = True
+
+ for h in ts.dbMatch(rpm.RPMTAG_NAME, name):
+ if h['version'] != version:
+ continue
+
+ found = True
+
+ for fname, flags, md5sum in zip(h['filenames'], h['fileflags'], h['filemd5s']):
+ haveMD5 = fileMD5(fname)
+ if not haveMD5:
+ if flags & RPMFILE_MISSINGOK:
+ logging.info("%s is missing or unreadable from %s %s; "
+ "that's ok.", fname, name, h['version'])
+ else:
+ logging.warn("%s is missing or unreadable from %s %s."
+ fname, name, h['version'])
+ all_ok = False
+ elif haveMD5 == md5sum:
+ logging.info("%s is unchanged from %s %s",
+ fname, name, h['version'])
+ else:
+ # file changed. If it's not configuration, that's a problem.
+ if not flags & RPMFILE_CONFIG:
+ logging.warn("%s changed from installed version of %s %s",
+ fname, name, h['version'])
+ all_ok = False
+
+ return found and all_ok
+
+class RPMPackageHandle(thandy.packagesys.PackageSystem.PackageHandle):
+ def __init__(self, name, version, filename):
+ self._name = name
+ self._version = version
+ self._filename = filename
+
+ def anyVersionInstalled(self, transaction=None):
+ return len(getInstalledRPMVersions(self.name, transaction)) > 1
+
+ def getInstalledVersion(self, transaction=None):
+ s = max(getInstalledRPMVersions(self._name, transaction))
+
+ def install(self, transaction):
+ addRPMInstall(transaction._trans, self._filename)
+
+ def remove(self, transaction):
+ addRPMErase(transaction._trans, self._name)
+
+ def isInstalled(self, transaction=None):
+ return self._version in getInstalledRPMVersions(self._name,transaction)
+
+ def checkInstall(self, transaction=None):
+ return checkRPMInstall(self._name, self._version)
+
diff --git a/lib/thandy/packagesys/__init__.py b/lib/thandy/packagesys/__init__.py
new file mode 100644
index 0000000..4dd7019
--- /dev/null
+++ b/lib/thandy/packagesys/__init__.py
@@ -0,0 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
+
+__all__ = [ ]
+