--- /dev/null
+#!/usr/bin/env python
+
+# Sync the ISC configuartion file and the SQL database
+# Copyright (C) 2000 James Troup <james@nocrew.org>
+# $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()
+
--- /dev/null
+#!/usr/bin/env python
+
+# Quick hack to import override files
+# Copyright (C) 2000 James Troup <james@nocrew.org>
+# $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()
+
--- /dev/null
+#!/usr/bin/env python
+
+# Output override files for apt-ftparchive and indices/
+# Copyright (C) 2000 James Troup <james@nocrew.org>
+# $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()
+
--- /dev/null
+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.
--- /dev/null
+#!/usr/bin/env python
+
+# General purpose archive tool for ftpmaster
+# Copyright (C) 2000 James Troup <james@nocrew.org>
+# $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 <foo>.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()
+
--- /dev/null
+#!/usr/bin/env python
+
+# Manipulate override files
+# Copyright (C) 2000 James Troup <james@nocrew.org>
+# $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()
+
+++ /dev/null
-#!/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) } <STDIN>) || die $!;
-close(STDOUT) || die $!;