]> git.decadent.org.uk Git - dak.git/blob - dak/dakdb/update28.py
suites -> _suites
[dak.git] / dak / dakdb / update28.py
1 #!/usr/bin/env python
2 # coding=utf8
3
4 """
5 keep contents of binary packages in tables so we can generate contents.gz files from dak
6
7 @contact: Debian FTP Master <ftpmaster@debian.org>
8 @copyright: 2009  Mike O'Connor <stew@debian.org>
9 @license: GNU General Public License version 2 or later
10 """
11
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
16
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
26 ################################################################################
27
28
29 ################################################################################
30
31 import psycopg2
32 import time
33 from daklib.dak_exceptions import DBUpdateError
34
35 ################################################################################
36
37 def _suites():
38     """
39     return a list of suites to operate on
40     """
41     if Config().has_key( "%s::%s" %(options_prefix,"Suite")):
42         suites = utils.split_args(Config()[ "%s::%s" %(options_prefix,"Suite")])
43     else:
44         suites = Config().SubTree("Suite").List()
45
46     return suites
47
48 def arches(cursor, suite):
49     """
50     return a list of archs to operate on
51     """
52     arch_list = []
53     cursor.execute("""SELECT s.architecture, a.arch_string
54     FROM suite_architectures s
55     JOIN architecture a ON (s.architecture=a.id)
56     WHERE suite = :suite""", {'suite' : suite })
57
58     while True:
59         r = cursor.fetchone()
60         if not r:
61             break
62
63         if r[1] != "source" and r[1] != "all":
64             arch_list.append((r[0], r[1]))
65
66     return arch_list
67
68 def do_update(self):
69     """
70     Adding contents table as first step to maybe, finally getting rid
71     of apt-ftparchive
72     """
73
74     print __doc__
75
76     try:
77         c = self.db.cursor()
78
79         c.execute("""CREATE TABLE pending_bin_contents (
80         id serial NOT NULL,
81         package text NOT NULL,
82         version debversion NOT NULL,
83         arch int NOT NULL,
84         filename text NOT NULL,
85         type int NOT NULL,
86         PRIMARY KEY(id))""" );
87
88         c.execute("""CREATE TABLE deb_contents (
89         filename text,
90         section text,
91         package text,
92         binary_id integer,
93         arch integer,
94         suite integer)""" )
95
96         c.execute("""CREATE TABLE udeb_contents (
97         filename text,
98         section text,
99         package text,
100         binary_id integer,
101         suite integer,
102         arch integer)""" )
103
104         c.execute("""ALTER TABLE ONLY deb_contents
105         ADD CONSTRAINT deb_contents_arch_fkey
106         FOREIGN KEY (arch) REFERENCES architecture(id)
107         ON DELETE CASCADE;""")
108
109         c.execute("""ALTER TABLE ONLY udeb_contents
110         ADD CONSTRAINT udeb_contents_arch_fkey
111         FOREIGN KEY (arch) REFERENCES architecture(id)
112         ON DELETE CASCADE;""")
113
114         c.execute("""ALTER TABLE ONLY deb_contents
115         ADD CONSTRAINT deb_contents_pkey
116         PRIMARY KEY (filename,package,arch,suite);""")
117
118         c.execute("""ALTER TABLE ONLY udeb_contents
119         ADD CONSTRAINT udeb_contents_pkey
120         PRIMARY KEY (filename,package,arch,suite);""")
121
122         c.execute("""ALTER TABLE ONLY deb_contents
123         ADD CONSTRAINT deb_contents_suite_fkey
124         FOREIGN KEY (suite) REFERENCES suite(id)
125         ON DELETE CASCADE;""")
126
127         c.execute("""ALTER TABLE ONLY udeb_contents
128         ADD CONSTRAINT udeb_contents_suite_fkey
129         FOREIGN KEY (suite) REFERENCES suite(id)
130         ON DELETE CASCADE;""")
131
132         c.execute("""ALTER TABLE ONLY deb_contents
133         ADD CONSTRAINT deb_contents_binary_fkey
134         FOREIGN KEY (binary_id) REFERENCES binaries(id)
135         ON DELETE CASCADE;""")
136
137         c.execute("""ALTER TABLE ONLY udeb_contents
138         ADD CONSTRAINT udeb_contents_binary_fkey
139         FOREIGN KEY (binary_id) REFERENCES binaries(id)
140         ON DELETE CASCADE;""")
141
142         c.execute("""CREATE INDEX ind_deb_contents_binary ON deb_contents(binary_id);""" )
143
144         suites = _suites()
145
146         for suite in [i.lower() for i in suites]:
147             suite_id = DBConn().get_suite_id(suite)
148             arch_list = arches(c, suite_id)
149             arch_list = arches(c, suite_id)
150
151             for (arch_id,arch_str) in arch_list:
152                 c.execute( "CREATE INDEX ind_deb_contents_%s_%s ON deb_contents (arch,suite) WHERE (arch=2 OR arch=%d) AND suite=$d"%(arch_str,suite,arch_id,suite_id) )
153
154             for section, sname in [("debian-installer","main"),
155                                   ("non-free/debian-installer", "nonfree")]:
156                 c.execute( "CREATE INDEX ind_udeb_contents_%s_%s ON udeb_contents (section,suite) WHERE section=%s AND suite=$d"%(sname,suite,section,suite_id) )
157
158
159         c.execute( """CREATE OR REPLACE FUNCTION update_contents_for_bin_a() RETURNS trigger AS  $$
160     event = TD["event"]
161     if event == "DELETE" or event == "UPDATE":
162
163         plpy.execute(plpy.prepare("DELETE FROM deb_contents WHERE binary_id=$1 and suite=$2",
164                                   ["int","int"]),
165                                   [TD["old"]["bin"], TD["old"]["suite"]])
166
167     if event == "INSERT" or event == "UPDATE":
168
169        content_data = plpy.execute(plpy.prepare(
170             \"\"\"SELECT s.section, b.package, b.architecture, ot.type
171             FROM override o
172             JOIN override_type ot on o.type=ot.id
173             JOIN binaries b on b.package=o.package
174             JOIN files f on b.file=f.id
175             JOIN location l on l.id=f.location
176             JOIN section s on s.id=o.section
177             WHERE b.id=$1
178             AND o.suite=$2
179             \"\"\",
180             ["int", "int"]),
181             [TD["new"]["bin"], TD["new"]["suite"]])[0]
182
183        tablename="%s_contents" % content_data['type']
184
185        plpy.execute(plpy.prepare(\"\"\"DELETE FROM %s
186                    WHERE package=$1 and arch=$2 and suite=$3\"\"\" % tablename,
187                    ['text','int','int']),
188                    [content_data['package'],
189                    content_data['architecture'],
190                    TD["new"]["suite"]])
191
192        filenames = plpy.execute(plpy.prepare(
193            "SELECT bc.file FROM bin_contents bc where bc.binary_id=$1",
194            ["int"]),
195            [TD["new"]["bin"]])
196
197        for filename in filenames:
198            plpy.execute(plpy.prepare(
199                \"\"\"INSERT INTO %s
200                    (filename,section,package,binary_id,arch,suite)
201                    VALUES($1,$2,$3,$4,$5,$6)\"\"\" % tablename,
202                ["text","text","text","int","int","int"]),
203                [filename["file"],
204                 content_data["section"],
205                 content_data["package"],
206                 TD["new"]["bin"],
207                 content_data["architecture"],
208                 TD["new"]["suite"]] )
209 $$ LANGUAGE plpythonu VOLATILE SECURITY DEFINER;
210 """)
211
212
213         c.execute( """CREATE OR REPLACE FUNCTION update_contents_for_override() RETURNS trigger AS  $$
214     event = TD["event"]
215     if event == "UPDATE":
216
217         otype = plpy.execute(plpy.prepare("SELECT type from override_type where id=$1",["int"]),[TD["new"]["type"]] )[0];
218         if otype["type"].endswith("deb"):
219             section = plpy.execute(plpy.prepare("SELECT section from section where id=$1",["int"]),[TD["new"]["section"]] )[0];
220
221             table_name = "%s_contents" % otype["type"]
222             plpy.execute(plpy.prepare("UPDATE %s set section=$1 where package=$2 and suite=$3" % table_name,
223                                       ["text","text","int"]),
224                                       [section["section"],
225                                       TD["new"]["package"],
226                                       TD["new"]["suite"]])
227
228 $$ LANGUAGE plpythonu VOLATILE SECURITY DEFINER;
229 """)
230
231         c.execute("""CREATE OR REPLACE FUNCTION update_contents_for_override()
232                       RETURNS trigger AS  $$
233     event = TD["event"]
234     if event == "UPDATE" or event == "INSERT":
235         row = TD["new"]
236         r = plpy.execute(plpy.prepare( \"\"\"SELECT 1 from suite_architectures sa
237                   JOIN binaries b ON b.architecture = sa.architecture
238                   WHERE b.id = $1 and sa.suite = $2\"\"\",
239                 ["int", "int"]),
240                 [row["bin"], row["suite"]])
241         if not len(r):
242             plpy.error("Illegal architecture for this suite")
243
244 $$ LANGUAGE plpythonu VOLATILE;""")
245
246         c.execute( """CREATE TRIGGER illegal_suite_arch_bin_associations_trigger
247                       BEFORE INSERT OR UPDATE ON bin_associations
248                       FOR EACH ROW EXECUTE PROCEDURE update_contents_for_override();""")
249
250         c.execute( """CREATE TRIGGER bin_associations_contents_trigger
251                       AFTER INSERT OR UPDATE OR DELETE ON bin_associations
252                       FOR EACH ROW EXECUTE PROCEDURE update_contents_for_bin_a();""")
253         c.execute("""CREATE TRIGGER override_contents_trigger
254                       AFTER UPDATE ON override
255                       FOR EACH ROW EXECUTE PROCEDURE update_contents_for_override();""")
256
257
258         c.execute( "CREATE INDEX ind_deb_contents_name ON deb_contents(package);");
259         c.execute( "CREATE INDEX ind_udeb_contents_name ON udeb_contents(package);");
260
261         c.execute("UPDATE config SET value = '28' WHERE name = 'db_revision'")
262
263         self.db.commit()
264
265     except psycopg2.ProgrammingError, msg:
266         self.db.rollback()
267         raise DBUpdateError, "Unable to apply process-new update 28, rollback issued. Error message : %s" % (str(msg))
268