]> git.decadent.org.uk Git - dak.git/blob - dak/update_db.py
merge from master
[dak.git] / dak / update_db.py
1 #!/usr/bin/env python
2
3 """ Database Update Main Script """
4 # Copyright (C) 2008  Michael Casadevall <mcasadevall@debian.org>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 ################################################################################
21
22 # <Ganneff> when do you have it written?
23 # <NCommander> Ganneff, after you make my debian account
24 # <Ganneff> blackmail wont work
25 # <NCommander> damn it
26
27 ################################################################################
28
29 import psycopg2, sys, fcntl, os
30 import apt_pkg
31 import time
32 import errno
33 from daklib import database
34 from daklib import utils
35
36 ################################################################################
37
38 Cnf = None
39 projectB = None
40 required_database_schema = 4
41
42 ################################################################################
43
44 class UpdateDB:
45     def usage (self, exit_code=0):
46         print """Usage: dak update-db
47 Updates dak's database schema to the lastest version. You should disable crontabs while this is running
48
49   -h, --help                show this help and exit."""
50         sys.exit(exit_code)
51
52
53 ################################################################################
54
55     def update_db_to_zero(self):
56         """ This function will attempt to update a pre-zero database schema to zero """
57
58         # First, do the sure thing, and create the configuration table
59         try:
60             print "Creating configuration table ..."
61             c = self.db.cursor()
62             c.execute("""CREATE TABLE config (
63                                   id SERIAL PRIMARY KEY NOT NULL,
64                                   name TEXT UNIQUE NOT NULL,
65                                   value TEXT
66                                 );""")
67             c.execute("INSERT INTO config VALUES ( nextval('config_id_seq'), 'db_revision', '0')")
68             self.db.commit()
69
70         except psycopg2.ProgrammingError:
71             self.db.rollback()
72             print "Failed to create configuration table."
73             print "Can the projectB user CREATE TABLE?"
74             print ""
75             print "Aborting update."
76             sys.exit(-255)
77
78 ################################################################################
79
80     def get_db_rev(self):
81         global projectB
82
83         # We keep database revision info the config table
84         # Try and access it
85
86         try:
87             c = self.db.cursor()
88             q = c.execute("SELECT value FROM config WHERE name = 'db_revision';")
89             return c.fetchone()[0]
90
91         except psycopg2.ProgrammingError:
92             # Whoops .. no config table ...
93             self.db.rollback()
94             print "No configuration table found, assuming dak database revision to be pre-zero"
95             return -1
96
97 ################################################################################
98
99     def update_db(self):
100         # Ok, try and find the configuration table
101         print "Determining dak database revision ..."
102
103         try:
104             # Build a connect string
105             connect_str = "dbname=%s"% (Cnf["DB::Name"])
106             if Cnf["DB::Host"] != '': connect_str += " host=%s" % (Cnf["DB::Host"])
107             if Cnf["DB::Port"] != '-1': connect_str += " port=%d" % (int(Cnf["DB::Port"]))
108
109             self.db = psycopg2.connect(connect_str)
110
111         except:
112             print "FATAL: Failed connect to database"
113             pass
114
115         database_revision = int(self.get_db_rev())
116
117         if database_revision == -1:
118             print "dak database schema predates update-db."
119             print ""
120             print "This script will attempt to upgrade it to the lastest, but may fail."
121             print "Please make sure you have a database backup handy. If you don't, press Ctrl-C now!"
122             print ""
123             print "Continuing in five seconds ..."
124             time.sleep(5)
125             print ""
126             print "Attempting to upgrade pre-zero database to zero"
127
128             self.update_db_to_zero()
129             database_revision = 0
130
131         print "dak database schema at " + str(database_revision)
132         print "dak version requires schema " + str(required_database_schema)
133
134         if database_revision == required_database_schema:
135             print "no updates required"
136             sys.exit(0)
137
138         for i in range (database_revision, required_database_schema):
139             print "updating databse schema from " + str(database_revision) + " to " + str(i+1)
140             try:
141                 dakdb = __import__("dakdb", globals(), locals(), ['update'+str(i+1)])
142                 update_module = getattr(dakdb, "update"+str(i+1))
143                 update_module.do_update(self)
144             except DBUpdateError, e:
145                 # Seems the update did not work.
146                 print "Was unable to update database schema from %s to %s." % (str(database_revision), str(i+1))
147                 print "The error message received was %s" % (e)
148                 utils.fubar("DB Schema upgrade failed")
149             database_revision += 1
150
151 ################################################################################
152
153     def init (self):
154         global Cnf, projectB
155
156         Cnf = utils.get_conf()
157         arguments = [('h', "help", "Update-DB::Options::Help")]
158         for i in [ "help" ]:
159             if not Cnf.has_key("Update-DB::Options::%s" % (i)):
160                 Cnf["Update-DB::Options::%s" % (i)] = ""
161
162         arguments = apt_pkg.ParseCommandLine(Cnf, arguments, sys.argv)
163
164         options = Cnf.SubTree("Update-DB::Options")
165         if options["Help"]:
166             self.usage()
167         elif arguments:
168             utils.warn("dak update-db takes no arguments.")
169             self.usage(exit_code=1)
170
171
172         self.update_db()
173
174         try:
175             lock_fd = os.open(Cnf["Dinstall::LockFile"], os.O_RDWR | os.O_CREAT)
176             fcntl.lockf(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
177         except IOError, e:
178             if errno.errorcode[e.errno] == 'EACCES' or errno.errorcode[e.errno] == 'EAGAIN':
179                 utils.fubar("Couldn't obtain lock; assuming another 'dak process-unchecked' is already running.")
180
181
182 ################################################################################
183
184 if __name__ == '__main__':
185     app = UpdateDB()
186     app.init()
187
188 def main():
189     app = UpdateDB()
190     app.init()