]> git.decadent.org.uk Git - dak.git/blobdiff - katie
ship logging module
[dak.git] / katie
diff --git a/katie b/katie
index 5b92f91b9415deebdeeb92a72497631293fa78ec..cf26804343ea59c541b53fb202d2016e36a89a6b 100755 (executable)
--- a/katie
+++ b/katie
@@ -2,7 +2,7 @@
 
 # Installs Debian packaes
 # Copyright (C) 2000, 2001  James Troup <james@nocrew.org>
-# $Id: katie,v 1.52 2001-07-07 21:25:52 troup Exp $
+# $Id: katie,v 1.56 2001-07-28 18:07:58 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
@@ -36,6 +36,8 @@ import FCNTL, commands, fcntl, getopt, gzip, os, pg, pwd, re, shutil, stat, stri
 import apt_inst, apt_pkg
 import utils, db_access, logging
 
+from types import *;
+
 ###############################################################################
 
 re_isanum = re.compile (r"^\d+$");
@@ -232,9 +234,12 @@ def check_changes(filename):
         files = utils.build_file_list(changes, "");
     except utils.changes_parse_error_exc, line:
         reject_message = reject_message + "Rejected: error parsing changes file '%s', can't grok: %s.\n" % (filename, line);
+    except utils.nk_format_exc, format:
+        reject_message = reject_message + "Rejected: unknown format '%s' of changes file '%s'.\n" % (format, filename);
+        return 0;
 
     # Check for mandatory fields
-    for i in ("source", "binary", "architecture", "version", "distribution","maintainer", "files"):
+    for i in ("source", "binary", "architecture", "version", "distribution", "maintainer", "files"):
         if not changes.has_key(i):
             reject_message = reject_message + "Rejected: Missing field `%s' in changes file.\n" % (i)
             return 0    # Avoid <undef> errors during later tests
@@ -265,6 +270,10 @@ def check_changes(filename):
             if re_isanum.match (i) == None:
                 reject_message = reject_message + "Rejected: `%s' from Closes field isn't a number.\n" % (i)
 
+    # Ensure there _is_ a target distribution
+    if changes["distribution"].keys() == []:
+        reject_message = reject_message + "Rejected: huh? Distribution field is empty in changes file.\n";
+            
     # Map frozen to unstable if frozen doesn't exist
     if changes["distribution"].has_key("frozen") and not Cnf.has_key("Suite::Frozen"):
         del changes["distribution"]["frozen"]
@@ -273,19 +282,17 @@ def check_changes(filename):
 
     # Map testing to unstable
     if changes["distribution"].has_key("testing"):
-        del changes["distribution"]["testing"]
-        changes["distribution"]["unstable"] = 1;
-        reject_message = reject_message + "Mapping testing to unstable.\n"
+        if len(changes["distribution"].keys()) > 1:
+            del changes["distribution"]["testing"];
+            reject_message = reject_message + "Warning: Ignoring testing as a target suite.\n";
+        else:
+            reject_message = reject_message + "Rejected: invalid distribution 'testing'.\n";
 
     # Ensure target distributions exist
     for i in changes["distribution"].keys():
         if not Cnf.has_key("Suite::%s" % (i)):
             reject_message = reject_message + "Rejected: Unknown distribution `%s'.\n" % (i)
 
-    # Ensure there _is_ a target distribution
-    if changes["distribution"].keys() == []:
-        reject_message = reject_message + "Rejected: huh? Distribution field is empty in changes file.\n";
-            
     # Map unreleased arches from stable to unstable
     if changes["distribution"].has_key("stable"):
         for i in changes["architecture"].keys():
@@ -423,7 +430,7 @@ def check_files():
                 files[file]["package"] = m.group(1)
                 files[file]["version"] = m.group(2)
                 files[file]["type"] = m.group(3)
-                
+
                 # Ensure the source package name matches the Source filed in the .changes
                 if changes["source"] != files[file]["package"]:
                     reject_message = reject_message + "Rejected: %s: changes file doesn't say %s for Source\n" % (file, files[file]["package"])
@@ -468,7 +475,7 @@ def check_files():
                 
             if files[file]["type"] == "deb":
                 # Find any old binary packages
-                q = projectB.query("SELECT b.id, b.version, f.filename, l.path, c.name FROM binaries b, bin_associations ba, suite s, location l, component c, architecture a, files f WHERE b.package = '%s' AND s.suite_name = '%s' AND a.arch_string = '%s' AND ba.bin = b.id AND ba.suite = s.id AND b.architecture = a.id AND f.location = l.id AND l.component = c.id AND b.file = f.id"
+                q = projectB.query("SELECT b.id, b.version, f.filename, l.path, c.name FROM binaries b, bin_associations ba, suite s, location l, component c, architecture a, files f WHERE b.package = '%s' AND s.suite_name = '%s' AND (a.arch_string = '%s' OR a.arch_string = 'all') AND ba.bin = b.id AND ba.suite = s.id AND b.architecture = a.id AND f.location = l.id AND l.component = c.id AND b.file = f.id"
                                    % (files[file]["package"], suite, files[file]["architecture"]))
                 oldfiles = q.dictresult()
                 for oldfile in oldfiles:
@@ -560,6 +567,11 @@ def check_dsc ():
                 reject_message = reject_message + "Rejected: error parsing .dsc file '%s', can't grok: %s.\n" % (file, line);
                 continue;
 
+            # Enforce mandatory fields
+            for i in ("format", "source", "version", "binary", "maintainer", "architecture", "files"):
+                if not dsc.has_key(i):
+                    reject_message = reject_message + "Rejected: Missing field `%s' in dsc file.\n" % (i)
+
             # The dpkg maintainer from hell strikes again! Bumping the
             # version number of the .dsc breaks extraction by stable's
             # dpkg-source.
@@ -569,6 +581,23 @@ def check_dsc ():
           installed.
 """;
 
+            # Ensure the version number in the .dsc matches the version number in the .changes
+            epochless_dsc_version = utils.re_no_epoch.sub('', dsc.get("version"));
+            changes_version = files[file]["version"];
+            if epochless_dsc_version != files[file]["version"]:
+                reject_message = reject_message + "Rejected: version ('%s') in .dsc does not match version ('%s') in .changes\n" % (epochless_dsc_version, changes_version);
+
+            # Ensure source is newer than existing source in target suites
+            package = dsc.get("source");
+            new_version = dsc.get("version");
+            for suite in changes["distribution"].keys():
+                q = projectB.query("SELECT s.version FROM source s, src_associations sa, suite su WHERE s.source = '%s' AND su.suite_name = '%s' AND sa.source = s.id AND sa.suite = su.id"
+                                   % (package, suite));
+                ql = map(lambda x: x[0], q.getresult());
+                for old_version in ql:
+                    if apt_pkg.VersionCompare(new_version, old_version) != 1:
+                        reject_message = reject_message + "Rejected: %s Old version `%s' >= new version `%s'.\n" % (file, old_version, new_version)
+
             # Try and find all files mentioned in the .dsc.  This has
             # to work harder to cope with the multiple possible
             # locations of an .orig.tar.gz.
@@ -733,10 +762,14 @@ def check_override ():
 def update_subst (changes_filename):
     global Subst;
 
-    if changes.has_key("architecture"):
-        Subst["__ARCHITECTURE__"] = string.join(changes["architecture"].keys(), ' ' );
-    else:
-        Subst["__ARCHITECTURE__"] = "Unknown";
+    # If katie crashed out in the right place, architecture may still be a string.
+    if not changes.has_key("architecture") or not isinstance(changes["architecture"], DictType):
+        changes["architecture"] = { "Unknown" : "" };
+    # and maintainer822 may not exist.
+    if not changes.has_key("maintainer822"):
+        changes["maintainer822"] = Cnf["Dinstall::MyEmailAddress"];
+
+    Subst["__ARCHITECTURE__"] = string.join(changes["architecture"].keys(), ' ' );
     Subst["__CHANGES_FILENAME__"] = os.path.basename(changes_filename);
     Subst["__FILE_CONTENTS__"] = changes.get("filecontents", "");
 
@@ -761,7 +794,7 @@ def action (changes_filename):
 
     # changes["distribution"] may not exist in corner cases
     # (e.g. unreadable changes files)
-    if not changes.has_key("distribution"):
+    if not changes.has_key("distribution") or not isinstance(changes["distribution"], DictType):
         changes["distribution"] = {};
     
     for suite in changes["distribution"].keys():
@@ -1355,7 +1388,7 @@ def main():
     Subst = {}
     Subst["__ADMIN_ADDRESS__"] = Cnf["Dinstall::MyAdminAddress"];
     Subst["__BUG_SERVER__"] = Cnf["Dinstall::BugServer"];
-    bcc = "X-Katie: $Revision: 1.52 $"
+    bcc = "X-Katie: $Revision: 1.56 $"
     if Cnf.has_key("Dinstall::Bcc"):
         Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"]);
     else: