import optparse import os import wizard from wizard import deploy from wizard import util from wizard import shell from wizard.command import _base from wizard.command import migrate def main(argv, global_options, logger = None): usage = """usage: %prog massmigrate [ARGS] APPLICATION Mass migrates an application to the new repository format. Essentially equivalent to running '%prog migrate' on all autoinstalls for a particular application found by parallel-find, but with advanced reporting. """ parser = _base.WizardOptionParser(usage) parser.add_option("--no-parallelize", dest="no_parallelize", action="store_true", default=False, help="Turn off parallelization") parser.add_option("--dry-run", dest="dry_run", action="store_true", default=False, help="Print commands that would be run. Implies --no-parallelize") parser.add_option("--max", dest="max", default=10, help="Maximum subprocesses to run concurrently") options, args, logger = parser.parse_all(argv, logger) if len(args) > 1: parser.error("too many arguments") elif not args: parser.error("must specify application to migrate") if options.verbose or options.dry_run: options.no_parallelize = True app = args[0] errors = {} base_args = _base.makeBaseArgs(options, dry_run="--dry-run") # check if we have root uid = os.getuid() user = None # dry run is purposely omitted if options.no_parallelize: sh = shell.DummyParallelShell(logger=logger) else: sh = shell.ParallelShell(logger=logger, max=int(options.max)) for line in deploy.getInstallLines(global_options): # validate and filter the deployments try: d = deploy.Deployment.parse(line) except deploy.DeploymentParseError, deploy.NoSuchApplication: continue name = d.getApplication().name if name != app: continue # actual meat def on_success(stdout, stderr): pass # yay! don't do anything def make_on_error(d): # make it early binding def on_error(e): if e.name == "wizard.command.migrate.AlreadyMigratedError": logger.info("Skipped already migrated %s" % d.location) else: name = e.name if name not in errors: errors[name] = [] errors[name].append(d) logger.error("ERROR [%s] in %s" % (name, d.location)) return on_error on_error = make_on_error(d) sh.wait() # wait for a parallel processing slot to be available sh.callAsUser(shell.wizard, "migrate", d.location, *base_args, user=user, on_success=on_success, on_error=on_error) sh.join() for name, deploys in errors.items(): logger.warning("ERROR [%s] from %d installs" % (name, len(deploys)))