]> git.decadent.org.uk Git - dak.git/blob - dak/check_overrides.py
Stop using silly names, and migrate to a saner directory structure.
[dak.git] / dak / check_overrides.py
1 #!/usr/bin/env python
2
3 # Cruft checker and hole filler for overrides
4 # Copyright (C) 2000, 2001, 2002, 2004  James Troup <james@nocrew.org>
5 # Copyright (C) 2005  Jeroen van Wolffelaar <jeroen@wolffelaar.nl>
6 # $Id: cindy,v 1.14 2005-11-15 09:50:32 ajt Exp $
7
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
12
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
22 ################################################################################
23
24 ######################################################################
25 # NB: cindy is not a good idea with New Incoming as she doesn't take #
26 # into account accepted.  You can minimize the impact of this by     #
27 # running her immediately after kelly but that's still racy because  #
28 # lisa doesn't lock with kelly.  A better long term fix is the evil  #
29 # plan for accepted to be in the DB.                                 #
30 ######################################################################
31
32 # cindy should now work fine being done during cron.daily, for example just
33 # before denise (after kelly and jenna). At that point, queue/accepted should
34 # be empty and installed, so... Cindy does now take into account suites
35 # sharing overrides
36
37 # TODO:
38 # * Only update out-of-sync overrides when corresponding versions are equal to
39 #   some degree
40 # * consistency checks like:
41 #   - section=debian-installer only for udeb and # dsc
42 #   - priority=source iff dsc
43 #   - (suite, package, 'dsc') is unique,
44 #   - just as (suite, package, (u)deb) (yes, across components!)
45 #   - sections match their component (each component has an own set of sections,
46 #     could probably be reduced...)
47
48 ################################################################################
49
50 import pg, sys, os;
51 import utils, db_access, logging;
52 import apt_pkg;
53
54 ################################################################################
55
56 Options = None;
57 projectB = None;
58 Logger = None
59 sections = {}
60 priorities = {}
61 blacklist = {}
62
63 ################################################################################
64
65 def usage (exit_code=0):
66     print """Usage: cindy
67 Check for cruft in overrides.
68
69   -n, --no-action            don't do anything
70   -h, --help                 show this help and exit"""
71
72     sys.exit(exit_code)
73
74 ################################################################################
75
76 def gen_blacklist(dir):
77     for entry in os.listdir(dir):
78         entry = entry.split('_')[0]
79         blacklist[entry] = 1
80
81 def process(osuite, affected_suites, originosuite, component, type):
82     global Logger, Options, projectB, sections, priorities;
83
84     osuite_id = db_access.get_suite_id(osuite);
85     if osuite_id == -1:
86         utils.fubar("Suite '%s' not recognised." % (osuite));
87     originosuite_id = None
88     if originosuite:
89         originosuite_id = db_access.get_suite_id(originosuite);
90         if originosuite_id == -1:
91             utils.fubar("Suite '%s' not recognised." % (originosuite));
92
93     component_id = db_access.get_component_id(component);
94     if component_id == -1:
95         utils.fubar("Component '%s' not recognised." % (component));
96
97     type_id = db_access.get_override_type_id(type);
98     if type_id == -1:
99         utils.fubar("Type '%s' not recognised. (Valid types are deb, udeb and dsc)" % (type));
100     dsc_type_id = db_access.get_override_type_id("dsc");
101     deb_type_id = db_access.get_override_type_id("deb")
102
103     source_priority_id = db_access.get_priority_id("source")
104
105     if type == "deb" or type == "udeb":
106         packages = {};
107         q = projectB.query("""
108 SELECT b.package FROM binaries b, bin_associations ba, files f,
109                               location l, component c
110  WHERE b.type = '%s' AND b.id = ba.bin AND f.id = b.file AND l.id = f.location
111    AND c.id = l.component AND ba.suite IN (%s) AND c.id = %s
112 """ % (type, ",".join(map(str,affected_suites)), component_id));
113         for i in q.getresult():
114             packages[i[0]] = 0;
115
116     src_packages = {};
117     q = projectB.query("""
118 SELECT s.source FROM source s, src_associations sa, files f, location l,
119                      component c
120  WHERE s.id = sa.source AND f.id = s.file AND l.id = f.location
121    AND c.id = l.component AND sa.suite IN (%s) AND c.id = %s
122 """ % (",".join(map(str,affected_suites)), component_id));
123     for i in q.getresult():
124         src_packages[i[0]] = 0;
125
126     # -----------
127     # Drop unused overrides
128
129     q = projectB.query("SELECT package, priority, section, maintainer FROM override WHERE suite = %s AND component = %s AND type = %s" % (osuite_id, component_id, type_id));
130     projectB.query("BEGIN WORK");
131     if type == "dsc":
132         for i in q.getresult():
133             package = i[0];
134             if src_packages.has_key(package):
135                 src_packages[package] = 1
136             else:
137                 if blacklist.has_key(package):
138                     utils.warn("%s in incoming, not touching" % package)
139                     continue
140                 Logger.log(["removing unused override", osuite, component,
141                     type, package, priorities[i[1]], sections[i[2]], i[3]])
142                 if not Options["No-Action"]:
143                     projectB.query("""DELETE FROM override WHERE package =
144                         '%s' AND suite = %s AND component = %s AND type =
145                         %s""" % (package, osuite_id, component_id, type_id));
146         # create source overrides based on binary overrides, as source
147         # overrides not always get created
148         q = projectB.query(""" SELECT package, priority, section,
149             maintainer FROM override WHERE suite = %s AND component = %s
150             """ % (osuite_id, component_id));
151         for i in q.getresult():
152             package = i[0]
153             if not src_packages.has_key(package) or src_packages[package]:
154                 continue
155             src_packages[package] = 1
156             
157             Logger.log(["add missing override", osuite, component,
158                 type, package, "source", sections[i[2]], i[3]])
159             if not Options["No-Action"]:
160                 projectB.query("""INSERT INTO override (package, suite,
161                     component, priority, section, type, maintainer) VALUES
162                     ('%s', %s, %s, %s, %s, %s, '%s')""" % (package,
163                     osuite_id, component_id, source_priority_id, i[2],
164                     dsc_type_id, i[3]));
165         # Check whether originosuite has an override for us we can
166         # copy
167         if originosuite:
168             q = projectB.query("""SELECT origin.package, origin.priority,
169                 origin.section, origin.maintainer, target.priority,
170                 target.section, target.maintainer FROM override origin LEFT
171                 JOIN override target ON (origin.package = target.package AND
172                 target.suite=%s AND origin.component = target.component AND origin.type =
173                 target.type) WHERE origin.suite = %s AND origin.component = %s
174                 AND origin.type = %s""" %
175                 (osuite_id, originosuite_id, component_id, type_id));
176             for i in q.getresult():
177                 package = i[0]
178                 if not src_packages.has_key(package) or src_packages[package]:
179                     if i[4] and (i[1] != i[4] or i[2] != i[5] or i[3] != i[6]):
180                         Logger.log(["syncing override", osuite, component,
181                             type, package, "source", sections[i[5]], i[6], "source", sections[i[2]], i[3]])
182                         if not Options["No-Action"]:
183                             projectB.query("""UPDATE override SET section=%s,
184                                 maintainer='%s' WHERE package='%s' AND
185                                 suite=%s AND component=%s AND type=%s""" %
186                                 (i[2], i[3], package, osuite_id, component_id,
187                                 dsc_type_id));
188                     continue
189                 # we can copy
190                 src_packages[package] = 1
191                 Logger.log(["copying missing override", osuite, component,
192                     type, package, "source", sections[i[2]], i[3]])
193                 if not Options["No-Action"]:
194                     projectB.query("""INSERT INTO override (package, suite,
195                         component, priority, section, type, maintainer) VALUES
196                         ('%s', %s, %s, %s, %s, %s, '%s')""" % (package,
197                         osuite_id, component_id, source_priority_id, i[2],
198                         dsc_type_id, i[3]));
199
200         for package, hasoverride in src_packages.items():
201             if not hasoverride:
202                 utils.warn("%s has no override!" % package)
203
204     else: # binary override
205         for i in q.getresult():
206             package = i[0];
207             if packages.has_key(package):
208                 packages[package] = 1
209             else:
210                 if blacklist.has_key(package):
211                     utils.warn("%s in incoming, not touching" % package)
212                     continue
213                 Logger.log(["removing unused override", osuite, component,
214                     type, package, priorities[i[1]], sections[i[2]], i[3]])
215                 if not Options["No-Action"]:
216                     projectB.query("""DELETE FROM override WHERE package =
217                         '%s' AND suite = %s AND component = %s AND type =
218                         %s""" % (package, osuite_id, component_id, type_id));
219
220         # Check whether originosuite has an override for us we can
221         # copy
222         if originosuite:
223             q = projectB.query("""SELECT origin.package, origin.priority,
224                 origin.section, origin.maintainer, target.priority,
225                 target.section, target.maintainer FROM override origin LEFT
226                 JOIN override target ON (origin.package = target.package AND
227                 target.suite=%s AND origin.component = target.component AND
228                 origin.type = target.type) WHERE origin.suite = %s AND
229                 origin.component = %s AND origin.type = %s""" % (osuite_id,
230                 originosuite_id, component_id, type_id));
231             for i in q.getresult():
232                 package = i[0]
233                 if not packages.has_key(package) or packages[package]:
234                     if i[4] and (i[1] != i[4] or i[2] != i[5] or i[3] != i[6]):
235                         Logger.log(["syncing override", osuite, component,
236                             type, package, priorities[i[4]], sections[i[5]],
237                             i[6], priorities[i[1]], sections[i[2]], i[3]])
238                         if not Options["No-Action"]:
239                             projectB.query("""UPDATE override SET priority=%s, section=%s,
240                                 maintainer='%s' WHERE package='%s' AND
241                                 suite=%s AND component=%s AND type=%s""" %
242                                 (i[1], i[2], i[3], package, osuite_id,
243                                 component_id, type_id));
244                     continue
245                 # we can copy
246                 packages[package] = 1
247                 Logger.log(["copying missing override", osuite, component,
248                     type, package, priorities[i[1]], sections[i[2]], i[3]])
249                 if not Options["No-Action"]:
250                     projectB.query("""INSERT INTO override (package, suite,
251                         component, priority, section, type, maintainer) VALUES
252                         ('%s', %s, %s, %s, %s, %s, '%s')""" % (package, osuite_id, component_id, i[1], i[2], type_id, i[3]));
253
254         for package, hasoverride in packages.items():
255             if not hasoverride:
256                 utils.warn("%s has no override!" % package)
257
258     projectB.query("COMMIT WORK");
259     sys.stdout.flush()
260
261
262 ################################################################################
263
264 def main ():
265     global Logger, Options, projectB, sections, priorities;
266
267     Cnf = utils.get_conf()
268
269     Arguments = [('h',"help","Cindy::Options::Help"),
270                  ('n',"no-action", "Cindy::Options::No-Action")];
271     for i in [ "help", "no-action" ]:
272         if not Cnf.has_key("Cindy::Options::%s" % (i)):
273             Cnf["Cindy::Options::%s" % (i)] = "";
274     apt_pkg.ParseCommandLine(Cnf, Arguments, sys.argv);
275     Options = Cnf.SubTree("Cindy::Options")
276
277     if Options["Help"]:
278         usage();
279
280     projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]));
281     db_access.init(Cnf, projectB);
282
283     # init sections, priorities:
284     q = projectB.query("SELECT id, section FROM section")
285     for i in q.getresult():
286         sections[i[0]] = i[1]
287     q = projectB.query("SELECT id, priority FROM priority")
288     for i in q.getresult():
289         priorities[i[0]] = i[1]
290
291     if not Options["No-Action"]:
292         Logger = logging.Logger(Cnf, "cindy")
293     else:
294         Logger = logging.Logger(Cnf, "cindy", 1)
295
296     gen_blacklist(Cnf["Dir::Queue::Accepted"])
297
298     for osuite in Cnf.SubTree("Cindy::OverrideSuites").List():
299         if "1" != Cnf["Cindy::OverrideSuites::%s::Process" % osuite]:
300             continue
301
302         osuite = osuite.lower()
303
304         originosuite = None
305         originremark = ""
306         try:
307             originosuite = Cnf["Cindy::OverrideSuites::%s::OriginSuite" % osuite];
308             originosuite = originosuite.lower()
309             originremark = " taking missing from %s" % originosuite
310         except KeyError:
311             pass
312
313         print "Processing %s%s..." % (osuite, originremark);
314         # Get a list of all suites that use the override file of 'osuite'
315         ocodename = Cnf["Suite::%s::codename" % osuite]
316         suites = []
317         for suite in Cnf.SubTree("Suite").List():
318             if ocodename == Cnf["Suite::%s::OverrideCodeName" % suite]:
319                 suites.append(suite)
320
321         q = projectB.query("SELECT id FROM suite WHERE suite_name in (%s)" \
322             % ", ".join(map(repr, suites)).lower())
323
324         suiteids = []
325         for i in q.getresult():
326             suiteids.append(i[0])
327             
328         if len(suiteids) != len(suites) or len(suiteids) < 1:
329             utils.fubar("Couldn't find id's of all suites: %s" % suites)
330
331         for component in Cnf.SubTree("Component").List():
332             if component == "mixed":
333                 continue; # Ick
334             # It is crucial for the dsc override creation based on binary
335             # overrides that 'dsc' goes first
336             otypes = Cnf.ValueList("OverrideType")
337             otypes.remove("dsc")
338             otypes = ["dsc"] + otypes
339             for otype in otypes:
340                 print "Processing %s [%s - %s] using %s..." \
341                     % (osuite, component, otype, suites);
342                 sys.stdout.flush()
343                 process(osuite, suiteids, originosuite, component, otype);
344
345     Logger.close()
346
347 ################################################################################
348
349 if __name__ == '__main__':
350     main()
351