forked from YellLabs/yellfabric
/
python.py
270 lines (197 loc) · 6.47 KB
/
python.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
import os
import context_managers
import utils
import operations
from fabric.api import env, require, cd, runs_once, sudo, abort
@runs_once
def setup_paths():
require("python_root", "project_name", "vhost")
env.vhost_path = os.path.join(env.python_root, env.vhost)
env.project_path = os.path.join(env.vhost_path, env.project_name)
env.virtualenv_path = \
os.path.join(env.vhost_path, "%s-env" % env.project_name)
env.requirements_path = \
os.path.join(env.project_path, "requirements", "project.txt")
env.wsgi_path = \
os.path.join(env.project_path, "deploy", "*.wsgi")
env.config_source = "local_settings.py.template"
env.config_target = "local_settings.py"
def create_virtualenv():
"""
Create a Python virtual environment.
"""
require(
"virtualenv_path",
"python_bin",
"http_proxy",
"https_proxy",
"sudo_user",
)
# Added system-site-packages as environment
# uses global packages like MySQLdb
cmd = "virtualenv --python %s %s --system-site-packages" % (env.python_bin, env.virtualenv_path)
with context_managers.proxy(env.http_proxy, env.https_proxy):
# Needs to cd into a directory that the sudo user can temporarily write
# to.
with cd("/tmp"):
sudo(cmd, user=env.sudo_user)
def pip_requirements():
"""
Install project requirements using PIP into a Python virtual environment.
"""
require(
"virtualenv_path",
"requirements_path",
"http_proxy",
"https_proxy",
"sudo_user",
)
cmd = "pip install --quiet --requirement %s" % env.requirements_path
# append packages url if specified
if env.get("packages_url") is not None:
cmd += " -f %s" % env.get("packages_url")
with context_managers.proxy(env.http_proxy, env.https_proxy):
with context_managers.virtualenv(env.virtualenv_path):
sudo(cmd, user=env.sudo_user)
def render_settings_template(debug=False):
"""
Render a settings file from a template in a local checkout.
"""
require("tempdir", "project_path", "settings_vars")
source = os.path.join(env.tempdir, "local_settings.py.template")
target = os.path.join(env.tempdir, "local_settings.py")
context = utils.template_context(env.settings_vars)
# Treat as a string even though it's going to be rendered as unquoted.
# Clobbers anything from env in the project's own fabfile because the
# default should always be False.
if "%s" % debug in ["True", "False"]:
context["DEBUG"] = debug
else:
abort("local_settings.DEBUG may only be True or False")
utils.template_to_file(source, target, context)
def refresh_wsgi():
"""
Touch a WSGI file so that Apache w/mod_wsgi reloads a project.
"""
require("wsgi_path", "sudo_user")
cmd = "touch -c %s" % env.wsgi_path
sudo(cmd, user=env.sudo_user)
@runs_once
def syncdb():
"""
Perform 'syncdb' action for a Django project.
"""
require("virtualenv_path", "project_path", "sudo_user")
utils.django_manage_run(
env.virtualenv_path,
env.project_path,
"syncdb",
env.sudo_user,
)
@runs_once
def migratedb(rollback=False):
"""
Perform 'migrate' action for a Django project.
"""
require("virtualenv_path", "project_path", "sudo_user")
#
# Some things need to be done first (i.e. if they need a different
# database connection or some custom args)
#
if "migratedb_first" in env:
for app, args in env.migratedb_first.iteritems():
version = get_south_migrate_version(app, rollback)
migrate_app_db(app, version, args)
#
# Do the rest afterwards
#
if has_version_info():
apps = env.south_migrations.keys()
for app in apps:
print app
version = get_south_migrate_version(app, rollback)
migrate_app_db(app, version)
#
# If we know nothing, just migrate everything
#
else:
migrate_app_db()
def migrate_app_db(app=None, version=None, args=None):
require("virtualenv_path", "project_path", "sudo_user")
if app:
if args:
command = ' '.join(['migrate', app, version, args])
else:
command = ' '.join(['migrate', app, version])
else:
command = "migrate"
print command
utils.django_manage_run(
env.virtualenv_path,
env.project_path,
command,
env.sudo_user,
)
def get_south_migrate_version(app, rollback=False):
version = None if rollback else "auto"
if has_version_info():
if app in env.south_migrations:
if rollback:
version = env.south_migrations[app]["rollback"]
else:
version = env.south_migrations[app]["deploy"]
return version
def has_version_info():
if "south_migrations" in env:
if "scm_tag" in env:
return True
return False
@runs_once
def create_superuser(username=None, email=None):
"""
Create a django superuser
"""
require("virtualenv_path", "project_path", "sudo_user")
cmd = "createsuperuser"
if username:
cmd = "%s --username=%s" % (cmd, username)
if email:
cmd = "%s --email=%s" % (cmd, email)
utils.django_manage_run(
env.virtualenv_path,
env.project_path,
cmd,
env.sudo_user,
interactive=True,
)
def deploy_django(ref=None, debug=False, dirty=False):
"""
Standard Django deployment actions.
"""
create_virtualenv()
operations.fetch_render_copy(ref, debug, dirty, True)
pip_requirements()
migratedb()
refresh_wsgi()
def rollback_django(ref=None, debug=False, dirty=False):
"""
There is nothing standard about rolling back.
"""
if has_version_info():
#
# To roll back we need to fetch the existing version, execute the
# database rollback, and then do a deploy of a specific version
#
create_virtualenv()
# Copy the new code... the one we want to back out, as we need the
# migrations from this
fetch_render_copy(ref, debug, dirty)
# Rollback the database
migratedb(True)
# Get the old code
del env['tempdir']
fetch_render_copy(env.scm_tag["rollback"], debug, dirty, True)
pip_requirements()
refresh_wsgi()
else:
abort("No version info present to allow rollback")