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