]> scripts.mit.edu Git - wizard.git/blob - lib/wizard/command/migrate.py
Final touches on migration script.
[wizard.git] / lib / wizard / command / migrate.py
1 import optparse
2 import sys
3 import os
4 import shutil
5 import logging.handlers
6
7 from wizard import *
8 import wizard.deploy as wd
9 import wizard.shell as sh
10
11 class PermissionsError(UserException):
12     def __init__(self, dir):
13         self.dir = dir
14     def __str__(self):
15         return """
16
17 ERROR: You don't have permissions to access this directory.
18 Do you have tickets for AFS with your root instance, and
19 is your root instance on scripts-security-upd?
20
21 You can check by running the commands 'klist' and
22 'blanche scripts-security-upd'.  We recommend getting
23 root tickets using Nelson Elhage's krbroot script
24 at /mit/nelhage/Public/krbroot (for which you run
25 'krbroot shell' and then 'aklog').
26 """
27
28 class NoSuchDirectoryError(UserException):
29     def __init__(self, dir):
30         self.dir = dir
31     def __str__(self):
32         return """
33
34 ERROR: No such directory... check your typing
35 """
36
37 class AlreadyMigratedError(UserException):
38     def __init__(self, dir):
39         self.dir = dir
40     def __str__(self):
41         return """
42
43 ERROR: Directory already contains a .git directory.
44 Did you already migrate it?
45 """
46
47 class NotAutoinstallError(UserException):
48     def __init__(self, dir):
49         self.dir = dir
50     def __str__(self):
51         return """
52
53 ERROR: Could not find .scripts-version file. Are you sure
54 this is an autoinstalled application?
55 """
56
57 class NoRepositoryError(UserException):
58     def __init__(self, app):
59         self.app = app
60     def __str__(self):
61         return """
62
63 ERROR: Could not find repository for this application. Have
64 you converted the repository over? Is the name %s
65 the same as the name of the .git folder?
66 """ % self.app
67
68 class NoTagError(UserException):
69     def __init__(self, version):
70         self.version = version
71     def __str__(self):
72         return """
73
74 ERROR: Could not find tag v%s-scripts in repository
75 for %s.  Double check and make sure
76 the repository was prepared with all necessary tags!
77 """ % (self.version.version, self.version.application.name)
78
79 def migrate(argv, global_options, logger = None):
80     usage = """usage: %prog migrate [ARGS] DIR
81
82 Migrates a directory to our Git-based autoinstall format.
83 Performs basic sanity checking and intelligently determines
84 what repository and tag to use."""
85     parser = WizardOptionParser(usage)
86     parser.add_option("--dry-run", dest="dry_run", action="store_true",
87             default=False, help="Prints would would be run without changing anything")
88     parser.add_option("--force", "-f", dest="force", action="store_true",
89             default=False, help="If .git or .scripts directory already exists, delete them and migrate")
90     options, args, logger = parser.parse_all(argv, logger)
91     if len(args) > 1:
92         parser.error("too many arguments")
93     elif not args:
94         parser.error("must specify directory")
95     dir = args[0]
96     try:
97         os.chdir(dir)
98     except OSError as e:
99         if e.errno == 13:
100             raise PermissionsError(dir)
101         elif e.errno == 2:
102             raise NoSuchDirectoryError(dir)
103         else: raise e
104     if os.path.isdir(".git") or os.path.isdir(".scripts"):
105         if not options.force:
106             raise AlreadyMigratedError(dir)
107         else:
108             if os.path.isdir(".git"):
109                 logger.warning("Force removing .git directory")
110                 shutil.rmtree(".git")
111             if os.path.isdir(".scripts"):
112                 logger.warning("Force removing .scripts directory")
113                 shutil.rmtree(".scripts")
114     try:
115         deploy = wd.Deployment.fromDir(".")
116         version = deploy.getAppVersion()
117     except IOError as e:
118         if e.errno == 2:
119             raise NotAutoinstallError(dir)
120         else: raise e
121     # calculate the repository we'll be pulling out of
122     application = version.application
123     app = application.name
124     repo = os.path.join("/afs/athena.mit.edu/contrib/scripts/wizard/srv", app + ".git")
125     if not os.path.isdir(repo):
126         raise NoRepositoryError(app)
127     # begin the command line process
128     shell = sh.Shell(logger, options.dry_run)
129     # check if the version we're trying to convert exists. We assume
130     # a convention here, namely, v1.2.3-scripts is what we want. If
131     # you broke the convention... shame on you.
132     try:
133         tag = "v%s-scripts" % version.version
134         shell.call("git", "--git-dir", repo, "rev-parse", tag)
135     except sh.CalledProcessError:
136         raise NoTagError(version)
137     did_git_init = False
138     did_git_checkout_scripts = False
139     try:
140         # create repository
141         shell.call("git", "init")
142         did_git_init = True
143         # configure our remote
144         shell.call("git", "remote", "add", "origin", repo)
145         # configure what would normally be set up on a 'git clone' for consistency
146         shell.call("git", "config", "branch.master.remote", "origin")
147         shell.call("git", "config", "branch.master.merge", "refs/heads/master")
148         # perform the initial fetch
149         shell.call("git", "fetch", "origin")
150         # soft reset to our tag
151         shell.call("git", "reset", tag)
152         # checkout the .scripts directory
153         shell.call("git", "checkout", ".scripts")
154         did_git_checkout_scripts = True
155         # XXX: setup .scripts/version???
156         # for verbose purposes, give us a git status and git diff
157         if options.verbose:
158             shell.call("git", "status")
159             shell.call("git", "diff")
160     except:
161         # this... is pretty bad
162         logger.critical("ERROR: Exception detected! Rolling back...")
163         if did_git_init:
164             shell.call("rm", "-Rf", ".git")
165         if did_git_checkout_scripts:
166             shell.call("rm", "-Rf", ".scripts")
167         raise