def runScript(script): """ Runs a script located in the source.tgz or zup """ if not os.path.exists(script): return elif not os.path.isfile(script) or \ not (os.access(script, os.X_OK) and os.access(script, os.R_OK)): raise ZenUpException("Could not run script: %s" % script) log.info("Running script: %s", script) root_log = logging.getLogger() p = subprocess.Popen(script, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) # ZEN-6550: Stream output to the log and console until finished while True: line = p.stdout.readline() if not line: break line = line.strip('\n') root_log.debug(line) log.debug("OUTPUT: %s", line) p.wait() # set p.returncode if p.returncode: raise ZenUpException("%s returned a non-zero exit code: %s." % (script, p.returncode))
def _loadProducts(self): status = os.path.join(self.HOME, self.STATUS_FILE) if not self.HOME or \ not os.path.exists(self.HOME) or \ not os.path.isdir(self.HOME) or \ not zuputils.hasAccess(self.HOME): raise ZenUpException("Unable to access zenup home: %s" % self.HOME) elif not os.path.exists(status): return try: with open(status) as fp: productYaml = yaml.load_all(fp) if not productYaml: return for productData in productYaml: product = zupproduct.ZupProduct(**productData) log.debug("Loaded product: %s", product.id_) self.products[product.id_] = product except Exception as e: raise ZenUpException("Error loading products from %s: %s" % (self.STATUS_FILE, e))
def _install(self): try: if self.args.dryrun: print "Performing a dry run..." else: if self.args.force: try: raw_input("WARNING: ALL custom patches and " "edits will be reverted! Press " "ENTER to continue or <CTRL+C> to " "quit.") except KeyboardInterrupt: raise ZenUpException("User cancelled operation") print "Installing..." out = self.api.install(self.args.zupfile, self.args.dryrun, self.args.force, displayOutput=True) print "\n".join(out) except ZenUpException as e: log.error("Error performing install.") self._error(e) else: print "Success!" finally: if self.args.dryrun: print "No changes have been applied to your system"
def patchProduct(self, productId, patchfile, message=None, options=None): product = self.getProduct(productId) if not product: raise ZenUpException("Product not found: %s" % productId) product.patch(patchfile, message=message, options=options) # Update time is modified self._saveProducts()
def _saveProducts(self): try: with open(os.path.join(self.HOME, self.STATUS_FILE), "w") as fp: yaml.dump_all([product.__dict__ for product in \ self.products.itervalues()], fp, default_flow_style=False, canonical=True) except Exception as e: raise ZenUpException("Error writing %s. Changes not saved: %s" % (self.STATUS_FILE, e))
def localDiff(self, productId, verbose=True): log.info("Generating local diff for product id: %s", productId) product = self.getProduct(productId) if not product: raise ZenUpException("Product not found: %s" % productId) ld = product.localDiff(verbose) log.info("Done generating local diff for product id: %s", productId) yield str(ld)
def initProduct(self, source, home, name=None, displayOutput=False): log.info("Initializing a new product") if self.getProduct(name): raise ZenUpException("Product name already in use: %s" % name) else: product = zupproduct.ZupProduct(home, name=name) pgen = product.install(source, self.HOME, displayOutput=displayOutput) # Verify unique product id pgen.next() if self.getProduct(product.id_): raise ZenUpException("Product id already in use: %s" % product.id_) pgen.next() self.products[product.id_] = product self._saveProducts() log.info("Done adding product: %s", product.id_)
def deleteProduct(self, productId): log.info("Deleting product: %s", productId) product = self.getProduct(productId) if not product: raise ZenUpException("Product not found: %s" % productId) elif product.id_ not in self.products: raise ZenUpInternalError("Key not found: %s" % product.id_) else: id_ = product.id_ product.uninstall() del self.products[id_] self._saveProducts() log.info("Done deleting product: %s", productId)
def display(self, showFix=None): ret = [] if showFix: fixgen = ifilter(lambda x: x.id.upper() == showFix.upper(), self.fixes) try: ret.extend(self._print_patch(fixgen.next())) except StopIteration: raise ZenUpException("Fix not found: %s" % showFix) else: for fix in self.fixes: ret.extend(["*"*79, "*"*79]) ret.extend(self._print_patch(fix)) return "\n".join(ret)
def applyPatch(patchfp, *options): cmd = ["patch"] if options: cmd.extend(options) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=patchfp, stderr=subprocess.PIPE) stdout, stderr = p.communicate() # Non-critical error when applying the patch, like conflicting changes # when trying to apply a patch (results reported in stderr) if p.returncode == 1: raise ZenUpException(stdout) # Critical error when applying the patch (results reported in stderr) elif p.returncode == 2: raise ZenUpInternalError(stderr)
def displayProductStats(self, productId=None, verbose=False): if productId is None: log.info("Displaying status for all products") if self.products: separator = "" for product in self.products.itervalues(): product.verbose = verbose yield "%s%s" % (separator, str(product)) separator = "---\n" else: yield "No Products Installed" else: log.info("Displaying status for product %s" % productId) product = self.getProduct(productId) if product: product.verbose = verbose yield "%s" % str(product) else: raise ZenUpException("Product not found: %s" % productId) log.info("Done displaying product status")
def install(self, zupfile, dryRun=False, force=False, displayOutput=False): with zuparchive.ZupArchive(zupfile) as archive: product = self.getProduct(archive.product) if not product: raise ZenUpException("Product not found: %s" % archive.product) if dryRun: files_added, files_deleted, files_modified, output = \ product.dryRun(zupfile) yield "\nFiles modified:" yield "\n".join(files_modified) yield "\nFiles added:" yield "\n".join(files_added) yield "\nFiles deleted:" yield "\n".join(files_deleted) if output: yield "\nResults:" yield "%s" % output else: product.upgrade(zupfile, force, displayOutput=displayOutput) self._saveProducts() yield ""
def upgrade(self, zupfile, force=False, displayOutput=False): with zuprunner.ZupRunner(self.id_) as runner: try: files_added, files_deleted, files_modified, output = \ self._dry_run(zupfile, runner, force=force) except KeyboardInterrupt as e: raise ZenUpException("User cancelled operation") zup = runner.archives.get(self._NEW_ZUP) # Run pre script if displayOutput: print "Running pre-copy steps..." zup.pre() # Copy all of the patched files if displayOutput: print "Copying files..." copy_files = sorted(chain(files_added, files_modified)) for filename in copy_files: src = os.path.join(runner.source, self.SOURCE_ARCH_SOURCE, filename) dest = os.path.join(self.home, filename) if os.path.isdir(src): os.makedirs(dest) else: destdir = os.path.dirname(dest) if not os.path.exists(destdir): os.makedirs(destdir) shutil.copyfile(src, dest) # Delete all of the applicable files delete_files = sorted(files_deleted, reverse=True) for filename in delete_files: dest = os.path.join(self.home, filename) if os.path.isdir(dest): shutil.rmtree(dest) else: os.remove(dest) # Run post script if displayOutput: print "Running post-copy steps..." zup.post() # Update the product lastUpdate = datetime.now() if displayOutput: print "Finishing up..." new_zup = "%s-SP%s.zup" % (self.id_, zup.revision) directory = self.getPacksDirPath() if not os.path.exists(directory): os.mkdir(directory) shutil.copyfile(zupfile, os.path.join(directory, new_zup)) self.zupfile = new_zup self.revision = zup.revision self.lastupdate = lastUpdate.strftime("%c") # If force, clear the message file if force and os.path.exists(self.getMessageFilePath()): with open(self.getMessageFilePath(), "a") as fp: fp.write("%s Installed ZUP revision %s %s" % ("=" * 10, self.revision, "=" * 10)) destfile = "%s.%s" % (self.getMessageFilePath(), lastUpdate.strftime("%Y%m%d%H%M")) shutil.move(self.getMessageFilePath(), destfile)
def patch(self, patchfile, message=None, options=None): """ Applies a single patch directly onto the product's home directory while allowing the user to add their own individualized comments. """ message = message or "" pwd = os.getcwd() patchfile = os.path.join(pwd, patchfile) if not zuputils.hasAccess(patchfile): raise ZenUpException("Cannot access patch file %s" % patchfile) if not zuputils.hasAccess(self.home): raise ZenUpInternalError("Cannot access product home %s (%s)" % (self.home, self.id_)) isStrip = False if options: ops = options.split() for op in ops: if op.startswith(("-p", "--strip")): isStrip = True break else: ops = [] if not isStrip: ops.append("-p0") try: os.chdir(self.home) with open(patchfile) as fp: zuputils.applyPatch(fp, "--dry-run", *ops) fp.seek(0) filename = os.path.basename(patchfile) directory = self.getPatchesDirPath() fname, ext = os.path.splitext( filename) # "hello_world", ".txt" i = 1 while os.path.exists(os.path.join(directory, filename)): i += 1 filename = "%s%s.%d" % (fname, ext, i) if not os.path.exists(directory): os.mkdir(directory) path = os.path.join(directory, filename) shutil.copyfile(patchfile, path) zuputils.applyPatch(fp, *ops) except ZenUpInternalError as e: raise ZenUpException(e) finally: os.chdir(pwd) with open(self.getMessageFilePath(), "a") as fp: timestamp = datetime.now().strftime("%c") if options: fp.write('%s [%s "%s"] %s\n' % (timestamp, filename, options, message)) else: fp.write('%s [%s] %s\n' % (timestamp, filename, message)) self.lastupdate = timestamp