]> scripts.mit.edu Git - wizard.git/blob - wizard/old_log.py
More bugfixes from running live.
[wizard.git] / wizard / old_log.py
1 import os.path
2 import sys
3 import dateutil.parser
4
5 import wizard
6 import wizard.deploy # to break circular loop
7
8 # This code operates off of the assumption of .scripts-version, which
9 # is not true.
10
11 class DeployLog(list):
12     # As per #python; if you decide to start overloading magic methods,
13     # we should remove this subclass
14     """Equivalent to .scripts-version: a series of DeployRevisions."""
15     def __init__(self, revs = []):
16         """`revs`  List of DeployRevision objects"""
17         list.__init__(self, revs) # pass to list
18     def __repr__(self):
19         return '<DeployLog %s>' % list.__repr__(self)
20     @staticmethod
21     def load(deployment):
22         """Loads a scripts version file and parses it into
23         DeployLog and DeployRevision objects"""
24         # XXX: DIRTY DIRTY HACK
25         # What we should actually do is parse the git logs
26         file = deployment.old_version_file
27         i = 0
28         rev = DeployRevision()
29         revs = []
30         def append(rev):
31             if i:
32                 if i != 4:
33                     raise ScriptsVersionNotEnoughFieldsError(file)
34                 revs.append(rev)
35         try:
36             fh = open(file)
37         except IOError:
38             raise ScriptsVersionNoSuchFile(file)
39         for line in fh:
40             line = line.rstrip()
41             if not line:
42                 append(rev)
43                 i = 0
44                 rev = DeployRevision()
45                 continue
46             if i == 0:
47                 # we need the dateutil parser in order to
48                 # be able to parse time offsets
49                 rev.datetime = dateutil.parser.parse(line)
50             elif i == 1:
51                 rev.user = line
52             elif i == 2:
53                 rev.source = DeploySource.parse(line)
54             elif i == 3:
55                 try:
56                     rev.version = wizard.deploy.ApplicationVersion.parse(line)
57                 except wizard.deploy.Error as e:
58                     e.location = deployment.location
59                     raise e, None, sys.exc_info()[2]
60             else:
61                 # ruh oh
62                 raise ScriptsVersionTooManyFieldsError(file)
63             i += 1
64         append(rev)
65         return DeployLog(revs)
66
67 class DeployRevision(object):
68     """A single entry in the .scripts-version file. Contains who deployed
69     this revision, what application version this is, etc."""
70     def __init__(self, datetime=None, user=None, source=None, version=None):
71         """ `datetime`  Time this revision was deployed
72             `user`      Person who deployed this revision, in user@host format.
73             `source`    Instance of DeploySource
74             `version`   Instance of ApplicationVersion
75         Note: This object is typically built incrementally."""
76         self.datetime = datetime
77         self.user = user
78         self.source = source
79         self.version = version
80
81 class DeploySource(object):
82     """Source of the deployment; see subclasses for examples"""
83     def __init__(self):
84         raise NotImplementedError # abstract class
85     @staticmethod
86     def parse(line):
87         # munge out common prefix
88         rel = os.path.relpath(line, "/afs/athena.mit.edu/contrib/scripts/")
89         parts = rel.split("/")
90         if parts[0] == "wizard":
91             return WizardUpdate()
92         elif parts[0] == "deploy" or parts[0] == "deploydev":
93             isDev = ( parts[0] == "deploydev" )
94             try:
95                 if parts[1] == "updates":
96                     return OldUpdate(isDev)
97                 else:
98                     return TarballInstall(line, isDev)
99             except IndexError:
100                 pass
101         return UnknownDeploySource(line)
102
103 class TarballInstall(DeploySource):
104     """Original installation from tarball, characterized by
105     /afs/athena.mit.edu/contrib/scripts/deploy/APP-x.y.z.tar.gz
106     """
107     def __init__(self, location, isDev):
108         self.location = location
109         self.isDev = isDev
110
111 class OldUpdate(DeploySource):
112     """Upgrade using old upgrade infrastructure, characterized by
113     /afs/athena.mit.edu/contrib/scripts/deploydev/updates/update-scripts-version.pl
114     """
115     def __init__(self, isDev):
116         self.isDev = isDev
117
118 class WizardUpdate(DeploySource):
119     """Upgrade using wizard infrastructure, characterized by
120     /afs/athena.mit.edu/contrib/scripts/wizard/bin/wizard HASHGOBBLEDYGOOK
121     """
122     def __init__(self):
123         pass
124
125 class UnknownDeploySource(DeploySource):
126     """Deployment that we don't know the meaning of. Wot!"""
127     def __init__(self, line):
128         self.line = line
129
130 ## -- Exceptions --
131
132 class Error(wizard.Error):
133     """Base error class for log errors."""
134     pass
135
136 class ScriptsVersionError(Error):
137     """Errors specific to the parsing of a full .scripts-version file
138     (errors that could also be triggered while parsing a parallel-find
139     output should not be this subclass.)"""
140     pass
141
142 class ScriptsVersionTooManyFieldsError(ScriptsVersionError):
143     def __str__(self):
144         return """
145
146 ERROR: Could not parse .scripts-version file.  It
147 contained too many fields.
148 """
149
150 class ScriptsVersionNotEnoughFieldsError(ScriptsVersionError):
151     def __str__(self):
152         return """
153
154 ERROR: Could not parse .scripts-version file. It
155 didn't contain enough fields.
156 """
157
158 class ScriptsVersionNoSuchFile(ScriptsVersionError):
159     def __init__(self, file):
160         self.file = file
161     def __str__(self):
162         return """
163
164 ERROR: File %s didn't exist.
165 """ % self.file
166