]> scripts.mit.edu Git - wizard.git/blob - wizard/deploy.py
a5a5ee181074e79022beb9e80e1939392976f130
[wizard.git] / wizard / deploy.py
1 import os.path
2 import fileinput
3 import dateutil.parser
4 import distutils.version
5
6 import wizard
7 from wizard import log
8
9 ## -- Global Functions --
10
11 def getInstallLines(vs):
12     """Retrieves a list of lines from the version directory that
13     can be passed to Deployment.parse()"""
14     if os.path.isfile(vs):
15         return fileinput.input([vs])
16     return fileinput.input([vs + "/" + f for f in os.listdir(vs)])
17
18 ## -- Model Objects --
19
20 class Deployment(object):
21     """Represents a deployment of an autoinstall; i.e. a concrete
22     directory in web_scripts that has .scripts-version in it."""
23     def __init__(self, location, log=None, version=None):
24         """ `location`  Location of the deployment
25             `version`   ApplicationVersion of the app (this is cached info)
26             `log`       DeployLog of the app"""
27         self.location = location
28         self._version = version
29         self._log = log
30     @property
31     def version_file(self):
32         return os.path.join(self.location, '.scripts-version')
33     @property
34     def application(self):
35         return self.app_version.application
36     @property
37     def log(self):
38         if not self._log:
39             self._log = log.DeployLog.load(self.version_file)
40         return self._log
41     @property
42     def version(self):
43         """Returns the distutils Version of the deployment"""
44         return self.app_version.version
45     @property
46     def app_version(self, force = False):
47         """Returns the ApplicationVersion of the deployment"""
48         if self._version and not force: return self._version
49         else: return self.log[-1].version
50     @staticmethod
51     def parse(line):
52         """Parses a line from the results of parallel-find.pl.
53         This will work out of the box with fileinput, see
54         getInstallLines()"""
55         line = line.rstrip()
56         try:
57             location, deploydir = line.split(":")
58         except ValueError:
59             return Deployment(line) # lazy loaded version
60         return Deployment(location, version=ApplicationVersion.parse(deploydir, location))
61
62 class Application(object):
63     """Represents the generic notion of an application, i.e.
64     mediawiki or phpbb."""
65     def __init__(self, name):
66         self.name = name
67         self.versions = {}
68     @property
69     def repository(self):
70         """Returns the Git repository that would contain this application."""
71         repo = os.path.join("/afs/athena.mit.edu/contrib/scripts/git/autoinstalls", self.name + ".git")
72         if not os.path.isdir(repo):
73             raise NoRepositoryError(app)
74         return repo
75     def makeVersion(self, version):
76         if version not in self.versions:
77             self.versions[version] = ApplicationVersion(distutils.version.LooseVersion(version), self)
78         return self.versions[version]
79
80 class ApplicationVersion(object):
81     """Represents an abstract notion of a version for an application"""
82     def __init__(self, version, application):
83         """ `version`       Instance of distutils.LooseVersion
84             `application`   Instance of Application
85         WARNING: Please don't call this directly; instead, use getVersion()
86         on the application you want, so that this version gets registered."""
87         self.version = version
88         self.application = application
89     @property
90     def scripts_tag(self):
91         """Returns the name of the Git tag for this version"""
92         # XXX: This assumes that there's only a -scripts version
93         # which will not be true in the future.  Unfortunately, finding
94         # the "true" latest version is computationally expensive
95         return "v%s-scripts" % self.version
96     def __cmp__(x, y):
97         return cmp(x.version, y.version)
98     @staticmethod
99     def parse(deploydir,location,applookup=None):
100         # The version of the deployment, will be:
101         #   /afs/athena.mit.edu/contrib/scripts/deploy/APP-x.y.z for old style installs
102         name = deploydir.split("/")[-1]
103         try:
104             if name.find(" ") != -1:
105                 raw_app, raw_version = name.split(" ")
106                 version = raw_version[1:] # remove leading v
107                 app, _ = raw_app.split(".") # remove trailing .git
108             elif name.find("-") != -1:
109                 app, _, version = name.partition("-")
110             else:
111                 app = name
112                 version = "trunk"
113         except ValueError: # mostly from the a, b = foo.split(' ')
114             raise DeploymentParseError(deploydir, location)
115         if not applookup: applookup = applications
116         try:
117             # defer to the application for version creation
118             return applookup[app].makeVersion(version)
119         except KeyError:
120             raise NoSuchApplication(app, location)
121
122 ## -- Exceptions --
123
124 class Error(Exception):
125     """Base error class for this module"""
126     pass
127
128 class NoSuchApplication(Error):
129     def __init__(self, name, location):
130         self.name = name
131         self.location = location
132     def __str__(self):
133         return "ERROR: Unrecognized app '%s' at %s" % (self.name, self.location)
134
135 class DeploymentParseError(Error):
136     def __init__(self, malformed, location):
137         self.malformed = malformed
138         self.location = location
139     def __str__(self):
140         return """ERROR: Unparseable '%s' at %s""" % (self.malformed, self.location)
141
142 class NoRepositoryError(Error):
143     def __init__(self, app):
144         self.app = app
145         self.location = "unknown"
146     def __str__(self):
147         return """
148
149 ERROR: Could not find repository for this application. Have
150 you converted the repository over? Is the name %s
151 the same as the name of the .git folder?
152 """ % self.app
153
154 # If you want, you can wrap this up into a registry and access things
155 # through that, but it's not really necessary
156
157 application_list = [
158     "mediawiki", "wordpress", "joomla", "e107", "gallery2",
159     "phpBB", "advancedbook", "phpical", "trac", "turbogears", "django",
160     # these are technically deprecated
161     "advancedpoll", "gallery",
162 ]
163
164 """Hash table for looking up string application name to instance"""
165 applications = dict([(n,Application(n)) for n in application_list ])
166