#! /usr/bin/env python3
""" Bulk manipulation of the overrides """
# Copyright (C) 2000, 2001, 2002, 2003, 2006 James Troup <james@nocrew.org>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
################################################################################
# On 30 Nov 1998, James Troup wrote:
#
# > James Troup<2> <troup2@debian.org>
# >
# > James is a clone of James; he's going to take over the world.
# > After he gets some sleep.
#
# Could you clone other things too? Sheep? Llamas? Giant mutant turnips?
#
# Your clone will need some help to take over the world, maybe clone up an
# army of penguins and threaten to unleash them on the world, forcing
# governments to sway to the new James' will!
#
# Yes, I can envision a day when James' duplicate decides to take a horrific
# vengance on the James that spawned him and unleashes his fury in the form
# of thousands upon thousands of chickens that look just like Captin Blue
# Eye! Oh the horror.
#
# Now you'll have to were name tags to people can tell you apart, unless of
# course the new clone is truely evil in which case he should be easy to
# identify!
#
# Jason
# Chicken. Black. Helicopters.
# Be afraid.
# <Pine.LNX.3.96.981130011300.30365Z-100000@wakko>
################################################################################
import sys
import time
import apt_pkg
from daklib.dbconn import *
from daklib.config import Config
from daklib import utils
from daklib import daklog
from daklib.regexes import re_comments
################################################################################
Logger = None
################################################################################
[docs]def usage(exit_code=0):
print("""Usage: dak control-overrides [OPTIONS]
-h, --help print this help and exit
-c, --component=CMPT list/set overrides by component
(contrib,*main,non-free)
-s, --suite=SUITE list/set overrides by suite
(experimental,stable,testing,*unstable)
-t, --type=TYPE list/set overrides by type
(*deb,dsc,udeb)
-a, --add add overrides (changes and deletions are ignored)
-S, --set set overrides
-C, --change change overrides (additions and deletions are ignored)
-l, --list list overrides
-q, --quiet be less verbose
-n, --no-action only list the action that would have been done
starred (*) values are default""")
sys.exit(exit_code)
################################################################################
[docs]def process_file(file, suite, component, otype, mode, action, session):
cnf = Config()
s = get_suite(suite, session=session)
if s is None:
utils.fubar("Suite '%s' not recognised." % (suite))
suite_id = s.suite_id
c = get_component(component, session=session)
if c is None:
utils.fubar("Component '%s' not recognised." % (component))
component_id = c.component_id
o = get_override_type(otype)
if o is None:
utils.fubar("Type '%s' not recognised. (Valid types are deb, udeb and dsc.)" % (otype))
type_id = o.overridetype_id
# --set is done mostly internal for performance reasons; most
# invocations of --set will be updates and making people wait 2-3
# minutes while 6000 select+inserts are run needlessly isn't cool.
original = {}
new = {}
c_skipped = 0
c_added = 0
c_updated = 0
c_removed = 0
c_error = 0
q = session.execute("""SELECT o.package, o.priority, o.section, o.maintainer, p.priority, s.section
FROM override o, priority p, section s
WHERE o.suite = :suiteid AND o.component = :componentid AND o.type = :typeid
and o.priority = p.id and o.section = s.id""",
{'suiteid': suite_id, 'componentid': component_id, 'typeid': type_id})
for i in q.fetchall():
original[i[0]] = i[1:]
start_time = time.time()
section_cache = get_sections(session)
priority_cache = get_priorities(session)
# Our session is already in a transaction
for line in file.readlines():
line = re_comments.sub('', line).strip()
if line == "":
continue
maintainer_override = None
if otype == "dsc":
split_line = line.split(None, 2)
if len(split_line) == 2:
(package, section) = split_line
elif len(split_line) == 3:
(package, section, maintainer_override) = split_line
else:
utils.warn("'%s' does not break into 'package section [maintainer-override]'." % (line))
c_error += 1
continue
priority = "optional"
else: # binary or udeb
split_line = line.split(None, 3)
if len(split_line) == 3:
(package, priority, section) = split_line
elif len(split_line) == 4:
(package, priority, section, maintainer_override) = split_line
else:
utils.warn("'%s' does not break into 'package priority section [maintainer-override]'." % (line))
c_error += 1
continue
if section not in section_cache:
utils.warn("'%s' is not a valid section. ['%s' in suite %s, component %s]." % (section, package, suite, component))
c_error += 1
continue
section_id = section_cache[section]
if priority not in priority_cache:
utils.warn("'%s' is not a valid priority. ['%s' in suite %s, component %s]." % (priority, package, suite, component))
c_error += 1
continue
priority_id = priority_cache[priority]
if package in new:
utils.warn("Can't insert duplicate entry for '%s'; ignoring all but the first. [suite %s, component %s]" % (package, suite, component))
c_error += 1
continue
new[package] = ""
if package in original:
(old_priority_id, old_section_id, old_maintainer_override, old_priority, old_section) = original[package]
if mode == "add" or old_priority_id == priority_id and \
old_section_id == section_id and \
old_maintainer_override == maintainer_override:
# If it's unchanged or we're in 'add only' mode, ignore it
c_skipped += 1
continue
else:
# If it's changed, delete the old one so we can
# reinsert it with the new information
c_updated += 1
if action:
session.execute("""DELETE FROM override WHERE suite = :suite AND component = :component
AND package = :package AND type = :typeid""",
{'suite': suite_id, 'component': component_id,
'package': package, 'typeid': type_id})
# Log changes
if old_priority_id != priority_id:
Logger.log(["changed priority", package, old_priority, priority])
if old_section_id != section_id:
Logger.log(["changed section", package, old_section, section])
if old_maintainer_override != maintainer_override:
Logger.log(["changed maintainer override", package, old_maintainer_override, maintainer_override])
update_p = 1
elif mode == "change":
# Ignore additions in 'change only' mode
c_skipped += 1
continue
else:
c_added += 1
update_p = 0
if action:
if not maintainer_override:
m_o = None
else:
m_o = maintainer_override
session.execute("""INSERT INTO override (suite, component, type, package,
priority, section, maintainer)
VALUES (:suiteid, :componentid, :typeid,
:package, :priorityid, :sectionid,
:maintainer)""",
{'suiteid': suite_id, 'componentid': component_id,
'typeid': type_id, 'package': package,
'priorityid': priority_id, 'sectionid': section_id,
'maintainer': m_o})
if not update_p:
Logger.log(["new override", suite, component, otype, package, priority, section, maintainer_override])
if mode == "set":
# Delete any packages which were removed
for package in original.keys():
if package not in new:
if action:
session.execute("""DELETE FROM override
WHERE suite = :suiteid AND component = :componentid
AND package = :package AND type = :typeid""",
{'suiteid': suite_id, 'componentid': component_id,
'package': package, 'typeid': type_id})
c_removed += 1
Logger.log(["removed override", suite, component, otype, package])
if action:
session.commit()
if not cnf["Control-Overrides::Options::Quiet"]:
print("Done in %d seconds. [Updated = %d, Added = %d, Removed = %d, Skipped = %d, Errors = %d]" % (int(time.time() - start_time), c_updated, c_added, c_removed, c_skipped, c_error))
Logger.log(["set complete", c_updated, c_added, c_removed, c_skipped, c_error])
################################################################################
[docs]def list_overrides(suite, component, otype, session):
dat = {}
s = get_suite(suite, session)
if s is None:
utils.fubar("Suite '%s' not recognised." % (suite))
dat['suiteid'] = s.suite_id
c = get_component(component, session)
if c is None:
utils.fubar("Component '%s' not recognised." % (component))
dat['componentid'] = c.component_id
o = get_override_type(otype)
if o is None:
utils.fubar("Type '%s' not recognised. (Valid types are deb, udeb and dsc)" % (otype))
dat['typeid'] = o.overridetype_id
if otype == "dsc":
q = session.execute("""SELECT o.package, s.section, o.maintainer FROM override o, section s
WHERE o.suite = :suiteid AND o.component = :componentid
AND o.type = :typeid AND o.section = s.id
ORDER BY s.section, o.package""", dat)
for i in q.fetchall():
print(utils.result_join(i))
else:
q = session.execute("""SELECT o.package, p.priority, s.section, o.maintainer, p.level
FROM override o, priority p, section s
WHERE o.suite = :suiteid AND o.component = :componentid
AND o.type = :typeid AND o.priority = p.id AND o.section = s.id
ORDER BY s.section, p.level, o.package""", dat)
for i in q.fetchall():
print(utils.result_join(i[:-1]))
################################################################################
[docs]def main():
global Logger
cnf = Config()
Arguments = [('a', "add", "Control-Overrides::Options::Add"),
('c', "component", "Control-Overrides::Options::Component", "HasArg"),
('h', "help", "Control-Overrides::Options::Help"),
('l', "list", "Control-Overrides::Options::List"),
('q', "quiet", "Control-Overrides::Options::Quiet"),
('s', "suite", "Control-Overrides::Options::Suite", "HasArg"),
('S', "set", "Control-Overrides::Options::Set"),
('C', "change", "Control-Overrides::Options::Change"),
('n', "no-action", "Control-Overrides::Options::No-Action"),
('t', "type", "Control-Overrides::Options::Type", "HasArg")]
# Default arguments
for i in ["add", "help", "list", "quiet", "set", "change", "no-action"]:
key = "Control-Overrides::Options::%s" % i
if key not in cnf:
cnf[key] = ""
if "Control-Overrides::Options::Component" not in cnf:
cnf["Control-Overrides::Options::Component"] = "main"
if "Control-Overrides::Options::Suite" not in cnf:
cnf["Control-Overrides::Options::Suite"] = "unstable"
if "Control-Overrides::Options::Type" not in cnf:
cnf["Control-Overrides::Options::Type"] = "deb"
file_list = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv)
if cnf["Control-Overrides::Options::Help"]:
usage()
session = DBConn().session()
mode = None
for i in ["add", "list", "set", "change"]:
if cnf["Control-Overrides::Options::%s" % (i)]:
if mode:
utils.fubar("Can not perform more than one action at once.")
mode = i
# Need an action...
if mode is None:
utils.fubar("No action specified.")
(suite, component, otype) = (cnf["Control-Overrides::Options::Suite"],
cnf["Control-Overrides::Options::Component"],
cnf["Control-Overrides::Options::Type"])
if mode == "list":
list_overrides(suite, component, otype, session)
else:
if get_suite(suite).untouchable:
utils.fubar("%s: suite is untouchable" % suite)
action = True
if cnf["Control-Overrides::Options::No-Action"]:
utils.warn("In No-Action Mode")
action = False
Logger = daklog.Logger("control-overrides", mode)
if file_list:
for f in file_list:
process_file(open(f), suite, component, otype, mode, action, session)
else:
process_file(sys.stdin, suite, component, otype, mode, action, session)
Logger.close()
#######################################################################################
if __name__ == '__main__':
main()