""" General purpose package removal tool for ftpmaster """
# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 James Troup <james@nocrew.org>
+# Copyright (C) 2010 Alexander Reichle-Schmehl <tolimar@debian.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
from daklib import utils
from daklib.dak_exceptions import *
from daklib.regexes import re_strip_source_version, re_build_dep_arch
+import debianbts as bts
################################################################################
-c, --component=COMPONENT act on this component
-C, --carbon-copy=EMAIL send a CC of removal message to EMAIL
-d, --done=BUG# send removal message as closure to bug#
+ -D, --do-close also close all bugs associated to that package
-h, --help show this help and exit
-m, --reason=MSG reason for removal
-n, --no-action don't do anything
(result, output) = commands.getstatusoutput("gunzip -c %s > %s" % (filename, temp_filename))
if (result != 0):
utils.fubar("Gunzip invocation failed!\n%s\n" % (output), result)
+ # Also check for udebs
+ filename = "%s/dists/%s/%s/debian-installer/binary-%s/Packages.gz" % (cnf["Dir::Root"], suites[0], component, architecture)
+ if os.path.exists(filename):
+ (result, output) = commands.getstatusoutput("gunzip -c %s >> %s" % (filename, temp_filename))
+ if (result != 0):
+ utils.fubar("Gunzip invocation failed!\n%s\n" % (output), result)
packages = utils.open_file(temp_filename)
Packages = apt_pkg.ParseTagFile(packages)
while Packages.Step():
('c',"component", "Rm::Options::Component", "HasArg"),
('C',"carbon-copy", "Rm::Options::Carbon-Copy", "HasArg"), # Bugs to Cc
('d',"done","Rm::Options::Done", "HasArg"), # Bugs fixed
+ ('D',"do-close","Rm::Options::Do-Close"),
('R',"rdep-check", "Rm::Options::Rdep-Check"),
('m',"reason", "Rm::Options::Reason", "HasArg"), # Hysterical raisins; -m is old-dinstall option for rejection reason
('n',"no-action","Rm::Options::No-Action"),
for i in [ "architecture", "binary-only", "carbon-copy", "component",
"done", "help", "no-action", "partial", "rdep-check", "reason",
- "source-only" ]:
+ "source-only", "Do-Close" ]:
if not cnf.has_key("Rm::Options::%s" % (i)):
cnf["Rm::Options::%s" % (i)] = ""
if not cnf.has_key("Rm::Options::Suite"):
if Options["Architecture"] and not Options["Partial"]:
utils.warn("-a/--architecture implies -p/--partial.")
Options["Partial"] = "true"
+ if Options["Do-Close"] and not Options["Done"]:
+ utils.fubar("No.")
+ if Options["Do-Close"] and Options["Binary-Only"]:
+ utils.fubar("No.")
+ if Options["Do-Close"] and Options["Source-Only"]:
+ utils.fubar("No.")
+ if Options["Do-Close"] and Options["Suite"] != 'unstable':
+ utils.fubar("No.")
# Force the admin to tell someone if we're not doing a 'dak
# cruft-report' inspired removal (or closing a bug, which counts
summary = ""
removals = d.keys()
removals.sort()
+ versions = []
for package in removals:
versions = d[package].keys()
versions.sort(apt_pkg.VersionCompare)
logfile.write("Closed bugs: %s\n" % (Options["Done"]))
logfile.write("\n------------------- Reason -------------------\n%s\n" % (Options["Reason"]))
logfile.write("----------------------------------------------\n")
- logfile.flush()
+ logfile.write("=========================================================================\n")
+ logfile.close()
# Do the same in rfc822 format
logfile822 = utils.open_file(cnf["Rm::LogFile822"], 'a')
if element[2].find("source") > 0:
sources.append("%s_%s" % tuple(elem.strip(" ") for elem in element[:2]))
element[2] = sub("source\s?,?", "", element[2]).strip(" ")
- if len(element[2]):
+ if element[2]:
binaries.append("%s_%s [%s]" % tuple(elem.strip(" ") for elem in element))
- if len(sources):
+ if sources:
logfile822.write("Sources:\n")
for source in sources:
logfile822.write(" %s\n" % source)
- if len(binaries):
+ if binaries:
logfile822.write("Binaries:\n")
for binary in binaries:
logfile822.write(" %s\n" % binary)
- logfile822.write("Reason: %s\n" % (Options["Reason"]))
+ logfile822.write("Reason: %s\n" % Options["Reason"].replace('\n', '\n '))
if Options["Done"]:
- logfile822.write("Bug: %s\n" % (Options["Done"]))
+ logfile822.write("Bug: %s\n" % Options["Done"])
logfile822.write("\n")
- logfile822.flush()
logfile822.close()
dsc_type_id = get_override_type('dsc', session).overridetype_id
session.commit()
print "done."
+ Subst = {}
+ Subst["__RM_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"]
+ Subst["__BUG_SERVER__"] = cnf["Dinstall::BugServer"]
+ bcc = []
+ if cnf.Find("Dinstall::Bcc") != "":
+ bcc.append(cnf["Dinstall::Bcc"])
+ if cnf.Find("Rm::Bcc") != "":
+ bcc.append(cnf["Rm::Bcc"])
+ if bcc:
+ Subst["__BCC__"] = "Bcc: " + ", ".join(bcc)
+ else:
+ Subst["__BCC__"] = "X-Filler: 42"
+ Subst["__CC__"] = "X-DAK: dak rm"
+ if carbon_copy:
+ Subst["__CC__"] += "\nCc: " + ", ".join(carbon_copy)
+ Subst["__SUITE_LIST__"] = suites_list
+ Subst["__SUBJECT__"] = "Removed package(s) from %s" % (suites_list)
+ Subst["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
+ Subst["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
+ Subst["__WHOAMI__"] = whoami
+
# Send the bug closing messages
if Options["Done"]:
- Subst = {}
- Subst["__RM_ADDRESS__"] = cnf["Rm::MyEmailAddress"]
- Subst["__BUG_SERVER__"] = cnf["Dinstall::BugServer"]
- bcc = []
- if cnf.Find("Dinstall::Bcc") != "":
- bcc.append(cnf["Dinstall::Bcc"])
- if cnf.Find("Rm::Bcc") != "":
- bcc.append(cnf["Rm::Bcc"])
- if bcc:
- Subst["__BCC__"] = "Bcc: " + ", ".join(bcc)
- else:
- Subst["__BCC__"] = "X-Filler: 42"
- Subst["__CC__"] = "X-DAK: dak rm"
- if carbon_copy:
- Subst["__CC__"] += "\nCc: " + ", ".join(carbon_copy)
- Subst["__SUITE_LIST__"] = suites_list
summarymail = "%s\n------------------- Reason -------------------\n%s\n" % (summary, Options["Reason"])
summarymail += "----------------------------------------------\n"
Subst["__SUMMARY__"] = summarymail
- Subst["__SUBJECT__"] = "Removed package(s) from %s" % (suites_list)
- Subst["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
- Subst["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
- Subst["__WHOAMI__"] = whoami
whereami = utils.where_am_i()
Archive = cnf.SubTree("Archive::%s" % (whereami))
Subst["__MASTER_ARCHIVE__"] = Archive["OriginServer"]
mail_message = utils.TemplateSubst(Subst,cnf["Dir::Templates"]+"/rm.bug-close")
utils.send_mail(mail_message)
- logfile.write("=========================================================================\n")
- logfile.close()
+ # close associated bug reports
+ # FIXME: We should also close possible WNPP bugs for that package, but
+ # currently there's no sane way to determine them
+ if Options["Do-Close"]:
+ if len(versions) == 1:
+ Subst["__VERSION__"] = versions[0]
+ else:
+ utils.fubar("Closing bugs with multiple package versions is not supported. Do it yourself.")
+ whereami = utils.where_am_i()
+ Archive = cnf.SubTree("Archive::%s" % (whereami))
+ # at this point, I just assume, that the first closed bug gives
+ # some usefull information on why the package got removed
+ Subst["__BUG_NUMBER__"] = utils.split_args(Options["Done"])[0]
+ if len(sources) > 1:
+ utils.fubar("Closing bugs for multiple source pakcages is not supported. Do it yourself.")
+ Subst["__BUG_NUMBER_ALSO__"] = ""
+ Subst["__SOURCE__"] = source.split("_", 1)[0]
+ for bug in bts.get_bugs('src', source.split("_", 1)[0], 'status', 'open'):
+ Subst["__BUG_NUMBER_ALSO__"] += str(bug) + "-done@" + cnf["Dinstall::BugServer"] + ","
+ mail_message = utils.TemplateSubst(Subst,cnf["Dir::Templates"]+"/rm.bug-close-related")
+ if Subst["__BUG_NUMBER_ALSO__"]:
+ utils.send_mail(mail_message)
#######################################################################################