TODO NOW:
+- Check how many autoinstalls are missing w bits for
+ daemon.scripts
- Whiteboard the flow for performing an upgrade on a single
install. How assisted does it need to be?
- Conduct migration tool testing (check andersk, geofft for
-import logging
-import sys
-import optparse
-
-def makeLogger(options):
- logger = logging.getLogger("main")
- logger.setLevel(logging.INFO)
- stdout = logging.StreamHandler(sys.stdout)
- logger.addHandler(stdout)
- if options.verbose:
- logger.verbose = True
- else:
- if not options.debug: stdout.setLevel(logging.ERROR)
- if options.debug: logger.setLevel(logging.DEBUG)
- return logger
-
-class UserException(Exception):
- """User friendly exceptions inherit from here"""
+class Error(Exception):
+ """Base exception for all Wizard exceptions"""
pass
-class NullLogHandler(logging.Handler):
- """Log handler that doesn't do anything"""
- def emit(self, record):
- pass
-
-class WizardOptionParser(optparse.OptionParser):
- """Configures some default user-level options"""
- def __init__(self, *args, **kwargs):
- optparse.OptionParser.__init__(self, *args, **kwargs)
- self.add_option("-v", "--verbose", dest="verbose", action="store_true",
- default=False, help="Turns on verbose output")
- self.add_option("--debug", dest="debug", action="store_true",
- default=False, help="Turns on debugging output")
- def parse_all(self, argv, logger):
- options, numeric_args = self.parse_args(argv)
- return options, numeric_args, logger and logger or makeLogger(options)
from migrate import migrate
from summary import summary
from massmigrate import massmigrate
+
--- /dev/null
+import logging
+import sys
+import optparse
+
+import wizard
+
+class Error(wizard.Error):
+ """Base error class for all command errors"""
+ pass
+
+def makeLogger(options):
+ logger = logging.getLogger("main")
+ logger.setLevel(logging.INFO)
+ stdout = logging.StreamHandler(sys.stdout)
+ logger.addHandler(stdout)
+ if options.verbose:
+ logger.verbose = True
+ else:
+ if not options.debug: stdout.setLevel(logging.ERROR)
+ if options.debug: logger.setLevel(logging.DEBUG)
+ return logger
+
+class NullLogHandler(logging.Handler):
+ """Log handler that doesn't do anything"""
+ def emit(self, record):
+ pass
+
+class WizardOptionParser(optparse.OptionParser):
+ """Configures some default user-level options"""
+ def __init__(self, *args, **kwargs):
+ optparse.OptionParser.__init__(self, *args, **kwargs)
+ self.add_option("-v", "--verbose", dest="verbose", action="store_true",
+ default=False, help="Turns on verbose output")
+ self.add_option("--debug", dest="debug", action="store_true",
+ default=False, help="Turns on debugging output")
+ def parse_all(self, argv, logger):
+ options, numeric_args = self.parse_args(argv)
+ return options, numeric_args, logger and logger or makeLogger(options)
import sys
import subprocess
-import wizard.deploy as wd
+from wizard import deploy
def prettify(loc):
return loc.replace("/afs/athena.mit.edu/contrib/scripts", "~scripts")
parser.error("too many arguments")
elif not args:
parser.error("must specify directory")
- deploy = wd.Deployment.fromDir(args[0])
- deploy.getLog() # force the log to be loaded, to pre-empt errors
+ d = deploy.Deployment.fromDir(args[0])
+ d.getLog() # force the log to be loaded, to pre-empt errors
proc = False
# This is prime candidate for refactoring. This code pipes
# stdout to less, so that you get scrolling and stuff.
try:
if options.reverse: munge = lambda x: x
else: munge = reversed
- for entry in munge(deploy.getLog()):
+ for entry in munge(d.getLog()):
print "%s %s" % (entry.version.application.name, entry.version.version)
print "User: %s" % entry.user
print "Date: %s" % entry.datetime.strftime("%a %b %0d %H:%M:%S %Y %z")
print
info = "Unknown"
- if isinstance(entry.source, wd.TarballInstall):
+ if isinstance(entry.source, deploy.TarballInstall):
info = "Installed with tarball at:\n%s" % \
prettify(entry.source.location)
print indent(info, 4)
import optparse
-import sys
-import os
-import shutil
+from wizard import deploy
+
+import _base
import migrate
-import wizard.deploy as wd
-import wizard.shell as sh
-from wizard import *
def massmigrate(argv, global_options, logger = None):
usage = """usage: %prog massmigrate [ARGS] APPLICATION
NOTE: --verbose implies --no-parallelize, as it results in
output going to stdout/stderr."""
- parser = WizardOptionParser(usage)
+ 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",
if options.verbose: base_args.append("--verbose")
if options.dry_run: base_args.append("--dry-run")
deploys = []
- for line in wd.getInstallLines(global_options):
+ for line in deploy.getInstallLines(global_options):
try:
- deploy = wd.Deployment.parse(line)
- except wd.DeploymentParseError, wd.NoSuchApplication:
+ d = deploy.Deployment.parse(line)
+ except deploy.DeploymentParseError, deploy.NoSuchApplication:
continue
- name = deploy.getApplication().name
+ name = d.getApplication().name
if name != app: continue
- deploys.append(deploy)
+ deploys.append(d)
# parallelization code would go here
errors = {}
- for deploy in deploys:
- sub_argv = base_args + [deploy.location]
+ for d in deploys:
+ sub_argv = base_args + [d.location]
logger.info("$ wizard migrate " + " ".join(sub_argv))
try:
migrate.migrate(sub_argv, global_options, logger)
except migrate.AlreadyMigratedError as e:
logger.info("Skipped already migrated %s" % d.location)
- except UserException as e:
+ except migrate.Error as e:
name = e.__class__.__name__
if name not in errors: errors[name] = []
- errors[name].append(deploy)
+ errors[name].append(d)
logger.error("ERROR [%s] in %s" % (name, d.location))
for name, deploys in errors.items():
logger.warning("ERROR [%s] from %d installs" % (name, len(deploys)))
import shutil
import logging.handlers
-from wizard import *
-import wizard.deploy as wd
-import wizard.shell as sh
+from wizard import deploy
+from wizard import shell
-class PermissionsError(UserException):
+import _base
+import wizard
+
+class Error(_base.Error):
+ """Base exception for all exceptions raised by migrate"""
+ pass
+
+class PermissionsError(Error):
def __init__(self, dir):
self.dir = dir
def __str__(self):
'krbroot shell' and then 'aklog').
"""
-class NoSuchDirectoryError(UserException):
+class NoSuchDirectoryError(Error):
def __init__(self, dir):
self.dir = dir
def __str__(self):
ERROR: No such directory... check your typing
"""
-class AlreadyMigratedError(UserException):
+class AlreadyMigratedError(Error):
def __init__(self, dir):
self.dir = dir
def __str__(self):
Did you already migrate it?
"""
-class NotAutoinstallError(UserException):
+class NotAutoinstallError(Error):
def __init__(self, dir):
self.dir = dir
def __str__(self):
this is an autoinstalled application?
"""
-class NoRepositoryError(UserException):
+class NoRepositoryError(Error):
def __init__(self, app):
self.app = app
def __str__(self):
the same as the name of the .git folder?
""" % self.app
-class NoTagError(UserException):
+class NoTagError(Error):
def __init__(self, version):
self.version = version
def __str__(self):
Migrates a directory to our Git-based autoinstall format.
Performs basic sanity checking and intelligently determines
what repository and tag to use."""
- parser = WizardOptionParser(usage)
+ parser = _base.WizardOptionParser(usage)
parser.add_option("--dry-run", dest="dry_run", action="store_true",
default=False, help="Prints would would be run without changing anything")
parser.add_option("--force", "-f", dest="force", action="store_true",
logger.warning("Force removing .scripts directory")
if not options.dry_run: shutil.rmtree(".scripts")
try:
- deploy = wd.Deployment.fromDir(".")
- version = deploy.getAppVersion()
+ d = deploy.Deployment.fromDir(".")
+ version = d.getAppVersion()
except IOError as e:
if e.errno == 2:
raise NotAutoinstallError(dir)
if not os.path.isdir(repo):
raise NoRepositoryError(app)
# begin the command line process
- shell = sh.Shell(logger, options.dry_run)
+ sh = shell.Shell(logger, options.dry_run)
# check if the version we're trying to convert exists. We assume
# a convention here, namely, v1.2.3-scripts is what we want. If
# you broke the convention... shame on you.
try:
tag = "v%s-scripts" % version.version
- shell.call("git", "--git-dir", repo, "rev-parse", tag)
- except sh.CalledProcessError:
+ sh.call("git", "--git-dir", repo, "rev-parse", tag)
+ except shell.CalledProcessError:
raise NoTagError(version)
did_git_init = False
did_git_checkout_scripts = False
try:
# create repository
- shell.call("git", "--git-dir=.git", "init")
+ sh.call("git", "--git-dir=.git", "init")
did_git_init = True
# configure our remote
- shell.call("git", "remote", "add", "origin", repo)
+ sh.call("git", "remote", "add", "origin", repo)
# configure what would normally be set up on a 'git clone' for consistency
- shell.call("git", "config", "branch.master.remote", "origin")
- shell.call("git", "config", "branch.master.merge", "refs/heads/master")
+ sh.call("git", "config", "branch.master.remote", "origin")
+ sh.call("git", "config", "branch.master.merge", "refs/heads/master")
# perform the initial fetch
- shell.call("git", "fetch", "origin")
+ sh.call("git", "fetch", "origin")
# soft reset to our tag
- shell.call("git", "reset", tag, "--")
+ sh.call("git", "reset", tag, "--")
# checkout the .scripts directory
- shell.call("git", "checkout", ".scripts")
+ sh.call("git", "checkout", ".scripts")
did_git_checkout_scripts = True
# XXX: setup .scripts/version???
# for verbose purposes, give us a git status and git diff
if options.verbose:
- shell.call("git", "status")
- shell.call("git", "diff")
+ sh.call("git", "status")
+ sh.call("git", "diff")
except:
# this... is pretty bad
logger.critical("ERROR: Exception detected! Rolling back...")
if did_git_init:
- shell.call("rm", "-Rf", ".git")
+ sh.call("rm", "-Rf", ".git")
if did_git_checkout_scripts:
- shell.call("rm", "-Rf", ".scripts")
+ sh.call("rm", "-Rf", ".scripts")
raise
import optparse
-import wizard.deploy as wd
import sys
+from wizard import deploy
+
# XXX: Migrate this to use logger
class Printer(object):
def __init__(self, quiet, verbose):
parser.add_option("--count-exists", dest="count_exists",
default=False, help="Count deployments that contain a file")
options, show = parser.parse_args(argv)
- fi = wd.getInstallLines(global_options)
- if not show: show = wd.applications.keys()
+ fi = deploy.getInstallLines(global_options)
+ if not show: show = deploy.applications.keys()
show = frozenset(show)
errors = 0
unrecognized = 0
for line in fi:
printer.tick()
try:
- deploy = wd.Deployment.parse(line)
- except wd.DeploymentParseError:
+ d = deploy.Deployment.parse(line)
+ except deploy.DeploymentParseError:
errors += 1
continue
- except wd.NoSuchApplication:
+ except deploy.NoSuchApplication:
unrecognized += 1
continue
- name = deploy.getApplication().name
- if name + "-" + str(deploy.getVersion()) in show:
+ name = d.getApplication().name
+ if name + "-" + str(d.getVersion()) in show:
printer.write("%s-%s deployment at %s" \
- % (name, deploy.getVersion(), deploy.location))
+ % (name, d.getVersion(), d.location))
elif name in show:
pass
else:
continue
- deploy.count()
+ d.count()
if options.count_exists:
- r = deploy.count_exists(options.count_exists)
+ r = d.count_exists(options.count_exists)
if r:
- printer.chat("Found " + options.count_exists + " in " + deploy.location)
+ printer.chat("Found " + options.count_exists + " in " + d.location)
printer.write()
- for app in wd.applications.values():
+ for app in deploy.applications.values():
if app.name not in show: continue
printer.write(app.report())
printer.write()