and use some of the functions in this module in order to specify
new applications.
+There are some submodules for programming languages that define common
+functions and data that may be used by applications in that language. See:
+
+* :mod:`wizard.app.php`
+
.. testsetup:: *
import re
#: a conflict marker string and a result list. See :mod:`wizard.resolve`
#: for more information.
resolutions = {}
+ #: Instance of :class:`wizard.install.ArgSchema` that defines the arguments
+ #: this application requires.
+ install_schema = None
def __init__(self, name):
self.name = name
self.versions = {}
should provide an implementation.
"""
raise NotImplementedError
+ def detectVersionFromFile(self, filename, regex):
+ """
+ Helper method that detects a version by using a regular expression
+ from a file. The regexed value is passed through :mod:`shlex`.
+ This assumes that the current working directory is the deployment.
+ """
+ contents = open(filename).read()
+ match = regex.search(contents)
+ if not match: return None
+ return distutils.version.LooseVersion(shlex.split(match.group(2))[0])
def download(self, version):
"""
Returns a URL that can be used to download a tarball of ``version`` of
this application.
"""
raise NotImplementedError
- def checkWeb(self, deployment, output=None):
+ def checkWeb(self, deployment):
"""
- Checks if the autoinstall is viewable from the web. To get
- the HTML source that was retrieved, pass a variable containing
- an empty list to ``output``; it will be mutated to have its
- first element be the output. Subclasses should provide an
- implementation.
+ Checks if the autoinstall is viewable from the web. Subclasses should
+ provide an implementation.
.. note::
Finding a reasonable heuristic that works across skinning
not to depend on pages that are not the main page.
"""
raise NotImplementedError
+ def checkWebPage(self, deployment, page, output):
+ """
+ Checks if a given page of an autoinstall contains a particular string.
+ """
+ page = deployment.fetch(page)
+ result = page.find(output) != -1
+ if result:
+ logging.debug("checkWebPage (passed):\n\n" + page)
+ else:
+ logging.info("checkWebPage (failed):\n\n" + page)
+ return result
def checkConfig(self, deployment):
"""
Checks whether or not an autoinstall has been configured/installed
def make_extractors(seed):
"""
- Take a dictionary of ``key``s to ``(file, regex)`` tuples and convert them into
+ Take a dictionary of ``key`` to ``(file, regex)`` tuples and convert them into
extractor functions (which take a :class:`wizard.deploy.Deployment`
and return the value of the second subpattern of ``regex`` when matched
with the contents of ``file``).
def make_substitutions(seed):
"""
- Take a dictionary of ``key``s to ``(file, regex)`` tuples and convert them into substitution
+ Take a dictionary of ``key`` to ``(file, regex)`` tuples and convert them into substitution
functions (which take a :class:`wizard.deploy.Deployment`, replace the second subpattern
of ``regex`` with ``key`` in ``file``, and returns the number of substitutions made.)
"""
# XXX: add support for getting these out of options
vars = d.extract()
if 'WIZARD_DBNAME' not in vars:
- raise app.BackupFailure("Could not determine database name")
+ raise BackupFailure("Could not determine database name")
triplet = scripts.get_sql_credentials(vars)
args = []
if triplet is not None:
"""Generic error class for this module."""
pass
-class NonfatalFailure(Error):
- """Bad parameters given to installer."""
- pass
-
class NoRepositoryError(Error):
"""
:class:`Application` does not appear to have a Git repository
def __init__(self, app):
self.app = app
-class UpgradeFailure(Error):
+class Failure(Error):
+ """
+ Represents a failure when performing some double-dispatched operation
+ such as an installation or an upgrade. Failure classes are postfixed
+ with Failure, not Error.
+ """
+ pass
+
+class InstallFailure(Error):
+ """Installation failed for unknown reason."""
+ def __str__(self):
+ return """Installation failed for unknown reason."""
+
+class RecoverableInstallFailure(InstallFailure):
+ """
+ Installation failed, but we were able to determine what the
+ error was, and should give the user a second chance if we were
+ running interactively.
+ """
+ #: List of the errors that were found.
+ errors = None
+ def __init__(self, errors):
+ self.errors = errors
+ def __str__(self):
+ return """Installation failed due to the following errors: %s""" % ", ".join(self.errors)
+
+class UpgradeFailure(Failure):
"""Upgrade script failed."""
#: String details of failure (possibly stdout or stderr output)
details = None
%s""" % self.details
-class UpgradeVerificationFailure(Error):
+class UpgradeVerificationFailure(Failure):
"""Upgrade script passed, but website wasn't accessible afterwards"""
- #: String details of failure (possibly stdout or stderr output)
- details = None
- def __init__(self, details):
- self.details = details
def __str__(self):
return """
-ERROR: Upgrade script passed, but website wasn't accessible afterwards. Details:
-
-%s""" % self.details
+ERROR: Upgrade script passed, but website wasn't accessible afterwards. Check
+the debug logs for the contents of the page."""
-class BackupFailure(Error):
+class BackupFailure(Failure):
"""Backup script failed."""
#: String details of failure
details = None
%s""" % self.details
-class RestoreFailure(Error):
+class RestoreFailure(Failure):
"""Restore script failed."""
#: String details of failure
details = None