From 43722e2ebdfdcc25098483f3fa05b7ee857b1466 Mon Sep 17 00:00:00 2001 From: James Troup Date: Wed, 10 Jan 2001 05:58:26 +0000 Subject: [PATCH] Add new scripts; remove old ones. --- alyson | 80 +++++++++++ contrib/hack.1 | 81 +++++++++++ denise | 155 ++++++++++++++++++++ docs/README.names | 19 +++ melanie | 352 ++++++++++++++++++++++++++++++++++++++++++++++ natalie.py | 222 +++++++++++++++++++++++++++++ sortover.pl | 13 -- 7 files changed, 909 insertions(+), 13 deletions(-) create mode 100755 alyson create mode 100755 contrib/hack.1 create mode 100755 denise create mode 100644 docs/README.names create mode 100755 melanie create mode 100755 natalie.py delete mode 100755 sortover.pl diff --git a/alyson b/alyson new file mode 100755 index 00000000..5e602ecd --- /dev/null +++ b/alyson @@ -0,0 +1,80 @@ +#!/usr/bin/env python + +# Sync the ISC configuartion file and the SQL database +# Copyright (C) 2000 James Troup +# $Id: alyson,v 1.1 2001-01-10 05:58:26 troup Exp $ + +# 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 + +################################################################################ + +import pg, sys +import utils, db_access +import apt_pkg; + +################################################################################ + +Cnf = None; +projectB = None; + +################################################################################ + +def main (): + global Cnf, projectB; + + apt_pkg.init(); + + Cnf = apt_pkg.newConfiguration(); + apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file()); + Arguments = [('D',"debug","Alyson::Options::Debug", "IntVal"), + ('h',"help","Alyson::Options::Help"), + ('v',"version","Alyson::Options::Version")]; + apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv); + + projectB = pg.connect('projectb', 'localhost'); + db_access.init(Cnf, projectB); + + # Quick hack to populate section, priority and bin_type; the rest todo later + + projectB.query("BEGIN WORK"); + projectB.query("DELETE FROM override_type"); + for type in Cnf.SubTree("OverrideType").List(): + projectB.query("INSERT INTO override_type (type) VALUES ('%s')" % (type)); + projectB.query("COMMIT WORK"); + + projectB.query("BEGIN WORK"); + projectB.query("DELETE FROM priority"); + for priority in Cnf.SubTree("Priority").List(): + projectB.query("INSERT INTO priority (priority, level) VALUES ('%s', %s)" % (priority, Cnf["Priority::%s" % (priority)])); + projectB.query("COMMIT WORK"); + + projectB.query("BEGIN WORK"); + projectB.query("DELETE FROM section"); + for component in Cnf.SubTree("Component").List(): + if component != 'main': + prefix = component + '/'; + else: + prefix = ""; + for section in Cnf.SubTree("Section").List(): + projectB.query("INSERT INTO section (section) VALUES ('%s%s')" % (prefix, section)); + projectB.query("COMMIT WORK"); + + + +####################################################################################### + +if __name__ == '__main__': + main() + diff --git a/contrib/hack.1 b/contrib/hack.1 new file mode 100755 index 00000000..6a123fdf --- /dev/null +++ b/contrib/hack.1 @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +# Quick hack to import override files +# Copyright (C) 2000 James Troup +# $Id: hack.1,v 1.1 2001-01-10 05:58:26 troup Exp $ + +# 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 + +################################################################################ + +import os, pg, sys, string +import utils, db_access +import apt_pkg; + +################################################################################ + +Cnf = None; +projectB = None; + +################################################################################ + +def main (): + global Cnf, projectB; + + apt_pkg.init(); + + Cnf = apt_pkg.newConfiguration(); + apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file()); + Arguments = [('D',"debug","Alyson::Options::Debug", "IntVal"), + ('h',"help","Alyson::Options::Help"), + ('v',"version","Alyson::Options::Version")]; + apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv); + + projectB = pg.connect('projectb', 'localhost'); + db_access.init(Cnf, projectB); + + for filename in os.listdir('.'): + if not os.path.isfile(filename) or filename[:9] != 'override.': + continue; + x = string.split(filename, '.') + suite = x[1]; + type = "deb"; + if suite == "experimental": + continue; + else: + component = x[2]; + if suite == "woody": + suite = "unstable"; + elif suite == "potato": + suite = "stable"; + else: + print "say what?"; + sys.exit(3); + if len(x) == 4: + type = x[3]; + if type == "debian-installer": + type = "udeb"; + elif type == "src": + type = "dsc"; + else: + print "say WHAT?"; + sys.exit(4); + print "cat %s | natalie --set --suite=%s --component=%s --type=%s" % (filename, suite, component, type); + +####################################################################################### + +if __name__ == '__main__': + main() + diff --git a/denise b/denise new file mode 100755 index 00000000..9e8eebb5 --- /dev/null +++ b/denise @@ -0,0 +1,155 @@ +#!/usr/bin/env python + +# Output override files for apt-ftparchive and indices/ +# Copyright (C) 2000 James Troup +# $Id: denise,v 1.1 2001-01-10 05:58:26 troup Exp $ + +# 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 + +# This is seperate because it's horribly Debian specific and I don't +# want that kind of horribleness in the otherwise generic natalie. It +# does duplicate code tho. + +################################################################################ + +import pg, sys, string +import utils, db_access, natalie +import apt_pkg; + +################################################################################ + +Cnf = None; +projectB = None; +override = {} + +################################################################################ + +def list(suite, component, type): + global override; + + suite_id = db_access.get_suite_id(suite); + if suite_id == -1: + sys.stderr.write("Suite '%s' not recognised.\n" % (suite)); + sys.exit(2); + + component_id = db_access.get_component_id(component); + if component_id == -1: + sys.stderr.write("Component '%s' not recognised.\n" % (component)); + sys.exit(2); + + type_id = db_access.get_override_type_id(type); + if type_id == -1: + sys.stderr.write("Type '%s' not recognised. (Valid types are deb, udeb and dsc.)\n" % (type)); + sys.exit(2); + + if not override.has_key(suite): + override[suite] = {}; + if not override[suite].has_key(component): + override[suite][component] = {}; + if not override[suite][component].has_key(type): + override[suite][component][type] = {}; + + if type == "dsc": + q = projectB.query("SELECT o.package, s.section, o.maintainer FROM override o, section s WHERE o.suite = %s AND o.component = %s AND o.type = %s AND o.section = s.id ORDER BY s.section, o.package" % (suite_id, component_id, type_id)); + for i in q.getresult(): + override[suite][component][type][i[0]] = i; + print string.join(i, '\t'); + else: + q = projectB.query("SELECT o.package, p.priority, s.section, o.maintainer, p.level FROM override o, priority p, section s WHERE o.suite = %s AND o.component = %s AND o.type = %s AND o.priority = p.id AND o.section = s.id ORDER BY s.section, p.level, o.package" % (suite_id, component_id, type_id)); + for i in q.getresult(): + i = i[:-1]; # Strip the priority level + override[suite][component][type][i[0]] = i; + print string.join(i, '\t'); + +################################################################################ + +def main (): + global Cnf, projectB, override; + + apt_pkg.init(); + + Cnf = apt_pkg.newConfiguration(); + apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file()); + Arguments = [('D',"debug","Denise::Options::Debug", "IntVal"), + ('h',"help","Denise::Options::Help"), + ('V',"version","Denise::Options::Version")]; + apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv); + + projectB = pg.connect('projectb', 'localhost'); + db_access.init(Cnf, projectB); + + natalie.init(); + + for suite in [ "stable", "unstable" ]: + sys.stderr.write("Processing %s...\n" % (suite)); + override_suite = Cnf["Suite::%s::OverrideCodeName" % (suite)]; + for component in Cnf.SubTree("Component").List(): + if component == "mixed": + continue; # Ick + for type in Cnf.SubTree("OverrideType").List(): + if type == "deb": + override_type = ""; + elif type == "udeb": + if suite != "unstable" or component != "main": + continue; # Ick2 + override_type = ".debian-installer"; + elif type == "dsc": + override_type = ".src"; + filename = "override.%s.%s%s" % (override_suite, component, override_type); + file = utils.open_file(filename, 'w'); + sys.stdout = file; + list(suite, component, type); + sys.stdout.close(); + + # Munge the override file for testing by using unstable's where + # possible and falling back on stable's where it's not. + + sys.stderr.write("Processing testing...\n"); + suite = "testing"; + suite_id = db_access.get_suite_id(suite); + for component in Cnf.SubTree("Component").List(): + if component == "mixed": + continue; + component_id = db_access.get_component_id(component); + for type in Cnf.SubTree("OverrideType").List(): + if type == "deb": + override_type = ""; + q = projectB.query("SELECT DISTINCT b.package FROM bin_associations ba, binaries b, files f, location l WHERE ba.suite = %s AND l.component = %s AND ba.bin = b.id AND b.file = f.id AND f.location = l.id" % (suite_id, component_id)); + elif type == "dsc": + q = projectB.query("SELECT DISTINCT s.source FROM src_associations sa, source s, files f, location l WHERE sa.suite = %s AND l.component = %s AND sa.source = s.id AND s.file = f.id AND f.location = l.id" % (suite_id, component_id)); + override_type = ".src"; + elif type == "udeb": + continue; + filename = "override.testing.%s%s" % (component, override_type); + file = utils.open_file(filename, 'w'); + sys.stdout = file; + for i in q.getresult(): + package = i[0]; + if override["unstable"][component][type].has_key(package): + print string.join(override["unstable"][component][type][package], '\t'); + elif override["stable"][component][type].has_key(package): + print string.join(override["stable"][component][type][package], '\t'); + else: + if type == "dsc" and (override["unstable"][component]["deb"].has_key(package) or override["stable"][component]["deb"].has_key(package)): + continue; # source falls back on binary; so accept silently + sys.stderr.write("W: Can't find override entry for testing package '%s' (component %s, type %s).\n" % (package, component, type)); + sys.stdout.close(); + + +####################################################################################### + +if __name__ == '__main__': + main() + diff --git a/docs/README.names b/docs/README.names new file mode 100644 index 00000000..d5db95c7 --- /dev/null +++ b/docs/README.names @@ -0,0 +1,19 @@ +alyson - sync's the ISC-style configuration file with the SQL DB +catherine - poolifies packages; i.e. moves them from legacy dists/ locations into the pool +charisma - generates Maintainers files used by e.g. the Debian BTS +claire - generates compatability symlink tree for legacy dists/ locations +heidi - manipulates suite tags; i.e. removes/adds packages from any given suite +jenna - generates lists of files in suites which are then fed to apt-ftparchive +katie - installs packages into the pool +madison - shows which suites a binary package is in +melanie - archive maintenance tool; removes packages from the distribution +natalie - manpiulates override entries +neve - populates the SQL database +rhona - cleans old packages out of the pool and the database +shania - cleans cruft from incoming +tea - sanity checks the database + +With apologies to Alyson Hannigan, Catherine Zeta Jones, Charisma +Carpenter, Claire Daines, Heidi Klum, Jenna Elfman, Katie Holmes, +Madison Michele, Melanie Sykes, Natalie Portman, Neve Campbell, Rhona +Mitre, Shania Twain and Tea Leoni. diff --git a/melanie b/melanie new file mode 100755 index 00000000..a4ec6b09 --- /dev/null +++ b/melanie @@ -0,0 +1,352 @@ +#!/usr/bin/env python + +# General purpose archive tool for ftpmaster +# Copyright (C) 2000 James Troup +# $Id: melanie,v 1.1 2001-01-10 05:58:26 troup Exp $ + +# 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 + +# X-Listening-To: Astronomy, Metallica - Garage Inc. + +################################################################################ + +import commands, os, pg, pwd, re, string, sys, tempfile +import utils, db_access +import apt_pkg, apt_inst; + +################################################################################ + +re_strip_source_version = re.compile (r'\s+.*$'); + +################################################################################ + +Cnf = None; +projectB = None; + +################################################################################ + +def game_over(): + print "Continue (y/N)? ", + answer = string.lower(utils.our_raw_input()); + if answer != "y": + print "Aborted." + sys.exit(1); + +################################################################################ + +def main (): + global Cnf, projectB; + + apt_pkg.init(); + + Cnf = apt_pkg.newConfiguration(); + apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file()); + + Arguments = [('D',"debug","Melanie::Options::Debug", "IntVal"), + ('h',"help","Melanie::Options::Help"), + ('V',"version","Melanie::Options::Version"), + ('a',"architecture","Melanie::Options::Architecture", "HasArg"), + ('b',"binary", "Melanie::Options::Binary-Only"), + ('c',"component", "Melanie::Options::Component", "HasArg"), + ('d',"done","Melanie::Options::Done", "HasArg"), # Bugs fixed + ('m',"reason", "Melanie::Options::Reason", "HasArg"), # Hysterical raisins; -m is old-dinstall option for rejection reason + ('n',"no-action","Melanie::Options::No-Action"), + ('o',"orphan", "Melanie::Options::Orphan"), + ('p',"partial", "Melanie::Options::Partial"), + ('s',"suite","Melanie::Options::Suite", "HasArg"), + ('S',"source-only", "Melanie::Options::Source-Only"), + ]; + + arguments = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv); + projectB = pg.connect('projectb', 'localhost'); + db_access.init(Cnf, projectB); + + # Sanity check options + if arguments == []: + sys.stderr.write("E: need at least one package name as an argument.\n"); + sys.exit(1); + if Cnf["Melanie::Options::Architecture"] and Cnf["Melanie::Options::Source-Only"]: + sys.stderr.write("E: can't use -a/--architecutre and -S/--source-only options simultaneously.\n"); + sys.exit(1); + if Cnf["Melanie::Options::Binary-Only"] and Cnf["Melanie::Options::Source-Only"]: + sys.stderr.write("E: can't use -b/--binary-only and -S/--source-only options simultaneously.\n"); + sys.exit(1); + if Cnf["Melanie::Options::Architecture"] and not Cnf["Melanie::Options::Partial"]: + sys.stderr.write("W: -a/--architecture implies -p/--partial.\n"); + Cnf["Melanie::Options::Partial"] = "true"; + + packages = {}; + if Cnf["Melanie::Options::Binary-Only"]: + field = "b.package"; + else: + field = "s.source"; + con_packages = "AND ("; + for package in arguments: + con_packages = con_packages + "%s = '%s' OR " % (field, package) + packages[package] = ""; + con_packages = con_packages[:-3] + ")" + + suites_list = ""; + suite_ids_list = []; + con_suites = "AND ("; + for suite in string.split(Cnf["Melanie::Options::Suite"]): + + if suite == "stable": + print "**WARNING** About to remove from the stable suite!" + print "This should only be done just prior to a (point) release and not at" + print "any other time." + game_over(); + elif suite == "testing": + print "**WARNING About to remove from the testing suite!" + print "There's no need to do this normally as removals from unstable will" + print "propogate to testing automagically." + game_over(); + + suite_id = db_access.get_suite_id(suite); + if suite_id == -1: + sys.stderr.write("W: suite '%s' not recognised.\n" % (suite)); + else: + con_suites = con_suites + "su.id = %s OR " % (suite_id) + + suites_list = suites_list + suite + ", " + suite_ids_list.append(suite_id); + con_suites = con_suites[:-3] + ")" + suites_list = suites_list[:-2]; + + if Cnf["Melanie::Options::Component"]: + con_components = "AND ("; + over_con_components = "AND ("; + for component in string.split(Cnf["Melanie::Options::Component"]): + component_id = db_access.get_component_id(component); + if component_id == -1: + sys.stderr.write("W: component '%s' not recognised.\n" % (component)); + else: + con_components = con_components + "c.id = %s OR " % (component_id); + over_con_components = over_con_components + "component = %s OR " % (component_id); + con_components = con_components[:-3] + ")" + over_con_components = over_con_components[:-3] + ")"; + else: + con_components = ""; + over_con_components = ""; + + if Cnf["Melanie::Options::Architecture"]: + con_architectures = "AND ("; + for architecture in string.split(Cnf["Melanie::Options::Architecture"]): + architecture_id = db_access.get_architecture_id(architecture); + if architecture_id == -1: + sys.stderr.write("W: architecture '%s' not recognised.\n" % (architecture)); + else: + con_architectures = con_architectures + "a.id = %s OR " % (architecture_id) + con_architectures = con_architectures[:-3] + ")" + else: + con_architectures = ""; + + + print "Working...", + sys.stdout.flush(); + to_remove = []; + # We have 3 modes of package selection: binary-only, source-only + # and source+binary. The first two are trivial and obvious; the + # latter is a nasty mess, but very nice from a UI perspective so + # we try to support it. + + if Cnf["Melanie::Options::Binary-Only"]: + # Binary-only + q = projectB.query("SELECT b.package, b.version, a.arch_string, b.id FROM binaries b, bin_associations ba, architecture a, suite su, files f, location l, component c WHERE ba.bin = b.id AND ba.suite = su.id AND b.architecture = a.id AND b.file = f.id AND f.location = l.id AND l.component = c.id %s %s %s %s" % (con_packages, con_suites, con_components, con_architectures)); + for i in q.getresult(): + to_remove.append(i); + else: + # Source-only + source_packages = {}; + q = projectB.query("SELECT l.path, f.filename, s.source, s.version, 'source', s.id FROM source s, src_associations sa, suite su, files f, location l, component c WHERE sa.source = s.id AND sa.suite = su.id AND s.file = f.id AND f.location = l.id AND l.component = c.id %s %s %s" % (con_packages, con_suites, con_components)); + for i in q.getresult(): + source_packages[i[2]] = i[:2]; + to_remove.append(i[2:]); + if not Cnf["Melanie::Options::Source-Only"]: + # Source + Binary + binary_packages = {}; + # First get a list of binary package names we suspect are linked to the source + q = projectB.query("SELECT DISTINCT package FROM binaries WHERE EXISTS (SELECT s.source, s.version, l.path, f.filename FROM source s, src_associations sa, suite su, files f, location l, component c WHERE binaries.source = s.id AND sa.source = s.id AND sa.suite = su.id AND s.file = f.id AND f.location = l.id AND l.component = c.id %s %s %s)" % (con_packages, con_suites, con_components)); + for i in q.getresult(): + binary_packages[i[0]] = ""; + # Then parse each .dsc that we found earlier to see what binary packages it thinks it produces + for i in source_packages.keys(): + filename = string.join(source_packages[i], '/'); + try: + dsc = utils.parse_changes(filename); + except utils.cant_open_exc: + sys.stderr.write("W: couldn't open '%s'.\n" % (filename)); + continue; + for package in string.split(dsc.get("binary"), ','): + package = string.strip(package); + binary_packages[package] = ""; + # Then for each binary package: find any version in + # unstable, check the Source: field in the deb matches our + # source package and if so add it to the list of packages + # to be removed. + for package in binary_packages.keys(): + q = projectB.query("SELECT l.path, f.filename, b.package, b.version, a.arch_string, b.id FROM binaries b, bin_associations ba, architecture a, suite su, files f, location l, component c WHERE ba.bin = b.id AND ba.suite = su.id AND b.architecture = a.id AND b.file = f.id AND f.location = l.id AND l.component = c.id %s %s %s AND b.package = '%s'" % (con_suites, con_components, con_architectures, package)); + for i in q.getresult(): + filename = string.join(i[:2], '/'); + control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(filename,"r"))) + source = control.Find("Source", control.Find("Package")); + source = re_strip_source_version.sub('', source); + if source_packages.has_key(source): + to_remove.append(i[2:]); + #else: + #sys.stderr.write("W: skipping '%s' as it's source ('%s') isn't one of the source packages.\n" % (filename, source)); + print "done." + + # If we don't have a reason; spawn an editor so the user can add one + # Write the rejection email out as the .reason file + if not Cnf["Melanie::Options::Reason"]: + temp_filename = tempfile.mktemp(); + fd = os.open(temp_filename, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700); + os.close(fd); + result = os.system("vi %s" % (temp_filename)) + if result != 0: + sys.stderr.write ("vi invocation failed for `%s'!" % (temp_filename)) + sys.exit(result) + file = utils.open_file(temp_filename, 'r'); + for line in file.readlines(): + Cnf["Melanie::Options::Reason"] = Cnf["Melanie::Options::Reason"] + line; + os.unlink(temp_filename); + + # Generate the summary of what's to be removed + d = {}; + for i in to_remove: + package = i[0]; + version = i[1]; + architecture = i[2]; + if not d.has_key(package): + d[package] = {}; + if not d[package].has_key(version): + d[package][version] = []; + d[package][version].append(architecture); + + summary = ""; + packages = d.keys(); + packages.sort(); + for package in packages: + versions = d[package].keys(); + versions.sort(); + for version in versions: + summary = summary + "%10s | %10s | " % (package, version); + for architecture in d[package][version]: + summary = "%s%s, " % (summary, architecture); + summary = summary[:-2] + '\n'; + + print "Will remove the following packages from %s:" % (suites_list); + print + print summary + if Cnf["Melanie::Options::Done"]: + print "Will also close bugs: "+Cnf["Melanie::Options::Done"]; + print + print "------------------- Reason -------------------" + print Cnf["Melanie::Options::Reason"]; + print "----------------------------------------------" + print + + # If -n/--no-action, drop out here + if Cnf["Melanie::Options::No-Action"]: + sys.exit(0); + + game_over(); + + whoami = string.replace(string.split(pwd.getpwuid(os.getuid())[4],',')[0], '.', ''); + date = commands.getoutput('date -R'); + + # Log first; if it all falls apart I want a record that we at least tried. + logfile = utils.open_file(Cnf["Melanie::LogFile"], 'a'); + logfile.write("=========================================================================\n"); + logfile.write("[Date: %s] [ftpmaster: %s]\n" % (date, whoami)); + logfile.write("Removed the following packages from %s:\n\n%s" % (suites_list, summary)); + if Cnf["Melanie::Options::Done"]: + logfile.write("Closed bugs: %s\n" % (Cnf["Melanie::Options::Done"])); + logfile.write("\n------------------- Reason -------------------\n%s\n" % (Cnf["Melanie::Options::Reason"])); + logfile.write("----------------------------------------------\n"); + logfile.flush(); + + dsc_type_id = db_access.get_override_type_id('dsc'); + deb_type_id = db_access.get_override_type_id('deb'); + + # Do the actual deletion + print "Deleting...", + sys.stdout.flush(); + projectB.query("BEGIN WORK"); + for i in to_remove: + package = i[0]; + architecture = i[2]; + package_id = i[3]; + for suite_id in suite_ids_list: + if architecture == "source": + projectB.query("DELETE FROM src_associations WHERE source = %s AND suite = %s" % (package_id, suite_id)); + #print "DELETE FROM src_associations WHERE source = %s AND suite = %s" % (package_id, suite_id); + else: + projectB.query("DELETE FROM bin_associations WHERE bin = %s AND suite = %s" % (package_id, suite_id)); + #print "DELETE FROM bin_associations WHERE bin = %s AND suite = %s" % (package_id, suite_id); + # Delete from the override file + if not Cnf["Melanie::Options::Partial"]: + if architecture == "source": + type_id = dsc_type_id; + else: + type_id = deb_type_id; + projectB.query("DELETE FROM override WHERE package = '%s' AND type = %s AND suite = %s %s" % (package, type_id, suite_id, over_con_components)); + projectB.query("COMMIT WORK"); + print "done." + + # Send the bug closing messages + if Cnf["Melanie::Options::Done"]: + for bug in string.split(Cnf["Melanie::Options::Done"]): + mail_message = """Return-Path: %s +From: %s +To: %s-close@bugs.debian.org +Bcc: troup@auric.debian.org +Subject: Bug#%s: fixed + +We believe that the bug you reported is now fixed; the following +package(s) have been removed from %s: + +%s +Note that the package(s) have simply been removed from the tag +database and may (or may not) still be in the pool; this is not a bug. +The package(s) will be physically removed automatically when no suite +references them (and in the case of source, when no binary references +it). Please also remember that the changes have been done on the +master archive (ftp-master.debian.org) and will not propagate to any +mirrors (ftp.debian.org included) until the next cron.daily run at the +earliest. + +Thank you for reporting the bug, which will now be closed. If you +have further comments please address them to %s@bugs.debian.org. + +This message was generated automatically; if you believe that there is +a problem with it please contact the archive administrators by mailing +ftpmaster@debian.org. + +Debian distribution maintenance software +pp. +%s (the ftpmaster behind the curtain) +""" % (Cnf["Melanie::MyEmailAddress"], Cnf["Melanie::MyEmailAddress"], bug, bug, suites_list, summary, bug, whoami); + utils.send_mail (mail_message, "") + + logfile.write("=========================================================================\n"); + logfile.close(); + +####################################################################################### + +if __name__ == '__main__': + main() + diff --git a/natalie.py b/natalie.py new file mode 100755 index 00000000..8206ddfe --- /dev/null +++ b/natalie.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python + +# Manipulate override files +# Copyright (C) 2000 James Troup +# $Id: natalie.py,v 1.1 2001-01-10 05:58:26 troup Exp $ + +# 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 + +################################################################################ + +import pg, string, sys, time +import utils, db_access +import apt_pkg; + +################################################################################ + +Cnf = None; +projectB = None; + +################################################################################ + +def init(): + global projectB; + + projectB = pg.connect('projectb', 'localhost'); + db_access.init(Cnf, projectB); + +def process_file (file, suite, component, type, action): + suite_id = db_access.get_suite_id(suite); + if suite_id == -1: + sys.stderr.write("Suite '%s' not recognised.\n" % (suite)); + sys.exit(2); + + component_id = db_access.get_component_id(component); + if component_id == -1: + sys.stderr.write("Component '%s' not recognised.\n" % (component)); + sys.exit(2); + + type_id = db_access.get_override_type_id(type); + if type_id == -1: + sys.stderr.write("Type '%s' not recognised. (Valid types are deb, udeb and dsc.)\n" % (type)); + sys.exit(2); + + # --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 = projectB.query("SELECT package, priority, section, maintainer FROM override WHERE suite = %s AND component = %s AND type = %s" + % (suite_id, component_id, type_id)); + for i in q.getresult(): + original[i[0]] = i[1:]; + + start_time = time.time(); + projectB.query("BEGIN WORK"); + for line in file.readlines(): + line = string.strip(utils.re_comments.sub('', line[:-1])) + if line == "": + continue; + + maintainer_override = ""; + if type == "dsc": + split_line = string.split(line, None, 2); + if len(split_line) == 2: + (package, section) = split_line; + elif len(split_line) == 3: + (package, section, maintainer_override) = split_line; + else: + sys.stderr.write("W: '%s' does not break into 'package section [maintainer override]'.\n" % (line)); + c_error = c_error + 1; + continue; + priority = "source"; + else: # binary or udeb + split_line = string.split(line, 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: + sys.stderr.write("W: '%s' does not break into 'package priority section [maintainer override]'.\n" % (line)); + c_error = c_error + 1; + continue; + + section_id = db_access.get_section_id(section); + if section_id == -1: + sys.stderr.write("W: '%s' is not a valid section. ['%s' in suite %s, component %s].\n" % (section, package, suite, component)); + c_error = c_error + 1; + continue; + priority_id = db_access.get_priority_id(priority); + if priority_id == -1: + sys.stderr.write("W: '%s' is not a valid priority. ['%s' in suite %s, component %s].\n" % (priority, package, suite, component)); + c_error = c_error + 1; + continue; + + if new.has_key(package): + sys.stderr.write("W: Can't insert duplicate entry for '%s'; ignoring all but the first. [suite %s, component %s]\n" % (package, suite, component)); + c_error = c_error + 1; + continue; + new[package] = ""; + if original.has_key(package): + (old_priority_id, old_section_id, old_maintainer_override) = original[package]; + if old_priority_id == priority_id and old_section_id == section_id and old_maintainer_override == maintainer_override: + # Same? Ignore it + c_skipped = c_skipped + 1; + continue; + else: + # Changed? Delete the old one so we can reinsert it with the new information + c_updated = c_updated + 1; + projectB.query("DELETE FROM override WHERE suite = %s AND component = %s AND package = '%s' AND type = %s" + % (suite_id, component_id, package, type_id)); + else: + c_added = c_added + 1; + + if maintainer_override: + projectB.query("INSERT INTO override (suite, component, type, package, priority, section, maintainer) VALUES (%s, %s, %s, '%s', %s, %s, '%s')" + % (suite_id, component_id, type_id, package, priority_id, section_id, maintainer_override)); + else: + projectB.query("INSERT INTO override (suite, component, type, package, priority, section) VALUES (%s, %s, %s, '%s', %s, %s)" + % (suite_id, component_id, type_id, package, priority_id, section_id)); + + + # Delete any packages which were removed + for package in original.keys(): + if not new.has_key(package): + projectB.query("DELETE FROM override WHERE suite = %s AND component = %s AND package = '%s' AND type = %s" + % (suite_id, component_id, package, type_id)); + c_removed = c_removed + 1; + + projectB.query("COMMIT WORK"); + 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); + +################################################################################ + +def list(suite, component, type): + suite_id = db_access.get_suite_id(suite); + if suite_id == -1: + sys.stderr.write("Suite '%s' not recognised.\n" % (suite)); + sys.exit(2); + + component_id = db_access.get_component_id(component); + if component_id == -1: + sys.stderr.write("Component '%s' not recognised.\n" % (component)); + sys.exit(2); + + type_id = db_access.get_override_type_id(type); + if type_id == -1: + sys.stderr.write("Type '%s' not recognised. (Valid types are deb, udeb and dsc.)\n" % (type)); + sys.exit(2); + + if type == "dsc": + q = projectB.query("SELECT o.package, s.section, o.maintainer FROM override o, section s WHERE o.suite = %s AND o.component = %s AND o.type = %s AND o.section = s.id ORDER BY s.section, o.package" % (suite_id, component_id, type_id)); + for i in q.getresult(): + print string.join(i, '\t'); + else: + q = projectB.query("SELECT o.package, p.priority, s.section, o.maintainer, p.level FROM override o, priority p, section s WHERE o.suite = %s AND o.component = %s AND o.type = %s AND o.priority = p.id AND o.section = s.id ORDER BY s.section, p.level, o.package" % (suite_id, component_id, type_id)); + for i in q.getresult(): + print string.join(i[:-1], '\t'); + +################################################################################ + +def main (): + global Cnf, projectB; + + apt_pkg.init(); + + Cnf = apt_pkg.newConfiguration(); + apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file()); + Arguments = [('D',"debug","Natalie::Options::Debug", "IntVal"), + ('h',"help","Natalie::Options::Help"), + ('V',"version","Natalie::Options::Version"), + ('c',"component", "Natalie::Options::Component", "HasArg"), + ('l',"list", "Natalie::Options::List"), + ('s',"suite","Natalie::Options::Suite", "HasArg"), + ('S',"set","Natalie::Options::Set"), + ('t',"type","Natalie::Options::Type", "HasArg")]; + file_list = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv); + + init(); + + action = None; + for i in [ "list", "set" ]: + if Cnf["Natalie::Options::%s" % (i)]: + if action != None: + sys.stderr.write("Can not perform more than one action at once.\n"); + sys.exit(2); + action = i; + + (suite, component, type) = (Cnf["Natalie::Options::Suite"], Cnf["Natalie::Options::Component"], Cnf["Natalie::Options::Type"]) + + if action == "list": + list(suite, component, type); + else: + if file_list != []: + for file in file_list: + process_file(utils.open_file(file,'r'), suite, component, type, action); + else: + process_file(sys.stdin, suite, component, type, action); + +####################################################################################### + +if __name__ == '__main__': + main() + diff --git a/sortover.pl b/sortover.pl deleted file mode 100755 index 3328ceec..00000000 --- a/sortover.pl +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -%iv=qw(required 00 - important 01 - standard 02 - optional 03 - extra 04); -sub t { - return $_[0] if $_[0] =~ m/^\#/; - $_[0] =~ m/^(\S+)\s+(\S+)\s+(\S+)\s/ || die "$0: `$_[0]'"; - return "$3 $iv{$2} $1"; -} -print(sort { &t($a) cmp &t($b) } ) || die $!; -close(STDOUT) || die $!; -- 2.39.2