Coverage for dak/control_overrides.py: 59%
177 statements
« prev ^ index » next coverage.py v6.5.0, created at 2025-08-26 22:11 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2025-08-26 22:11 +0000
1#! /usr/bin/env python3
3"""Bulk manipulation of the overrides"""
4# Copyright (C) 2000, 2001, 2002, 2003, 2006 James Troup <james@nocrew.org>
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.
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.
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
20################################################################################
22# On 30 Nov 1998, James Troup wrote:
23#
24# > James Troup<2> <troup2@debian.org>
25# >
26# > James is a clone of James; he's going to take over the world.
27# > After he gets some sleep.
28#
29# Could you clone other things too? Sheep? Llamas? Giant mutant turnips?
30#
31# Your clone will need some help to take over the world, maybe clone up an
32# army of penguins and threaten to unleash them on the world, forcing
33# governments to sway to the new James' will!
34#
35# Yes, I can envision a day when James' duplicate decides to take a horrific
36# vengance on the James that spawned him and unleashes his fury in the form
37# of thousands upon thousands of chickens that look just like Captin Blue
38# Eye! Oh the horror.
39#
40# Now you'll have to were name tags to people can tell you apart, unless of
41# course the new clone is truely evil in which case he should be easy to
42# identify!
43#
44# Jason
45# Chicken. Black. Helicopters.
46# Be afraid.
48# <Pine.LNX.3.96.981130011300.30365Z-100000@wakko>
50################################################################################
52import sys
53import time
55import apt_pkg
57from daklib import daklog, utils
58from daklib.config import Config
59from daklib.dbconn import (
60 DBConn,
61 get_component,
62 get_override_type,
63 get_priorities,
64 get_sections,
65 get_suite,
66)
67from daklib.regexes import re_comments
69################################################################################
71Logger = None
73################################################################################
76def usage(exit_code=0):
77 print(
78 """Usage: dak control-overrides [OPTIONS]
79 -h, --help print this help and exit
81 -c, --component=CMPT list/set overrides by component
82 (contrib,*main,non-free)
83 -s, --suite=SUITE list/set overrides by suite
84 (experimental,stable,testing,*unstable)
85 -t, --type=TYPE list/set overrides by type
86 (*deb,dsc,udeb)
88 -a, --add add overrides (changes and deletions are ignored)
89 -S, --set set overrides
90 -C, --change change overrides (additions and deletions are ignored)
91 -l, --list list overrides
93 -q, --quiet be less verbose
94 -n, --no-action only list the action that would have been done
95 -f, --force also work on untouchable suites
97 starred (*) values are default"""
98 )
99 sys.exit(exit_code)
102################################################################################
105def process_file(file, suite, component, otype, mode, action, session):
106 cnf = Config()
108 s = get_suite(suite, session=session)
109 if s is None: 109 ↛ 110line 109 didn't jump to line 110, because the condition on line 109 was never true
110 utils.fubar("Suite '%s' not recognised." % (suite))
111 suite_id = s.suite_id
113 c = get_component(component, session=session)
114 if c is None: 114 ↛ 115line 114 didn't jump to line 115, because the condition on line 114 was never true
115 utils.fubar("Component '%s' not recognised." % (component))
116 component_id = c.component_id
118 o = get_override_type(otype)
119 if o is None: 119 ↛ 120line 119 didn't jump to line 120, because the condition on line 119 was never true
120 utils.fubar(
121 "Type '%s' not recognised. (Valid types are deb, udeb and dsc.)" % (otype)
122 )
123 type_id = o.overridetype_id
125 # --set is done mostly internal for performance reasons; most
126 # invocations of --set will be updates and making people wait 2-3
127 # minutes while 6000 select+inserts are run needlessly isn't cool.
129 original = {}
130 new = {}
131 c_skipped = 0
132 c_added = 0
133 c_updated = 0
134 c_removed = 0
135 c_error = 0
137 q = session.execute(
138 """SELECT o.package, o.priority, o.section, o.maintainer, p.priority, s.section
139 FROM override o, priority p, section s
140 WHERE o.suite = :suiteid AND o.component = :componentid AND o.type = :typeid
141 and o.priority = p.id and o.section = s.id""",
142 {"suiteid": suite_id, "componentid": component_id, "typeid": type_id},
143 )
144 for i in q.fetchall():
145 original[i[0]] = i[1:]
147 start_time = time.time()
149 section_cache = get_sections(session)
150 priority_cache = get_priorities(session)
152 # Our session is already in a transaction
154 for line in file.readlines():
155 line = re_comments.sub("", line).strip()
156 if line == "": 156 ↛ 157line 156 didn't jump to line 157, because the condition on line 156 was never true
157 continue
159 maintainer_override = None
160 if otype == "dsc":
161 split_line = line.split(None, 2)
162 if len(split_line) == 2: 162 ↛ 164line 162 didn't jump to line 164, because the condition on line 162 was never false
163 (package, section) = split_line
164 elif len(split_line) == 3:
165 (package, section, maintainer_override) = split_line
166 else:
167 utils.warn(
168 "'%s' does not break into 'package section [maintainer-override]'."
169 % (line)
170 )
171 c_error += 1
172 continue
173 priority = "optional"
174 else: # binary or udeb
175 split_line = line.split(None, 3)
176 if len(split_line) == 3: 176 ↛ 178line 176 didn't jump to line 178, because the condition on line 176 was never false
177 (package, priority, section) = split_line
178 elif len(split_line) == 4:
179 (package, priority, section, maintainer_override) = split_line
180 else:
181 utils.warn(
182 "'%s' does not break into 'package priority section [maintainer-override]'."
183 % (line)
184 )
185 c_error += 1
186 continue
188 if section not in section_cache: 188 ↛ 189line 188 didn't jump to line 189, because the condition on line 188 was never true
189 utils.warn(
190 "'%s' is not a valid section. ['%s' in suite %s, component %s]."
191 % (section, package, suite, component)
192 )
193 c_error += 1
194 continue
196 section_id = section_cache[section]
198 if priority not in priority_cache: 198 ↛ 199line 198 didn't jump to line 199, because the condition on line 198 was never true
199 utils.warn(
200 "'%s' is not a valid priority. ['%s' in suite %s, component %s]."
201 % (priority, package, suite, component)
202 )
203 c_error += 1
204 continue
206 priority_id = priority_cache[priority]
208 if package in new: 208 ↛ 209line 208 didn't jump to line 209, because the condition on line 208 was never true
209 utils.warn(
210 "Can't insert duplicate entry for '%s'; ignoring all but the first. [suite %s, component %s]"
211 % (package, suite, component)
212 )
213 c_error += 1
214 continue
215 new[package] = ""
217 if package in original: 217 ↛ 218line 217 didn't jump to line 218
218 (
219 old_priority_id,
220 old_section_id,
221 old_maintainer_override,
222 old_priority,
223 old_section,
224 ) = original[package]
225 if (
226 mode == "add"
227 or old_priority_id == priority_id
228 and old_section_id == section_id
229 and old_maintainer_override == maintainer_override
230 ):
231 # If it's unchanged or we're in 'add only' mode, ignore it
232 c_skipped += 1
233 continue
234 else:
235 # If it's changed, delete the old one so we can
236 # reinsert it with the new information
237 c_updated += 1
238 if action:
239 session.execute(
240 """DELETE FROM override WHERE suite = :suite AND component = :component
241 AND package = :package AND type = :typeid""",
242 {
243 "suite": suite_id,
244 "component": component_id,
245 "package": package,
246 "typeid": type_id,
247 },
248 )
250 # Log changes
251 if old_priority_id != priority_id:
252 Logger.log(["changed priority", package, old_priority, priority])
253 if old_section_id != section_id:
254 Logger.log(["changed section", package, old_section, section])
255 if old_maintainer_override != maintainer_override:
256 Logger.log(
257 [
258 "changed maintainer override",
259 package,
260 old_maintainer_override,
261 maintainer_override,
262 ]
263 )
264 update_p = 1
265 elif mode == "change": 265 ↛ 267line 265 didn't jump to line 267, because the condition on line 265 was never true
266 # Ignore additions in 'change only' mode
267 c_skipped += 1
268 continue
269 else:
270 c_added += 1
271 update_p = 0
273 if action: 273 ↛ 295line 273 didn't jump to line 295, because the condition on line 273 was never false
274 if not maintainer_override: 274 ↛ 277line 274 didn't jump to line 277, because the condition on line 274 was never false
275 m_o = None
276 else:
277 m_o = maintainer_override
278 session.execute(
279 """INSERT INTO override (suite, component, type, package,
280 priority, section, maintainer)
281 VALUES (:suiteid, :componentid, :typeid,
282 :package, :priorityid, :sectionid,
283 :maintainer)""",
284 {
285 "suiteid": suite_id,
286 "componentid": component_id,
287 "typeid": type_id,
288 "package": package,
289 "priorityid": priority_id,
290 "sectionid": section_id,
291 "maintainer": m_o,
292 },
293 )
295 if not update_p: 295 ↛ 154line 295 didn't jump to line 154, because the condition on line 295 was never false
296 Logger.log(
297 [
298 "new override",
299 suite,
300 component,
301 otype,
302 package,
303 priority,
304 section,
305 maintainer_override,
306 ]
307 )
309 if mode == "set": 309 ↛ 311line 309 didn't jump to line 311, because the condition on line 309 was never true
310 # Delete any packages which were removed
311 for package in original.keys():
312 if package not in new:
313 if action:
314 session.execute(
315 """DELETE FROM override
316 WHERE suite = :suiteid AND component = :componentid
317 AND package = :package AND type = :typeid""",
318 {
319 "suiteid": suite_id,
320 "componentid": component_id,
321 "package": package,
322 "typeid": type_id,
323 },
324 )
325 c_removed += 1
326 Logger.log(["removed override", suite, component, otype, package])
328 if action: 328 ↛ 331line 328 didn't jump to line 331, because the condition on line 328 was never false
329 session.commit()
331 if not cnf["Control-Overrides::Options::Quiet"]: 331 ↛ 344line 331 didn't jump to line 344, because the condition on line 331 was never false
332 print(
333 "Done in %d seconds. [Updated = %d, Added = %d, Removed = %d, Skipped = %d, Errors = %d]"
334 % (
335 int(time.time() - start_time),
336 c_updated,
337 c_added,
338 c_removed,
339 c_skipped,
340 c_error,
341 )
342 )
344 Logger.log(["set complete", c_updated, c_added, c_removed, c_skipped, c_error])
347################################################################################
350def list_overrides(suite, component, otype, session):
351 dat = {}
352 s = get_suite(suite, session)
353 if s is None: 353 ↛ 354line 353 didn't jump to line 354, because the condition on line 353 was never true
354 utils.fubar("Suite '%s' not recognised." % (suite))
356 dat["suiteid"] = s.suite_id
358 c = get_component(component, session)
359 if c is None: 359 ↛ 360line 359 didn't jump to line 360, because the condition on line 359 was never true
360 utils.fubar("Component '%s' not recognised." % (component))
362 dat["componentid"] = c.component_id
364 o = get_override_type(otype)
365 if o is None: 365 ↛ 366line 365 didn't jump to line 366, because the condition on line 365 was never true
366 utils.fubar(
367 "Type '%s' not recognised. (Valid types are deb, udeb and dsc)" % (otype)
368 )
370 dat["typeid"] = o.overridetype_id
372 if otype == "dsc": 372 ↛ 373line 372 didn't jump to line 373, because the condition on line 372 was never true
373 q = session.execute(
374 """SELECT o.package, s.section, o.maintainer FROM override o, section s
375 WHERE o.suite = :suiteid AND o.component = :componentid
376 AND o.type = :typeid AND o.section = s.id
377 ORDER BY s.section, o.package""",
378 dat,
379 )
380 for i in q.fetchall():
381 print(utils.result_join(i))
382 else:
383 q = session.execute(
384 """SELECT o.package, p.priority, s.section, o.maintainer, p.level
385 FROM override o, priority p, section s
386 WHERE o.suite = :suiteid AND o.component = :componentid
387 AND o.type = :typeid AND o.priority = p.id AND o.section = s.id
388 ORDER BY s.section, p.level, o.package""",
389 dat,
390 )
391 for i in q.fetchall(): 391 ↛ 392line 391 didn't jump to line 392, because the loop on line 391 never started
392 print(utils.result_join(i[:-1]))
395################################################################################
398def main():
399 global Logger
401 cnf = Config()
402 Arguments = [
403 ("a", "add", "Control-Overrides::Options::Add"),
404 ("c", "component", "Control-Overrides::Options::Component", "HasArg"),
405 ("h", "help", "Control-Overrides::Options::Help"),
406 ("l", "list", "Control-Overrides::Options::List"),
407 ("q", "quiet", "Control-Overrides::Options::Quiet"),
408 ("s", "suite", "Control-Overrides::Options::Suite", "HasArg"),
409 ("S", "set", "Control-Overrides::Options::Set"),
410 ("C", "change", "Control-Overrides::Options::Change"),
411 ("n", "no-action", "Control-Overrides::Options::No-Action"),
412 ("t", "type", "Control-Overrides::Options::Type", "HasArg"),
413 ("f", "force", "Control-Overrides::Options::Force"),
414 ]
416 # Default arguments
417 for i in ["add", "help", "list", "quiet", "set", "change", "no-action"]:
418 key = "Control-Overrides::Options::%s" % i
419 if key not in cnf: 419 ↛ 417line 419 didn't jump to line 417, because the condition on line 419 was never false
420 cnf[key] = ""
421 if "Control-Overrides::Options::Component" not in cnf: 421 ↛ 423line 421 didn't jump to line 423, because the condition on line 421 was never false
422 cnf["Control-Overrides::Options::Component"] = "main"
423 if "Control-Overrides::Options::Suite" not in cnf: 423 ↛ 425line 423 didn't jump to line 425, because the condition on line 423 was never false
424 cnf["Control-Overrides::Options::Suite"] = "unstable"
425 if "Control-Overrides::Options::Type" not in cnf: 425 ↛ 428line 425 didn't jump to line 428, because the condition on line 425 was never false
426 cnf["Control-Overrides::Options::Type"] = "deb"
428 file_list = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv)
430 if cnf["Control-Overrides::Options::Help"]:
431 usage()
433 session = DBConn().session()
435 mode = None
436 for i in ["add", "list", "set", "change"]:
437 if cnf["Control-Overrides::Options::%s" % (i)]:
438 if mode: 438 ↛ 439line 438 didn't jump to line 439, because the condition on line 438 was never true
439 utils.fubar("Can not perform more than one action at once.")
440 mode = i
442 # Need an action...
443 if mode is None: 443 ↛ 444line 443 didn't jump to line 444, because the condition on line 443 was never true
444 utils.fubar("No action specified.")
446 (suite, component, otype) = (
447 cnf["Control-Overrides::Options::Suite"],
448 cnf["Control-Overrides::Options::Component"],
449 cnf["Control-Overrides::Options::Type"],
450 )
452 if mode == "list":
453 list_overrides(suite, component, otype, session)
454 else:
455 if ( 455 ↛ 459line 455 didn't jump to line 459
456 get_suite(suite).untouchable
457 and not cnf["Control-Overrides::Options::Force"]
458 ):
459 utils.fubar("%s: suite is untouchable" % suite)
461 action = True
462 if cnf["Control-Overrides::Options::No-Action"]: 462 ↛ 463line 462 didn't jump to line 463, because the condition on line 462 was never true
463 utils.warn("In No-Action Mode")
464 action = False
466 Logger = daklog.Logger("control-overrides", mode)
467 if file_list: 467 ↛ 468line 467 didn't jump to line 468, because the condition on line 467 was never true
468 for f in file_list:
469 process_file(open(f), suite, component, otype, mode, action, session)
470 else:
471 process_file(sys.stdin, suite, component, otype, mode, action, session)
472 Logger.close()
475#######################################################################################
478if __name__ == "__main__":
479 main()