X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=katie;h=1532a5e1725b9978ef142a4287d774be2acd6cd8;hb=8e7b460758fb8a59697f2a95f1dc6279a676998f;hp=7ce746c5b0c5fb262e1a98acc532023d74ca4d34;hpb=53f1d77f290ed84db4b4436bfd2748d63e0e6892;p=dak.git diff --git a/katie b/katie index 7ce746c5..1532a5e1 100755 --- a/katie +++ b/katie @@ -2,7 +2,7 @@ # Installs Debian packaes # Copyright (C) 2000 James Troup -# $Id: katie,v 1.17 2001-01-10 06:08:03 troup Exp $ +# $Id: katie,v 1.26 2001-01-31 03:36:36 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 @@ -91,13 +91,14 @@ legacy_source_untouchable = {}; def usage (exit_code): print """Usage: dinstall [OPTION]... [CHANGES]... -a, --automatic automatic run - -d, --debug=VALUE debug - -k, --ack-new acknowledge new packages + -D, --debug=VALUE turn on debugging + -h, --help show this help and exit. + -k, --ack-new acknowledge new packages !! for cron.daily only !! -m, --manual-reject=MSG manual reject with `msg' - -n, --dry-run don't do anything + -n, --no-action don't do anything -p, --no-lock don't check lockfile !! for cron.daily only !! - -r, --no-version-check override version check - -u, --distribution=DIST override distribution to `dist'""" + -u, --distribution=DIST override distribution to `dist' + -v, --version display the version number and exit""" sys.exit(exit_code) def check_signature (filename): @@ -105,7 +106,7 @@ def check_signature (filename): (result, output) = commands.getstatusoutput("gpg --emulate-md-encode-bug --batch --no-options --no-default-keyring --always-trust --keyring=%s --keyring=%s < %s >/dev/null" % (Cnf["Dinstall::PGPKeyring"], Cnf["Dinstall::GPGKeyring"], filename)) if (result != 0): - reject_message = "Rejected: GPG signature check failed on `%s'.\n%s\n" % (filename, output) + reject_message = "Rejected: GPG signature check failed on `%s'.\n%s\n" % (os.path.basename(filename), output) return 0 return 1 @@ -113,14 +114,18 @@ def check_signature (filename): # See if a given package is in the override table -def in_override_p (package, component, suite, binary_type): - global overrides; - +def in_override_p (package, component, suite, binary_type, file): + global files; + if binary_type == "": # must be source type = "dsc"; else: type = binary_type; + # Override suite name; used for example with proposed-updates + if Cnf.Find("Suite::%s::OverrideSuite" % (suite)) != "": + suite = Cnf["Suite::%s::OverrideSuite" % (suite)]; + # Avoid on unknown distributions suite_id = db_access.get_suite_id(suite); if suite_id == -1: @@ -132,15 +137,20 @@ def in_override_p (package, component, suite, binary_type): if string.lower(component[:7]) == "non-us/": component = component[7:]; - q = projectB.query("SELECT package FROM override WHERE package = '%s' AND suite = %s AND component = %s AND type = %s" + q = projectB.query("SELECT s.section, p.priority FROM override o, section s, priority p WHERE package = '%s' AND suite = %s AND component = %s AND type = %s AND o.section = s.id AND o.priority = p.id" % (package, suite_id, component_id, type_id)); result = q.getresult(); # If checking for a source package fall back on the binary override type if type == "dsc" and not result: type_id = db_access.get_override_type_id("deb"); - q = projectB.query("SELECT package FROM override WHERE package = '%s' AND suite = %s AND component = %s AND type = %s" + q = projectB.query("SELECT s.section, p.priority FROM override o, section s, priority p WHERE package = '%s' AND suite = %s AND component = %s AND type = %s AND o.section = s.id AND o.priority = p.id" % (package, suite_id, component_id, type_id)); result = q.getresult(); + + # Remember the section and priority so we can check them later if appropriate + if result != []: + files[file]["override section"] = result[0][0]; + files[file]["override priority"] = result[0][1]; return result; @@ -151,7 +161,7 @@ def check_changes(filename): # Parse the .changes field into a dictionary [FIXME - need to trap errors, pass on to reject_message etc.] try: - changes = utils.parse_changes(filename) + changes = utils.parse_changes(filename, 0) except utils.cant_open_exc: reject_message = "Rejected: can't read changes file '%s'.\n" % (filename) return 0; @@ -161,17 +171,17 @@ def check_changes(filename): return 0; # Parse the Files field from the .changes into another dictionary [FIXME need to trap errors as above] - files = utils.build_file_list(changes, "") + try: + files = utils.build_file_list(changes, ""); + except utils.changes_parse_error_exc, line: + reject_message = "Rejected: error parsing changes file '%s', can't grok: %s.\n" % (filename, line); # Check for mandatory fields for i in ("source", "binary", "architecture", "version", "distribution","maintainer", "files"): if not changes.has_key(i): - reject_message = "Rejected: Missing field `%s' in changes file." % (i) + reject_message = "Rejected: Missing field `%s' in changes file.\n" % (i) return 0 # Avoid errors during later tests - # Fix the Maintainer: field to be RFC822 compatible - (changes["maintainer822"], changes["maintainername"], changes["maintaineremail"]) = utils.fix_maintainer (changes["maintainer"]) - # Override the Distribution: field if appropriate if Cnf["Dinstall::Options::Override-Distribution"] != "": reject_message = reject_message + "Warning: Distribution was overriden from %s to %s.\n" % (changes["distribution"], Cnf["Dinstall::Options::Override-Distribution"]) @@ -186,6 +196,17 @@ def check_changes(filename): for j in string.split(o): changes[i][j] = 1 + # Fix the Maintainer: field to be RFC822 compatible + (changes["maintainer822"], changes["maintainername"], changes["maintaineremail"]) = utils.fix_maintainer (changes["maintainer"]) + + # Fix the Changed-By: field to be RFC822 compatible; if it exists. + (changes["changedby822"], changes["changedbyname"], changes["changedbyemail"]) = utils.fix_maintainer(changes.get("changed-by","")); + + # For source uploads the Changed-By field wins; otherwise Maintainer wins. + if changes["architecture"].has_key("source"): + changes["uploader822"] = "To: %s\nCc: %s" % (changes["changedby822"], changes["maintainer822"]); + # changes["uploadername"], changes["uploaderemail"]) = (changes["changedby822"], changes["changedbyname"], changes["changedbyemail"]); + # Ensure all the values in Closes: are numbers if changes.has_key("closes"): for i in changes["closes"].keys(): @@ -195,11 +216,13 @@ def check_changes(filename): # 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"] + changes["distribution"]["unstable"] = 1; reject_message = reject_message + "Mapping frozen to unstable.\n" # 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" # Ensure target distributions exist @@ -207,12 +230,17 @@ def check_changes(filename): 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(): if not Cnf.has_key("Suite::Stable::Architectures::%s" % (i)): reject_message = reject_message + "Mapping stable to unstable for unreleased arch `%s'.\n" % (i) del changes["distribution"]["stable"] + changes["distribution"]["unstable"] = 1; # Map arches not being released from frozen to unstable if changes["distribution"].has_key("frozen"): @@ -220,6 +248,7 @@ def check_changes(filename): if not Cnf.has_key("Suite::Frozen::Architectures::%s" % (i)): reject_message = reject_message + "Mapping frozen to unstable for non-releasing arch `%s'.\n" % (i) del changes["distribution"]["frozen"] + changes["distribution"]["unstable"] = 1; # Handle uploads to stable if changes["distribution"].has_key("stable"): @@ -268,8 +297,15 @@ def check_files(): files[file]["type"] = "byhand"; # Checks for a binary package... elif re_isadeb.match(file) != None: + files[file]["type"] = "deb"; + # Extract package information using dpkg-deb - control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(file,"r"))) + try: + control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(file,"r"))) + except: + reject_message = reject_message + "Rejected: %s: debExtractControl() raised %s.\n" % (file, sys.exc_type); + # Can't continue, none of the checks on control would work. + continue; # Check for mandatory fields if control.Find("Package") == None: @@ -308,7 +344,6 @@ def check_files(): files[file]["dbtype"] = "deb"; else: reject_message = reject_message + "Rejected: %s is neither a .deb or a .udeb.\n " % (file); - files[file]["type"] = "deb"; files[file]["fullname"] = "%s_%s_%s.deb" % (control.Find("Package", ""), epochless_version, control.Find("Architecture", "")) files[file]["source"] = control.Find("Source", ""); if files[file]["source"] == "": @@ -347,7 +382,7 @@ def check_files(): else: files[file]["byhand"] = 1; files[file]["type"] = "byhand"; - + files[file]["oldfiles"] = {} for suite in changes["distribution"].keys(): # Skip byhand @@ -359,7 +394,7 @@ def check_files(): continue # See if the package is NEW - if not in_override_p(files[file]["package"], files[file]["component"], suite, files[file].get("dbtype","")): + if not in_override_p(files[file]["package"], files[file]["component"], suite, files[file].get("dbtype",""), file): files[file]["new"] = 1 # Find any old binary packages @@ -371,11 +406,7 @@ def check_files(): files[file]["oldfiles"][suite] = oldfile # Check versions [NB: per-suite only; no cross-suite checking done (yet)] if apt_pkg.VersionCompare(files[file]["version"], oldfile["version"]) != 1: - if Cnf["Dinstall::Options::No-Version-Check"]: - reject_message = reject_message + "Overriden rejection" - else: - reject_message = reject_message + "Rejected" - reject_message = reject_message + ": %s Old version `%s' >= new version `%s'.\n" % (file, oldfile["version"], files[file]["version"]) + reject_message = reject_message + "Rejected: %s Old version `%s' >= new version `%s'.\n" % (file, oldfile["version"], files[file]["version"]) # Check for existing copies of the file if not changes.has_key("stable upload"): q = projectB.query("SELECT b.id FROM binaries b, architecture a WHERE b.package = '%s' AND b.version = '%s' AND a.arch_string = '%s' AND a.id = b.architecture" % (files[file]["package"], files[file]["version"], files[file]["architecture"])) @@ -400,7 +431,7 @@ def check_files(): # Check the md5sum & size against existing files (if any) location = Cnf["Dir::PoolDir"]; files[file]["location id"] = db_access.get_location_id (location, component, archive); - + files[file]["pool name"] = utils.poolify (changes["source"], files[file]["component"]); files_id = db_access.get_files_id(files[file]["pool name"] + file, files[file]["size"], files[file]["md5sum"], files[file]["location id"]); if files_id == -1: @@ -427,18 +458,24 @@ def check_dsc (): for file in files.keys(): if files[file]["type"] == "dsc": try: - dsc = utils.parse_changes(file) + dsc = utils.parse_changes(file, 1) except utils.cant_open_exc: reject_message = reject_message + "Rejected: can't read changes file '%s'.\n" % (filename) return 0; except utils.changes_parse_error_exc, line: reject_message = reject_message + "Rejected: error parsing changes file '%s', can't grok: %s.\n" % (filename, line) return 0; + except utils.invalid_dsc_format_exc, line: + reject_message = reject_message + "Rejected: syntax error in .dsc file '%s', line %s.\n" % (filename, line) + return 0; try: dsc_files = utils.build_file_list(dsc, 1) except utils.no_files_exc: reject_message = reject_message + "Rejected: no Files: field in .dsc file.\n"; continue; + except utils.changes_parse_error_exc, line: + reject_message = "Rejected: error parsing .dsc file '%s', can't grok: %s.\n" % (filename, line); + continue; # Try and find all files mentioned in the .dsc. This has # to work harder to cope with the multiple possible @@ -451,6 +488,16 @@ def check_dsc (): # Check the file does not already exist in the archive if not changes.has_key("stable upload"): q = projectB.query("SELECT f.id FROM files f, location l WHERE (f.filename ~ '/%s$' OR f.filename = '%s') AND l.id = f.location" % (utils.regex_safe(dsc_file), dsc_file)); + + # "It has not broken them. It has fixed a + # brokenness. Your crappy hack exploited a + # bug in the old dinstall. + # + # "(Come on! I thought it was always obvious + # that one just doesn't release different + # files with the same name and version.)" + # -- ajk@ on d-devel@l.d.o + if q.getresult() != []: reject_message = reject_message + "Rejected: can not overwrite existing copy of '%s' already in the archive.\n" % (dsc_file) elif dsc_file[-12:] == ".orig.tar.gz": @@ -458,7 +505,6 @@ def check_dsc (): q = projectB.query("SELECT l.path, f.filename, l.type, f.id FROM files f, location l WHERE (f.filename ~ '/%s$' OR f.filename = '%s') AND l.id = f.location" % (utils.regex_safe(dsc_file), dsc_file)); ql = q.getresult(); - if ql != []: # Unfortunately, we make get more than one match # here if, for example, the package was in potato @@ -506,7 +552,7 @@ def check_dsc (): reject_message = reject_message + "Rejected: %s refers to %s, but I can't find it in Incoming or in the pool.\n" % (file, dsc_file); continue; else: - reject_message = reject_message + "Rejected: %s refers to %s, but I can't find it in Incoming." % (file, dsc_file); + reject_message = reject_message + "Rejected: %s refers to %s, but I can't find it in Incoming.\n" % (file, dsc_file); continue; if actual_md5 != dsc_files[dsc_file]["md5sum"]: reject_message = reject_message + "Rejected: md5sum for %s doesn't match %s.\n" % (found, file); @@ -534,7 +580,7 @@ def check_diff (): file = gzip.GzipFile(filename, 'r'); for line in file.readlines(): if re_bad_diff.search(line): - reject_message = reject_message + "Rejected: source package was produced by broken dpkg 1.8.1[.1]; please rebuild with later version.\n"; + reject_message = reject_message + "Rejected: [dpkg-sucks] source package was produced by a broken version of dpkg-dev 1.8.x; please rebuild with >= 1.8.3 version installed.\n"; break; if string.find(reject_message, "Rejected:") != -1: @@ -556,6 +602,54 @@ def check_md5sums (): if apt_pkg.md5sum(file_handle) != files[file]["md5sum"]: reject_message = reject_message + "Rejected: md5sum check failed for %s.\n" % (file); +def check_override (): + # Only check section & priority on sourceful uploads + if not changes["architecture"].has_key("source"): + return; + + summary = "" + for file in files.keys(): + if not files[file].has_key("new") and (files[file]["type"] == "dsc" or files[file]["type"] == "deb"): + section = files[file]["section"]; + override_section = files[file]["override section"]; + if section != override_section and section != "-": + # Ignore this; it's a common mistake and not worth whining about + if string.lower(section) == "non-us/main" and string.lower(override_section) == "non-us": + continue; + summary = summary + "%s: section is overridden from %s to %s.\n" % (file, section, override_section); + if files[file]["type"] == "deb": # don't do priority for source + priority = files[file]["priority"]; + override_priority = files[file]["override priority"]; + if priority != override_priority and priority != "-": + summary = summary + "%s: priority is overridden from %s to %s.\n" % (file, priority, override_priority); + + if summary == "": + return; + + mail_message = """Return-Path: %s +From: %s +To: %s +Bcc: troup@auric.debian.org +Subject: %s override disparity + +There are disparities between your recently installed upload and the +override file for the following file(s): + +%s +Either the package or the override file is incorrect. If you think +the override is correct and the package wrong please fix the package +so that this disparity is fixed in the next upload. If you feel the +override is incorrect then please reply to this mail and explain why. + +-- +Debian distribution maintenance software + +(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) +""" % (Cnf["Dinstall::MyEmailAddress"], Cnf["Dinstall::MyEmailAddress"], changes["maintainer822"], changes["source"], summary); + utils.send_mail (mail_message, "") + ##################################################################################################################### def action (changes_filename): @@ -785,6 +879,7 @@ Installing: %s""" % (Cnf["Dinstall::MyEmailAddress"], Cnf["Dinstall::MyEmailAddress"], changes["maintainer822"], os.path.basename(changes_filename), reject_message, summary, installed_footer) utils.send_mail (mail_message, "") announce (short_summary, 1) + check_override (); ##################################################################################################################### @@ -896,8 +991,8 @@ def reject (changes_filename, manual_reject_mail_filename): if os.path.exists(file): try: utils.move (file, "%s/REJECT/%s" % (Cnf["Dir::IncomingDir"], file)); - except utils.cant_overwrite_exc: - sys.stderr.write("W: couldn't overwrite existing file '%s/REJECT/%s" % (Cnf["Dir::IncomingDir"], file)); + except: + sys.stderr.write("W: couldn't reject file '%s' [Got %s].\n" % (file, sys.exc_type)); pass; # If this is not a manual rejection generate the .reason file and rejection mail message @@ -1099,17 +1194,18 @@ non-maintainer upload. The .changes file follows. # into the .changes structure and reprocess the .changes file. def process_it (changes_file): - global reprocess, orig_tar_id, changes, dsc, dsc_files, files; + global reprocess, orig_tar_id, changes, dsc, dsc_files, files, reject_message; - reprocess = 1; - orig_tar_id = None; # Reset some globals + reprocess = 1; changes = {}; dsc = {}; dsc_files = {}; files = {}; orig_tar_id = None; legacy_source_untouchable = {}; + reject_message = ""; + orig_tar_id = None; # Absolutize the filename to avoid the requirement of being in the # same directory as the .changes file. @@ -1136,7 +1232,7 @@ def process_it (changes_file): ############################################################################### def main(): - global Cnf, projectB, reject_message, install_bytes, new_ack_old + global Cnf, projectB, install_bytes, new_ack_old apt_pkg.init(); @@ -1150,7 +1246,6 @@ def main(): ('m',"manual-reject","Dinstall::Options::Manual-Reject", "HasArg"), ('n',"no-action","Dinstall::Options::No-Action"), ('p',"no-lock", "Dinstall::Options::No-Lock"), - ('r',"no-version-check", "Dinstall::Options::No-Version-Check"), ('s',"no-mail", "Dinstall::Options::No-Mail"), ('u',"override-distribution", "Dinstall::Options::Override-Distribution", "HasArg"), ('v',"version","Dinstall::Options::Version")]; @@ -1197,7 +1292,6 @@ def main(): # Process the changes files for changes_file in changes_files: - reject_message = "" print "\n" + changes_file; process_it (changes_file);