5 import logging.handlers
8 from wizard import deploy
9 from wizard import shell
10 from wizard.command import _base
12 class Error(_base.Error):
13 """Base exception for all exceptions raised by migrate"""
16 class AlreadyMigratedError(Error):
17 def __init__(self, dir):
22 ERROR: Directory already contains a .git and/or
23 .scripts directory. Did you already migrate it?
26 class NotAutoinstallError(Error):
27 def __init__(self, dir):
32 ERROR: Could not find .scripts-version file. Are you sure
33 this is an autoinstalled application?
36 class NoRepositoryError(Error):
37 def __init__(self, app):
42 ERROR: Could not find repository for this application. Have
43 you converted the repository over? Is the name %s
44 the same as the name of the .git folder?
47 class NoTagError(Error):
48 def __init__(self, version):
49 self.version = version
53 ERROR: Could not find tag v%s-scripts in repository
54 for %s. Double check and make sure
55 the repository was prepared with all necessary tags!
56 """ % (self.version.version, self.version.application.name)
58 def main(argv, global_options, logger = None):
59 usage = """usage: %prog migrate [ARGS] DIR
61 Migrates a directory to our Git-based autoinstall format.
62 Performs basic sanity checking and intelligently determines
63 what repository and tag to use.
65 This command is meant to be run as the owner of the install
66 it is upgrading (see the scripts AFS kernel patch). Do
67 NOT run this command as root."""
68 parser = _base.WizardOptionParser(usage)
69 parser.add_option("--dry-run", dest="dry_run", action="store_true",
70 default=False, help="Prints would would be run without changing anything")
71 parser.add_option("--force", "-f", dest="force", action="store_true",
72 default=False, help="If .git or .scripts directory already exists, delete them and migrate")
73 options, args, logger = parser.parse_all(argv, logger)
75 parser.error("too many arguments")
77 parser.error("must specify directory")
78 logger.debug("uid is %d" % os.getuid())
83 if e.errno == errno.EACCES:
84 raise _base.PermissionsError(dir)
85 elif e.errno == errno.ENOENT:
86 raise _base.NoSuchDirectoryError(dir)
88 if os.path.isdir(".git") or os.path.isdir(".scripts"):
90 raise AlreadyMigratedError(dir)
92 if os.path.isdir(".git"):
93 logger.warning("Force removing .git directory")
94 if not options.dry_run: shutil.rmtree(".git")
95 if os.path.isdir(".scripts"):
96 logger.warning("Force removing .scripts directory")
97 if not options.dry_run: shutil.rmtree(".scripts")
99 d = deploy.Deployment.fromDir(".")
100 version = d.getAppVersion()
102 if e.errno == errno.ENOENT:
103 raise NotAutoinstallError(dir)
105 # calculate the repository we'll be pulling out of
106 application = version.application
107 app = application.name
108 repo = os.path.join("/afs/athena.mit.edu/contrib/scripts/wizard/srv", app + ".git")
109 if not os.path.isdir(repo):
110 raise NoRepositoryError(app)
111 # begin the command line process
112 sh = shell.Shell(logger, options.dry_run)
113 # check if the version we're trying to convert exists. We assume
114 # a convention here, namely, v1.2.3-scripts is what we want. If
115 # you broke the convention... shame on you.
117 tag = "v%s-scripts" % version.version
118 sh.call("git", "--git-dir", repo, "rev-parse", tag)
119 except shell.CallError:
120 raise NoTagError(version)
122 did_git_checkout_scripts = False
124 sh.call("git", "init")
126 # configure our alternates (to save space and make this quick)
127 data = os.path.join(repo, "objects")
128 file = ".git/objects/info/alternates"
129 if not options.dry_run:
130 alternates = open(file, "w")
131 alternates.write(data)
134 logger.info("# create %s containing \"%s\"" % (file, data))
135 # configure our remote
136 # (later on, we won't actually use these ourselves, since we
137 # might want to use an arbitrary repository)
138 sh.call("git", "remote", "add", "origin", repo)
139 # configure what would normally be set up on a 'git clone' for consistency
140 sh.call("git", "config", "branch.master.remote", "origin")
141 sh.call("git", "config", "branch.master.merge", "refs/heads/master")
142 # perform the initial fetch
143 sh.call("git", "fetch", "origin")
144 # soft reset to our tag
145 sh.call("git", "reset", tag, "--")
146 # checkout the .scripts directory
147 sh.call("git", "checkout", ".scripts")
148 did_git_checkout_scripts = True
149 # XXX: setup .scripts/version???
150 # for verbose purposes, give us a git status and git diff
153 sh.call("git", "status")
154 except shell.CallError:
157 sh.call("git", "diff")
158 except shell.CallError: