]> scripts.mit.edu Git - wizard.git/commitdiff
Flesh out object model for .scripts-version; not all fiddly bits
authorEdward Z. Yang <edwardzyang@thewritingpot.com>
Sun, 14 Jun 2009 20:32:47 +0000 (16:32 -0400)
committerEdward Z. Yang <edwardzyang@thewritingpot.com>
Sun, 14 Jun 2009 20:32:47 +0000 (16:32 -0400)
implemented.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
lib/wizard/command/__init__.py
lib/wizard/command/info.py [new file with mode: 0644]
lib/wizard/deploy.py

index 953e54e2e25a43c7f40eb9678a4bffcf24b5b581..96e12e8bb358c3178ef57448de6f7cc538ed8257 100644 (file)
@@ -1 +1,3 @@
-import migrate, summary
+import info
+import migrate
+import summary
diff --git a/lib/wizard/command/info.py b/lib/wizard/command/info.py
new file mode 100644 (file)
index 0000000..d17b9bf
--- /dev/null
@@ -0,0 +1,21 @@
+import optparse
+import sys
+
+import wizard.deploy as wd
+
+def main(argv, global_options):
+    usage = """usage: %prog info [ARGS] DIR
+
+Prints information about an autoinstalled directory,
+including its history and current version."""
+    parser = optparse.OptionParser(usage)
+    #parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
+    #        default=False, help="Print all commands and outputs")
+    options, args = parser.parse_args(argv)
+    if len(args) > 1:
+        parser.error("too many arguments")
+    elif not args:
+        parser.error("must specify directory")
+    dir = args[0]
+    print dir
+    print options
index a552437ac5bc21d481188e54d0336b92bb6946af..84166bd5e6e00b911ea723a44d0b85903654844e 100644 (file)
@@ -1,9 +1,12 @@
 import os.path
 import math
 import fileinput
+import dateutil.parser
 from distutils.version import LooseVersion as Version
 
 def getInstallLines(global_options):
+    """Retrieves a list of lines from the version directory that
+    can be passed to Deployment.parse()"""
     vd = global_options.version_dir
     try:
         return fileinput.input([vd + "/" + f for f in os.listdir(vd)])
@@ -18,14 +21,18 @@ class DeploymentParseError(Exception):
     pass
 
 class Deployment(object):
+    """Represents a deployment of an autoinstall; i.e. a concrete
+    directory in web_scripts that has .scripts-version in it."""
     def __init__(self, location, version):
+        # XXX: This constructor should change
         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"""
+        This will work out of the box with fileinput, see
+        getInstallLines()"""
         try:
             location, deploydir = line.rstrip().split(":")
         except ValueError:
@@ -43,6 +50,11 @@ class Deployment(object):
             return Deployment(location, applications[app].getVersion(version))
         except KeyError:
             raise NoSuchApplication
+    @staticmethod
+    def fromDir(dir):
+        """Creates a deployment from a directory"""
+        version_file = os.path.join(dir, '.scripts-version')
+        # needs deployment log
     def count(self):
         """Simple method which registers the deployment as a +1 on the
         appropriate version. No further inspection is done."""
@@ -56,6 +68,9 @@ class Deployment(object):
         return False
 
 class Application(object):
+    """Represents the generic notion of an application, i.e.
+    mediawiki or phpbb."""
+    # XXX: See below XXX
     HISTOGRAM_WIDTH = 30
     def __init__(self, name):
         self.name = name
@@ -68,6 +83,8 @@ class Application(object):
         if version not in self.versions:
             self.versions[version] = ApplicationVersion(Version(version), self)
         return self.versions[version]
+    # XXX: This code should go in summary.py; maybe as a mixin, maybe as
+    # a visitor acceptor
     def _graph(self, v):
         return '+' * int(math.ceil(float(v)/self._max * self.HISTOGRAM_WIDTH))
     def __str__(self):
@@ -79,14 +96,106 @@ class Application(object):
             ret.append("%d users have %s" % (c,f))
         return "\n".join(ret)
 
+class DeployLog(object):
+    """Equivalent to .scripts-version: a series of DeployRevisions."""
+    def __init__(self, revs = []):
+        """`revs`  List of DeployRevision objects"""
+        self.revs = revs
+    @staticmethod
+    def load(file):
+        """Loads a scripts version file and parses it into
+        DeployLog and DeployRevision objects"""
+        i = 0
+        rev = DeployRevision()
+        revs = []
+        for line in open(file):
+            line = line.rstrip()
+            if not line:
+                i = 0
+                revs.append(rev)
+                rev = DeployRevision()
+                continue
+            if i == 0:
+                rev.datetime = dateutil.parser.parse(line)
+            elif i == 1:
+                rev.user = line
+            elif i == 2:
+                rev.source = DeploySource.parse(line)
+            elif i == 3:
+                rev.version = ApplicationVersion.parse(line)
+            else:
+                # ruh oh
+                pass
+            i += 1
+        if i: revs.append(rev)
+        return DeployLog(revs)
+
+class DeployRevision(object):
+    """A single entry in the .scripts-version file. Contains who deployed
+    this revision, what application version this is, etc."""
+    def __init__(self, datetime=None, user=None, source=None, version=None):
+        """ `datetime`  Time this revision was deployed
+            `user`      Person who deployed this revision, in user@host format.
+            `source`    Instance of DeploySource
+            `version`   Instance of ApplicationVersion
+        Note: This object is typically built incrementally."""
+        self.datetime = datetime
+        self.user = user
+        self.source = source
+        self.version = version
+
+class DeploySource(object):
+    """Source of the deployment; see subclasses for examples"""
+    def __init__(self):
+        raise NotImplemented # abstract class
+    @staticmethod
+    def parse(line):
+        raise NotImplemented
+
+class TarballInstall(DeploySource):
+    """Original installation from tarball, characterized by
+    /afs/athena.mit.edu/contrib/scripts/deploy/APP-x.y.z.tar.gz
+    """
+    def __init__(self, location):
+        self.location = location
+
+class OldUpgrade(DeploySource):
+    """Upgrade using old upgrade infrastructure, characterized by
+    /afs/athena.mit.edu/contrib/scripts/deploydev/updates/update-scripts-version.pl
+    """
+    def __init__(self):
+        pass # prevent not implemented error
+
+class WizardUpgrade(DeploySource):
+    """Upgrade using wizard infrastructure, characterized by
+    /afs/athena.mit.edu/contrib/scripts/wizard/bin/wizard HASHGOBBLEDYGOOK
+    """
+    def __init__(self, rev):
+        self.rev = rev
+
+class UnknownDeploySource(DeploySource):
+    """Deployment that we don't know the meaning of. Wot!"""
+    def __init__(self, line):
+        self.line = line
+
 class ApplicationVersion(object):
+    """Represents an abstract notion of a version for an application"""
     def __init__(self, version, application):
+        """ `version`       Instance of distutils.LooseVersion
+            `application`   Instance of Application"""
         self.version = version
         self.application = application
         self.c = 0
         self.c_exists = {}
     def __cmp__(x, y):
         return cmp(x.version, y.version)
+    @staticmethod
+    def parse(line):
+        # The version of the deployment, will be:
+        #   /afs/athena.mit.edu/contrib/scripts/deploy/APP-x.y.z for old style installs
+        #   /afs/athena.mit.edu/contrib/scripts/wizard/srv/APP.git vx.y.z-scripts for new style installs
+        raise NotImplemented
+    # This is summary specific code
     def count(self, deployment):
         self.c += 1
         self.application._total += 1