def _restore(self, filename): ipath = path.normpath(path.join(self.installpath, filename)) bpath = path.normpath(path.join(self.backuppath, filename)) idir = path.dirname(ipath) if not path.isdir(idir): os.makedirs(idir) try: if path.isfile(ipath): log.debug("Removing file {0} before restoring old version".format(filename)) os.remove(ipath) log.debug("Restoring file {0} by moving from backup directory".format(filename)) shutil.move(bpath, ipath) except: log.debug("Restore failed for {0}".format(filename))
def _backup(self, filename, move=True): ipath = path.normpath(path.join(self.installpath, filename)) bpath = path.normpath(path.join(self.backuppath, filename)) if not path.isfile(ipath): return bdir = path.dirname(bpath) if not path.isdir(bdir): os.makedirs(bdir) try: if move: log.debug("Backing up file {0} by moving to backup directory".format(filename)) shutil.move(ipath, bpath) else: log.debug("Backing up file {0} by copying to backup directory".format(filename)) shutil.copy(ipath, bpath) except: log.debug("Backup failed for {0}".format(filename))
def apply(self, installpath, backuppath=None): """ Apply the manifest against the given installation path. """ self.installpath = installpath manifest = self.manifest # fetch and verify package if "package-uri" in manifest: packageuri = URI(manifest["package-uri"]) packagename = path.basename(packageuri["path"]) packagepath = path.join(tempfile.gettempdir(), packagename) packageformat = None if "package-format" in manifest: packageformat = manifest["package-format"] # download package file log.info("Fetching update package from {0}".format(packageuri.uri)) packageuri.fetch(packagepath) packageuri.close() # integrity check if "package-sha1" in manifest: packagesha1 = sha1(packagepath) if not packagesha1 == manifest["package-sha1"]: raise Exception("Package integrity check failed") self.package = Package(packagepath, packageformat) # create spot for backup files if backuppath is None: self.backuppath = tempfile.mkdtemp(prefix="update_") else: self.backuppath = backuppath if not path.isdir(self.backuppath): log.debug("Backup path {0} does not exist; creating".format(self.backuppath)) os.mkdir(self.backuppath) # start applying actions try: for info in manifest.actions: self._action(info) # handle update errors by rolling back except Exception as err: log.exception("Exception eaten; beginning rollback") for root, dirs, files in os.walk(self.backuppath): relpath = path.relpath(root, self.backuppath) if relpath == ".": relpath = "" for filename in files: filepath = path.join(relpath, filename) log.info("Rolling back file %s" % (filepath)) self._restore(filepath) log.info("Rollback completed; raising exception") raise # clean up finally: self.cleanup = False shutil.rmtree(self.backuppath, onerror=self._onerror) self.package.close() os.remove(packagepath) if self.cleanup: return self.backuppath
def fetch(self, target=None): parse = self.parse # local file if parse.scheme == "file": self.handle = File(parse.path, "r", format=self.format) if target: self.handle.decompress(target) self.handle.close() self.handle = File(target, "r") # package file elif parse.scheme == "package": if self.package is None: raise Exception("No package specified") filename = parse.path.lstrip("/") self.handle = self.package.open(filename, "r", format=self.format) if target: self.handle.decompress(target) self.handle.close() self.handle = File(target, "r") # remote http resource elif parse.scheme in ("http", "https"): failure = True tries = 0 while failure: failure = False try: if target: target = path.normpath(target) log.info("Downloading {0} to file {1}".format(self.uri, target)) downloadpath, headers = urllib.urlretrieve(self.uri) self.handle = File(downloadpath, "r", format=self.format) self.handle.decompress(target) self.handle.close() self.handle = File(target, "r") else: self.handle = urllib2.urlopen(self.uri) except: failure = True if tries < 3: log.info("Problem retrieving URI, retry in 3 seconds...") log.debug(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) time.sleep(3) else: log.info("Failed retrieving URI") raise finally: tries += 1 return self.handle else: raise Exception("Unsupported URI scheme {0}".format(parse.scheme)) return self.handle