X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=dak%2Fprocess_new.py;h=bd0653e0525d021da9e86b3855ac73bd092330ab;hb=86de24686031e6971970bf609e1a48f2e77f1142;hp=5d110f31715e6e31ed6fdbd700c6321098cff8bf;hpb=7aaaad3135c9164390af5897925660842368660b;p=dak.git diff --git a/dak/process_new.py b/dak/process_new.py index 5d110f31..bd0653e0 100755 --- a/dak/process_new.py +++ b/dak/process_new.py @@ -39,10 +39,10 @@ import copy, errno, os, readline, stat, sys, time import apt_pkg, apt_inst import examine_package -import dak.lib.database as database -import dak.lib.logging as logging -import dak.lib.queue as queue -import dak.lib.utils as utils +from daklib import database +from daklib import logging +from daklib import queue +from daklib import utils # Globals Cnf = None @@ -70,31 +70,36 @@ def recheck(): files = Upload.pkg.files reject_message = "" - for file in files.keys(): + for f in files.keys(): # The .orig.tar.gz can disappear out from under us is it's a # duplicate of one in the archive. - if not files.has_key(file): + if not files.has_key(f): continue # Check that the source still exists - if files[file]["type"] == "deb": - source_version = files[file]["source version"] - source_package = files[file]["source package"] + if files[f]["type"] == "deb": + source_version = files[f]["source version"] + source_package = files[f]["source package"] if not Upload.pkg.changes["architecture"].has_key("source") \ and not Upload.source_exists(source_package, source_version, Upload.pkg.changes["distribution"].keys()): source_epochless_version = utils.re_no_epoch.sub('', source_version) dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version) - if not os.path.exists(Cnf["Dir::Queue::Accepted"] + '/' + dsc_filename): - reject("no source found for %s %s (%s)." % (source_package, source_version, file)) + found = 0 + for q in ["Accepted", "Embargoed", "Unembargoed"]: + if Cnf.has_key("Dir::Queue::%s" % (q)): + if os.path.exists(Cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename): + found = 1 + if not found: + reject("no source found for %s %s (%s)." % (source_package, source_version, f)) # Version and file overwrite checks - if files[file]["type"] == "deb": - reject(Upload.check_binary_against_db(file)) - elif files[file]["type"] == "dsc": - reject(Upload.check_source_against_db(file)) - (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(file) - reject(reject_msg) - - if reject_message: + if files[f]["type"] == "deb": + reject(Upload.check_binary_against_db(f)) + elif files[f]["type"] == "dsc": + reject(Upload.check_source_against_db(f)) + (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(f) + reject(reject_msg, "") + + if reject_message.find("Rejected") != -1: answer = "XXX" if Options["No-Action"] or Options["Automatic"]: answer = 'S' @@ -116,77 +121,13 @@ def recheck(): elif answer == 'S': return 0 elif answer == 'Q': + end() sys.exit(0) return 1 ################################################################################ -def determine_new (changes, files): - new = {} - - # Build up a list of potentially new things - for file in files.keys(): - f = files[file] - # Skip byhand elements - if f["type"] == "byhand": - continue - pkg = f["package"] - priority = f["priority"] - section = f["section"] - # FIXME: unhardcode - if section == "non-US/main": - section = "non-US" - type = get_type(f) - component = f["component"] - - if type == "dsc": - priority = "source" - if not new.has_key(pkg): - new[pkg] = {} - new[pkg]["priority"] = priority - new[pkg]["section"] = section - new[pkg]["type"] = type - new[pkg]["component"] = component - new[pkg]["files"] = [] - else: - old_type = new[pkg]["type"] - if old_type != type: - # source gets trumped by deb or udeb - if old_type == "dsc": - new[pkg]["priority"] = priority - new[pkg]["section"] = section - new[pkg]["type"] = type - new[pkg]["component"] = component - new[pkg]["files"].append(file) - if f.has_key("othercomponents"): - new[pkg]["othercomponents"] = f["othercomponents"] - - for suite in changes["suite"].keys(): - suite_id = database.get_suite_id(suite) - for pkg in new.keys(): - component_id = database.get_component_id(new[pkg]["component"]) - type_id = database.get_override_type_id(new[pkg]["type"]) - q = projectB.query("SELECT package FROM override WHERE package = '%s' AND suite = %s AND component = %s AND type = %s" % (pkg, suite_id, component_id, type_id)) - ql = q.getresult() - if ql: - for file in new[pkg]["files"]: - if files[file].has_key("new"): - del files[file]["new"] - del new[pkg] - - if changes["suite"].has_key("stable"): - print "WARNING: overrides will be added for stable!" - if changes["suite"].has_key("oldstable"): - print "WARNING: overrides will be added for OLDstable!" - for pkg in new.keys(): - if new[pkg].has_key("othercomponents"): - print "WARNING: %s already present in %s distribution." % (pkg, new[pkg]["othercomponents"]) - - return new - -################################################################################ - def indiv_sg_compare (a, b): """Sort by source name, source, version, 'have source', and finally by filename.""" @@ -210,7 +151,7 @@ def indiv_sg_compare (a, b): def sg_compare (a, b): a = a[1] b = b[1] - """Sort by have note, time of oldest upload.""" + """Sort by have note, source already in database and time of oldest upload.""" # Sort by have note a_note_state = a["note_state"] b_note_state = b["note_state"] @@ -218,6 +159,10 @@ def sg_compare (a, b): return -1 elif a_note_state > b_note_state: return 1 + # Sort by source already in database (descending) + source_in_database = cmp(a["source_in_database"], b["source_in_database"]) + if source_in_database: + return -source_in_database # Sort by time of oldest upload return cmp(a["oldest"], b["oldest"]) @@ -252,6 +197,9 @@ def sort_changes(changes_files): per_source[source]["list"].append(cache[filename]) # Determine oldest time and have note status for each source group for source in per_source.keys(): + q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source) + ql = q.getresult() + per_source[source]["source_in_database"] = len(ql)>0 source_list = per_source[source]["list"] first = source_list[0] oldest = os.stat(first["filename"])[stat.ST_MTIME] @@ -320,25 +268,8 @@ class Priority_Completer: ################################################################################ -def check_valid (new): - for pkg in new.keys(): - section = new[pkg]["section"] - priority = new[pkg]["priority"] - type = new[pkg]["type"] - new[pkg]["section id"] = database.get_section_id(section) - new[pkg]["priority id"] = database.get_priority_id(new[pkg]["priority"]) - # Sanity checks - if (section == "debian-installer" and type != "udeb") or \ - (section != "debian-installer" and type == "udeb"): - new[pkg]["section id"] = -1 - if (priority == "source" and type != "dsc") or \ - (priority != "source" and type == "dsc"): - new[pkg]["priority id"] = -1 - -################################################################################ - def print_new (new, indexed, file=sys.stdout): - check_valid(new) + queue.check_valid(new) broken = 0 index = 0 for pkg in new.keys(): @@ -366,24 +297,6 @@ def print_new (new, indexed, file=sys.stdout): ################################################################################ -def get_type (f): - # Determine the type - if f.has_key("dbtype"): - type = f["dbtype"] - elif f["type"] == "orig.tar.gz" or f["type"] == "tar.gz" or f["type"] == "diff.gz" or f["type"] == "dsc": - type = "dsc" - else: - utils.fubar("invalid type (%s) for new. Dazed, confused and sure as heck not continuing." % (type)) - - # Validate the override type - type_id = database.get_override_type_id(type) - if type_id == -1: - utils.fubar("invalid type (%s) for new. Say wha?" % (type)) - - return type - -################################################################################ - def index_range (index): if index == 1: return "1" @@ -426,9 +339,9 @@ def edit_new (new): section = section[:-3] if priority.endswith("[!]"): priority = priority[:-3] - for file in new[pkg]["files"]: - Upload.pkg.files[file]["section"] = section - Upload.pkg.files[file]["priority"] = priority + for f in new[pkg]["files"]: + Upload.pkg.files[f]["section"] = section + Upload.pkg.files[f]["priority"] = priority new[pkg]["section"] = section new[pkg]["priority"] = priority @@ -437,13 +350,13 @@ def edit_new (new): def edit_index (new, index): priority = new[index]["priority"] section = new[index]["section"] - type = new[index]["type"] + ftype = new[index]["type"] done = 0 while not done: print "\t".join([index, priority, section]) answer = "XXX" - if type != "dsc": + if ftype != "dsc": prompt = "[B]oth, Priority, Section, Done ? " else: prompt = "[S]ection, Done ? " @@ -492,9 +405,9 @@ def edit_index (new, index): # Reset the readline completer readline.set_completer(None) - for file in new[index]["files"]: - Upload.pkg.files[file]["section"] = section - Upload.pkg.files[file]["priority"] = priority + for f in new[index]["files"]: + Upload.pkg.files[f]["section"] = section + Upload.pkg.files[f]["priority"] = priority new[index]["priority"] = priority new[index]["section"] = section return new @@ -517,7 +430,7 @@ def edit_overrides (new): got_answer = 0 while not got_answer: answer = utils.our_raw_input(prompt) - if not utils.str_isnum(answer): + if not answer.isdigit(): answer = answer[:1].upper() if answer == "E" or answer == "D": got_answer = 1 @@ -566,6 +479,7 @@ def edit_note(note): if answer == 'A': return elif answer == 'Q': + end() sys.exit(0) Upload.pkg.changes["process-new note"] = note Upload.dump_vars(Cnf["Dir::Queue::New"]) @@ -580,17 +494,17 @@ def check_pkg (): sys.stdout = less_fd examine_package.display_changes(Upload.pkg.changes_file) files = Upload.pkg.files - for file in files.keys(): - if files[file].has_key("new"): - type = files[file]["type"] - if type == "deb": - examine_package.check_deb(file) - elif type == "dsc": - examine_package.check_dsc(file) + for f in files.keys(): + if files[f].has_key("new"): + ftype = files[f]["type"] + if ftype == "deb": + examine_package.check_deb(f) + elif ftype == "dsc": + examine_package.check_dsc(f) finally: sys.stdout = stdout_fd except IOError, e: - if errno.errorcode[e.errno] == 'EPIPE': + if e.errno == errno.EPIPE: utils.warn("[examine_package] Caught EPIPE; skipping.") pass else: @@ -606,9 +520,9 @@ def check_pkg (): def do_bxa_notification(): files = Upload.pkg.files summary = "" - for file in files.keys(): - if files[file]["type"] == "deb": - control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(file))) + for f in files.keys(): + if files[f]["type"] == "deb": + control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f))) summary += "\n" summary += "Package: %s\n" % (control.Find("Package")) summary += "Description: %s\n" % (control.Find("Description")) @@ -631,9 +545,9 @@ def add_overrides (new): priority_id = new[pkg]["priority id"] section_id = new[pkg]["section id"] projectB.query("INSERT INTO override (suite, component, type, package, priority, section, maintainer) VALUES (%s, %s, %s, '%s', %s, %s, '')" % (suite_id, component_id, type_id, pkg, priority_id, section_id)) - for file in new[pkg]["files"]: - if files[file].has_key("new"): - del files[file]["new"] + for f in new[pkg]["files"]: + if files[f].has_key("new"): + del files[f]["new"] del new[pkg] projectB.query("COMMIT WORK") @@ -650,9 +564,9 @@ def prod_maintainer (): answer = 'E' while answer == 'E': os.system("%s %s" % (editor, temp_filename)) - file = utils.open_file(temp_filename) - prod_message = "".join(file.readlines()) - file.close() + f = utils.open_file(temp_filename) + prod_message = "".join(f.readlines()) + f.close() print "Prod message:" print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1) prompt = "[P]rod, Edit, Abandon, Quit ?" @@ -667,6 +581,7 @@ def prod_maintainer (): if answer == 'A': return elif answer == 'Q': + end() sys.exit(0) # Otherwise, do the proding... user_email_address = utils.whoami() + " <%s>" % ( @@ -701,6 +616,14 @@ def do_new(): for suite in changes["suite"].keys(): override = Cnf.Find("Suite::%s::OverrideSuite" % (suite)) if override: + (olderr, newerr) = (database.get_suite_id(suite) == -1, + database.get_suite_id(override) == -1) + if olderr or newerr: + (oinv, newinv) = ("", "") + if olderr: oinv = "invalid " + if newerr: ninv = "invalid " + print "warning: overriding %ssuite %s to %ssuite %s" % ( + oinv, suite, ninv, override) del changes["suite"][suite] changes["suite"][override] = 1 # Validate suites @@ -713,7 +636,7 @@ def do_new(): done = 0 while not done: # Find out what's new - new = determine_new(changes, files) + new = queue.determine_new(changes, files, projectB) if not new: break @@ -764,6 +687,7 @@ def do_new(): elif answer == 'S': done = 1 elif answer == 'Q': + end() sys.exit(0) ################################################################################ @@ -774,6 +698,7 @@ def usage (exit_code=0): print """Usage: dak process-new [OPTION]... [CHANGES]... -a, --automatic automatic run -h, --help show this help and exit. + -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new -m, --manual-reject=MSG manual reject with `msg' -n, --no-action don't do anything -V, --version display the version number and exit""" @@ -788,10 +713,11 @@ def init(): Arguments = [('a',"automatic","Process-New::Options::Automatic"), ('h',"help","Process-New::Options::Help"), + ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"), ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"), ('n',"no-action","Process-New::Options::No-Action")] - for i in ["automatic", "help", "manual-reject", "no-action", "version"]: + for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir"]: if not Cnf.has_key("Process-New::Options::%s" % (i)): Cnf["Process-New::Options::%s" % (i)] = "" @@ -823,13 +749,13 @@ def do_byhand(): will_install = 1 byhand = [] - for file in files.keys(): - if files[file]["type"] == "byhand": - if os.path.exists(file): - print "W: %s still present; please process byhand components and try again." % (file) + for f in files.keys(): + if files[f]["type"] == "byhand": + if os.path.exists(f): + print "W: %s still present; please process byhand components and try again." % (f) will_install = 0 else: - byhand.append(file) + byhand.append(f) answer = "XXXX" if Options["No-Action"]: @@ -850,8 +776,8 @@ def do_byhand(): if answer == 'A': done = 1 - for file in byhand: - del files[file] + for f in byhand: + del files[f] elif answer == 'M': Upload.do_reject(1, Options["Manual-Reject"]) os.unlink(Upload.pkg.changes_file[:-8]+".dak") @@ -859,39 +785,134 @@ def do_byhand(): elif answer == 'S': done = 1 elif answer == 'Q': + end() sys.exit(0) ################################################################################ +def get_accept_lock(): + retry = 0 + while retry < 10: + try: + os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL) + retry = 10 + except OSError, e: + if e.errno == errno.EACCES or e.errno == errno.EEXIST: + retry += 1 + if (retry >= 10): + utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.") + else: + print("Unable to get accepted lock (try %d of 10)" % retry) + time.sleep(60) + else: + raise + +def move_to_dir (dest, perms=0660, changesperms=0664): + utils.move (Upload.pkg.changes_file, dest, perms=changesperms) + file_keys = Upload.pkg.files.keys() + for f in file_keys: + utils.move (f, dest, perms=perms) + +def is_source_in_queue_dir(qdir): + entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"]) + and x.endswith(".changes") ] + for entry in entries: + # read the .dak + u = queue.Upload(Cnf) + u.pkg.changes_file = entry + u.update_vars() + if not Upload.pkg.changes["architecture"].has_key("source"): + # another binary upload, ignore + continue + if Upload.pkg.changes["version"] != u.pkg.changes["version"]: + # another version, ignore + continue + # found it! + return True + return False + +def move_to_holding(suite, queue_dir): + print "Moving to %s holding area." % (suite.upper(),) + if Options["No-Action"]: + return + Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file]) + Upload.dump_vars(queue_dir) + move_to_dir(queue_dir) + os.unlink(Upload.pkg.changes_file[:-8]+".dak") + +def do_accept_stableupdate(suite, q): + (summary, short_summary) = Upload.build_summaries() + queue_dir = Cnf["Dir::Queue::%s" % (q,)] + if not Upload.pkg.changes["architecture"].has_key("source"): + # It is not a sourceful upload. So its source may be either in p-u + # holding, in new, in accepted or already installed. + if is_source_in_queue_dir(queue_dir): + # It's in p-u holding, so move it there. + print "Binary-only upload, source in %s." % (q,) + move_to_holding(suite, queue_dir) + elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]): + # It's in NEW. We expect the source to land in p-u holding + # pretty soon. + print "Binary-only upload, source in new." + move_to_holding(suite, queue_dir) + elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]): + # The source is in accepted, the binary cleared NEW: accept it. + print "Binary-only upload, source in accepted." + Upload.accept(summary, short_summary) + os.unlink(Upload.pkg.changes_file[:-8]+".dak") + elif Upload.source_exists(Upload.pkg.changes["source"], + Upload.pkg.changes["version"]): + # dak tells us that there is source available. At time of + # writing this means that it is installed, so put it into + # accepted. + print "Binary-only upload, source installed." + Upload.accept(summary, short_summary) + os.unlink(Upload.pkg.changes_file[:-8]+".dak") + else: + # We are handling a sourceful upload. Move to accepted if currently + # in p-u holding and to p-u holding otherwise. + if is_source_in_queue_dir(queue_dir): + print "Sourceful upload in %s, accepting." % (q,) + Upload.accept(summary, short_summary) + os.unlink(Upload.pkg.changes_file[:-8]+".dak") + else: + move_to_holding(suite, queue_dir) + def do_accept(): print "ACCEPT" if not Options["No-Action"]: - retry = 0 - while retry < 10: - try: - lock_fd = os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL) - retry = 10 - except OSError, e: - if errno.errorcode[e.errno] == 'EACCES' or errno.errorcode[e.errno] == 'EEXIST': - retry += 1 - if (retry >= 10): - utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.") - else: - print("Unable to get accepted lock (try %d of 10)" % retry) - time.sleep(60) - else: - raise + get_accept_lock() (summary, short_summary) = Upload.build_summaries() - Upload.accept(summary, short_summary) - os.unlink(Upload.pkg.changes_file[:-8]+".dak") - os.unlink(Cnf["Process-New::AcceptedLockFile"]) + try: + if Cnf.FindB("Dinstall::SecurityQueueHandling"): + Upload.dump_vars(Cnf["Dir::Queue::Embargoed"]) + move_to_dir(Cnf["Dir::Queue::Embargoed"]) + Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"]) + # Check for override disparities + Upload.Subst["__SUMMARY__"] = summary + else: + # Stable updates need to be copied to proposed-updates holding + # area instead of accepted. Sourceful uploads need to go + # to it directly, binaries only if the source has not yet been + # accepted into p-u. + for suite, q in [("proposed-updates", "ProposedUpdates"), + ("oldstable-proposed-updates", "OldProposedUpdates")]: + if not Upload.pkg.changes["distribution"].has_key(suite): + continue + return do_accept_stableupdate(suite, q) + # Just a normal upload, accept it... + Upload.accept(summary, short_summary) + os.unlink(Upload.pkg.changes_file[:-8]+".dak") + finally: + if not Options["No-Action"]: + os.unlink(Cnf["Process-New::AcceptedLockFile"]) def check_status(files): new = byhand = 0 - for file in files.keys(): - if files[file]["type"] == "byhand": + for f in files.keys(): + if files[f]["type"] == "byhand": byhand = 1 - elif files[file].has_key("new"): + elif files[f].has_key("new"): new = 1 return (new, byhand) @@ -934,6 +955,58 @@ def end(): ################################################################################ +def do_comments(dir, opref, npref, line, fn): + for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]: + lines = open("%s/%s" % (dir, comm)).readlines() + if len(lines) == 0 or lines[0] != line + "\n": continue + changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_") + and x.endswith(".changes") ] + changes_files = sort_changes(changes_files) + for f in changes_files: + f = utils.validate_changes_file_arg(f, 0) + if not f: continue + print "\n" + f + fn(f, "".join(lines[1:])) + + if opref != npref and not Options["No-Action"]: + newcomm = npref + comm[len(opref):] + os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm)) + +################################################################################ + +def comment_accept(changes_file, comments): + Upload.pkg.changes_file = changes_file + Upload.init_vars() + Upload.update_vars() + Upload.update_subst() + files = Upload.pkg.files + + if not recheck(): + return # dak wants to REJECT, crap + + (new, byhand) = check_status(files) + if not new and not byhand: + do_accept() + +################################################################################ + +def comment_reject(changes_file, comments): + Upload.pkg.changes_file = changes_file + Upload.init_vars() + Upload.update_vars() + Upload.update_subst() + + if not recheck(): + pass # dak has its own reasons to reject as well, which is fine + + reject(comments) + print "REJECT\n" + reject_message, + if not Options["No-Action"]: + Upload.do_reject(0, reject_message) + os.unlink(Upload.pkg.changes_file[:-8]+".dak") + +################################################################################ + def main(): changes_files = init() if len(changes_files) > 50: @@ -942,18 +1015,26 @@ def main(): # Kill me now? **FIXME** Cnf["Dinstall::Options::No-Mail"] = "" - bcc = "X-DAK: dak process-new\nX-Katie: this header is obsolete" + bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $" if Cnf.has_key("Dinstall::Bcc"): Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"]) else: Upload.Subst["__BCC__"] = bcc - for changes_file in changes_files: - changes_file = utils.validate_changes_file_arg(changes_file, 0) - if not changes_file: - continue - print "\n" + changes_file - do_pkg (changes_file) + commentsdir = Cnf.get("Process-New::Options::Comments-Dir","") + if commentsdir: + if changes_files != []: + sys.stderr.write("Can't specify any changes files if working with comments-dir") + sys.exit(1) + do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept) + do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject) + else: + for changes_file in changes_files: + changes_file = utils.validate_changes_file_arg(changes_file, 0) + if not changes_file: + continue + print "\n" + changes_file + do_pkg (changes_file) end()