]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/install/__init__.py
Update documentation for upcoming plugin-ification.
[wizard.git] / wizard / install / __init__.py
index 6402efcecfacd74f537e01a610727b2a67da6cc1..291018cabf143b52b3b78603a6a60a95741964e0 100644 (file)
@@ -26,11 +26,13 @@ import sqlalchemy
 import warnings
 
 import wizard
-from wizard import scripts, shell, util
+from wizard import scripts, shell, sql, util
 
 def dsn_callback(options):
     if not isinstance(options.dsn, sqlalchemy.engine.url.URL):
         options.dsn = sqlalchemy.engine.url.make_url(options.dsn)
+    # do some guessing with sql
+    options.dsn = sql.fill_url(options.dsn)
     # perform some sanity checks on the database
     database = options.dsn.database
     options.dsn.database = None
@@ -53,18 +55,6 @@ def fetch(options, path, post=None):
     """
     return util.fetch(options.web_host, options.web_path, path, post)
 
-def preloads():
-    """
-    Retrieves a dictionary of string names to precanned :class:`ArgSet` objects.
-    """
-    return {
-            'web': WebArgSet(),
-            'db': DbArgSet(),
-            'admin': AdminArgSet(),
-            'email': EmailArgSet(),
-            'title': TitleArgSet(),
-            }
-
 class Strategy(object):
     """
     Represents a strategy for calculating arg values without user input.
@@ -129,6 +119,8 @@ class ScriptsWebStrategy(Strategy):
         self.dir = dir
     def prepare(self):
         """Uses :func:`wizard.scripts.get_web_host_and_path`."""
+        if self.dir is None:
+            raise StrategyFailed
         self._url = scripts.fill_url(self.dir, None)
         if not self._url:
             raise StrategyFailed
@@ -156,6 +148,8 @@ class ScriptsMysqlStrategy(Strategy):
             self._triplet = shell.eval("/mit/scripts/sql/bin/get-password").split()
         except shell.CallError:
             raise StrategyFailed
+        if len(self._triplet) != 3:
+            raise StrategyFailed
         self._username = os.getenv('USER')
         if self._username is None:
             raise StrategyFailed
@@ -163,8 +157,8 @@ class ScriptsMysqlStrategy(Strategy):
         """Creates a new database for the user using ``get-next-database`` and ``create-database``."""
         host, username, password = self._triplet
         # race condition
-        database = self._username + '+' + shell.eval("/mit/scripts/sql/bin/get-next-database", os.path.basename(self.dir))
-        shell.call("/mit/scripts/sql/bin/create-database", database)
+        name = shell.eval("/mit/scripts/sql/bin/get-next-database", os.path.basename(self.dir))
+        database = shell.eval("/mit/scripts/sql/bin/create-database", name)
         options.dsn = sqlalchemy.engine.url.URL("mysql", username=username, password=password, host=host, database=database)
 
 class ScriptsEmailStrategy(Strategy):
@@ -174,6 +168,7 @@ class ScriptsEmailStrategy(Strategy):
         """Uses :envvar:`USER` and assumes you are an MIT affiliate."""
         # XXX: should double-check that you're on a scripts server
         # and fail if you're not.
+        # XXX: This might be buggy, because locker might be set to USER
         self._user = os.getenv("USER")
         if self._user is None:
             raise StrategyFailed
@@ -264,14 +259,28 @@ class TitleArgSet(ArgSet):
                     prompt="Please decide on a title for your new website."),
                 ]
 
+def preloads():
+    """
+    Retrieves a dictionary of string names to precanned :class:`ArgSet` objects.
+    """
+    return {
+            'web': WebArgSet(),
+            'db': DbArgSet(),
+            'admin': AdminArgSet(),
+            'email': EmailArgSet(),
+            'title': TitleArgSet(),
+            }
+
 class ArgSchema(object):
     """
     Schema container for arguments.
 
     Valid identifiers for subclasses of :class:`ArgSet` are:
 
-    * ``mysql``, which populates the options ``mysql_host``, ``mysql_db``,
-      ``mysql_user`` and ``mysql_password``.
+    * ``db``, which populates the option ``dsn``, which is a SQLAlchemy
+      database source name, with properties for ``drivername``,
+      ``username``, ``password``, ``host``, ``port``, ``database`` and
+      ``query``.
     * ``admin``, which populates the options ``admin_name`` and
       ``admin_password``.
     * ``email``, which populates the option ``email``.
@@ -281,7 +290,7 @@ class ArgSchema(object):
 
     Example::
 
-        parser = ArgHandler("mysql", "admin", "email")
+        parser = ArgHandler("db", "admin", "email")
         parser.add(Arg("title", help="Title of the new application"))
     """
     #: Dictionary of argument names to :class:`Arg` objects in schema.
@@ -304,7 +313,7 @@ class ArgSchema(object):
     def add(self, arg):
         """Adds an argument to our schema."""
         self.args[arg.name] = arg
-    def commit(self, application, dir):
+    def commit(self, application, dir, web_stub_path):
         """Populates :attr:`strategies` and :attr:`provides`"""
         self.strategies = []
         self.provides = set()
@@ -312,12 +321,10 @@ class ArgSchema(object):
         raw_strategies = [
                 EnvironmentStrategy(self),
                 ScriptsWebStrategy(dir),
+                ScriptsWebStrategy(web_stub_path),
                 ScriptsMysqlStrategy(application, dir),
                 ScriptsEmailStrategy(),
                 ]
-        for arg in self.args.values():
-            if os.getenv(arg.envname) is not None:
-                self.provides.add(arg.name)
         for strategy in raw_strategies:
             try:
                 strategy.prepare()
@@ -348,6 +355,8 @@ class ArgSchema(object):
         if missing:
             raise MissingRequiredParam(missing)
         for strategy in self.strategies:
+            # If the application being installed doesn't need all of the
+            # parameters a strategy could provide, we don't use it.
             if any(not hasattr(options, name) for name in strategy.provides):
                 if any(hasattr(options, name) for name in strategy.provides):
                     logging.warning("Ignored partial strategy %s" % strategy)