]> scripts.mit.edu Git - wizard.git/blob - wizard/command/research.py
add825b44e8278fae20738e19fc46ffd7a22902c
[wizard.git] / wizard / command / research.py
1 import logging
2 import traceback
3 import itertools
4 import random
5
6 from wizard import command, deploy, shell, util
7
8 def main(argv, baton):
9     options, show = parse_args(argv, baton)
10     sh = shell.Shell()
11     deploys = deploy.parse_install_lines(show, options.versions_path)
12     stats = {}
13     iffy = 0
14     clean = 0
15     total = 0
16     deploys = itertools.islice(deploys, options.limit)
17     if options.sample:
18         deploys = random.sample(list(deploys), options.sample)
19     try:
20         for d in deploys:
21             logging.info("Processing " + d.location)
22             try:
23                 d.verify()
24                 d.verifyTag(options.srv_path)
25                 d.verifyGit(options.srv_path)
26                 d.verifyConfigured()
27                 with util.ChangeDirectory(d.location):
28                     results = []
29                     out = sh.safeCall('git', 'diff', '--numstat', d.app_version.scripts_tag, strip=True)
30                     total += 1
31                     for line in out.split("\n"):
32                         added, deleted, filename = line.split(None, 3)
33                         if filename.endswith("php.ini"): continue
34                         if added == '-': continue
35                         if deleted == '-': continue
36                         added = int(added)
37                         deleted = int(deleted)
38                         # hook
39                         if filename == "LocalSettings.php":
40                             if added == deleted == 10:
41                                 continue
42                             elif added == deleted == 9:
43                                 continue
44                         elif filename == "AdminSettings.php":
45                             if added == 0 and deleted == 20:
46                                 continue
47                         elif filename == "config/index.php" or filename == "config/index.php5":
48                             if added == 0:
49                                 continue
50                         if not added and not deleted:
51                             continue
52                         results.append((added,deleted,filename))
53                     if len(results) > options.filter:
54                         print "-       -       " +  d.location
55                         iffy += 1
56                         continue
57                     if not results:
58                         clean += 1
59                     for added,deleted,filename in results:
60                         stats.setdefault(filename, 0)
61                         stats[filename] += 1
62                         # hook
63                         if filename == "LocalSettings.php" and not options.verbose:
64                             continue
65                         print "%-7d %-7d %s/%s" % (added,deleted,d.location,filename)
66             except (deploy.NotConfiguredError, deploy.NotMigratedError):
67                 # XXX: These should error, but for now don't
68                 pass
69             except (deploy.Error, shell.CallError):
70                 # XXX: Maybe should also do app.Error
71                 logging.error("%s in %s" % (traceback.format_exc(), d.location))
72             except KeyboardInterrupt:
73                 raise
74             except:
75                 logging.critical("%s in %s" % (traceback.format_exc(), d.location))
76     except KeyboardInterrupt:
77         print
78         print "Caught signal..."
79         pass
80     print '-' * 50
81     for filename in sorted(stats.keys()):
82         count = stats[filename]
83         if not count: continue
84         print "%-7d %s" % (count, filename)
85     print '-' * 50
86     print "%d out of %d (%.1f%%) had large diffstats" % (iffy, total, float(iffy)/total*100)
87     print "%d out of %d (%.1f%%) had clean diffstats" % (clean, total, float(clean)/total*100)
88
89 def parse_args(argv, baton):
90     usage = """usage: %prog research APP
91
92 Tells you how spectacularly an upgrade here will explode."""
93     parser = command.WizardOptionParser(usage)
94     parser.add_option("--limit", dest="limit", type="int",
95             default=None, help="Limit the number of autoinstalls to look at.")
96     parser.add_option("--sample", dest="sample", type="int", metavar="N",
97             default=None, help="Instead of researching all installs, research a random sample of N size.")
98     parser.add_option("--filter", dest="filter", type="int", metavar="N",
99             default=4, help="How many files are permitted in a diffstat before treating the install as having a 'large diffstat'")
100     baton.push(parser, "srv_path")
101     baton.push(parser, "versions_path")
102     options, args = parser.parse_all(argv)
103     if len(args) > 1:
104         parser.error("too many arguments")
105     if not args:
106         parser.error("must specify application to research")
107     return options, args
108