]> scripts.mit.edu Git - wizard.git/blobdiff - bin/wizard
Convert migrate to logger, and misc refactoring.
[wizard.git] / bin / wizard
index 5615047330e49e6966187676ddfced658f01fe58..4a204e84d472cc706ac9f74c75fec780ce868d87 100755 (executable)
 #!/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()