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."""
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)
71 parser.error("too many arguments")
73 parser.error("must specify directory")
74 logger.debug("uid is %d" % os.getuid())
79 if e.errno == errno.EACCES:
80 raise _base.PermissionsError(dir)
81 elif e.errno == errno.ENOENT:
82 raise _base.NoSuchDirectoryError(dir)
84 if os.path.isdir(".git") or os.path.isdir(".scripts"):
86 raise AlreadyMigratedError(dir)
88 if os.path.isdir(".git"):
89 logger.warning("Force removing .git directory")
90 if not options.dry_run: shutil.rmtree(".git")
91 if os.path.isdir(".scripts"):
92 logger.warning("Force removing .scripts directory")
93 if not options.dry_run: shutil.rmtree(".scripts")
95 d = deploy.Deployment.fromDir(".")
96 version = d.getAppVersion()
98 if e.errno == errno.ENOENT:
99 raise NotAutoinstallError(dir)
101 # calculate the repository we'll be pulling out of
102 application = version.application
103 app = application.name
104 repo = os.path.join("/afs/athena.mit.edu/contrib/scripts/wizard/srv", app + ".git")
105 if not os.path.isdir(repo):
106 raise NoRepositoryError(app)
107 # begin the command line process
108 sh = shell.Shell(logger, options.dry_run)
109 # check if the version we're trying to convert exists. We assume
110 # a convention here, namely, v1.2.3-scripts is what we want. If
111 # you broke the convention... shame on you.
113 tag = "v%s-scripts" % version.version
114 sh.call("git", "--git-dir", repo, "rev-parse", tag)
115 except shell.CallError:
116 raise NoTagError(version)
118 did_git_checkout_scripts = False
121 sh.call("git", "--git-dir=.git", "init")
123 # configure our alternates (to save space and make this quick)
124 data = os.path.join(repo, "objects")
125 file = ".git/objects/info/alternates"
126 if not options.dry_run:
127 alternates = open(file, "w")
128 alternates.write(data)
131 logger.info("# create %s containing \"%s\"" % (file, data))
132 # configure our remote
133 sh.call("git", "remote", "add", "origin", repo)
134 # configure what would normally be set up on a 'git clone' for consistency
135 sh.call("git", "config", "branch.master.remote", "origin")
136 sh.call("git", "config", "branch.master.merge", "refs/heads/master")
137 # perform the initial fetch
138 sh.call("git", "fetch", "origin")
139 # soft reset to our tag
140 sh.call("git", "reset", tag, "--")
141 # checkout the .scripts directory
142 sh.call("git", "checkout", ".scripts")
143 did_git_checkout_scripts = True
144 # XXX: setup .scripts/version???
145 # for verbose purposes, give us a git status and git diff
148 sh.call("git", "status")
149 except shell.CallError:
152 sh.call("git", "diff")
153 except shell.CallError:
156 # this... is pretty bad
157 logger.critical("ERROR: Exception detected! Rolling back...")
159 sh.call("rm", "-Rf", ".git")
160 if did_git_checkout_scripts:
161 sh.call("rm", "-Rf", ".scripts")