1 from __future__ import with_statement
8 logging.basicConfig(stream=sys.stderr, format="%(levelname)s:: %(message)s", level=logging.INFO)
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 for dir in (self.env['CONFIG_DIR'], self.env['APP_DIR']):
78 full_path = os.path.join(dir, path)
79 if os.path.isfile(full_path):
82 raise ValueError("Resource '%s' not found" % path)
85 def run_deploy(cls, *args, **kwargs):
86 site = cls(*args, **kwargs)
89 class WSGISite(DeploySite):
91 def __init__(self, **env):
92 super(WSGISite, self).__init__(**env)
94 if 'WSGI_FILE' not in self.env:
95 self.env['WSGI_FILE'] = os.path.join(self.env['ROOT'], 'www',
96 'wsgi', self.env['PROJECT_NAME']) + '.wsgi'
98 if 'WSGI_SOURCE_FILE' not in self.env:
99 self.env['WSGI_SOURCE_FILE'] = 'wsgi_app.template'
101 if 'WSGI_USER' not in self.env:
102 self.env['WSGI_USER'] = 'www-data'
104 def restart_app(self):
105 self.info("Restarting wsgi application: %s", self.env['WSGI_FILE'])
106 os.system("touch %s" % self.env['WSGI_FILE'])
108 def update_config(self):
109 source = self.find_resource(self.env['WSGI_SOURCE_FILE'])
110 self.render_template(source, self.env['WSGI_FILE'])
112 class PIPSite(DeploySite):
114 def install_dependencies(self):
115 self.info("Installing requirements")
116 os.system("pip install -r %s" % self.find_resource('requirements.txt'))
119 self.info("Installing local requirements")
120 os.system("pip install -r %s" % self.find_resource('requirements_local.txt'))
124 class GitSite(DeploySite):
126 def update_app(self):
127 self.info("Updating repository.")
128 os.system("cd %s; git pull" % self.env['APP_DIR'])
130 class ApacheSite(DeploySite):
132 def __init__(self, **env):
133 super(ApacheSite, self).__init__(**env)
135 if 'VHOST_SOURCE_FILE' not in self.env:
136 self.env['VHOST_SOURCE_FILE'] = 'apache_vhost.template'
138 if 'VHOST_FILE' not in self.env:
139 self.env['VHOST_FILE'] = os.path.join(self.env['CONFIG_DIR'], self.env['PROJECT_NAME'] + '.vhost')
141 def update_config(self):
142 source = self.find_resource(self.env['VHOST_SOURCE_FILE'])
143 self.render_template(source, self.env['VHOST_CONFIG_FILE'])