4 import distutils.version
9 ## -- Global Functions --
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)])
18 ## -- Model Objects --
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
31 def version_file(self):
32 return os.path.join(self.location, '.scripts-version')
34 def application(self):
35 return self.app_version.application
39 self._log = log.DeployLog.load(self.version_file)
43 """Returns the distutils Version of the deployment"""
44 return self.app_version.version
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
52 """Parses a line from the results of parallel-find.pl.
53 This will work out of the box with fileinput, see
57 location, deploydir = line.split(":")
59 return Deployment(line) # lazy loaded version
60 return Deployment(location, version=ApplicationVersion.parse(deploydir, location))
62 class Application(object):
63 """Represents the generic notion of an application, i.e.
64 mediawiki or phpbb."""
65 def __init__(self, name):
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)
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]
81 """Makes an application, but uses the correct subtype if available."""
83 __import__("wizard.app." + name)
84 return getattr(wizard.app, name).Application(name)
86 return Application(name)
88 class ApplicationVersion(object):
89 """Represents an abstract notion of a version for an application"""
90 def __init__(self, version, application):
91 """ `version` Instance of distutils.LooseVersion
92 `application` Instance of Application
93 WARNING: Please don't call this directly; instead, use getVersion()
94 on the application you want, so that this version gets registered."""
95 self.version = version
96 self.application = application
98 def scripts_tag(self):
99 """Returns the name of the Git tag for this version"""
100 # XXX: This assumes that there's only a -scripts version
101 # which will not be true in the future. Unfortunately, finding
102 # the "true" latest version is computationally expensive
103 return "v%s-scripts" % self.version
105 return cmp(x.version, y.version)
107 def parse(deploydir,location,applookup=None):
108 # The version of the deployment, will be:
109 # /afs/athena.mit.edu/contrib/scripts/deploy/APP-x.y.z for old style installs
110 name = deploydir.split("/")[-1]
112 if name.find(" ") != -1:
113 raw_app, raw_version = name.split(" ")
114 version = raw_version[1:] # remove leading v
115 app, _ = raw_app.split(".") # remove trailing .git
116 elif name.find("-") != -1:
117 app, _, version = name.partition("-")
121 except ValueError: # mostly from the a, b = foo.split(' ')
122 raise DeploymentParseError(deploydir, location)
123 if not applookup: applookup = applications()
125 # defer to the application for version creation
126 return applookup[app].makeVersion(version)
128 raise NoSuchApplication(app, location)
132 class Error(Exception):
133 """Base error class for this module"""
136 class NoSuchApplication(Error):
137 def __init__(self, name, location):
139 self.location = location
141 return "ERROR: Unrecognized app '%s' at %s" % (self.name, self.location)
143 class DeploymentParseError(Error):
144 def __init__(self, malformed, location):
145 self.malformed = malformed
146 self.location = location
148 return """ERROR: Unparseable '%s' at %s""" % (self.malformed, self.location)
150 class NoRepositoryError(Error):
151 def __init__(self, app):
153 self.location = "unknown"
157 ERROR: Could not find repository for this application. Have
158 you converted the repository over? Is the name %s
159 the same as the name of the .git folder?
162 # If you want, you can wrap this up into a registry and access things
163 # through that, but it's not really necessary
166 "mediawiki", "wordpress", "joomla", "e107", "gallery2",
167 "phpBB", "advancedbook", "phpical", "trac", "turbogears", "django",
168 # these are technically deprecated
169 "advancedpoll", "gallery",
174 """Hash table for looking up string application name to instance"""
176 if not _applications:
177 _applications = dict([(n,Application.make(n)) for n in application_list ])