import commands, errno, fcntl, os, re, shutil, stat, sys, time, tempfile, traceback
import apt_inst, apt_pkg
-import syck
import daklib.database
import daklib.logging
-import daklib.queue
+import daklib.queue
import daklib.utils
from types import *
-
################################################################################
re_valid_version = re.compile(r"^([0-9]+:)?[0-9A-Za-z\.\-\+:~]+$")
re_changelog_versions = re.compile(r"^\w[-+0-9a-z.]+ \([^\(\) \t]+\)")
re_strip_revision = re.compile(r"-([^-]+)$")
re_strip_srcver = re.compile(r"\s+\(\S+\)$")
+re_spacestrip = re.compile('(\s)')
################################################################################
# Strip a source version in brackets from the source field
if re_strip_srcver.search(changes["source"]):
- changes["source"] = re_strip_srcver.sub('', changes["source"])
+ changes["source"] = re_strip_srcver.sub('', changes["source"])
# Ensure the source field is a valid package name.
if not re_valid_pkg_name.match(changes["source"]):
except daklib.utils.ParseMaintError, msg:
(changes["changedby822"], changes["changedby2047"],
changes["changedbyname"], changes["changedbyemail"]) = \
- ("", "", "", "")
+ ("", "", "", "")
reject("%s: Changed-By field ('%s') failed to parse: %s" \
% (filename, changes["changed-by"], msg))
for file in file_keys:
# Ensure the file does not already exist in one of the accepted directories
for dir in [ "Accepted", "Byhand", "New", "ProposedUpdates", "OldProposedUpdates", "Embargoed", "Unembargoed" ]:
- if not Cnf.has_key("Dir::Queue::%s" % (dir)): continue
+ if not Cnf.has_key("Dir::Queue::%s" % (dir)): continue
if os.path.exists(Cnf["Dir::Queue::%s" % (dir) ]+'/'+file):
reject("%s file already exists in the %s directory." % (file, dir))
if not daklib.utils.re_taint_free.match(file):
if depends == '':
reject("%s: Depends field is empty." % (file))
+ # Sanity-check the Provides field
+ provides = control.Find("Provides")
+ if provides:
+ provide = re_spacestrip.sub('', provides)
+ if provide == '':
+ reject("%s: Provides field is empty." % (file))
+ prov_list = provide.split(",")
+ for prov in prov_list:
+ if not re_valid_pkg_name.match(prov):
+ reject("%s: Invalid Provides field content %s." % (file, prov))
+
+
# Check the section & priority match those given in the .changes (non-fatal)
if control.Find("Section") and files[file]["section"] != "" and files[file]["section"] != control.Find("Section"):
reject("%s control file lists section as `%s', but changes file has `%s'." % (file, control.Find("Section", ""), files[file]["section"]), "Warning: ")
elif os.path.exists(Cnf["Dir::Queue::New"] + '/' + dsc_filename):
files[file]["new"] = 1
else:
- dsc_file_exists = 0
+ dsc_file_exists = 0
for myq in ["Accepted", "Embargoed", "Unembargoed", "ProposedUpdates", "OldProposedUpdates"]:
- if Cnf.has_key("Dir::Queue::%s" % (myq)):
- if os.path.exists(Cnf["Dir::Queue::"+myq] + '/' + dsc_filename):
- dsc_file_exists = 1
- break
- if not dsc_file_exists:
+ if Cnf.has_key("Dir::Queue::%s" % (myq)):
+ if os.path.exists(Cnf["Dir::Queue::"+myq] + '/' + dsc_filename):
+ dsc_file_exists = 1
+ break
+ if not dsc_file_exists:
reject("no source found for %s %s (%s)." % (source_package, source_version, file))
# Check the version and for file overwrites
reject(Upload.check_binary_against_db(file),"")
m = daklib.utils.re_issource.match(f)
if not m:
reject("%s: %s in Files field not recognised as source." % (dsc_filename, f))
- continue
+ continue
type = m.group(3)
if type == "orig.tar.gz" or type == "tar.gz":
has_tar = 1
def check_source():
# Bail out if:
- # a) there's no source
+ # a) there's no source
# or b) reprocess is 2 - we will do this check next time when orig.tar.gz is in 'files'
# or c) the orig.tar.gz is MIA
if not changes["architecture"].has_key("source") or reprocess == 2 \
################################################################################
-def check_md5sums ():
- for file in files.keys():
+def check_hashes ():
+ # Make sure we recognise the format of the Files: field
+ format = changes.get("format", "0.0").split(".",1)
+ if len(format) == 2:
+ format = int(format[0]), int(format[1])
+ else:
+ format = int(float(format[0])), 0
+
+ check_hash(".changes", files, "md5sum", apt_pkg.md5sum)
+ check_hash(".dsc", dsc_files, "md5sum", apt_pkg.md5sum)
+
+ if format >= (1,8):
+ hashes = [("sha1", apt_pkg.sha1sum),
+ ("sha256", apt_pkg.sha256sum)]
+ else:
+ hashes = []
+
+ for x in changes:
+ if x.startswith("checksum-"):
+ h = x.split("-",1)[1]
+ if h not in dict(hashes):
+ reject("Unsupported checksum field in .changes" % (h))
+
+ for x in dsc:
+ if x.startswith("checksum-"):
+ h = x.split("-",1)[1]
+ if h not in dict(hashes):
+ reject("Unsupported checksum field in .dsc" % (h))
+
+ for h,f in hashes:
try:
- file_handle = daklib.utils.open_file(file)
- except daklib.utils.cant_open_exc:
- continue
+ fs = daklib.utils.build_file_list(changes, 0, "checksums-%s" % h, h)
+ check_hash(".changes %s" % (h), fs, h, f, files)
+ except daklib.utils.no_files_exc:
+ reject("No Checksums-%s: field in .changes" % (h))
- # Check md5sum
- if apt_pkg.md5sum(file_handle) != files[file]["md5sum"]:
- reject("%s: md5sum check failed." % (file))
- file_handle.close()
- # Check size
- actual_size = os.stat(file)[stat.ST_SIZE]
- size = int(files[file]["size"])
- if size != actual_size:
- reject("%s: actual file size (%s) does not match size (%s) in .changes"
- % (file, actual_size, size))
+ if "source" not in changes["architecture"]: continue
+
+ try:
+ fs = daklib.utils.build_file_list(dsc, 1, "checksums-%s" % h, h)
+ check_hash(".dsc %s" % (h), fs, h, f, dsc_files)
+ except daklib.utils.no_files_exc:
+ reject("No Checksums-%s: field in .dsc" % (h))
+
+################################################################################
+
+def check_hash (where, files, key, testfn, basedict = None):
+ if basedict:
+ for file in basedict.keys():
+ if file not in files:
+ reject("%s: no %s checksum" % (file, key))
+
+ for file in files.keys():
+ if basedict and file not in basedict:
+ reject("%s: extraneous entry in %s checksums" % (file, key))
- for file in dsc_files.keys():
try:
file_handle = daklib.utils.open_file(file)
except daklib.utils.cant_open_exc:
continue
- # Check md5sum
- if apt_pkg.md5sum(file_handle) != dsc_files[file]["md5sum"]:
- reject("%s: md5sum check failed." % (file))
+ # Check hash
+ if testfn(file_handle) != files[file][key]:
+ reject("%s: %s check failed." % (file, key))
file_handle.close()
# Check size
actual_size = os.stat(file)[stat.ST_SIZE]
- size = int(dsc_files[file]["size"])
+ size = int(files[file]["size"])
if size != actual_size:
- reject("%s: actual file size (%s) does not match size (%s) in .dsc"
- % (file, actual_size, size))
+ reject("%s: actual file size (%s) does not match size (%s) in %s"
+ % (file, actual_size, size, where))
################################################################################
except:
reject("%s: deb contents timestamp check failed [%s: %s]" % (filename, sys.exc_type, sys.exc_value))
-################################################################################
-################################################################################
-
-# We reject packages if the release team defined a transition for them
-def check_transition(sourcepkg):
- # No sourceful upload -> no need to do anything else, direct return
- if changes["architecture"].has_key("source"):
- return
-
- # Also only check if there is a file defined (and existant) with checks. It's a little bit
- # specific to Debian, not much use for others, so return early there.
- if not Cnf.has_key("Dinstall::Reject::ReleaseTransitions") or not os.path.exists("%s" % (Cnf["Dinstall::Reject::ReleaseTransitions"])):
- return
-
- # Parse the yaml file
- sourcefile = file(Cnf["Dinstall::Reject::ReleaseTransitions"], 'r')
- sourcecontent = sourcefile.read()
- try:
- transitions = syck.load(sourcecontent)
- except syck.error, msg:
- # This shouldn't happen, there is a wrapper to edit the file which checks it, but we prefer
- # to be safe than ending up rejecting everything.
- daklib.utils.warn("Not checking transitions, the transitions file is broken: %s." % (msg))
- return
-
- # Now look through all defined transitions
- for trans in transitions:
- t = transitions[trans]
- source = t["source"]
- expected = t["new"]
-
- # Will be None if nothing is in testing.
- current = daklib.database.get_suite_version(source, "testing")
- if not current == None:
- compare = apt_pkg.VersionCompare(current, expected)
-
- if current == None or compare < 0:
- # This is still valid, the current version in testing is older than
- # the new version we wait for, or there is none in testing yet
-
- # Check if the source we look at is affected by this.
- if sourcepkg in t['packages']:
- # The source is affected, lets reject it.
- reject("""%s: part of the %s transition.
-
-Your package is part of a testing transition designed to get %s migrated
-(it currently is at version %s, we need version %s)
-
-Transition description: %s
-
-This transition is managed by the Release Team, and %s
-is the Release-Team member responsible for it.
-Please contact %s or debian-release@lists.debian.org if you
-need further assistance.
- """ % (sourcepkg, trans, source, current, expected, t["reason"], t["rm"], t["rm"]))
- return 0
-
################################################################################
def lookup_uid_from_fingerprint(fpr):
if uid == None:
uid, uid_email = changes["fingerprint"], uid
may_nmu, may_sponsor = 1, 1
- # XXX by default new dds don't have a fingerprint/uid in the db atm,
- # and can't get one in there if we don't allow nmu/sponsorship
+ # XXX by default new dds don't have a fingerprint/uid in the db atm,
+ # and can't get one in there if we don't allow nmu/sponsorship
elif uid[:3] == "dm:":
uid_email = uid[3:]
may_nmu, may_sponsor = 0, 0
if uid_name == "": sponsored = 1
else:
sponsored = 1
-
- if sponsored and not may_sponsor:
+ if ("source" in changes["architecture"] and
+ daklib.utils.is_email_alias(uid_email)):
+ sponsor_addresses = daklib.utils.gpg_get_key_addresses(changes["fingerprint"])
+ if (changes["maintaineremail"] not in sponsor_addresses and
+ changes["changedbyemail"] not in sponsor_addresses):
+ changes["sponsoremail"] = uid_email
+
+ if sponsored and not may_sponsor:
reject("%s is not authorised to sponsor uploads" % (uid))
if not sponsored and not may_nmu:
source_ids = []
- check_suites = changes["distribution"].keys()
- if "unstable" not in check_suites: check_suites.append("unstable")
+ check_suites = changes["distribution"].keys()
+ if "unstable" not in check_suites: check_suites.append("unstable")
for suite in check_suites:
suite_id = daklib.database.get_suite_id(suite)
q = Upload.projectB.query("SELECT s.id FROM source s JOIN src_associations sa ON (s.id = sa.source) WHERE s.source = '%s' AND sa.suite = %d" % (changes["source"], suite_id))
for b in changes["binary"].keys():
for suite in changes["distribution"].keys():
suite_id = daklib.database.get_suite_id(suite)
- q = Upload.projectB.query("SELECT DISTINCT s.source FROM source s JOIN binaries b ON (s.id = b.source) JOIN bin_associations ba On (b.id = ba.bin) WHERE b.package = '%s' AND ba.suite = %s" % (b, suite_id))
- for s in q.getresult():
+ q = Upload.projectB.query("SELECT DISTINCT s.source FROM source s JOIN binaries b ON (s.id = b.source) JOIN bin_associations ba On (b.id = ba.bin) WHERE b.package = '%s' AND ba.suite = %s" % (b, suite_id))
+ for s in q.getresult():
if s[0] != changes["source"]:
reject("%s may not hijack %s from source package %s in suite %s" % (uid, b, s, suite))
for file in files.keys():
- if files[file].has_key("byhand"):
+ if files[file].has_key("byhand"):
reject("%s may not upload BYHAND file %s" % (uid, file))
if files[file].has_key("new"):
reject("%s may not upload NEW file %s" % (uid, file))
# q-unapproved hax0ring
queue_info = {
"New": { "is": is_new, "process": acknowledge_new },
- "Autobyhand" : { "is" : is_autobyhand, "process": do_autobyhand },
+ "Autobyhand" : { "is" : is_autobyhand, "process": do_autobyhand },
"Byhand" : { "is": is_byhand, "process": do_byhand },
- "OldStableUpdate" : { "is": is_oldstableupdate,
- "process": do_oldstableupdate },
+ "OldStableUpdate" : { "is": is_oldstableupdate,
+ "process": do_oldstableupdate },
"StableUpdate" : { "is": is_stableupdate, "process": do_stableupdate },
"Unembargo" : { "is": is_unembargo, "process": queue_unembargo },
"Embargo" : { "is": is_embargo, "process": queue_embargo },
break
if queue:
print "%s for %s\n%s%s" % (
- queue.upper(), ", ".join(changes["distribution"].keys()),
+ queue.upper(), ", ".join(changes["distribution"].keys()),
reject_message, summary),
queuekey = queue[0].upper()
if queuekey in "RQSA":
def is_unembargo ():
q = Upload.projectB.query(
- "SELECT package FROM disembargo WHERE package = '%s' AND version = '%s'" %
+ "SELECT package FROM disembargo WHERE package = '%s' AND version = '%s'" %
(changes["source"], changes["version"]))
ql = q.getresult()
if ql:
if Options["No-Action"]: return 1
Upload.projectB.query(
- "INSERT INTO disembargo (package, version) VALUES ('%s', '%s')" %
+ "INSERT INTO disembargo (package, version) VALUES ('%s', '%s')" %
(changes["source"], changes["version"]))
return 1
def is_stableupdate ():
if not changes["distribution"].has_key("proposed-updates"):
- return 0
+ return 0
if not changes["architecture"].has_key("source"):
pusuite = daklib.database.get_suite_id("proposed-updates")
q = Upload.projectB.query(
- "SELECT S.source FROM source s JOIN src_associations sa ON (s.id = sa.source) WHERE s.source = '%s' AND s.version = '%s' AND sa.suite = %d" %
+ "SELECT S.source FROM source s JOIN src_associations sa ON (s.id = sa.source) WHERE s.source = '%s' AND s.version = '%s' AND sa.suite = %d" %
(changes["source"], changes["version"], pusuite))
ql = q.getresult()
if ql:
def is_oldstableupdate ():
if not changes["distribution"].has_key("oldstable-proposed-updates"):
- return 0
+ return 0
if not changes["architecture"].has_key("source"):
pusuite = daklib.database.get_suite_id("oldstable-proposed-updates")
q = Upload.projectB.query(
- "SELECT S.source FROM source s JOIN src_associations sa ON (s.id = sa.source) WHERE s.source = '%s' AND s.version = '%s' AND sa.suite = %d" %
+ "SELECT S.source FROM source s JOIN src_associations sa ON (s.id = sa.source) WHERE s.source = '%s' AND s.version = '%s' AND sa.suite = %d" %
(changes["source"], changes["version"], pusuite))
ql = q.getresult()
if ql:
any_auto = 0
for file in files.keys():
if files[file].has_key("byhand"):
- any_auto = 1
-
- # filename is of form "PKG_VER_ARCH.EXT" where PKG, VER and ARCH
- # don't contain underscores, and ARCH doesn't contain dots.
- # further VER matches the .changes Version:, and ARCH should be in
- # the .changes Architecture: list.
- if file.count("_") < 2:
- all_auto = 0
- continue
-
- (pkg, ver, archext) = file.split("_", 2)
- if archext.count(".") < 1 or changes["version"] != ver:
- all_auto = 0
- continue
-
- ABH = Cnf.SubTree("AutomaticByHandPackages")
- if not ABH.has_key(pkg) or \
- ABH["%s::Source" % (pkg)] != changes["source"]:
- print "not match %s %s" % (pkg, changes["source"])
- all_auto = 0
- continue
-
- (arch, ext) = archext.split(".", 1)
- if arch not in changes["architecture"]:
- all_auto = 0
- continue
-
- files[file]["byhand-arch"] = arch
- files[file]["byhand-script"] = ABH["%s::Script" % (pkg)]
+ any_auto = 1
+
+ # filename is of form "PKG_VER_ARCH.EXT" where PKG, VER and ARCH
+ # don't contain underscores, and ARCH doesn't contain dots.
+ # further VER matches the .changes Version:, and ARCH should be in
+ # the .changes Architecture: list.
+ if file.count("_") < 2:
+ all_auto = 0
+ continue
+
+ (pkg, ver, archext) = file.split("_", 2)
+ if archext.count(".") < 1 or changes["version"] != ver:
+ all_auto = 0
+ continue
+
+ ABH = Cnf.SubTree("AutomaticByHandPackages")
+ if not ABH.has_key(pkg) or \
+ ABH["%s::Source" % (pkg)] != changes["source"]:
+ print "not match %s %s" % (pkg, changes["source"])
+ all_auto = 0
+ continue
+
+ (arch, ext) = archext.split(".", 1)
+ if arch not in changes["architecture"]:
+ all_auto = 0
+ continue
+
+ files[file]["byhand-arch"] = arch
+ files[file]["byhand-script"] = ABH["%s::Script" % (pkg)]
return any_auto and all_auto
os.system("ls -l %s" % byhandfile)
result = os.system("%s %s %s %s %s" % (
- files[file]["byhand-script"], byhandfile,
+ files[file]["byhand-script"], byhandfile,
changes["version"], files[file]["byhand-arch"],
os.path.abspath(pkg.changes_file)))
if result == 0:
valid_dsc_p = check_dsc()
if valid_dsc_p:
check_source()
- check_md5sums()
+ check_hashes()
check_urgency()
check_timestamps()
check_signed_by_key()
- check_transition(changes["source"])
Upload.update_subst(reject_message)
action()
except SystemExit:
raise
except:
print "ERROR"
- traceback.print_exc(file=sys.stderr)
+ traceback.print_exc(file=sys.stderr)
pass
# Restore previous WD
if __name__ == '__main__':
main()
-