7 from wizard import deploy
8 from wizard import shell
9 from wizard import util
10 from wizard.command import _base
12 def main(argv, global_options):
13 options, args = parse_args(argv)
16 logging.debug("uid is %d" % os.getuid())
19 check_if_already_migrated(options)
21 version = calculate_version()
22 repo = version.application.getRepository()
23 tag = version.getScriptsTag()
25 os.unsetenv("GIT_DIR") # prevent some perverse errors
27 sh = shell.Shell(options.dry_run)
28 check_if_tag_exists(sh, repo, tag)
29 make_repository(sh, options, repo, tag)
31 os.rename(".scripts-version", ".scripts/old-version") # archive
34 usage = """usage: %prog migrate [ARGS] DIR
36 Migrates a directory to our Git-based autoinstall format.
37 Performs basic sanity checking and intelligently determines
38 what repository and tag to use.
40 This command is meant to be run as the owner of the install
41 it is upgrading (see the scripts AFS kernel patch). Do
42 NOT run this command as root."""
43 parser = _base.WizardOptionParser(usage)
44 parser.add_option("--dry-run", dest="dry_run", action="store_true",
45 default=False, help="Prints would would be run without changing anything")
46 parser.add_option("--force", "-f", dest="force", action="store_true",
47 default=False, help="If .git or .scripts directory already exists, delete them and migrate")
48 options, args = parser.parse_all(argv)
50 parser.error("too many arguments")
52 parser.error("must specify directory")
53 return (options, args)
55 def check_if_already_migrated(options):
56 if os.path.isdir(".git") or os.path.isdir(".scripts"):
58 raise AlreadyMigratedError(dir)
60 if os.path.isdir(".git"):
61 logging.warning("Force removing .git directory")
62 if not options.dry_run: shutil.rmtree(".git")
63 if os.path.isdir(".scripts"):
64 logging.warning("Force removing .scripts directory")
65 if not options.dry_run: shutil.rmtree(".scripts")
67 def calculate_version():
69 d = deploy.Deployment.fromDir(".")
70 return d.getAppVersion()
72 if e.errno == errno.ENOENT:
73 raise NotAutoinstallError(dir)
76 def check_if_tag_exists(sh, repo, tag):
77 # check if the version we're trying to convert exists. We assume
78 # a convention here, namely, v1.2.3-scripts is what we want. If
79 # you broke the convention... shame on you.
81 sh.call("git", "--git-dir", repo, "rev-parse", tag)
82 except shell.CallError:
83 raise NoTagError(version)
85 def make_repository(sh, options, repo, tag):
86 sh.call("git", "init") # create repository
87 # configure our alternates (to save space and make this quick)
88 data = os.path.join(repo, "objects")
89 file = ".git/objects/info/alternates"
90 if not options.dry_run:
91 alternates = open(file, "w")
92 alternates.write(data)
95 logging.info("# create %s containing \"%s\"" % (file, data))
96 # configure our remote (this is merely for convenience; wizard scripts
97 # will not rely on this)
98 sh.call("git", "remote", "add", "origin", repo)
99 # configure what would normally be set up on a 'git clone' for consistency
100 sh.call("git", "config", "branch.master.remote", "origin")
101 sh.call("git", "config", "branch.master.merge", "refs/heads/master")
102 # perform the initial fetch
103 sh.call("git", "fetch", "origin")
104 # soft reset to our tag
105 sh.call("git", "reset", tag, "--")
106 # checkout the .scripts directory
107 sh.call("git", "checkout", ".scripts")
108 # commit user local changes
109 lines = ["Initial commit after migration."
111 ,"Wizard-version: %s" % util.get_version()
112 ,"Wizard-args: %s" % " ".join(sys.argv)
115 lines.append("Migrated-by: " + util.get_operator_git())
116 # maybe this should go in massmigrate
117 op_realname, op_email = util.get_operator_info()
118 os.putenv("GIT_COMMITTER_NAME", op_realname)
119 os.putenv("GIT_COMMITTER_EMAIL", op_email)
120 except util.NoOperatorInfo:
123 lockername = util.get_dir_owner(".")
124 os.putenv("GIT_AUTHOR_NAME", "%s locker" % lockername)
125 os.putenv("GIT_AUTHOR_EMAIL", "%s@scripts.mit.edu" % lockername)
128 sh.call("git", "commit", "--allow-empty", "-a", "-m", "\n".join(lines))
129 # for verbose purposes, give us a git status and git diff
132 sh.call("git", "status")
133 except shell.CallError:
136 sh.call("git", "diff")
137 except shell.CallError:
140 class Error(_base.Error):
141 """Base exception for all exceptions raised by migrate"""
144 class AlreadyMigratedError(Error):
145 def __init__(self, dir):
150 ERROR: Directory already contains a .git and/or
151 .scripts directory. Did you already migrate it?
154 class NotAutoinstallError(Error):
155 def __init__(self, dir):
160 ERROR: Could not find .scripts-version file. Are you sure
161 this is an autoinstalled application?
164 class NoRepositoryError(Error):
165 def __init__(self, app):
170 ERROR: Could not find repository for this application. Have
171 you converted the repository over? Is the name %s
172 the same as the name of the .git folder?
175 class NoTagError(Error):
176 def __init__(self, version):
177 self.version = version
181 ERROR: Could not find tag v%s-scripts in repository
182 for %s. Double check and make sure
183 the repository was prepared with all necessary tags!
184 """ % (self.version.version, self.version.application.name)