import urlparse
import time
import errno
+import sqlalchemy
import wizard
-from wizard import shell, util, user
+from wizard import deploy, shell, install, util, user
def deploy_web(dir):
# try the directory
return None
def user_email(name):
- # XXX: simplistic strategy which doesn't work most of the time
+ # XXX: simplistic install which doesn't work most of the time
return "%s@scripts.mit.edu" % name
def user_operator():
name, password, uid, gid, gecos, homedir, console = result.split(":")
realname = gecos.split(",")[0]
return user.Info(name, uid, gid, realname, homedir, console)
+
+class MysqlStrategy(install.Strategy):
+ """
+ Performs scripts specific guesses for MySQL variables. This
+ may create an appropriate database for the user.
+ """
+ side_effects = True
+ provides = frozenset(["dsn"])
+ def prepare(self):
+ """Uses the SQL programs in the scripts locker"""
+ if self.application.database != "mysql":
+ raise install.StrategyFailed
+ try:
+ self._triplet = shell.eval("/mit/scripts/sql/bin/get-password").split()
+ except shell.CallError:
+ raise install.StrategyFailed
+ if len(self._triplet) != 3:
+ raise install.StrategyFailed
+ self._username = os.getenv('USER')
+ if self._username is None:
+ raise install.StrategyFailed
+ def execute(self, options):
+ """Creates a new database for the user using ``get-next-database`` and ``create-database``."""
+ host, username, password = self._triplet
+ # race condition
+ 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 EmailStrategy(install.Strategy):
+ """Performs script specific guess for email."""
+ provides = frozenset(["email"])
+ def prepare(self):
+ """Uses :envvar:`USER` and assumes you are an MIT affiliate."""
+ # XXX: This might be buggy, because locker might be set to USER
+ self._user = os.getenv("USER")
+ if self._user is None:
+ raise install.StrategyFailed
+ def execute(self, options):
+ """No-op."""
+ options.email = self._user + "@mit.edu"
import logging
import sqlalchemy
import warnings
+import pkg_resources
import wizard
from wizard import deploy, shell, sql, util
provides = frozenset()
#: Whether or not this strategy has side effects.
side_effects = False
+ # Set at runtime
+ #: The :class:`ArgSchema` being created
+ schema = None
+ #: The :class:`wizard.app.Application` being installed.
+ application = None
+ #: The directory we are being installed to.
+ dir = None
+ #: The directory web stub files are being installed to.
+ web_stub_path = None
+ def __init__(self, schema, application, dir, web_stub_path):
+ self.schema = schema
+ self.application = application
+ self.dir = dir
+ self.web_stub_path = web_stub_path
def prepare(self):
"""
Performs all side-effectless computation associated with this
Fills in values from environment variables, based off of
:attr:`Arg.envname` from ``schema``.
"""
- def __init__(self, schema):
+ def __init__(self, *args):
+ Strategy.__init__(self, *args)
self.provides = set()
self.envlookup = {}
- for arg in schema.args.values():
+ for arg in self.schema.args.values():
if os.getenv(arg.envname) is not None:
self.provides.add(arg.name)
self.envlookup[arg.name] = arg.envname
continue
setattr(options, name, os.getenv(envname))
-class ScriptsWebStrategy(Strategy):
- """Performs scripts specific guesses for web variables."""
- # XXX: This actually isn't too scripts specific
+class WebStrategy(Strategy):
+ """Performs guesses for web variables using the URL hook."""
provides = frozenset(["web_host", "web_path"])
- def __init__(self, dir):
- self.dir = dir
def prepare(self):
"""Uses :func:`deploy.web`."""
if self.dir is None:
raise StrategyFailed
- urls = deploy.web(self.dir, None)
- if not urls:
- raise StrategyFailed
+ if not os.path.exists(self.dir):
+ os.mkdir(self.dir)
try:
- self._url = urls.next() # pylint: disable-msg=E1101
- except StopIteration:
- raise StrategyFailed
+ urls = deploy.web(self.dir, None)
+ if not urls:
+ raise StrategyFailed
+ try:
+ self._url = urls.next() # pylint: disable-msg=E1101
+ except StopIteration:
+ raise install.StrategyFailed
+ except:
+ os.rmdir(self.dir)
+ raise
def execute(self, options):
"""No-op."""
options.web_host = self._url.netloc # pylint: disable-msg=E1101
options.web_path = self._url.path # pylint: disable-msg=E1101
options.web_inferred = True # hacky: needed to see if we need a .scripts/url file
-class ScriptsMysqlStrategy(Strategy):
- """
- Performs scripts specific guesses for MySQL variables. This
- may create an appropriate database for the user.
- """
- side_effects = True
- provides = frozenset(["dsn"])
- def __init__(self, application, dir):
- self.application = application
- self.dir = dir
- def prepare(self):
- """Uses the SQL programs in the scripts locker"""
- if self.application.database != "mysql":
- raise StrategyFailed
- try:
- 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
- def execute(self, options):
- """Creates a new database for the user using ``get-next-database`` and ``create-database``."""
- host, username, password = self._triplet
- # race condition
- 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):
- """Performs script specific guess for email."""
- provides = frozenset(["email"])
- def prepare(self):
- """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
- def execute(self, options):
- """No-op."""
- options.email = self._user + "@mit.edu"
-
class Arg(object):
"""
Represent a required, named argument for installation.
"""Populates :attr:`strategies` and :attr:`provides`"""
self.strategies = []
self.provides = set()
- # XXX: separate out soon
raw_strategies = [
- EnvironmentStrategy(self),
- ScriptsWebStrategy(dir),
- ScriptsWebStrategy(web_stub_path),
- ScriptsMysqlStrategy(application, dir),
- ScriptsEmailStrategy(),
+ EnvironmentStrategy,
+ WebStrategy,
]
- for strategy in raw_strategies:
+ for entry in pkg_resources.iter_entry_points("wizard.install.strategy"):
+ cls = entry.load()
+ raw_strategies.append(cls)
+ for strategy_cls in raw_strategies:
try:
+ strategy = strategy_cls(self, application, dir, web_stub_path)
strategy.prepare()
self.provides |= strategy.provides
self.strategies.append(strategy)