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