# Installs Debian packaes
# Copyright (C) 2000 James Troup <james@nocrew.org>
-# $Id: katie,v 1.21 2001-01-22 22:32:47 troup Exp $
+# $Id: katie,v 1.29 2001-02-09 22:15:45 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
###############################################################################
re_isanum = re.compile (r'^\d+$');
-re_isadeb = re.compile (r'.*\.u?deb$');
-re_issource = re.compile (r'(.+)_(.+?)\.(orig\.tar\.gz|diff\.gz|tar\.gz|dsc)');
re_changes = re.compile (r'changes$');
re_default_answer = re.compile(r"\[(.*)\]");
re_fdnic = re.compile("\n\n");
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, --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):
def check_changes(filename):
global reject_message, changes, files
- # Parse the .changes field into a dictionary [FIXME - need to trap errors, pass on to reject_message etc.]
+ # Default in case we bail out
+ changes["maintainer822"] = Cnf["Dinstall::MyEmailAddress"];
+
+ # Parse the .changes field into a dictionary
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;
except utils.changes_parse_error_exc, line:
reject_message = "Rejected: error parsing changes file '%s', can't grok: %s.\n" % (filename, line)
- changes["maintainer822"] = Cnf["Dinstall::MyEmailAddress"];
return 0;
- # Parse the Files field from the .changes into another dictionary [FIXME need to trap errors as above]
+ # Parse the Files field from the .changes into another dictionary
try:
files = utils.build_file_list(changes, "");
except utils.changes_parse_error_exc, 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 <undef> 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"])
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():
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():
files[file]["byhand"] = 1;
files[file]["type"] = "byhand";
# Checks for a binary package...
- elif re_isadeb.match(file) != None:
+ elif utils.re_isadeb.match(file) != None:
+ files[file]["type"] = "deb";
+
# Extract package information using dpkg-deb
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:
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"] == "":
files[file]["source"] = files[file]["package"];
# Checks for a source package...
else:
- m = re_issource.match(file)
+ m = utils.re_issource.match(file)
if m != None:
files[file]["package"] = m.group(1)
files[file]["version"] = m.group(2)
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"]))
if component_id == -1:
reject_message = reject_message + "Rejected: file '%s' has unknown component '%s'.\n" % (file, component);
continue;
+
+ # Validate the priority
+ if string.find(files[file]["priority"],'/') != -1:
+ reject_message = reject_message + "Rejected: file '%s' has invalid priority '%s' [contains '/'].\n" % (file, files[file]["priority"]);
# Check the md5sum & size against existing files (if any)
location = Cnf["Dir::PoolDir"];
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:
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
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);
summary = ""
for file in files.keys():
- if not files[file].has_key("new") and (files[file]["type"] == "dsc" or files[file]["type"] == "deb"):
+ if not files[file].has_key("new") and 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);
+ 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;
for file in files.keys():
if files[file]["type"] == "deb":
new_changelog.write("stable/%s/binary-%s/%s\n" % (files[file]["component"], files[file]["architecture"], file));
- elif re_issource.match(file) != None:
+ elif utils.re_issource.match(file) != None:
new_changelog.write("stable/%s/source/%s\n" % (files[file]["component"], file));
else:
new_changelog.write("%s\n" % (file));
# Move the .changes files and it's contents into REJECT/ (if we can; errors are ignored)
try:
utils.move (changes_filename, "%s/REJECT/%s" % (Cnf["Dir::IncomingDir"], base_changes_filename));
- except utils.cant_overwrite_exc:
- sys.stderr.write("W: couldn't overwrite existing file '%s/REJECT/%s" % (Cnf["Dir::IncomingDir"], base_changes_filename));
+ except:
+ sys.stderr.write("W: couldn't reject changes file '%s' [Got %s]" % (base_changes_filename, sys.exc_type));
pass;
for file in files.keys():
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
control_message = ""
for bug in bugs:
summary = summary + "%s " % (bug)
- control_message = control_message + "severity %s fixed\n" % (bug)
+ control_message = control_message + "tag %s + fixed\n" % (bug)
if action and control_message != "":
mail_message = """Return-Path: %s
From: %s
# 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.
###############################################################################
def main():
- global Cnf, projectB, reject_message, install_bytes, new_ack_old
+ global Cnf, projectB, install_bytes, new_ack_old
apt_pkg.init();
('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")];
# Process the changes files
for changes_file in changes_files:
- reject_message = ""
print "\n" + changes_file;
process_it (changes_file);