1 from __future__ import with_statement
 
   8 logging.basicConfig(stream=sys.stderr, format="%(levelname)s:: %(message)s")
 
  10 from string import Template
 
  12 class DeploySite(object):
 
  14     def __init__(self, **env):
 
  17         for arg in ('ROOT', 'PROJECT_NAME', 'PYTHON_VERSION'):
 
  18             if arg not in self.env:
 
  19                 raise ValueError("Argument '%s' is required." % arg)
 
  21         if 'PYTHON_BASE' not in self.env:
 
  22             self.env['PYTHON_BASE'] = os.path.join(self.env['ROOT'], 'pythonenv')
 
  24         if 'PYTHON_BIN' not in self.env:
 
  25             self.env['PYTHON_BIN'] = os.path.join(
 
  26                         self.env['PYTHON_BASE'], 'bin', 'python') + self.env['PYTHON_VERSION']
 
  28         if 'PYTHON_SITE' not in self.env:
 
  29             self.env['PYTHON_SITE'] = os.path.join(
 
  30                         self.env['PYTHON_BASE'], 'lib',
 
  31                         'python' + self.env['PYTHON_VERSION'], 'site-packages')
 
  33         if 'APP_DIR' not in self.env:
 
  34             self.env['APP_DIR'] = os.path.join(self.env['ROOT'], 'application')
 
  36         if 'CONFIG_DIR' not in self.env:
 
  37             self.env['CONFIG_DIR'] = os.path.join(self.env['ROOT'], 'etc')
 
  39         if 'MEDIA_DIR' not in self.env:
 
  40             self.env['MEDIA_DIR'] = os.path.join(self.env['ROOT'], 'www', 'media')
 
  42         self._logger = logging.getLogger("deployment")
 
  44     def info(self, *args, **kwargs):
 
  45         self._logger.info(*args, **kwargs)
 
  47     def render_template(self, source, dest, extra_context={}):
 
  48         self.info("Rendering template: %s", source)
 
  50         with open(source, 'rb') as source_file:
 
  51             t = Template(source_file.read())
 
  53         context = dict(self.env)
 
  54         context.update(extra_context)
 
  56         with open(dest, 'wb') as dest_file:
 
  57             dest_file.write(t.safe_substitute(context))
 
  61     def restart_app(self):
 
  67     def install_dependencies(self):
 
  72         self.install_dependencies()
 
  76     def find_resource(self, path):
 
  77         full_path = os.path.join(self.env['APP_DIR'], path)
 
  78         if os.path.isfile(full_path):
 
  80         raise ValueError("Resource '%s' not found" % path)
 
  83     def run_deploy(cls, *args, **kwargs):
 
  84         site = cls(*args, **kwargs)
 
  87 class WSGISite(DeploySite):
 
  89     def __init__(self, **env):
 
  90         super(WSGISite, self).__init__(**env)
 
  92         if 'WSGI_FILE' not in self.env:
 
  93             self.env['WSGI_FILE'] = os.path.join(self.env['ROOT'], 'www',
 
  94                                         'wsgi', self.env['PROJECT_NAME']) + '.wsgi'
 
  96         if 'WSGI_SOURCE_FILE' not in self.env:
 
  97             self.env['WSGI_SOURCE_FILE'] = 'wsgi_app.template'
 
  99         if 'WSGI_USER' not in self.env:
 
 100             self.env['WSGI_USER'] = 'www-data'
 
 102     def restart_app(self):
 
 103         self.info("Restarting wsgi application: %s", self.env['WSGI_FILE'])
 
 104         os.system("touch %s" % self.env['WSGI_FILE'])
 
 106     def update_config(self):
 
 107         source = self.find_resource(self.env['WSGI_SOURCE_FILE'])
 
 108         self.render_template(source, self.env['WSGI_FILE'])
 
 110 class PIPSite(DeploySite):
 
 112     def install_dependencies(self):
 
 113         self.info("Installing requirements")
 
 114         os.system("pip install -r %s" % self.find_resource('requirements.txt'))
 
 117             self.info("Installing local requirements")
 
 118             os.system("pip install -r %s" % self.find_resource('requirements_local.txt'))
 
 122 class GitSite(DeploySite):
 
 124     def update_app(self):
 
 125         self.info("Updating repository.")
 
 126         os.system("cd %s; git pull" % self.env['APP_DIR'])
 
 128 class ApacheSite(DeploySite):
 
 130     def __init__(self, **env):
 
 131         super(ApacheSite, self).__init__(**env)
 
 133         if 'VHOST_SOURCE_FILE' not in self.env:
 
 134             self.env['VHOST_SOURCE_FILE'] = 'apache_vhost.template'
 
 136         if 'VHOST_FILE' not in self.env:
 
 137             self.env['VHOST_FILE'] = os.path.join(self.env['CONFIG_DIR'], self.env['PROJECT_NAME'] + '.vhost')
 
 139     def update_config(self):
 
 140         source = self.find_resource(self.env['VHOST_SOURCE_FILE'])
 
 141         self.render_template(source, self.env['VHOST_CONFIG_FILE'])