8b55e587fd6aa67a44c49c73e1bc4fc0134f1eb8
[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     run('cd %(path)s/releases; ln -s . current; ln -s . previous' % env, pty=True)
52     deploy()
53
54 def deploy():
55     """
56     Deploy the latest version of the site to the servers, 
57     install any required third party modules, 
58     install the virtual host and then restart the webserver
59     """
60     require('hosts', 'path', provided_by=[staging, production])
61
62     import time
63     env.release = time.strftime('%Y-%m-%dT%H%M')
64
65     upload_tar_from_git()
66     upload_pybundle()
67     install_requirements()
68     symlink_current_release()
69     migrate()
70     restart_webserver()
71
72 def deploy_version(version):
73     "Specify a specific version to be made live"
74     require('hosts', 'path', provided_by=[localhost,webserver])
75     env.version = version
76     with cd(env.path):
77         run('rm releases/previous; mv releases/current releases/previous;', pty=True)
78         run('ln -s %(version)s releases/current' % env, pty=True)
79     restart_webserver()
80
81 def rollback():
82     """
83     Limited rollback capability. Simple loads the previously current
84     version of the code. Rolling back again will swap between the two.
85     """
86     require('hosts', provided_by=[staging, production])
87     require('path')
88     with cd(env.path):
89         run('mv releases/current releases/_previous;', pty=True)
90         run('mv releases/previous releases/current;', pty=True)
91         run('mv releases/_previous releases/previous;', pty=True)
92     restart_webserver()
93
94
95 # =====================================================================
96 # = Helpers. These are called by other functions rather than directly =
97 # =====================================================================
98 def upload_tar_from_git():
99     "Create an archive from the current Git master branch and upload it"
100     print '>>> upload tar from git'
101     require('release', provided_by=[deploy])
102     local('git archive --format=tar master | gzip > %(release)s.tar.gz' % env)
103     run('mkdir -p %(path)s/releases/%(release)s' % env, pty=True)
104     run('mkdir -p %(path)s/packages' % env, pty=True)
105     put('%(release)s.tar.gz' % env, '%(path)s/packages/' % env)
106     run('cd %(path)s/releases/%(release)s && tar zxf ../../packages/%(release)s.tar.gz' % env, pty=True)
107     local('rm %(release)s.tar.gz' % env)
108
109 def install_requirements():
110     "Install the required packages from the requirements file using pip"
111     print '>>> install requirements'
112     require('release', provided_by=[deploy])
113     run('cd %(path)s; %(pip)s install -E . requirements.pybundle' % env)
114
115 def upload_pybundle():
116     "Create pybundle with required libraries and upload it"
117     print ">>> upload pybundle"
118     require('release', provided_by=[deploy])
119     with settings(warn_only=True):
120         pip_options = run('cat %(path)s/releases/%(release)s/pip-options.txt' % env)
121         if pip_options.failed:
122             env.pip_options = ''
123         else:
124             env.pip_options = pip_options
125             
126     requirements_mtime = os.path.getmtime('requirements.txt')
127     bundle_mtime = 0
128     try:
129         bundle_mtime = os.path.getmtime('requirements.pybundle')
130     except os.error:
131         pass
132
133     if requirements_mtime > bundle_mtime:
134         local('pip bundle requirements.pybundle %(pip_options)s -r requirements.txt' % env)
135         put('requirements.pybundle', '%(path)s' % env)
136
137 def symlink_current_release():
138     "Symlink our current release"
139     print '>>> symlink current release'
140     require('release', provided_by=[deploy])
141     require('path', provided_by=[staging, production])
142     with cd(env.path):
143         run('rm releases/previous; mv releases/current releases/previous')
144         run('ln -s %(release)s releases/current' % env)
145
146 def migrate():
147     "Update the database"
148     print '>>> migrate'
149     require('project_name', provided_by=[staging, production])
150     with cd('%(path)s/releases/current/%(project_name)s' % env):
151         run('../../../bin/python manage.py syncdb --noinput' % env, pty=True)
152         if env.use_south:
153             run('../../../bin/python manage.py migrate' % env, pty=True)
154
155 def restart_webserver():
156     "Restart the web server"
157     print '>>> restart webserver'
158     run('touch %(path)s/releases/current/%(project_name)s/%(project_name)s.wsgi' % env)