X-Git-Url: https://scripts.mit.edu/gitweb/wizard.git/blobdiff_plain/5b06859324adc10fed4c79bfe50a82d76446d5b5..193c996c0df943f6bd955bdb475548b04ec9e711:/bin/wizard diff --git a/bin/wizard b/bin/wizard index 5615047..4a204e8 100755 --- a/bin/wizard +++ b/bin/wizard @@ -1,159 +1,12 @@ #!/usr/bin/env python -""" -This script does everything autoinstalls! - -Specifically, it: -* Generates basic statistics about autoinstall versions -* Migrates autoinstalls to the new Git format -""" - import os import optparse -import fileinput -import math import sys -from distutils.version import LooseVersion as Version - -class NoSuchApplication(Exception): - pass - -class DeploymentParseError(Exception): - pass - -class Deployment(object): - def __init__(self, location, version): - self.location = location - self.version = version - self.application = version.application - @staticmethod - def parse(line): - """Parses a line from the results of parallel-find.pl. - This will work out of the box with fileinput""" - try: - location, deploydir = line.rstrip().split(":") - except ValueError: - raise DeploymentParseError - name = deploydir.split("/")[-1] - if name.find("-") != -1: - app, version = name.split("-") - elif name == "deploy": - # Assume that it's django, since those were botched - app = "django" - version = "0.1-scripts" - else: - raise DeploymentParseError - try: - return Deployment(location, applications[app].getVersion(version)) - except KeyError: - raise NoSuchApplication - def count(self): - """Simple method which registers the deployment as a +1 on the - appropriate version. No further inspection is done.""" - self.version.count(self) - return True - def count_exists(self, file): - """Checks if the codebase has a certain file/directory in it.""" - if os.path.exists(self.location + "/" + file): - self.version.count_exists(self, file) - return True - return False - -class Application(object): - HISTOGRAM_WIDTH = 30 - def __init__(self, name): - self.name = name - self.versions = {} - # Some cache variables for fast access of calculated data - self._total = 0 - self._max = 0 - self._c_exists = {} - def getVersion(self, version): - if version not in self.versions: - self.versions[version] = ApplicationVersion(Version(version), self) - return self.versions[version] - def _graph(self, v): - return '+' * int(math.ceil(float(v)/self._max * self.HISTOGRAM_WIDTH)) - def __str__(self): - if not self.versions: return "%-11s no installs" % self.name - ret = \ - ["%-16s %3d installs" % (self.name, self._total)] + \ - [str(v) for v in sorted(self.versions.values())] - for f,c in self._c_exists.items(): - ret.append("%d users have %s" % (c,f)) - return "\n".join(ret) - -class ApplicationVersion(object): - def __init__(self, version, application): - self.version = version - self.application = application - self.c = 0 - self.c_exists = {} - def __cmp__(x, y): - return cmp(x.version, y.version) - def count(self, deployment): - self.c += 1 - self.application._total += 1 - if self.c > self.application._max: - self.application._max = self.c - def count_exists(self, deployment, n): - if n in self.c_exists: self.c_exists[n] += 1 - else: self.c_exists[n] = 1 - if n in self.application._c_exists: self.application._c_exists[n] += 1 - else: self.application._c_exists[n] = 1 - def __str__(self): - return " %-12s %3d %s" \ - % (self.version, self.c, self.application._graph(self.c)) - -class Printer(object): - def __init__(self, quiet, verbose): - self.i = 0 - self.quiet = quiet - self.verbose = verbose - self.hanging = False - def tick(self): - self.i += 1 - if not self.quiet and self.i % 10 == 0: - sys.stdout.write(".") - sys.stdout.flush() - self.hanging = True - def _hang(self): - if self.hanging: - self.hanging = False - print - def write(self, str = ""): - self._hang() - print str - def qwrite(self, str = ""): - if not self.quiet: - self._hang - print str - def tweet(self, str = ""): - if not self.quiet: - self._hang() - print str, # note comma - def chat(self, str = ""): - if self.verbose: - self._hang() - print str - -application_list = [ - "mediawiki", "wordpress", "joomla", "e107", "gallery2", - "phpBB", "advancedbook", "phpical", "trac", "turbogears", "django", - # these are technically deprecated - "advancedpoll", "gallery", -] -"""Hash table for looking up string application name to instance""" -applications = dict([(n,Application(n)) for n in application_list ]) - -def getInstallLines(global_options): - vd = global_options.version_dir - try: - return fileinput.input([vd + "/" + f for f in os.listdir(vd)]) - except OSError: - print "No permissions; check if AFS is mounted" - raise SystemExit(-1) +# Add lib to path +sys.path.insert(0,os.path.abspath(os.path.join(__file__,'../../lib'))) +import wizard.command def main(): usage = """usage: %prog [-d|--version-dir] COMMAND [ARGS] @@ -161,11 +14,11 @@ def main(): Wizard is a Git-based autoinstall management system for scripts. Its commands are: - stat Generate statistics about autoinstalls + info Reports information about an autoinstall + migrate Migrate autoinstalls from old format to Git-based format + summary Generate statistics about autoinstalls -See '%prog help COMMAND' for more information on a specific command. -""" -# migrate Migrate autoinstalls from old format to Git-based format +See '%prog help COMMAND' for more information on a specific command.""" parser = optparse.OptionParser(usage) parser.add_option("-d", "--version-dir", dest="version_dir", @@ -176,88 +29,29 @@ See '%prog help COMMAND' for more information on a specific command. try: while not sys.argv[i] or sys.argv[i][0] == '-': if sys.argv[i] == "-h" or sys.argv[i] == "--help": - parser.print_usage() + parser.print_help() raise SystemExit(-1) i += 1 except IndexError: - parser.error("no action specified") + parser.print_help() + raise SystemExit(-1) options, args = parser.parse_args(sys.argv[1:i+1]) rest_argv = sys.argv[i+1:] command = args[0] # shouldn't fail - commands = { - "stat": stat - } if command == "help": try: - commands[rest_argv[0]](['-h'], options) - except KeyError: + getattr(wizard.command, rest_argv[0])(['-h'], options) + except AttributeError: parser.error("invalid action") except IndexError: - parser.print_usage() + parser.print_help() raise SystemExit(-1) # Dispatch commands - if command not in commands: + try: + command_fn = getattr(wizard.command, command) + except AttributeError: parser.error("invalid action") - return commands[command](rest_argv, options) - -def stat(argv, global_options): - usage = """usage: %prog stat [ARGS] APPS - -Scans all of the collected data from parallel-find.pl, and -determines version histograms for our applications. You may -optionally pass application parameters to filter the installs. - -Examples: - %prog stat - Basic usage - %prog stat mediawiki - Displays only MediaWiki statistics - %prog stat -v -q mediawiki-1.2.3 - Displays all deployments of this version""" - parser = optparse.OptionParser(usage) - parser.add_option("-v", "--verbose", dest="verbose", action="store_true", - default=False, help="Print interesting directories") - parser.add_option("-q", "--quiet", dest="quiet", action="store_true", - default=False, help="Suppresses progress output") - parser.add_option("--count-exists", dest="count_exists", - default=False, help="Count deployments that contain a file") - options, show = parser.parse_args(argv) - fi = getInstallLines(global_options) - if not show: show = applications.keys() - show = frozenset(show) - errors = 0 - unrecognized = 0 - processed = 0 - printer = Printer(options.quiet, options.verbose) - printer.tweet("Processing") - for line in fi: - printer.tick() - try: - deploy = Deployment.parse(line) - except DeploymentParseError: - errors += 1 - continue - except NoSuchApplication: - unrecognized += 1 - continue - if deploy.application.name + "-" + str(deploy.version.version) in show: - printer.write("%s-%s deployment at %s" \ - % (deploy.application.name, deploy.version.version, deploy.location)) - elif deploy.application.name in show: - pass - else: - continue - deploy.count() - if options.count_exists: - r = deploy.count_exists(options.count_exists) - if r: - printer.chat("Found " + options.count_exists + " in " + deploy.location) - printer.write() - for app in applications.values(): - if app.name not in show: continue - printer.write(app) - printer.write() - printer.write("With %d errors and %d unrecognized applications" % (errors, unrecognized)) + command_fn(rest_argv, options) if __name__ == "__main__": main()