Skip to content
Newer
Older
100755 351 lines (282 sloc) 9.92 KB
644d47d @mikeboers Started the blog.
authored Aug 12, 2011
1 #!bin/python
9cd5976 @mikeboers Initial commit.
authored Aug 5, 2011
2
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
3 from inspect import getargspec
4c31c21 @mikeboers Improved manage.py serve/kill.
authored Feb 29, 2012
4 from subprocess import Popen, call, CalledProcessError
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
5 import datetime
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
6 import glob
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
7 import logging
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
8 import os
9 import re
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
10 import site
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
11 import socket
12 import subprocess
13 import sys
5dedeb6 @mikeboers Better js watcher.
authored Mar 20, 2012
14 import time
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
15
16 from baker import command
17 import baker
5dedeb6 @mikeboers Better js watcher.
authored Mar 21, 2012
18 import watchdog.observers
19
ca31250 @mikeboers Use baker from PyPI
authored Aug 13, 2011
20
6746740 @mikeboers Define check_output.
authored Aug 17, 2011
21 try:
22 from subprocess import check_output
23 except ImportError:
24 def check_output(cmd, *args, **kwargs):
25 input = kwargs.pop('input', None)
26 proc = subprocess.Popen(cmd, *args,
27 stdin=kwargs.pop('stdin', subprocess.PIPE),
28 stdout=kwargs.pop('stdout', subprocess.PIPE),
29 stderr=kwargs.pop('stderr', subprocess.PIPE),
30 **kwargs
31 )
32 out, err = proc.communicate(input or '')
33 if proc.returncode:
34 e = subprocess.CalledProcessError(proc.returncode, cmd)
35 e.output = out
36 e.error = err
37 raise e
38 return out
39
40
ca31250 @mikeboers Use baker from PyPI
authored Aug 13, 2011
41 # We have to monkey patch baker so that we can use commands without any args.
42 # It will remove the first arg if it is "self", so we latch on to that action.
43 def patched_get_argspec(fn):
44 arglist, vargsname, kwargsname, defaults = getargspec(fn)
45 if not arglist:
46 arglist = ['self']
47 return arglist, vargsname, kwargsname, defaults
48 baker.getargspec = patched_get_argspec
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
49
50
51 log = logging.getLogger(os.path.basename(__file__))
52
53 # Make sure the working directory is right here.
54 root = os.path.abspath(os.path.dirname(__file__))
55 os.chdir(root)
56
57
58
59
60 try:
61 check_output = subprocess.check_output
62 except AttributeError:
63 def check_output(cmd, *args, **kwargs):
64 input = kwargs.pop('input', None)
65 proc = subprocess.Popen(cmd, *args,
66 stdin=kwargs.pop('stdin', subprocess.PIPE),
67 stdout=kwargs.pop('stdout', subprocess.PIPE),
68 stderr=kwargs.pop('stderr', subprocess.PIPE),
69 **kwargs
70 )
71 out, err = proc.communicate(input or '')
72 if proc.returncode:
73 e = subprocess.CalledProcessError(proc.returncode, cmd)
74 e.output = out
75 e.error = err
76 raise e
77 return out
78
79
80 def auto_config():
81 from app import config
82 if not config.siteconfig.exists:
83 print 'Site installation not setup!'
84 print 'Please input desired configuration.'
85 config.siteconfig.interactive_build()
86 config.siteconfig.save()
ccf8c07 @mikeboers Fix naming collision in manage.
authored Feb 29, 2012
87 __bulitins__.reload(config)
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
88
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
89
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
90 @command
91 def config():
92 from app import config as module
93 module.siteconfig.interactive_build()
94 module.siteconfig.save()
ccf8c07 @mikeboers Fix naming collision in manage.
authored Feb 29, 2012
95 __bulitins__.reload(module)
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
96
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
97
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
98 @command
5705f05 @mikeboers Nginx.conf
authored Feb 29, 2012
99 def nginx_conf():
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
100 auto_config()
101 import app.config
5705f05 @mikeboers Nginx.conf
authored Feb 29, 2012
102
103 from mako.lookup import TemplateLookup
104 lookup = TemplateLookup(directories=['.'])
105 open('nginx.conf', 'w').write(lookup.get_template('nginx.conf.mako').render(**app.config.__dict__))
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
106
107
108 # Determine running user.
109 user = os.environ.get('SUDO_USER') or check_output(['id', '-un']).strip()
110 uid = int(check_output(['id', '-u', user]))
111
112 # Determine server group
113 group = None
114 for name in 'www', 'www-data':
115 try:
116 gid = int(check_output(['id', '-g', name]))
117 group = name
118 break
119 except CalledProcessError:
120 pass
121 else:
122 print 'Could not determine server group.'
123 exit(1)
124
125
126
127 @command
128 def info(all=False):
129 auto_config()
130
131 print 'uid: %d (%s)' % (uid, user)
132 print 'gid: %d (%s)' % (gid, group)
133 print '-----'
134
135 import app.config
136
137 if all:
138 obj = app.config.__dict__
139 else:
140 obj = app.config.siteconfig
141
142 for k, v in sorted(obj.items()):
143 if k.startswith('_'):
144 continue
145 print '%s: %r' % (k, v)
146
147
148 @command
149 def git(check=False, update=False):
150 call('git submodule init'.split())
151 top_msg = False
152 for line in check_output('git submodule'.split()).splitlines():
153 if check and not line.startswith(' '):
154 if not top_msg:
155 print 'git submodules out of sync:'
156 top_msg = True
157 print '\t' + line.split(' ', 1)[1]
158 if update or line.startswith('-'):
159 path = line.split(' ', 1)[1]
160 call('git submodule update --'.split() + [path])
161 if check and not top_msg:
162 print 'git submodules are up to date.'
163
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
164
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
165 @command
166 def directories():
167 for name in '''
168 assets
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
169 assets/flickr
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
170 logs
171 tmp
172 tmp/cache
173 tmp/imgsizer
174 '''.strip().split():
175 if not os.path.exists(name):
176 print 'mkdir -p', name
177 os.makedirs(name)
178 call('chmod g+s'.split() + [name])
179
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
180
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
181 @command
182 def permissions(verbose=False):
183 # print 'Permissions should no longer matter.'
184 # return
185 all_files = glob.glob('*')
186 call(['chown', '-R' + ('v' if verbose else ''), user ] + all_files)
187 call(['chgrp', '-R' + ('v' if verbose else ''), group] + all_files)
188 call(['chmod', '-R' + ('v' if verbose else ''), 'o=' ] + all_files)
189 call(['chmod', '-R' + ('v' if verbose else ''), 'ug=rw,ug+X,g+s',
190 'data',
191 'logs',
192 'tmp',
193 'assets',
194 ])
4358d62 @mikeboers Start of cards.
authored Aug 5, 2011
195 call(['chmod', '-R' + ('v' if verbose else ''), 'u=rwX,g=rX', 'public'])
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
196
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
197
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
198 @command
199 def compass(watch=False):
200 if watch:
201 try:
68bf45c @mikeboers Clean up compass; move to `css`.
authored Feb 3, 2012
202 call(['compass', 'watch', './css', '--output-style', 'nested', '--force'])
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
203 except KeyboardInterrupt: pass
204 else:
68bf45c @mikeboers Clean up compass; move to `css`.
authored Feb 4, 2012
205 call(['compass', 'compile', './css', '--output-style', 'compressed', '--force'])
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
206
6303570 @mikeboers Javascript is concat-ed and minified.
authored Feb 3, 2012
207 @command
208 def js(watch=False):
5dedeb6 @mikeboers Better js watcher.
authored Mar 21, 2012
209
210
6303570 @mikeboers Javascript is concat-ed and minified.
authored Feb 4, 2012
211 if watch:
5dedeb6 @mikeboers Better js watcher.
authored Mar 21, 2012
212
213 affected_files = []
214 finals = ['%s.js' % x for x in 'main', 'admin', 'lib'] + ['%s.min.js' % x for x in 'main', 'admin', 'lib']
215
216 class EventHandler(object):
217 def dispatch(self, event):
218
219 # Ignore non-JS events.
220 if not event.src_path.endswith('.js'):
221 return
222
223 # Ignore the final files.
224 if os.path.basename(event.src_path) in finals:
225 return
226
227 affected_files.append((event.src_path, time.time()))
228
229 handler = EventHandler()
230 observer = watchdog.observers.Observer()
231 observer.schedule(handler, path="public/js", recursive=True)
232 observer.schedule(handler, path='src/nitrogen/static/js', recursive=True)
233 observer.start()
234
235 try:
236 while True:
237 time.sleep(0.25)
238 if affected_files:
239 while time.time() - affected_files[-1][1] < 0.25:
240 time.sleep(0.05)
241 affected_files[:] = []
242 js()
243
244 except KeyboardInterrupt:
245 observer.stop()
246 observer.join()
247 return
248
6303570 @mikeboers Javascript is concat-ed and minified.
authored Feb 4, 2012
249 else:
5dedeb6 @mikeboers Better js watcher.
authored Mar 21, 2012
250
6303570 @mikeboers Javascript is concat-ed and minified.
authored Feb 4, 2012
251 from jsmin import jsmin
252 for name in 'main', 'admin', 'lib':
253 print name
254 cmd = ('''sprockets --include js --include js/include --include src/nitrogen/static/js js/%s.js''' % name).split()
255 call(cmd, stdout=open('public/js/%s.js' % name, 'w'))
256 open('public/js/%s.min.js' % name, 'w').write(jsmin(open('public/js/%s.js' % name).read()))
257
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
258 @command(default=True)
259 def build():
4c31c21 @mikeboers Improved manage.py serve/kill.
authored Feb 29, 2012
260 nginx_conf()
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
261 compass()
4c31c21 @mikeboers Improved manage.py serve/kill.
authored Feb 29, 2012
262 js()
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
263 permissions()
264 git(check=True)
265
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
266
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
267 @command
9271035 @mikeboers More social, router tweaks, play with auth.
authored Aug 6, 2011
268 def routes():
269 from app.main import app
270 app.router.print_graph()
271
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
272
9271035 @mikeboers More social, router tweaks, play with auth.
authored Aug 7, 2011
273 @command
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
274 def schema(verbose=False, echo=False, dryrun=False):
275 from sqlalchemy import create_engine, MetaData, Table, Column, Integer, DateTime, String
276 import migrate # For monkey patches
277 from app import config
278
279 # Setup the db and our tables.
280 engine = create_engine(config.sqlalchemy_url, echo=echo)
281 meta = MetaData()
282 table = Table('schema_patches', meta,
283 Column('id', Integer, primary_key=True),
bb7aedc @mikeboers UTC times everywhere.
authored Aug 17, 2011
284 Column('time', DateTime, default=datetime.datetime.utcnow),
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
285 Column('name', String),
286 )
287 table.create(checkfirst=True, bind=engine)
288
289 patchdir = os.path.join(config.root, 'schema')
e43173f @mikeboers Schema pulls in default upgrade function too.
authored Aug 12, 2011
290 for dirpath, dirnames, filenames in os.walk(patchdir, followlinks=True):
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
291 for filename in filenames:
292 fullname = os.path.join(dirpath, filename)
293 relname = os.path.relpath(fullname, patchdir)
294 basename, ext = os.path.splitext(relname)
295 if fullname.endswith('.py'):
296 patches = []
297 namespace = dict(patch=patches.append)
298 execfile(fullname, namespace)
e43173f @mikeboers Schema pulls in default upgrade function too.
authored Aug 12, 2011
299 upgrade = namespace.get('upgrade')
300 if upgrade and upgrade not in patches:
301 patches.append(upgrade)
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
302
303 for patch in patches:
304 name = patch.__name__
305 patch_name = relname + ':' + name
306
307 for x in engine.execute(table.select().where(table.c.name == patch_name)):
0e1cca3 @mikeboers Remove local data.
authored Aug 12, 2011
308 if verbose:
309 print patch_name, 'applied on', x['time'].isoformat(' ')
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
310 break
311 else:
312 if dryrun:
0e1cca3 @mikeboers Remove local data.
authored Aug 13, 2011
313 print patch_name, 'would apply'
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
314 else:
0e1cca3 @mikeboers Remove local data.
authored Aug 13, 2011
315 print patch_name, 'applying...',
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
316 patch(engine)
317 engine.execute(table.insert(), name=patch_name)
318 print 'Done.'
319
dddb909 @mikeboers Attempted ./manage.py kill.
authored Aug 17, 2011
320
321 @command
4c31c21 @mikeboers Improved manage.py serve/kill.
authored Feb 29, 2012
322 def reload():
323 kill('hup')
dddb909 @mikeboers Attempted ./manage.py kill.
authored Aug 18, 2011
324
781b803 @mikeboers Replaced migrate script.
authored Aug 12, 2011
325 @command
4c31c21 @mikeboers Improved manage.py serve/kill.
authored Feb 29, 2012
326 def kill(signal='kill'):
327 pid = open('services/main/pid').read().strip()
328 call(['kill', '-' + signal, pid])
329
330 @command
9ced79b @mikeboers Blockquote styling; add floating marks.
authored Mar 15, 2012
331 def serve(watch=False, **kw):
4c31c21 @mikeboers Improved manage.py serve/kill.
authored Feb 29, 2012
332 watch_proc = None
333 if watch:
334 cmd = '''watchmedo shell-command --patterns *.py --recursive'''.split()
335 cmd.extend(['--command', '''kill -hup $(cat services/main/pid)'''])
336 cmd.append('app')
337 watch_proc = Popen(cmd)
338
339 proc = Popen(['./run'], cwd='services/main')
340 try:
341 proc.wait()
342 except KeyboardInterrupt:
343 proc.kill()
344 if watch_proc:
345 watch_proc.kill()
346
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
347
55062ba @mikeboers Cleanup manage.
authored Aug 13, 2011
348
9cd5976 @mikeboers Initial commit.
authored Aug 6, 2011
349 if __name__ == '__main__':
350 baker.run()
Something went wrong with that request. Please try again.