]> scripts.mit.edu Git - wizard.git/blob - wizard/command/migrate.py
Factor out common error messages to _base in prep for upgrade.
[wizard.git] / wizard / command / migrate.py
1 import optparse
2 import sys
3 import os
4 import shutil
5 import logging.handlers
6 import errno
7
8 from wizard import deploy
9 from wizard import shell
10 from wizard.command import _base
11
12 class Error(_base.Error):
13     """Base exception for all exceptions raised by migrate"""
14     pass
15
16 class AlreadyMigratedError(Error):
17     def __init__(self, dir):
18         self.dir = dir
19     def __str__(self):
20         return """
21
22 ERROR: Directory already contains a .git and/or
23 .scripts directory.  Did you already migrate it?
24 """
25
26 class NotAutoinstallError(Error):
27     def __init__(self, dir):
28         self.dir = dir
29     def __str__(self):
30         return """
31
32 ERROR: Could not find .scripts-version file. Are you sure
33 this is an autoinstalled application?
34 """
35
36 class NoRepositoryError(Error):
37     def __init__(self, app):
38         self.app = app
39     def __str__(self):
40         return """
41
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?
45 """ % self.app
46
47 class NoTagError(Error):
48     def __init__(self, version):
49         self.version = version
50     def __str__(self):
51         return """
52
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)
57
58 def main(argv, global_options, logger = None):
59     usage = """usage: %prog migrate [ARGS] DIR
60
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."""
64     parser = _base.WizardOptionParser(usage)
65     parser.add_option("--dry-run", dest="dry_run", action="store_true",
66             default=False, help="Prints would would be run without changing anything")
67     parser.add_option("--force", "-f", dest="force", action="store_true",
68             default=False, help="If .git or .scripts directory already exists, delete them and migrate")
69     options, args, logger = parser.parse_all(argv, logger)
70     if len(args) > 1:
71         parser.error("too many arguments")
72     elif not args:
73         parser.error("must specify directory")
74     dir = args[0]
75     try:
76         os.chdir(dir)
77     except OSError as e:
78         if e.errno == errno.EACCES:
79             raise _base.PermissionsError(dir)
80         elif e.errno == errno.ENOENT:
81             raise _base.NoSuchDirectoryError(dir)
82         else: raise e
83     if os.path.isdir(".git") or os.path.isdir(".scripts"):
84         if not options.force:
85             raise AlreadyMigratedError(dir)
86         else:
87             if os.path.isdir(".git"):
88                 logger.warning("Force removing .git directory")
89                 if not options.dry_run: shutil.rmtree(".git")
90             if os.path.isdir(".scripts"):
91                 logger.warning("Force removing .scripts directory")
92                 if not options.dry_run: shutil.rmtree(".scripts")
93     try:
94         d = deploy.Deployment.fromDir(".")
95         version = d.getAppVersion()
96     except IOError as e:
97         if e.errno == errno.ENOENT:
98             raise NotAutoinstallError(dir)
99         else: raise e
100     # calculate the repository we'll be pulling out of
101     application = version.application
102     app = application.name
103     repo = os.path.join("/afs/athena.mit.edu/contrib/scripts/wizard/srv", app + ".git")
104     if not os.path.isdir(repo):
105         raise NoRepositoryError(app)
106     # begin the command line process
107     sh = shell.Shell(logger, options.dry_run)
108     # check if the version we're trying to convert exists. We assume
109     # a convention here, namely, v1.2.3-scripts is what we want. If
110     # you broke the convention... shame on you.
111     try:
112         tag = "v%s-scripts" % version.version
113         sh.call("git", "--git-dir", repo, "rev-parse", tag)
114     except shell.CallError:
115         raise NoTagError(version)
116     did_git_init = False
117     did_git_checkout_scripts = False
118     try:
119         # create repository
120         sh.call("git", "--git-dir=.git", "init")
121         did_git_init = True
122         # configure our alternates (to save space and make this quick)
123         data = os.path.join(repo, "objects")
124         file = ".git/objects/info/alternates"
125         if not options.dry_run:
126             alternates = open(file, "w")
127             alternates.write(data)
128             alternates.close()
129         else:
130             logger.info("# create %s containing \"%s\"" % (file, data))
131         # configure our remote
132         sh.call("git", "remote", "add", "origin", repo)
133         # configure what would normally be set up on a 'git clone' for consistency
134         sh.call("git", "config", "branch.master.remote", "origin")
135         sh.call("git", "config", "branch.master.merge", "refs/heads/master")
136         # perform the initial fetch
137         sh.call("git", "fetch", "origin")
138         # soft reset to our tag
139         sh.call("git", "reset", tag, "--")
140         # checkout the .scripts directory
141         sh.call("git", "checkout", ".scripts")
142         did_git_checkout_scripts = True
143         # XXX: setup .scripts/version???
144         # for verbose purposes, give us a git status and git diff
145         if options.verbose:
146             try:
147                 sh.call("git", "status")
148             except shell.CallError:
149                 pass
150             try:
151                 sh.call("git", "diff")
152             except shell.CallError:
153                 pass
154     except:
155         # this... is pretty bad
156         logger.critical("ERROR: Exception detected! Rolling back...")
157         if did_git_init:
158             sh.call("rm", "-Rf", ".git")
159         if did_git_checkout_scripts:
160             sh.call("rm", "-Rf", ".scripts")
161         raise