X-Git-Url: https://scripts.mit.edu/gitweb/wizard.git/blobdiff_plain/30380c4b5b28df9670ea5952e14bc485d1d34133..f3096b4a2a5498c38c7451397eebdc4ac5ed0788:/wizard/install/__init__.py diff --git a/wizard/install/__init__.py b/wizard/install/__init__.py index 8ca40a3..291018c 100644 --- a/wizard/install/__init__.py +++ b/wizard/install/__init__.py @@ -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,12 @@ 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) + continue if all(getattr(options, name) is not None for name in strategy.provides): continue for name in strategy.provides: