-class Application(object):
- """Represents an application, i.e. mediawiki or phpbb."""
- #: String name of the application
- name = None
- #: Dictionary of version strings to :class:`ApplicationVersion`.
- #: See also :meth:`makeVersion`.
- versions = None
- #: List of files that need to be modified when parametrizing.
- #: This is a class-wide constant, and should not normally be modified.
- parametrized_files = []
- def __init__(self, name):
- self.name = name
- self.versions = {}
- # cache variables
- self._extractors = {}
- self._parametrizers = {}
- def repository(self, srv_path):
- """
- Returns the Git repository that would contain this application.
- ``srv_path`` corresponds to ``options.srv_path`` from the global baton.
- Throws :exc:`NoRepositoryError` if the calculated path does not
- exist.
- """
- repo = os.path.join(srv_path, self.name + ".git")
- if not os.path.isdir(repo):
- repo = os.path.join(srv_path, self.name, ".git")
- if not os.path.isdir(repo):
- raise NoRepositoryError(self.name)
- return repo
- def makeVersion(self, version):
- """
- Creates or retrieves the :class:`ApplicationVersion` singleton for the
- specified version.
- """
- if version not in self.versions:
- self.versions[version] = ApplicationVersion(distutils.version.LooseVersion(version), self)
- return self.versions[version]
- def extract(self, deployment):
- """Extracts wizard variables from a deployment."""
- result = {}
- for k,extractor in self.extractors.items():
- result[k] = extractor(deployment)
- return result
- def parametrize(self, deployment, dir):
- """
- Takes a generic source checkout at dir and parametrizes
- it according to the values of deployment.
- """
- variables = deployment.extract()
- for file in self.parametrized_files:
- fullpath = os.path.join(dir, file)
- f = open(fullpath, "r")
- contents = f.read()
- f.close()
- for key, value in variables.items():
- if value is None: continue
- contents = contents.replace(key, value)
- tmp = tempfile.NamedTemporaryFile(delete=False)
- tmp.write(contents)
- tmp.close()
- os.rename(tmp.name, fullpath)
- @property
- def extractors(self):
- """
- Dictionary of variable names to extractor functions. These functions
- take a :class:`Deployment` as an argument and return the value of
- the variable, or ``None`` if it could not be found.
- See also :func:`wizard.app.filename_regex_extractor`.
- """
- return {}
- @staticmethod
- def make(name):
- """Makes an application, but uses the correct subtype if available."""
+class ProductionCopy(Deployment):
+ """
+ Represents the production copy of a deployment. This copy
+ is canonical, and is the only one guaranteed to be accessible
+ via web, have a database, etc.
+ """
+ @chdir_to_location
+ def upgrade(self, version, options):
+ """
+ Performs an upgrade of database schemas and other non-versioned data.
+ """
+ return self.application.upgrade(self, version, options)
+ @chdir_to_location
+ def backup(self, options):
+ """
+ Performs a backup of database schemas and other non-versioned data.
+ """
+ # There are retarded amounts of race-safety in this function,
+ # because we do NOT want to claim to have made a backup, when
+ # actually something weird happened to it.
+ backupdir = os.path.join(self.scripts_dir, "backups")
+ if not os.path.exists(backupdir):
+ try:
+ os.mkdir(backupdir)
+ except OSError as e:
+ if e.errno == errno.EEXIST:
+ pass
+ else:
+ raise
+ tmpdir = tempfile.mkdtemp() # actually will be kept around