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