]> git.decadent.org.uk Git - dak.git/blobdiff - dak/rm.py
Set the version subst variable for the removal of associated bugs
[dak.git] / dak / rm.py
index be3e16766e86b94d371f58954b3b1964acb8e208..c0f6810dd1baf27233ae32760897203d225c4031 100755 (executable)
--- a/dak/rm.py
+++ b/dak/rm.py
@@ -2,6 +2,7 @@
 
 """ 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
@@ -44,12 +45,14 @@ import os
 import sys
 import apt_pkg
 import apt_inst
+from re import sub
 
 from daklib.config import Config
 from daklib.dbconn import *
 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
 
 ################################################################################
 
@@ -66,6 +69,7 @@ Remove PACKAGE(s) from suite(s).
   -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
@@ -75,7 +79,7 @@ Remove PACKAGE(s) from suite(s).
   -S, --source-only          remove source only
 
 ARCH, BUG#, COMPONENT and SUITE can be comma (or space) separated lists, e.g.
-    --architecture=m68k,i386"""
+    --architecture=amd64,i386"""
 
     sys.exit(exit_code)
 
@@ -118,6 +122,12 @@ def reverse_depends_check(removals, suites, arches=None):
             (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():
@@ -262,6 +272,7 @@ def main ():
                  ('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"),
@@ -298,6 +309,14 @@ def main ():
     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
@@ -399,7 +418,7 @@ def main ():
             for i in source_packages.keys():
                 filename = "/".join(source_packages[i])
                 try:
-                    dsc = utils.parse_changes(filename)
+                    dsc = utils.parse_changes(filename, dsc_file=1)
                 except CantOpenError:
                     utils.warn("couldn't open '%s'." % (filename))
                     continue
@@ -460,6 +479,7 @@ def main ():
     summary = ""
     removals = d.keys()
     removals.sort()
+    versions = []
     for package in removals:
         versions = d[package].keys()
         versions.sort(apt_pkg.VersionCompare)
@@ -503,7 +523,38 @@ def main ():
         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')
+    logfile822.write("Date: %s\n" % date)
+    logfile822.write("Ftpmaster: %s\n" % whoami)
+    logfile822.write("Suite: %s\n" % suites_list)
+    sources = []
+    binaries = []
+    for package in summary.split("\n"):
+        for row in package.split("\n"):
+            element = row.split("|")
+            if len(element) == 3:
+                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 element[2]:
+                    binaries.append("%s_%s [%s]" % tuple(elem.strip(" ") for elem in element))
+    if sources:
+        logfile822.write("Sources:\n")
+        for source in sources:
+            logfile822.write(" %s\n" % source)
+    if binaries:
+        logfile822.write("Binaries:\n")
+        for binary in binaries:
+            logfile822.write(" %s\n" % binary)
+    logfile822.write("Reason: %s\n" % Options["Reason"].replace('\n', '\n '))
+    if Options["Done"]:
+        logfile822.write("Bug: %s\n" % Options["Done"])
+    logfile822.write("\n")
+    logfile822.close()
 
     dsc_type_id = get_override_type('dsc', session).overridetype_id
     deb_type_id = get_override_type('deb', session).overridetype_id
@@ -536,28 +587,32 @@ def main ():
     session.commit()
     print "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
+    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
-        Subst["__SUMMARY__"] = summary
-        Subst["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
-        Subst["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
-        Subst["__WHOAMI__"] = whoami
+        summarymail = "%s\n------------------- Reason -------------------\n%s\n" % (summary, Options["Reason"])
+        summarymail += "----------------------------------------------\n"
+        Subst["__SUMMARY__"] = summarymail
         whereami = utils.where_am_i()
         Archive = cnf.SubTree("Archive::%s" % (whereami))
         Subst["__MASTER_ARCHIVE__"] = Archive["OriginServer"]
@@ -567,8 +622,21 @@ def main ():
             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
+    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]
+        for bug in bts.get_bugs('src', package, 'status', 'open'):
+            Subst["__BUG_NUMBER_ALSO__"] += bug + "-done@" + cnf["Dinstall::BugServer"] + ","
+        mail_message = utils.TemplateSubst(Subst,cnf["Dir::Templates"]+"/rm.bug-close-related")
+        utils.send_mail(mail_message)
 
 #######################################################################################