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