TODO NOW:
-- The calling web code invocations are a mess, with stubs living
- in the install, deploy modules and the real deal living in util. Furthermore,
- we use the scripts-specific heuristic to determine where the app
- lives, and the only reason my test scripts work is because they
- get manually fed the domain and path by my environment variables.
-
- Use system similar to database, with option for explicit override,
- but otherwise attempting to determine from ambient code
-
- If you try to do an install on scripts w/o sql, it will sign you up but fail to write
the sql.cnf file. This sucks.
operations.
- Pay back code debt
- - Genericize callAsUser and drop_priviledges in shell
+ - Tidy up common code in callAsUser and drop_priviledges in shell
- Summary script should be more machine friendly, and should not
output summary charts when I increase specificity
- Summary script should do something intelligent when distinguishing
import sqlalchemy
import random
import string
+import urlparse
import wizard
from wizard import resolve, scripts, shell, util
# XXX: You'd have to put support for an explicit different database
# type here
return sqlalchemy.engine.url.URL(self.database, username=user, password=password, host=host, database=database)
+ def url(self, deployment):
+ """
+ Returns the deployment specific web URL. Uses the override file
+ in :file:`.scripts` if it exists, and otherwise attempt to extract
+ the variables from the source files.
+
+ This function might return ``None``, which indicates we couldn't figure
+ it out.
+ """
+ url = self.urlFromOverride(deployment)
+ if url:
+ return url
+ return self.urlFromExtract(deployment)
+ def urlFromOverride(self, deployment):
+ """
+ Extracts URL from explicit url override file.
+ """
+ try:
+ return urlparse.urlparse(open(deployment.url_file).read().strip())
+ except IOError:
+ return None
+ def urlFromExtract(self, deployment):
+ """
+ Extracts URL from a deployment, and returns ``None`` if we can't
+ figure it out. Default implementation is to fail; we might
+ do something clever with extractable variables in the future.
+ """
+ return None
def parametrize(self, deployment, ref_deployment):
"""
Takes a generic source checkout and parametrizes it according to the
application.install(distutils.version.LooseVersion(version), options)
if not old_options.no_commit:
git.commit_configure()
+ if not hasattr(options, "web_inferred"):
+ open(os.path.join(dir, ".scripts/url"), "w").write("http://%s%s" % (options.web_host, options.web_path)) # XXX: no support for https yet!
input.infobox("Congratulations, your new install is now accessible at:\n\nhttp://%s%s" % (options.web_host, options.web_path), width=80)
def configure_parser(parser, baton):
else:
name = e.name
if name == "WebVerificationError":
- try:
- host, path = scripts.get_web_host_and_path(d.location)
- url = "http://%s%s" % (host, path)
- except ValueError:
- url = d.location
+ url = d.url.geturl()
# This should actually be a warning, but
# it's a really common error
logging.info("[%04d] Could not verify application at %s" % (i, url))
self._read_cache = {}
self._old_log = None
self._dsn = None
+ self._url = None
def invalidateCache(self):
"""
Invalidates all cached variables. This currently applies to
"""The absolute path of the :file:`.scripts/dsn` override file."""
return os.path.join(self.scripts_dir, 'dsn')
@property
+ def url_file(self):
+ """The absolute path of the :file:`.scripts/url` override file."""
+ return os.path.join(self.scripts_dir, 'url')
+ @property
def application(self):
"""The :class:`app.Application` of this deployment."""
return self.app_version.application
return self._app_version
@property
def dsn(self):
+ """The :class:`sqlalchemy.engine.url.URL` for this deployment."""
if not self._dsn:
self._dsn = sql.fill_url(self.application.dsn(self))
return self._dsn
+ @property
+ def url(self):
+ """The :class:`urlparse.ParseResult` for this deployment."""
+ if not self._url:
+ self._url = scripts.fill_url(self.location, self.application.url(self))
+ if not self._url:
+ raise UnknownWebPath
+ return self._url
@staticmethod
def parse(line):
"""
"""
Performs a HTTP request on the website.
"""
- try:
- host, basepath = scripts.get_web_host_and_path(self.location)
- except (ValueError, TypeError):
- raise UnknownWebPath
- return util.fetch(host, basepath, path, post)
+ return util.fetch(self.url.netloc, self.url.path, path, post)
class WorkingCopy(Deployment):
"""
self.dir = dir
def prepare(self):
"""Uses :func:`wizard.scripts.get_web_host_and_path`."""
- self._tuple = scripts.get_web_host_and_path(self.dir)
- if not self._tuple:
+ self._url = scripts.fill_url(self.dir, None)
+ if not self._url:
raise StrategyFailed
def execute(self, options):
"""No-op."""
- options.web_host, options.web_path = self._tuple
+ options.web_host = self._url.netloc
+ options.web_path = self._url.path
+ options.web_inferred = True # hacky: needed to see if we need a .scripts/url file
class ScriptsMysqlStrategy(Strategy):
"""
import shlex
import errno
import logging
+import urlparse
import wizard
from wizard import shell, util
-def get_web_host_and_path(dir=None):
- """
- Attempts to determine webhost and path for the current directory
- as it would be accessible from the web. Works only for scripts
- servers. Returns a tuple web_host, web_path, or None if it failed.
- """
- # XXX: THIS CODE SUCKS
+def fill_url(dir, url=None):
+ if url:
+ return url
+
+ # hook hook
+
+ # try the directory
+ homedir, _, web_path = dir.partition("/web_scripts")
+ if web_path:
+ return urlparse.ParseResult(
+ "http",
+ util.get_dir_owner(homedir) + ".scripts.mit.edu",
+ web_path.rstrip('/'),
+ "", "", "")
+
+ # try the environment
host = os.getenv("WIZARD_WEB_HOST")
path = os.getenv("WIZARD_WEB_PATH")
if host is not None and path is not None:
- return (host, path.rstrip('/'))
- if not dir:
- dir = os.getcwd()
- # XXX: possible security risk?
- homedir, _, web_path = dir.partition("/web_scripts")
- if not web_path:
- return None
- return (util.get_dir_owner(homedir) + ".scripts.mit.edu", web_path.rstrip('/'))
+ return urlparse.ParseResult(
+ "http",
+ host,
+ path.rstrip('/'),
+ "", "", "")
+
+ return None
def get_quota_usage_and_limit(dir=None):
"""