5fcb36e8f6e4c115fc15acf7e8d0d56b09fa34c3
[redakcja.git] / fabfile.py
1 from __future__ import with_statement # needed for python 2.5
2 from fabric.api import *
3
4 import os
5
6
7 # ==========
8 # = Config =
9 # ==========
10 # Globals
11 env.project_name = 'platforma'
12 env.use_south = False
13
14 # Servers
15 def staging():
16     """Use staging server"""
17     env.hosts = ['stigma.nowoczesnapolska.org.pl:2222']
18     env.user = 'zuber'
19     env.path = '/var/services/platforma'
20     env.python = '/usr/bin/python'
21     env.virtualenv = '/usr/bin/virtualenv'
22     env.pip = '/usr/bin/pip'
23     
24 def production():
25     """Use production server"""
26     env.hosts = ['wolnelektury.pl:22123']
27     env.user = 'fundacja'
28     env.path = '/opt/lektury/platforma'
29     env.python = '/opt/lektury/basevirtualenv/bin/python'
30     env.virtualenv = '/opt/lektury/basevirtualenv/bin/virtualenv'
31     env.pip = '/opt/lektury/basevirtualenv/bin/pip'
32
33
34 # =========
35 # = Tasks =
36 # =========
37 def test():
38     "Run the test suite and bail out if it fails"
39     require('hosts', 'path', provided_by=[staging, production])
40     result = run('cd %(path)s/%(project_name)s; %(python)s manage.py test' % env)
41
42 def setup():
43     """
44     Setup a fresh virtualenv as well as a few useful directories, then run
45     a full deployment. virtualenv and pip should be already installed.
46     """
47     require('hosts', 'path', provided_by=[staging, production])
48
49     run('mkdir -p %(path)s; cd %(path)s; %(virtualenv)s --no-site-packages .;' % env, pty=True)
50     run('cd %(path)s; mkdir releases; mkdir shared; mkdir packages;' % env, pty=True)
51     deploy()
52
53 def deploy():
54     """
55     Deploy the latest version of the site to the servers, 
56     install any required third party modules, 
57     install the virtual host and then restart the webserver
58     """
59     require('hosts', 'path', provided_by=[staging, production])
60
61     import time
62     env.release = time.strftime('%Y-%m-%dT%H%M')
63
64     upload_tar_from_git()
65     upload_pybundle()
66     install_requirements()
67     symlink_current_release()
68     migrate()
69     restart_webserver()
70
71 def deploy_version(version):
72     "Specify a specific version to be made live"
73     require('hosts', 'path', provided_by=[localhost,webserver])
74     env.version = version
75     with cd(env.path):
76         run('rm releases/previous; mv releases/current releases/previous;', pty=True)
77         run('ln -s %(version)s releases/current' % env, pty=True)
78     restart_webserver()
79
80 def rollback():
81     """
82     Limited rollback capability. Simple loads the previously current
83     version of the code. Rolling back again will swap between the two.
84     """
85     require('hosts', provided_by=[staging, production])
86     require('path')
87     with cd(env.path):
88         run('mv releases/current releases/_previous;', pty=True)
89         run('mv releases/previous releases/current;', pty=True)
90         run('mv releases/_previous releases/previous;', pty=True)
91     restart_webserver()
92
93
94 # =====================================================================
95 # = Helpers. These are called by other functions rather than directly =
96 # =====================================================================
97 def upload_tar_from_git():
98     "Create an archive from the current Git master branch and upload it"
99     print '>>> upload tar from git'
100     require('release', provided_by=[deploy])
101     local('git archive --format=tar master | gzip > %(release)s.tar.gz' % env)
102     run('mkdir -p %(path)s/releases/%(release)s' % env, pty=True)
103     run('mkdir -p %(path)s/packages' % env, pty=True)
104     put('%(release)s.tar.gz' % env, '%(path)s/packages/' % env)
105     run('cd %(path)s/releases/%(release)s && tar zxf ../../packages/%(release)s.tar.gz' % env, pty=True)
106     local('rm %(release)s.tar.gz' % env)
107
108 def install_requirements():
109     "Install the required packages from the requirements file using pip"
110     print '>>> install requirements'
111     require('release', provided_by=[deploy])
112     run('cd %(path)s; %(pip)s install -E . requirements.pybundle' % env)
113
114 def upload_pybundle():
115     "Create pybundle with required libraries and upload it"
116     print ">>> upload pybundle"
117     require('release', provided_by=[deploy])
118     with settings(warn_only=True):
119         pip_options = run('cat %(path)s/releases/%(release)s/pip-options.txt' % env)
120         if pip_options.failed:
121             env.pip_options = ''
122         else:
123             env.pip_options = pip_options
124             
125     requirements_mtime = os.path.getmtime('requirements.txt')
126     bundle_mtime = 0
127     try:
128         bundle_mtime = os.path.getmtime('requirements.pybundle')
129     except os.error:
130         pass
131
132     if requirements_mtime > bundle_mtime:
133         local('pip bundle requirements.pybundle %(pip_options)s -r requirements.txt' % env)
134         put('requirements.pybundle', '%(path)s' % env)
135
136 def symlink_current_release():
137     "Symlink our current release"
138     print '>>> symlink current release'
139     require('release', provided_by=[deploy])
140     require('path', provided_by=[staging, production])
141     with cd(env.path):
142         run('rm releases/previous; mv releases/current releases/previous')
143         run('ln -s %(release)s releases/current' % env)
144
145 def migrate():
146     "Update the database"
147     print '>>> migrate'
148     require('project_name', provided_by=[staging, production])
149     with cd('%(path)s/releases/current/%(project_name)s' % env):
150         run('../../../bin/python manage.py syncdb --noinput' % env, pty=True)
151         if env.use_south:
152             run('../../../bin/python manage.py migrate' % env, pty=True)
153
154 def restart_webserver():
155     "Restart the web server"
156     print '>>> restart webserver'
157     run('touch %(path)s/releases/current/%(project_name)s/%(project_name)s.wsgi' % env)