summaryrefslogtreecommitdiff
path: root/postgresqleu/simplemigrate/management.py
blob: 48e99a256853a3cc0bb148eb4cf3dffa95601d83 (plain)
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
from django.db.models import signals
from django.db import connection, transaction

import os
from glob import glob
import re

def _get_app_files(appname):
	for fn in sorted(glob('%s/sqlupdate/*.sql' % appname)):
		m = re.search('/(\d+)(-[^/]+)?\.sql$', fn)
		if not m: continue
		yield (fn, int(m.groups(1)[0]))

def process_sql_scripts(app, created_models, verbosity=2, **kwargs):
	if not app.__name__.startswith('postgresqleu.'): return

	namepieces = app.__name__.split('.')
	if len(namepieces) != 3: return
	if namepieces[2] != 'models': return
	appname = namepieces[1]

	with transaction.atomic():
		appfiles = list(_get_app_files(appname))
		curs = connection.cursor()
		curs.execute("SELECT ver FROM _appscripts WHERE app=%s", [appname,])
		rows = curs.fetchall()
		if len(rows) == 0:
			# App not inserted yet, so do that
			if len(appfiles):
				# One or more appfiles exist, so we need to bypass them. This is the normal
				# usecase when doing a completely new deployment.
				(lastfile, lastver) = appfiles[-1]
				print "Initializing SQL update scripts for %s, setting last version to %s" % (appname, lastver)
				curs.execute("INSERT INTO _appscripts (app,ver) VALUES (%s,%s)", [appname, lastver])
				ver = lastver
			else:
				# No appfiles exist, meaning that this model has no updates. We do, however,
				# insert an empty record for it specifically so that we can handle the *next* time an
				# update shows up. Once the file shows up it will then be applied, whereas a completely
				# new deployment will have nothing and still bypass it.
				print "Initializing empty SQL update scripts for %s" % appname
				curs.execute("INSERT INTO _appscripts (app,ver) VALUES (%s,%s)", [appname, 0])
				ver = 0
		else:
			ver = rows[0][0]

		for (fn, filever) in appfiles:
			if ver >= filever:
				print "SQL script %s already applied." % fn
				continue

			print "Applying SQL script %s" % fn
			with open(fn) as f:
				sql = f.read()
				curs.execute(sql)
				curs.execute("UPDATE _appscripts SET ver=%s WHERE app=%s", [filever, appname])

signals.post_syncdb.connect(process_sql_scripts)