]> scripts.mit.edu Git - wizard.git/blob - wizard/command/prepare_pristine.py
Convert ad hoc shell calls to singleton instance; fix upgrade bug.
[wizard.git] / wizard / command / prepare_pristine.py
1 import urllib
2 import shutil
3 import os
4
5 from wizard import app, command, shell
6
7 def main(argv, baton):
8     options, args = parse_args(argv, baton)
9     check_directory(options)
10     if not os.path.exists(args[0]):
11         appname, _, version = args[0].partition("-")
12         application = app.applications()[appname]
13         url = application.download(version)
14         base = os.path.basename(url)
15         with open(base, "w") as outfile:
16             infile = urllib.urlopen(url)
17             shutil.copyfileobj(infile, outfile)
18         shell.call("tar", "xf", base)
19         os.unlink(base)
20     else:
21         base = args[0]
22         shell.call("tar", "xf", base)
23     # extract the files, but be smart: if only one directory is output,
24     # move the contents of that directory here
25     items = [f for f in os.listdir(os.getcwd()) if f[0] != "."]
26     if len(items) == 1 and os.path.isdir(items[0]):
27         os.rename(items[0], "_wizard_source")
28         shell.call("cp", "-R", "_wizard_source/.", ".")
29         shutil.rmtree("_wizard_source")
30         # populate empty directories with blank files
31         for dirpath, dirnames, filenames in os.walk(os.getcwd()):
32             if "/.git" in dirpath: continue
33             if not filenames and not dirnames:
34                 open(os.path.join(dirpath, ".preserve-dir"), "w").write("")
35         shell.call("git", "add", ".")
36
37 def parse_args(argv, baton):
38     usage = """usage: %prog prepare-pristine APP-VERSION
39
40 This is the first command to run when preparing an update.
41
42 Clears out the current working directory (preserving only the .git directory),
43 and then download, extract and rm the tarball.  It will then add .preserve-dir
44 files to all empty directories, and then run 'git add .'.  It will refuse to do
45 this if there are any untracked files in the directory, or if you have any
46 local diffs: you can override this safety mechanism with --force.
47 """
48     parser = command.WizardOptionParser(usage)
49     parser.add_option("-f", "--force", dest="force", action="store_true",
50         default=False, help="Force a replacement, even if unversioned files exist.")
51     options, args = parser.parse_all(argv)
52     if len(args) < 1:
53         parser.error("not enough arguments")
54     elif len(args) > 1:
55         parser.error("too many arguments")
56     return options, args
57
58 def check_directory(options):
59     files = shell.eval("git", "ls-files", "-o")
60     if files:
61         raise Exception("Unversioned files exist, refusing to remove (override with --force)")
62     try:
63         shell.call("git", "rev-parse", "HEAD")
64         _, _, ref = open(".git/HEAD").read().rstrip().partition(' ')
65         if not options.force:
66             if ref != "refs/heads/pristine" and os.path.exists(os.path.join(".git", ref)):
67                 raise Exception("Not on pristine branch (override with --force)")
68             try:
69                 shell.call("git", "status")
70                 raise Exception("Working copy is dirty (override with --force)")
71             except shell.CallError:
72                 pass
73         for f in os.listdir(os.getcwd()):
74             if f == ".git": continue
75             try:
76                 os.unlink(f)
77             except OSError as e:
78                 shutil.rmtree(f)
79     except shell.CallError:
80         # We're on a git repo with no HEAD
81         pass