X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=lisa;h=d98c0df683c77735d3fe47c512c5209abfb52f2e;hb=fb3d44c5e9b4a010f56cffd8fd5e35d6221805f9;hp=819623ac0225c8c43ff11d90fb74eae16d8e45ec;hpb=6f6e200c45974e79d7b556b4b20dff6fa7fe9fa2;p=dak.git diff --git a/lisa b/lisa index 819623ac..d98c0df6 100755 --- a/lisa +++ b/lisa @@ -1,8 +1,8 @@ #!/usr/bin/env python # Handles NEW and BYHAND packages -# Copyright (C) 2001, 2002 James Troup -# $Id: lisa,v 1.16 2002-05-23 09:54:23 troup Exp $ +# Copyright (C) 2001, 2002, 2003, 2004, 2005 James Troup +# $Id: lisa,v 1.31 2005-11-15 09:50:32 ajt 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 @@ -37,12 +37,12 @@ ################################################################################ -import copy, errno, os, readline, string, stat, sys, tempfile; +import copy, errno, os, readline, stat, sys, time; import apt_pkg, apt_inst; import db_access, fernanda, katie, logging, utils; # Globals -lisa_version = "$Revision: 1.16 $"; +lisa_version = "$Revision: 1.31 $"; Cnf = None; Options = None; @@ -62,7 +62,7 @@ reject_message = ""; def reject (str, prefix="Rejected: "): global reject_message; if str: - reject_message = reject_message + prefix + str + "\n"; + reject_message += prefix + str + "\n"; def recheck(): global reject_message; @@ -70,12 +70,16 @@ def recheck(): reject_message = ""; for file 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): + 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 not Katie.pkg.changes["architecture"].has_key("source") \ - and not Katie.source_exists(source_package, source_version): + and not Katie.source_exists(source_package, source_version, Katie.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): @@ -97,15 +101,17 @@ def recheck(): print "REJECT\n" + reject_message,; prompt = "[R]eject, Skip, Quit ?"; - while string.find(prompt, answer) == -1: + while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt); m = katie.re_default_answer.match(prompt); if answer == "": answer = m.group(1); - answer = string.upper(answer[:1]); + answer = answer[:1].upper(); if answer == 'R': Katie.do_reject(0, reject_message); + os.unlink(Katie.pkg.changes_file[:-8]+".katie"); + return 0; elif answer == 'S': return 0; elif answer == 'Q': @@ -170,6 +176,8 @@ def determine_new (changes, files): 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"]); @@ -205,8 +213,10 @@ def sg_compare (a, b): # Sort by have note a_note_state = a["note_state"]; b_note_state = b["note_state"]; - if a_note_state != b_note_state: - return cmp(a, b); + if a_note_state < b_note_state: + return -1; + elif a_note_state > b_note_state: + return 1; # Sort by time of oldest upload return cmp(a["oldest"], b["oldest"]); @@ -243,13 +253,13 @@ def sort_changes(changes_files): for source in per_source.keys(): source_list = per_source[source]["list"]; first = source_list[0]; - oldest = os.stat(first["filename"])[stat.ST_CTIME]; + oldest = os.stat(first["filename"])[stat.ST_MTIME]; have_note = 0; for d in per_source[source]["list"]: - ctime = os.stat(d["filename"])[stat.ST_CTIME]; - if ctime < oldest: - oldest = ctime; - have_note = have_note + (d.has_key("lisa note")); + mtime = os.stat(d["filename"])[stat.ST_MTIME]; + if mtime < oldest: + oldest = mtime; + have_note += (d.has_key("lisa note")); per_source[source]["oldest"] = oldest; if not have_note: per_source[source]["note_state"] = 0; # none @@ -258,10 +268,10 @@ def sort_changes(changes_files): else: per_source[source]["note_state"] = 2; # all per_source[source]["list"].sort(indiv_sg_compare); - per_source_items = per_source.items(); + per_source_items = per_source.items(); per_source_items.sort(sg_compare); for i in per_source_items: - for j in i[1]["list"]: + for j in i[1]["list"]: sorted_list.append(j["filename"]); return sorted_list; @@ -331,20 +341,20 @@ def print_new (new, indexed, file=sys.stdout): broken = 0; index = 0; for pkg in new.keys(): - index = index + 1; + index += 1; section = new[pkg]["section"]; priority = new[pkg]["priority"]; if new[pkg]["section id"] == -1: - section = section + "[!]"; + section += "[!]"; broken = 1; if new[pkg]["priority id"] == -1: - priority = priority + "[!]"; + priority += "[!]"; broken = 1; if indexed: line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section); else: line = "%-20s %-20s %-20s" % (pkg, priority, section); - line = string.strip(line)+'\n'; + line = line.strip()+'\n'; file.write(line); note = Katie.pkg.changes.get("lisa note"); if note: @@ -384,9 +394,7 @@ def index_range (index): def edit_new (new): # Write the current data to a temporary file - temp_filename = tempfile.mktemp(); - fd = os.open(temp_filename, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700); - os.close(fd); + temp_filename = utils.temp_filename(); temp_file = utils.open_file(temp_filename, 'w'); print_new (new, 0, temp_file); temp_file.close(); @@ -402,10 +410,10 @@ def edit_new (new): os.unlink(temp_filename); # Parse the new data for line in lines: - line = string.strip(line[:-1]); + line = line.strip(); if line == "": continue; - s = string.split(line); + s = line.split(); # Pad the list if necessary s[len(s):3] = [None] * (3-len(s)); (pkg, priority, section) = s[:3]; @@ -413,9 +421,9 @@ def edit_new (new): utils.warn("Ignoring unknown package '%s'" % (pkg)); else: # Strip off any invalid markers, print_new will readd them. - if section[-3:] == "[!]": + if section.endswith("[!]"): section = section[:-3]; - if priority[-3:] == "[!]": + if priority.endswith("[!]"): priority = priority[:-3]; for file in new[pkg]["files"]: Katie.pkg.files[file]["section"] = section; @@ -431,7 +439,7 @@ def edit_index (new, index): type = new[index]["type"]; done = 0 while not done: - print string.join([index, priority, section], '\t'); + print "\t".join([index, priority, section]); answer = "XXX"; if type != "dsc": @@ -440,12 +448,12 @@ def edit_index (new, index): prompt = "[S]ection, Done ? "; edit_priority = edit_section = 0; - while string.find(prompt, answer) == -1: + while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt); m = katie.re_default_answer.match(prompt) if answer == "": answer = m.group(1) - answer = string.upper(answer[:1]) + answer = answer[:1].upper() if answer == 'P': edit_priority = 1; @@ -461,8 +469,8 @@ def edit_index (new, index): readline.set_completer(Priorities.complete); got_priority = 0; while not got_priority: - new_priority = string.strip(utils.our_raw_input("New priority: ")); - if Priorities.priorities.count(new_priority) == 0: + new_priority = utils.our_raw_input("New priority: ").strip(); + if new_priority not in Priorities.priorities: print "E: '%s' is not a valid priority, try again." % (new_priority); else: got_priority = 1; @@ -473,8 +481,8 @@ def edit_index (new, index): readline.set_completer(Sections.complete); got_section = 0; while not got_section: - new_section = string.strip(utils.our_raw_input("New section: ")); - if Sections.sections.count(new_section) == 0: + new_section = utils.our_raw_input("New section: ").strip(); + if new_section not in Sections.sections: print "E: '%s' is not a valid section, try again." % (new_section); else: got_section = 1; @@ -500,7 +508,7 @@ def edit_overrides (new): new_index = {}; index = 0; for i in new.keys(): - index = index + 1; + index += 1; new_index[index] = i; prompt = "(%s) edit override , Editor, Done ? " % (index_range(index)); @@ -508,13 +516,14 @@ def edit_overrides (new): got_answer = 0 while not got_answer: answer = utils.our_raw_input(prompt); - answer = string.upper(answer[:1]); + if not utils.str_isnum(answer): + answer = answer[:1].upper(); if answer == "E" or answer == "D": got_answer = 1; elif katie.re_isanum.match (answer): answer = int(answer); if (answer < 1) or (answer > index): - print "%s is not a valid index (%s). Please retry." % (index_range(index), answer); + print "%s is not a valid index (%s). Please retry." % (answer, index_range(index)); else: got_answer = 1; @@ -531,9 +540,7 @@ def edit_overrides (new): def edit_note(note): # Write the current data to a temporary file - temp_filename = tempfile.mktemp(); - fd = os.open(temp_filename, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700); - os.close(fd); + temp_filename = utils.temp_filename(); temp_file = utils.open_file(temp_filename, 'w'); temp_file.write(note); temp_file.close(); @@ -542,18 +549,18 @@ def edit_note(note): while answer == 'E': os.system("%s %s" % (editor, temp_filename)) temp_file = utils.open_file(temp_filename); - note = string.rstrip(temp_file.read()); + note = temp_file.read().rstrip(); temp_file.close(); print "Note:"; print utils.prefix_multi_line_string(note," "); prompt = "[D]one, Edit, Abandon, Quit ?" answer = "XXX"; - while string.find(prompt, answer) == -1: + while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt); m = katie.re_default_answer.search(prompt); if answer == "": answer = m.group(1); - answer = string.upper(answer[:1]); + answer = answer[:1].upper(); os.unlink(temp_filename); if answer == 'A': return; @@ -566,7 +573,7 @@ def edit_note(note): def check_pkg (): try: - less_fd = os.popen("less -", 'w', 0); + less_fd = os.popen("less -R -", 'w', 0); stdout_fd = sys.stdout; try: sys.stdout = less_fd; @@ -601,12 +608,12 @@ def do_bxa_notification(): for file in files.keys(): if files[file]["type"] == "deb": control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(file))); - summary = summary + "\n"; - summary = summary + "Package: %s\n" % (control.Find("Package")); - summary = summary + "Description: %s\n" % (control.Find("Description")); + summary += "\n"; + summary += "Package: %s\n" % (control.Find("Package")); + summary += "Description: %s\n" % (control.Find("Description")); Katie.Subst["__BINARY_DESCRIPTIONS__"] = summary; bxa_mail = utils.TemplateSubst(Katie.Subst,Cnf["Dir::Templates"]+"/lisa.bxa_notification"); - utils.send_mail(bxa_mail,""); + utils.send_mail(bxa_mail); ################################################################################ @@ -622,7 +629,7 @@ def add_overrides (new): type_id = db_access.get_override_type_id(new[pkg]["type"]); priority_id = new[pkg]["priority id"]; section_id = new[pkg]["section id"]; - projectB.query("INSERT INTO override (suite, component, type, package, priority, section) VALUES (%s, %s, %s, '%s', %s, %s)" % (suite_id, component_id, type_id, pkg, priority_id, 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"]; @@ -635,6 +642,52 @@ def add_overrides (new): ################################################################################ +def prod_maintainer (): + # Here we prepare an editor and get them ready to prod... + temp_filename = utils.temp_filename(); + editor = os.environ.get("EDITOR","vi") + 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(); + print "Prod message:"; + print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1); + prompt = "[P]rod, Edit, Abandon, Quit ?" + answer = "XXX"; + while prompt.find(answer) == -1: + answer = utils.our_raw_input(prompt); + m = katie.re_default_answer.search(prompt); + if answer == "": + answer = m.group(1); + answer = answer[:1].upper(); + os.unlink(temp_filename); + if answer == 'A': + return; + elif answer == 'Q': + sys.exit(0); + # Otherwise, do the proding... + user_email_address = utils.whoami() + " <%s>" % ( + Cnf["Dinstall::MyAdminAddress"]); + + Subst = Katie.Subst; + + Subst["__FROM_ADDRESS__"] = user_email_address; + Subst["__PROD_MESSAGE__"] = prod_message; + Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]; + + prod_mail_message = utils.TemplateSubst( + Subst,Cnf["Dir::Templates"]+"/lisa.prod"); + + # Send the prod mail if appropriate + if not Cnf["Dinstall::Options::No-Mail"]: + utils.send_mail(prod_mail_message); + + print "Sent proding message"; + +################################################################################ + def do_new(): print "NEW\n"; files = Katie.pkg.files; @@ -677,16 +730,16 @@ def do_new(): print "W: [!] marked entries must be fixed before package can be processed."; if note: print "W: note must be removed before package can be processed."; - prompt = prompt + "Remove note, "; + prompt += "Remove note, "; - prompt = prompt + "Edit overrides, Check, Manual reject, Note edit, [S]kip, Quit ?"; + prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"; - while string.find(prompt, answer) == -1: + while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt); m = katie.re_default_answer.search(prompt); if answer == "": answer = m.group(1) - answer = string.upper(answer[:1]) + answer = answer[:1].upper() if answer == 'A': done = add_overrides (new); @@ -701,8 +754,10 @@ def do_new(): done = 1; elif answer == 'N': edit_note(changes.get("lisa note", "")); + elif answer == 'P': + prod_maintainer(); elif answer == 'R': - confirm = string.lower(utils.our_raw_input("Really clear note (y/N)? ")); + confirm = utils.our_raw_input("Really clear note (y/N)? ").lower(); if confirm == "y": del changes["lisa note"]; elif answer == 'S': @@ -790,12 +845,12 @@ def do_byhand(): else: prompt = "Manual reject, [S]kip, Quit ?"; - while string.find(prompt, answer) == -1: + while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt); m = katie.re_default_answer.search(prompt); if answer == "": answer = m.group(1); - answer = string.upper(answer[:1]); + answer = answer[:1].upper(); if answer == 'A': done = 1; @@ -815,9 +870,25 @@ def do_byhand(): def do_accept(): print "ACCEPT"; if not Options["No-Action"]: + retry = 0; + while retry < 10: + try: + lock_fd = os.open(Cnf["Lisa::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 jennifer is already running."); + else: + print("Unable to get accepted lock (try %d of 10)" % retry); + time.sleep(60); + else: + raise; (summary, short_summary) = Katie.build_summaries(); Katie.accept(summary, short_summary); os.unlink(Katie.pkg.changes_file[:-8]+".katie"); + os.unlink(Cnf["Lisa::AcceptedLockFile"]); def check_status(files): new = byhand = 0; @@ -875,7 +946,7 @@ def main(): # Kill me now? **FIXME** Cnf["Dinstall::Options::No-Mail"] = ""; - bcc = "X-Katie: %s" % (lisa_version); + bcc = "X-Katie: lisa %s" % (lisa_version); if Cnf.has_key("Dinstall::Bcc"): Katie.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"]); else: