-import optparse
-import sys
import os
import shutil
-import logging.handlers
+import logging
import errno
+import sys
-from wizard import deploy
-from wizard import shell
-from wizard.command import _base
+from wizard import command, deploy, shell, util
-class Error(_base.Error):
- """Base exception for all exceptions raised by migrate"""
- pass
+def main(argv, baton):
+ options, args = parse_args(argv)
+ dir = args[0]
-class AlreadyMigratedError(Error):
- def __init__(self, dir):
- self.dir = dir
- def __str__(self):
- return """
+ logging.debug("uid is %d" % os.getuid())
-ERROR: Directory already contains a .git and/or
-.scripts directory. Did you already migrate it?
-"""
+ command.chdir(dir)
+ check_if_already_migrated(options)
-class NotAutoinstallError(Error):
- def __init__(self, dir):
- self.dir = dir
- def __str__(self):
- return """
+ deployment = make_deployment() # uses chdir
+ version = deployment.app_version
+ repo = version.application.repository
+ tag = version.scripts_tag
-ERROR: Could not find .scripts-version file. Are you sure
-this is an autoinstalled application?
-"""
+ os.unsetenv("GIT_DIR") # prevent some perverse errors
-class NoRepositoryError(Error):
- def __init__(self, app):
- self.app = app
- def __str__(self):
- return """
+ sh = shell.Shell(options.dry_run)
+ check_if_tag_exists(sh, repo, tag)
+ make_repository(sh, options, repo, tag)
+ make_variables(deployment, options)
-ERROR: Could not find repository for this application. Have
-you converted the repository over? Is the name %s
-the same as the name of the .git folder?
-""" % self.app
-
-class NoTagError(Error):
- def __init__(self, version):
- self.version = version
- def __str__(self):
- return """
+ if not options.dry_run:
+ deployment.updateVersion()
+ os.rename(".scripts-version", ".scripts/old-version") # archive
+ else:
+ logging.info("# create .scripts/version containing \"%s-%s\"" % (deployment.application.name, deployment.version))
+ logging.info("mv .scripts-version .scripts/old-version")
-ERROR: Could not find tag v%s-scripts in repository
-for %s. Double check and make sure
-the repository was prepared with all necessary tags!
-""" % (self.version.version, self.version.application.name)
-
-def main(argv, global_options, logger = None):
+def parse_args(argv):
usage = """usage: %prog migrate [ARGS] DIR
Migrates a directory to our Git-based autoinstall format.
Performs basic sanity checking and intelligently determines
-what repository and tag to use."""
- parser = _base.WizardOptionParser(usage)
+what repository and tag to use.
+
+This command is meant to be run as the owner of the install
+it is upgrading (see the scripts AFS kernel patch). Do
+NOT run this command as root."""
+ parser = command.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",
default=False, help="If .git or .scripts directory already exists, delete them and migrate")
- options, args, logger = parser.parse_all(argv, logger)
+ options, args = parser.parse_all(argv)
if len(args) > 1:
parser.error("too many arguments")
elif not args:
parser.error("must specify directory")
- dir = args[0]
- try:
- os.chdir(dir)
- except OSError as e:
- if e.errno == errno.EACCES:
- raise _base.PermissionsError(dir)
- elif e.errno == errno.ENOENT:
- raise _base.NoSuchDirectoryError(dir)
- else: raise e
+ return (options, args)
+
+def check_if_already_migrated(options):
if os.path.isdir(".git") or os.path.isdir(".scripts"):
if not options.force:
raise AlreadyMigratedError(dir)
else:
if os.path.isdir(".git"):
- logger.warning("Force removing .git directory")
+ logging.warning("Force removing .git directory")
if not options.dry_run: shutil.rmtree(".git")
if os.path.isdir(".scripts"):
- logger.warning("Force removing .scripts directory")
+ logging.warning("Force removing .scripts directory")
if not options.dry_run: shutil.rmtree(".scripts")
+
+def make_deployment():
try:
- d = deploy.Deployment.fromDir(".")
- version = d.getAppVersion()
+ return deploy.Deployment(".")
except IOError as e:
if e.errno == errno.ENOENT:
raise NotAutoinstallError(dir)
else: raise e
- # calculate the repository we'll be pulling out of
- application = version.application
- app = application.name
- repo = os.path.join("/afs/athena.mit.edu/contrib/scripts/wizard/srv", app + ".git")
- if not os.path.isdir(repo):
- raise NoRepositoryError(app)
- # begin the command line process
- sh = shell.Shell(logger, options.dry_run)
+
+def check_if_tag_exists(sh, repo, tag):
# 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
sh.call("git", "--git-dir", repo, "rev-parse", tag)
except shell.CallError:
raise NoTagError(version)
- did_git_init = False
- did_git_checkout_scripts = False
+
+def make_repository(sh, options, repo, tag):
+ sh.call("git", "init") # create repository
+ # configure our alternates (to save space and make this quick)
+ data = os.path.join(repo, "objects")
+ file = ".git/objects/info/alternates"
+ if not options.dry_run:
+ alternates = open(file, "w")
+ alternates.write(data)
+ alternates.close()
+ htaccess = open(".git/.htaccess", "w")
+ htaccess.write("Deny from all\n")
+ htaccess.close()
+ else:
+ logging.info("# create %s containing \"%s\"" % (file, data))
+ logging.info('# create .htaccess containing "Deny from all"')
+ # configure our remote (this is merely for convenience; wizard scripts
+ # will not rely on this)
+ sh.call("git", "remote", "add", "origin", repo)
+ # configure what would normally be set up on a 'git clone' for consistency
+ sh.call("git", "config", "branch.master.remote", "origin")
+ sh.call("git", "config", "branch.master.merge", "refs/heads/master")
+ # perform the initial fetch
+ sh.call("git", "fetch", "origin")
+ # soft reset to our tag
+ sh.call("git", "reset", tag, "--")
+ # checkout the .scripts directory
+ sh.call("git", "checkout", ".scripts")
+ # commit user local changes
+ message = "Autoinstall migration of %s locker.\n\n%s" % (util.get_dir_owner(), util.get_git_footer())
+ util.set_git_env()
try:
- # create repository
- sh.call("git", "--git-dir=.git", "init")
- did_git_init = True
- # configure our alternates (to save space and make this quick)
- data = os.path.join(repo, "objects")
- file = ".git/objects/info/alternates"
- if not options.dry_run:
- alternates = open(file, "w")
- alternates.write(data)
- alternates.close()
+ message += "\nMigrated-by: " + util.get_operator_git()
+ except util.NoOperatorInfo:
+ pass
+ sh.call("git", "commit", "--allow-empty", "-a", "-m", message)
+ # for verbose purposes, give us a git status and git diff
+ if options.verbose:
+ try:
+ sh.call("git", "status")
+ except shell.CallError:
+ pass
+ try:
+ sh.call("git", "diff")
+ except shell.CallError:
+ pass
+
+def make_variables(d, options):
+ """Make .scripts/variables which contains variables based off of
+ what was regexed out of existing configuration files."""
+ variables = d.extract()
+ if not options.dry_run: f = open(".scripts/variables", "w")
+ for k,v in variables.items():
+ if v is None:
+ # once we get everything on the same version, you should
+ # actually start paying attention to these warnings
+ logging.warning("Variable %s not found" % k)
else:
- logger.info("# create %s containing \"%s\"" % (file, data))
- # configure our remote
- sh.call("git", "remote", "add", "origin", repo)
- # configure what would normally be set up on a 'git clone' for consistency
- sh.call("git", "config", "branch.master.remote", "origin")
- sh.call("git", "config", "branch.master.merge", "refs/heads/master")
- # perform the initial fetch
- sh.call("git", "fetch", "origin")
- # soft reset to our tag
- sh.call("git", "reset", tag, "--")
- # checkout the .scripts directory
- 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:
- try:
- sh.call("git", "status")
- except shell.CallError:
- pass
- try:
- sh.call("git", "diff")
- except shell.CallError:
- pass
- except:
- # this... is pretty bad
- logger.critical("ERROR: Exception detected! Rolling back...")
- if did_git_init:
- sh.call("rm", "-Rf", ".git")
- if did_git_checkout_scripts:
- sh.call("rm", "-Rf", ".scripts")
- raise
+ logging.debug("Variable %s is %s" % (k,v))
+ if not options.dry_run:
+ f.write("%s %s\n" % (k,v))
+ else:
+ logging.info('# write line "%s %s" to .scripts/variables' % (k,v))
+ if not options.dry_run: f.close()
+
+class Error(command.Error):
+ """Base exception for all exceptions raised by migrate"""
+ pass
+
+class AlreadyMigratedError(Error):
+ def __init__(self, dir):
+ self.dir = dir
+ def __str__(self):
+ return """
+
+ERROR: Directory already contains a .git and/or
+.scripts directory. Did you already migrate it?
+"""
+
+class NotAutoinstallError(Error):
+ def __init__(self, dir):
+ self.dir = dir
+ def __str__(self):
+ return """
+
+ERROR: Could not find .scripts-version file. Are you sure
+this is an autoinstalled application?
+"""
+
+class NoTagError(Error):
+ def __init__(self, version):
+ self.version = version
+ def __str__(self):
+ return """
+
+ERROR: Could not find tag v%s-scripts in repository
+for %s. Double check and make sure
+the repository was prepared with all necessary tags!
+""" % (self.version.version, self.version.application.name)