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