5 from wizard import deploy
6 from wizard import util
7 from wizard import shell
8 from wizard import cache
9 from wizard.command import _base
10 from wizard.command import migrate
12 def main(argv, global_options, logger = None):
13 usage = """usage: %prog massmigrate [ARGS] APPLICATION
15 Mass migrates an application to the new repository format.
16 Essentially equivalent to running '%prog migrate' on all
17 autoinstalls for a particular application found by parallel-find,
18 but with advanced reporting.
20 When doing an actual run, it is recommended to use --cache to
21 be able to resume gracefully (without it, massmigrate must
22 stat every install to find out if it migrated it yet).
24 parser = _base.WizardOptionParser(usage)
25 parser.add_option("--no-parallelize", dest="no_parallelize", action="store_true",
26 default=False, help="Turn off parallelization")
27 parser.add_option("--dry-run", dest="dry_run", action="store_true",
28 default=False, help="Print commands that would be run. Implies --no-parallelize")
29 parser.add_option("--max", dest="max",
30 default=10, help="Maximum subprocesses to run concurrently")
31 parser.add_option("--cache", dest="cache",
32 default=None, help="Cache file to read/write paths of already processed installs. These will be skipped.")
33 options, args, logger = parser.parse_all(argv, logger)
35 parser.error("too many arguments")
37 parser.error("must specify application to migrate")
39 options.no_parallelize = True
42 base_args = _base.makeBaseArgs(options, dry_run="--dry-run")
43 # check if we have root
46 # dry run is purposely omitted
47 if options.no_parallelize:
48 sh = shell.DummyParallelShell(logger=logger)
50 sh = shell.ParallelShell(logger=logger, max=int(options.max))
52 seen = cache.Cache(options.cache)
54 seen = cache.DummyCache()
55 for line in deploy.getInstallLines(global_options):
56 # validate and filter the deployments
58 d = deploy.Deployment.parse(line)
59 except deploy.DeploymentParseError, deploy.NoSuchApplication:
61 name = d.getApplication().name
62 if name != app: continue
63 if d.location in seen:
67 def on_success(stdout, stderr):
70 if e.name == "wizard.command.migrate.AlreadyMigratedError":
72 logger.info("Skipped already migrated %s" % d.location)
75 if name not in errors: errors[name] = []
76 errors[name].append(d)
77 logger.error("%s in %s" % (name, d.location))
78 return (on_success, on_error)
79 on_success, on_error = make_on_pair(d)
80 sh.wait() # wait for a parallel processing slot to be available
81 sh.callAsUser(shell.wizard, "migrate", d.location, *base_args,
82 user=user, on_success=on_success, on_error=on_error)
84 for name, deploys in errors.items():
85 logger.warning("%s from %d installs" % (name, len(deploys)))