]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/app/__init__.py
Expand documentation.
[wizard.git] / wizard / app / __init__.py
index 1fc1669461c5d0b608b3cbc046e9833354182e82..929cacfb35c66715e3ba2999da46cafaf875e243 100644 (file)
@@ -20,9 +20,11 @@ import re
 import distutils.version
 import decorator
 import shlex
 import distutils.version
 import decorator
 import shlex
+import logging
+import shutil
 
 import wizard
 
 import wizard
-from wizard import scripts, shell, util
+from wizard import resolve, scripts, shell, util
 
 _application_list = [
     "mediawiki", "wordpress", "joomla", "e107", "gallery2",
 
 _application_list = [
     "mediawiki", "wordpress", "joomla", "e107", "gallery2",
@@ -74,6 +76,9 @@ class Application(object):
     #: a conflict marker string and a result list.  See :mod:`wizard.resolve`
     #: for more information.
     resolutions = {}
     #: 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 = {}
     def __init__(self, name):
         self.name = name
         self.versions = {}
@@ -183,7 +188,7 @@ class Application(object):
         take a :class:`wizard.deploy.Deployment` as a parameter.)  Subclasses should
         provide an implementation.
         """
         take a :class:`wizard.deploy.Deployment` as a parameter.)  Subclasses should
         provide an implementation.
         """
-        raise NotImplemented
+        raise NotImplementedError
     def upgrade(self, deployment, version, options):
         """
         Run for 'wizard upgrade' to upgrade database schemas and other
     def upgrade(self, deployment, version, options):
         """
         Run for 'wizard upgrade' to upgrade database schemas and other
@@ -191,7 +196,7 @@ class Application(object):
         upgraded.  This assumes that the current working directory is the
         deployment.  Subclasses should provide an implementation.
         """
         upgraded.  This assumes that the current working directory is the
         deployment.  Subclasses should provide an implementation.
         """
-        raise NotImplemented
+        raise NotImplementedError
     def backup(self, deployment, outdir, options):
         """
         Run for 'wizard backup' and upgrades to backup database schemas
     def backup(self, deployment, outdir, options):
         """
         Run for 'wizard backup' and upgrades to backup database schemas
@@ -204,7 +209,7 @@ class Application(object):
             Static user files may not need to be backed up, since in
             many applications upgrades do not modify static files.
         """
             Static user files may not need to be backed up, since in
             many applications upgrades do not modify static files.
         """
-        raise NotImplemented
+        raise NotImplementedError
     def restore(self, deployment, backup_dir, options):
         """
         Run for 'wizard restore' and failed upgrades to restore database
     def restore(self, deployment, backup_dir, options):
         """
         Run for 'wizard restore' and failed upgrades to restore database
@@ -212,14 +217,20 @@ class Application(object):
         that the current working directory is the deployment.  Subclasses
         should provide an implementation.
         """
         that the current working directory is the deployment.  Subclasses
         should provide an implementation.
         """
-        raise NotImplemented
+        raise NotImplementedError
     def detectVersion(self, deployment):
         """
         Checks source files to determine the version manually.  This assumes
         that the current working directory is the deployment.  Subclasses
         should provide an implementation.
         """
     def detectVersion(self, deployment):
         """
         Checks source files to determine the version manually.  This assumes
         that the current working directory is the deployment.  Subclasses
         should provide an implementation.
         """
-        raise NotImplemented
+        raise NotImplementedError
+    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):
         """
         Checks if the autoinstall is viewable from the web.  To get
     def checkWeb(self, deployment, output=None):
         """
         Checks if the autoinstall is viewable from the web.  To get
@@ -235,14 +246,17 @@ class Application(object):
             page does not contain the features you search for.  Try
             not to depend on pages that are not the main page.
         """
             page does not contain the features you search for.  Try
             not to depend on pages that are not the main page.
         """
-        raise NotImplemented
+        raise NotImplementedError
     def checkConfig(self, deployment):
         """
         Checks whether or not an autoinstall has been configured/installed
         for use.  Assumes that the current working directory is the deployment.
         Subclasses should provide an implementation.
         """
     def checkConfig(self, deployment):
         """
         Checks whether or not an autoinstall has been configured/installed
         for use.  Assumes that the current working directory is the deployment.
         Subclasses should provide an implementation.
         """
-        raise NotImplemented
+        # XXX: Unfortunately, this doesn't quite work because we package
+        # bogus config files in the -scripts versions of installs.  Maybe
+        # we should check a hash or something?
+        raise NotImplementedError
     @staticmethod
     def make(name):
         """Makes an application, but uses the correct subtype if available."""
     @staticmethod
     def make(name):
         """Makes an application, but uses the correct subtype if available."""
@@ -459,9 +473,10 @@ def filename_regex_substitution(key, files, regex):
         return subs
     return h
 
         return subs
     return h
 
+# XXX: rename to show that it's mysql specific
 def backup_database(outdir, deployment):
     """
 def backup_database(outdir, deployment):
     """
-    Generic database backup function.  Assumes that ``WIZARD_DBNAME``
+    Generic database backup function for MySQL.  Assumes that ``WIZARD_DBNAME``
     is extractable, and that :func:`wizard.scripts.get_sql_credentials`
     works.
     """
     is extractable, and that :func:`wizard.scripts.get_sql_credentials`
     works.
     """
@@ -475,6 +490,10 @@ def backup_database(outdir, deployment):
         raise BackupFailure(e.stderr)
 
 def restore_database(backup_dir, deployment):
         raise BackupFailure(e.stderr)
 
 def restore_database(backup_dir, deployment):
+    """
+    Generic database restoration function for MySQL.  See :func:`backup_database`
+    for the assumptions that we make.
+    """
     sh = shell.Shell()
     if not os.path.exists(backup_dir):
         raise RestoreFailure("Backup %s doesn't exist", backup_dir.rpartition("/")[2])
     sh = shell.Shell()
     if not os.path.exists(backup_dir):
         raise RestoreFailure("Backup %s doesn't exist", backup_dir.rpartition("/")[2])
@@ -485,6 +504,10 @@ def restore_database(backup_dir, deployment):
     sql.close()
 
 def get_mysql_args(d):
     sql.close()
 
 def get_mysql_args(d):
+    """
+    Extracts arguments that would be passed to the command line mysql utility
+    from a deployment.
+    """
     # XXX: add support for getting these out of options
     vars = d.extract()
     if 'WIZARD_DBNAME' not in vars:
     # XXX: add support for getting these out of options
     vars = d.extract()
     if 'WIZARD_DBNAME' not in vars:
@@ -502,6 +525,19 @@ class Error(wizard.Error):
     """Generic error class for this module."""
     pass
 
     """Generic error class for this module."""
     pass
 
+class RecoverableFailure(Error):
+    """
+    The installer 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 NoRepositoryError(Error):
     """
     :class:`Application` does not appear to have a Git repository
 class NoRepositoryError(Error):
     """
     :class:`Application` does not appear to have a Git repository