def get_reject_reason(reason=''): """get reason for rejection @rtype: str @return: string giving the reason for the rejection or C{None} if the rejection should be cancelled """ answer = 'E' if Options['Automatic']: answer = 'R' while answer == 'E': reason = utils.call_editor(reason) print "Reject message:" print utils.prefix_multi_line_string(reason, " ", include_blank_lines=1) prompt = "[R]eject, Edit, Abandon, Quit ?" answer = "XXX" while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.search(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer == 'Q': sys.exit(0) if answer == 'R': return reason return None
def edit_overrides (new, upload, session): print done = 0 while not done: print_new (new, upload, indexed=1) new_index = {} index = 0 for i in new.keys(): index += 1 new_index[index] = i prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index)) got_answer = 0 while not got_answer: answer = utils.our_raw_input(prompt) if not answer.isdigit(): answer = answer[:1].upper() if answer == "E" or answer == "D": got_answer = 1 elif re_isanum.match (answer): answer = int(answer) if (answer < 1) or (answer > index): print "%s is not a valid index (%s). Please retry." % (answer, index_range(index)) else: got_answer = 1 if answer == 'E': edit_new(new, upload) elif answer == 'D': done = 1 else: edit_index (new, upload, new_index[answer]) return new
def edit_overrides (new, upload, session): print done = 0 while not done: print_new (upload, new, indexed=1, session=session) prompt = "edit override <n>, Editor, Done ? " got_answer = 0 while not got_answer: answer = utils.our_raw_input(prompt) if not answer.isdigit(): answer = answer[:1].upper() if answer == "E" or answer == "D": got_answer = 1 elif re_isanum.match (answer): answer = int(answer) if answer < 1 or answer > len(new): print "{0} is not a valid index. Please retry.".format(answer) else: got_answer = 1 if answer == 'E': new = edit_new(new, upload, session) elif answer == 'D': done = 1 else: edit_index (new, upload, answer - 1) return new
def recheck(upload, session): # STU: I'm not sure, but I don't thin kthis is necessary any longer: upload.recheck(session) if len(upload.rejects) > 0: answer = "XXX" if Options["No-Action"] or Options["Automatic"] or Options["Trainee"]: answer = 'S' print "REJECT\n%s" % '\n'.join(upload.rejects) prompt = "[R]eject, Skip, Quit ?" while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.match(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer == 'R': upload.do_reject(manual=0, reject_message='\n'.join(upload.rejects)) upload.pkg.remove_known_changes(session=session) session.commit() return 0 elif answer == 'S': return 0 elif answer == 'Q': end() sys.exit(0) return 1
def edit_overrides(new, upload, session): print done = 0 while not done: print_new(upload, new, indexed=1, session=session) prompt = "edit override <n>, Editor, Done ? " got_answer = 0 while not got_answer: answer = utils.our_raw_input(prompt) if not answer.isdigit(): answer = answer[:1].upper() if answer == "E" or answer == "D": got_answer = 1 elif re_isanum.match(answer): answer = int(answer) if answer < 1 or answer > len(new): print "{0} is not a valid index. Please retry.".format( answer) else: got_answer = 1 if answer == 'E': new = edit_new(new, upload, session) elif answer == 'D': done = 1 else: edit_index(new, upload, answer - 1) return new
def edit_transitions(): """ Edit the defined transitions. """ trans_file = Cnf["Dinstall::ReleaseTransitions"] edit_file = temp_transitions_file(load_transitions(trans_file)) editor = os.environ.get("EDITOR", "vi") while True: result = os.system("%s %s" % (editor, edit_file)) if result != 0: os.unlink(edit_file) utils.fubar("%s invocation failed for %s, not removing tempfile." % (editor, edit_file)) # Now try to load the new file test = load_transitions(edit_file) if test is None: # Edit is broken print("Edit was unparsable.") prompt = "[E]dit again, Drop changes?" default = "E" else: print("Edit looks okay.\n") print("The following transitions are defined:") print( "------------------------------------------------------------------------" ) transition_info(test) prompt = "[S]ave, Edit again, Drop changes?" default = "S" answer = "XXX" while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) if answer == "": answer = default answer = answer[:1].upper() if answer == 'E': continue elif answer == 'D': os.unlink(edit_file) print("OK, discarding changes") sys.exit(0) elif answer == 'S': # Ready to save break else: print("You pressed something you shouldn't have :(") sys.exit(1) # We seem to be done and also have a working file. Copy over. write_transitions_from_file(edit_file) os.unlink(edit_file) print("Transitions file updated.")
def edit_transitions(): """ Edit the defined transitions. """ trans_file = Cnf["Dinstall::ReleaseTransitions"] edit_file = temp_transitions_file(load_transitions(trans_file)) editor = os.environ.get("EDITOR", "vi") while True: result = os.system("%s %s" % (editor, edit_file)) if result != 0: os.unlink(edit_file) utils.fubar("%s invocation failed for %s, not removing tempfile." % (editor, edit_file)) # Now try to load the new file test = load_transitions(edit_file) if test == None: # Edit is broken print "Edit was unparsable." prompt = "[E]dit again, Drop changes?" default = "E" else: print "Edit looks okay.\n" print "The following transitions are defined:" print "------------------------------------------------------------------------" transition_info(test) prompt = "[S]ave, Edit again, Drop changes?" default = "S" answer = "XXX" while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) if answer == "": answer = default answer = answer[:1].upper() if answer == 'E': continue elif answer == 'D': os.unlink(edit_file) print "OK, discarding changes" sys.exit(0) elif answer == 'S': # Ready to save break else: print "You pressed something you shouldn't have :(" sys.exit(1) # We seem to be done and also have a working file. Copy over. write_transitions_from_file(edit_file) os.unlink(edit_file) print "Transitions file updated."
def main(): cnf = Config() Arguments = [('h',"help","Import-LDAP-Fingerprints::Options::Help")] for i in [ "help" ]: if not cnf.has_key("Import-LDAP-Fingerprints::Options::%s" % (i)): cnf["Import-LDAP-Fingerprints::Options::%s" % (i)] = "" apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) Options = cnf.subtree("Import-LDAP-Fingerprints::Options") if Options["Help"]: usage() session = DBConn().session() LDAPDn = cnf["Import-LDAP-Fingerprints::LDAPDn"] LDAPServer = cnf["Import-LDAP-Fingerprints::LDAPServer"] l = ldap.open(LDAPServer) l.simple_bind_s("","") Attrs = l.search_s(LDAPDn, ldap.SCOPE_ONELEVEL, "(&(keyfingerprint=*)(gidnumber=%s))" % (cnf["Import-Users-From-Passwd::ValidGID"]), ["uid", "keyfingerprint", "cn", "mn", "sn"]) # Our database session is already in a transaction # Sync LDAP with DB db_fin_uid = {} db_uid_name = {} ldap_fin_uid_id = {} q = session.execute(""" SELECT f.fingerprint, f.id, u.uid FROM fingerprint f, uid u WHERE f.uid = u.id UNION SELECT f.fingerprint, f.id, null FROM fingerprint f where f.uid is null""") for i in q.fetchall(): (fingerprint, fingerprint_id, uid) = i db_fin_uid[fingerprint] = (uid, fingerprint_id) q = session.execute("SELECT id, name FROM uid") for i in q.fetchall(): (uid, name) = i db_uid_name[uid] = name for i in Attrs: entry = i[1] fingerprints = entry["keyFingerPrint"] uid_name = entry["uid"][0] name = get_ldap_name(entry) uid = get_or_set_uid(uid_name, session) uid_id = uid.uid_id if not db_uid_name.has_key(uid_id) or db_uid_name[uid_id] != name: session.execute("UPDATE uid SET name = :name WHERE id = :uidid", {'name': name, 'uidid': uid_id}) print "Assigning name of %s as %s" % (uid_name, name) for fingerprint in fingerprints: ldap_fin_uid_id[fingerprint] = (uid_name, uid_id) if db_fin_uid.has_key(fingerprint): (existing_uid, fingerprint_id) = db_fin_uid[fingerprint] if not existing_uid: session.execute("UPDATE fingerprint SET uid = :uidid WHERE id = :fprid", {'uidid': uid_id, 'fprid': fingerprint_id}) print "Assigning %s to 0x%s." % (uid_name, fingerprint) elif existing_uid == uid_name: pass elif '@' not in existing_uid: session.execute("UPDATE fingerprint SET uid = :uidid WHERE id = :fprid", {'uidid': uid_id, 'fprid': fingerprint_id}) print "Promoting DM %s to DD %s with keyid 0x%s." % (existing_uid, uid_name, fingerprint) else: utils.warn("%s has %s in LDAP, but database says it should be %s." % \ (uid_name, fingerprint, existing_uid)) # Try to update people who sign with non-primary key q = session.execute("SELECT fingerprint, id FROM fingerprint WHERE uid is null") for i in q.fetchall(): (fingerprint, fingerprint_id) = i cmd = "gpg --no-default-keyring %s --fingerprint %s" \ % (utils.gpg_keyring_args(), fingerprint) (result, output) = commands.getstatusoutput(cmd) if result == 0: m = re_gpg_fingerprint.search(output) if not m: print output utils.fubar("0x%s: No fingerprint found in gpg output but it returned 0?\n%s" % \ (fingerprint, utils.prefix_multi_line_string(output, " [GPG output:] "))) primary_key = m.group(1) primary_key = primary_key.replace(" ","") if not ldap_fin_uid_id.has_key(primary_key): utils.warn("0x%s (from 0x%s): no UID found in LDAP" % (primary_key, fingerprint)) else: (uid, uid_id) = ldap_fin_uid_id[primary_key] session.execute("UPDATE fingerprint SET uid = :uid WHERE id = :fprid", {'uid': uid_id, 'fprid': fingerprint_id}) print "Assigning %s to 0x%s." % (uid, fingerprint) else: extra_keyrings = "" for keyring in cnf.value_list("Import-LDAP-Fingerprints::ExtraKeyrings"): extra_keyrings += " --keyring=%s" % (keyring) cmd = "gpg %s %s --list-key %s" \ % (utils.gpg_keyring_args(), extra_keyrings, fingerprint) (result, output) = commands.getstatusoutput(cmd) if result != 0: cmd = "gpg --keyserver=%s --allow-non-selfsigned-uid --recv-key %s" % (cnf["Import-LDAP-Fingerprints::KeyServer"], fingerprint) (result, output) = commands.getstatusoutput(cmd) if result != 0: print "0x%s: NOT found on keyserver." % (fingerprint) print cmd print result print output continue else: cmd = "gpg --list-key %s" % (fingerprint) (result, output) = commands.getstatusoutput(cmd) if result != 0: print "0x%s: --list-key returned error after --recv-key didn't." % (fingerprint) print cmd print result print output continue m = re_debian_address.search(output) if m: guess_uid = m.group(1) else: guess_uid = "???" name = " ".join(output.split('\n')[0].split()[3:]) print "0x%s -> %s -> %s" % (fingerprint, name, guess_uid) # FIXME: make me optionally non-interactive # FIXME: default to the guessed ID uid = None while not uid: uid = utils.our_raw_input("Map to which UID ? ") Attrs = l.search_s(LDAPDn,ldap.SCOPE_ONELEVEL,"(uid=%s)" % (uid), ["cn","mn","sn"]) if not Attrs: print "That UID doesn't exist in LDAP!" uid = None else: entry = Attrs[0][1] name = get_ldap_name(entry) prompt = "Map to %s - %s (y/N) ? " % (uid, name.replace(" "," ")) yn = utils.our_raw_input(prompt).lower() if yn == "y": uid_o = get_or_set_uid(uid, session=session) uid_id = uid_o.uid_id session.execute("UPDATE fingerprint SET uid = :uidid WHERE id = :fprid", {'uidid': uid_id, 'fprid': fingerprint_id}) print "Assigning %s to 0x%s." % (uid, fingerprint) else: uid = None # Commit it all session.commit()
def do_new(upload, upload_copy, handler, session): cnf = Config() run_user_inspect_command(upload, upload_copy) # The main NEW processing loop done = False missing = [] while not done: queuedir = upload.policy_queue.path byhand = upload.byhand missing = handler.missing_overrides(hints=missing) broken = not check_valid(missing, session) changesname = os.path.basename(upload.changes.changesname) print print changesname print "-" * len(changesname) print print " Target: {0}".format(upload.target_suite.suite_name) print " Changed-By: {0}".format(upload.changes.changedby) print #if len(byhand) == 0 and len(missing) == 0: # break if missing: print "NEW\n" answer = "XXX" if Options["No-Action"] or Options["Automatic"]: answer = 'S' note = print_new(upload, missing, indexed=0, session=session) prompt = "" has_unprocessed_byhand = False for f in byhand: path = os.path.join(queuedir, f.filename) if not f.processed and os.path.exists(path): print "W: {0} still present; please process byhand components and try again".format(f.filename) has_unprocessed_byhand = True if not has_unprocessed_byhand and not broken and not note: if len(missing) == 0: prompt = "Accept, " answer = 'A' else: prompt = "Add overrides, " if broken: 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 += "RemOve all notes, Remove note, " prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?" while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.search(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer in ( 'A', 'E', 'M', 'O', 'R' ) and Options["Trainee"]: utils.warn("Trainees can't do that") continue if answer == 'A' and not Options["Trainee"]: add_overrides(missing, upload.target_suite, session) if Config().find_b("Dinstall::BXANotify"): do_bxa_notification(missing, upload, session) handler.accept() done = True Logger.log(["NEW ACCEPT", upload.changes.changesname]) elif answer == 'C': check_pkg(upload, upload_copy, session) elif answer == 'E' and not Options["Trainee"]: missing = edit_overrides (missing, upload, session) elif answer == 'M' and not Options["Trainee"]: reason = Options.get('Manual-Reject', '') + "\n" reason = reason + "\n\n=====\n\n".join([n.comment for n in get_new_comments(upload.policy_queue, upload.changes.source, session=session)]) reason = get_reject_reason(reason) if reason is not None: Logger.log(["NEW REJECT", upload.changes.changesname]) handler.reject(reason) done = True elif answer == 'N': if edit_note(get_new_comments(upload.policy_queue, upload.changes.source, session=session), upload, session, bool(Options["Trainee"])) == 0: end() sys.exit(0) elif answer == 'P' and not Options["Trainee"]: if prod_maintainer(get_new_comments(upload.policy_queue, upload.changes.source, session=session), upload) == 0: end() sys.exit(0) Logger.log(["NEW PROD", upload.changes.changesname]) elif answer == 'R' and not Options["Trainee"]: confirm = utils.our_raw_input("Really clear note (y/N)? ").lower() if confirm == "y": for c in get_new_comments(upload.policy_queue, upload.changes.source, upload.changes.version, session=session): session.delete(c) session.commit() elif answer == 'O' and not Options["Trainee"]: confirm = utils.our_raw_input("Really clear all notes (y/N)? ").lower() if confirm == "y": for c in get_new_comments(upload.policy_queue, upload.changes.source, session=session): session.delete(c) session.commit() elif answer == 'S': done = True elif answer == 'Q': end() sys.exit(0) if handler.get_action(): print "PENDING %s\n" % handler.get_action()
def edit_index (new, upload, index): package = new[index]['package'] priority = new[index]["priority"] section = new[index]["section"] ftype = new[index]["type"] done = 0 while not done: print "\t".join([package, priority, section]) answer = "XXX" if ftype != "dsc": prompt = "[B]oth, Priority, Section, Done ? " else: prompt = "[S]ection, Done ? " edit_priority = edit_section = 0 while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.match(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer == 'P': edit_priority = 1 elif answer == 'S': edit_section = 1 elif answer == 'B': edit_priority = edit_section = 1 elif answer == 'D': done = 1 # Edit the priority if edit_priority: readline.set_completer(Priorities.complete) got_priority = 0 while not got_priority: 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 priority = new_priority # Edit the section if edit_section: readline.set_completer(Sections.complete) got_section = 0 while not got_section: 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 section = new_section # Reset the readline completer readline.set_completer(None) new[index]["priority"] = priority new[index]["section"] = section if section.find('/') != -1: component = section.split('/', 1)[0] else: component = 'main' new[index]['component'] = component return new
def update_db(self): # Ok, try and find the configuration table print("Determining dak database revision ...") cnf = Config() logger = Logger('update-db') modules = [] try: # Build a connect string if "DB::Service" in cnf: connect_str = "service=%s" % cnf["DB::Service"] else: connect_str = "dbname=%s" % (cnf["DB::Name"]) if "DB::Host" in cnf and cnf["DB::Host"] != '': connect_str += " host=%s" % (cnf["DB::Host"]) if "DB::Port" in cnf and cnf["DB::Port"] != '-1': connect_str += " port=%d" % (int(cnf["DB::Port"])) self.db = psycopg2.connect(connect_str) db_role = cnf.get("DB::Role") if db_role: self.db.cursor().execute('SET ROLE "{}"'.format(db_role)) except Exception as e: print("FATAL: Failed connect to database (%s)" % str(e)) sys.exit(1) database_revision = int(self.get_db_rev()) logger.log(['transaction id before update: %s' % self.get_transaction_id()]) if database_revision == -1: print("dak database schema predates update-db.") print("") print("This script will attempt to upgrade it to the lastest, but may fail.") print("Please make sure you have a database backup handy. If you don't, press Ctrl-C now!") print("") print("Continuing in five seconds ...") time.sleep(5) print("") print("Attempting to upgrade pre-zero database to zero") self.update_db_to_zero() database_revision = 0 dbfiles = glob(os.path.join(os.path.dirname(__file__), 'dakdb/update*.py')) required_database_schema = max(int(x) for x in findall(r'update(\d+).py', " ".join(dbfiles))) print("dak database schema at %d" % database_revision) print("dak version requires schema %d" % required_database_schema) if database_revision < required_database_schema: print("\nUpdates to be applied:") for i in range(database_revision, required_database_schema): i += 1 dakdb = __import__("dakdb", globals(), locals(), ['update' + str(i)]) update_module = getattr(dakdb, "update" + str(i)) print("Update %d: %s" % (i, next(s for s in update_module.__doc__.split("\n") if s))) modules.append((update_module, i)) if not Config().find_b("Update-DB::Options::Yes", False): prompt = "\nUpdate database? (y/N) " answer = utils.our_raw_input(prompt) if answer.upper() != 'Y': sys.exit(0) else: print("no updates required") logger.log(["no updates required"]) sys.exit(0) for module in modules: (update_module, i) = module try: update_module.do_update(self) message = "updated database schema from %d to %d" % (database_revision, i) print(message) logger.log([message]) except DBUpdateError as e: # Seems the update did not work. print("Was unable to update database schema from %d to %d." % (database_revision, i)) print("The error message received was %s" % (e)) logger.log(["DB Schema upgrade failed"]) logger.close() utils.fubar("DB Schema upgrade failed") database_revision += 1 logger.close()
def main(): global Cnf keyrings = None Cnf = utils.get_conf() Arguments = [('h', "help", "Add-User::Options::Help"), ('k', "key", "Add-User::Options::Key", "HasArg"), ('u', "user", "Add-User::Options::User", "HasArg"), ] for i in ["help"]: key = "Add-User::Options::%s" % i if key not in Cnf: Cnf[key] = "" apt_pkg.parse_commandline(Cnf, Arguments, sys.argv) Options = Cnf.subtree("Add-User::Options") if Options["help"]: usage() session = DBConn().session() if not keyrings: keyrings = get_active_keyring_paths() cmd = ["gpg", "--with-colons", "--no-secmem-warning", "--no-auto-check-trustdb", "--with-fingerprint", "--no-default-keyring"] cmd.extend(utils.gpg_keyring_args(keyrings).split()) cmd.extend(["--list-key", "--", Cnf["Add-User::Options::Key"]]) output = subprocess.check_output(cmd).rstrip() m = re_gpg_fingerprint_colon.search(output) if not m: print(output) utils.fubar("0x%s: (1) No fingerprint found in gpg output but it returned 0?\n%s" % (Cnf["Add-User::Options::Key"], utils.prefix_multi_line_string(output, " [GPG output:] "))) primary_key = m.group(1) primary_key = primary_key.replace(" ", "") uid = "" if "Add-User::Options::User" in Cnf and Cnf["Add-User::Options::User"]: uid = Cnf["Add-User::Options::User"] name = Cnf["Add-User::Options::User"] else: u = re_user_address.search(output) if not u: print(output) utils.fubar("0x%s: (2) No userid found in gpg output but it returned 0?\n%s" % (Cnf["Add-User::Options::Key"], utils.prefix_multi_line_string(output, " [GPG output:] "))) uid = u.group(1) n = re_user_name.search(output) name = n.group(1) # Look for all email addresses on the key. emails = [] for line in output.split('\n'): e = re_user_mails.search(line) if not e: continue emails.append(e.group(2)) print("0x%s -> %s <%s> -> %s -> %s" % (Cnf["Add-User::Options::Key"], name, emails[0], uid, primary_key)) prompt = "Add user %s with above data (y/N) ? " % (uid) yn = utils.our_raw_input(prompt).lower() if yn == "y": # Create an account for the user? summary = "" # Now add user to the database. # Note that we provide a session, so we're responsible for committing uidobj = get_or_set_uid(uid, session=session) uid_id = uidobj.uid_id session.commit() # Lets add user to the email-whitelist file if its configured. if "Dinstall::MailWhiteList" in Cnf and Cnf["Dinstall::MailWhiteList"] != "": f = utils.open_file(Cnf["Dinstall::MailWhiteList"], "a") for mail in emails: f.write(mail + '\n') f.close() print("Added:\nUid:\t %s (ID: %s)\nMaint:\t %s\nFP:\t %s" % (uid, uid_id, name, primary_key)) # Should we send mail to the newly added user? if Cnf.find_b("Add-User::SendEmail"): mail = name + "<" + emails[0] + ">" Subst = {} Subst["__NEW_MAINTAINER__"] = mail Subst["__UID__"] = uid Subst["__KEYID__"] = Cnf["Add-User::Options::Key"] Subst["__PRIMARY_KEY__"] = primary_key Subst["__FROM_ADDRESS__"] = Cnf["Dinstall::MyEmailAddress"] Subst["__ADMIN_ADDRESS__"] = Cnf["Dinstall::MyAdminAddress"] Subst["__HOSTNAME__"] = Cnf["Dinstall::MyHost"] Subst["__DISTRO__"] = Cnf["Dinstall::MyDistribution"] Subst["__SUMMARY__"] = summary new_add_message = utils.TemplateSubst(Subst, Cnf["Dir::Templates"] + "/add-user.added") utils.send_mail(new_add_message) else: uid = None
def action(directory, upload): changes = upload.changes processed = True global Logger cnf = Config() okay = upload.check() try: summary = changes.changes.get('Changes', '') except UnicodeDecodeError as e: summary = "Reading changes failed: %s" % (e) # the upload checks should have detected this, but make sure this # upload gets rejected in any case upload.reject_reasons.append(summary) package_info = [] if okay: if changes.source is not None: package_info.append("source:{0}".format(changes.source.dsc['Source'])) for binary in changes.binaries: package_info.append("binary:{0}".format(binary.control['Package'])) (prompt, answer) = ("", "XXX") if Options["No-Action"] or Options["Automatic"]: answer = 'S' print(summary) print() print("\n".join(package_info)) print() if len(upload.warnings) > 0: print("\n".join(upload.warnings)) print() if len(upload.reject_reasons) > 0: print("Reason:") print("\n".join(upload.reject_reasons)) print() path = os.path.join(directory, changes.filename) created = os.stat(path).st_mtime now = time.time() too_new = (now - created < int(cnf['Dinstall::SkipTime'])) if too_new: print("SKIP (too new)") prompt = "[S]kip, Quit ?" else: prompt = "[R]eject, Skip, Quit ?" if Options["Automatic"]: answer = 'R' elif upload.new: prompt = "[N]ew, Skip, Quit ?" if Options['Automatic']: answer = 'N' else: prompt = "[A]ccept, Skip, Quit ?" if Options['Automatic']: answer = 'A' while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.match(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer == 'R': reject(directory, upload) elif answer == 'A': # upload.try_autobyhand must not be run with No-Action. if Options['No-Action']: accept(directory, upload) elif upload.try_autobyhand(): accept(directory, upload) else: print("W: redirecting to BYHAND as automatic processing failed.") accept_to_new(directory, upload) elif answer == 'N': accept_to_new(directory, upload) elif answer == 'Q': sys.exit(0) elif answer == 'S': processed = False if not Options['No-Action']: upload.commit() return processed
def action(directory, upload): changes = upload.changes processed = True global Logger cnf = Config() okay = upload.check() summary = changes.changes.get('Changes', '') package_info = [] if okay: if changes.source is not None: package_info.append("source:{0}".format(changes.source.dsc['Source'])) for binary in changes.binaries: package_info.append("binary:{0}".format(binary.control['Package'])) (prompt, answer) = ("", "XXX") if Options["No-Action"] or Options["Automatic"]: answer = 'S' print(summary) print() print("\n".join(package_info)) print() if len(upload.warnings) > 0: print("\n".join(upload.warnings)) print() if len(upload.reject_reasons) > 0: print("Reason:") print("\n".join(upload.reject_reasons)) print() path = os.path.join(directory, changes.filename) created = os.stat(path).st_mtime now = time.time() too_new = (now - created < int(cnf['Dinstall::SkipTime'])) if too_new: print("SKIP (too new)") prompt = "[S]kip, Quit ?" else: prompt = "[R]eject, Skip, Quit ?" if Options["Automatic"]: answer = 'R' elif upload.new: prompt = "[N]ew, Skip, Quit ?" if Options['Automatic']: answer = 'N' else: prompt = "[A]ccept, Skip, Quit ?" if Options['Automatic']: answer = 'A' while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.match(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer == 'R': reject(directory, upload) elif answer == 'A': # upload.try_autobyhand must not be run with No-Action. if Options['No-Action']: accept(directory, upload) elif upload.try_autobyhand(): accept(directory, upload) else: print("W: redirecting to BYHAND as automatic processing failed.") accept_to_new(directory, upload) elif answer == 'N': accept_to_new(directory, upload) elif answer == 'Q': sys.exit(0) elif answer == 'S': processed = False if not Options['No-Action']: upload.commit() return processed
def main(): global Cnf keyrings = None Cnf = utils.get_conf() Arguments = [ ('h', "help", "Add-User::Options::Help"), ('k', "key", "Add-User::Options::Key", "HasArg"), ('u', "user", "Add-User::Options::User", "HasArg"), ] for i in ["help"]: key = "Add-User::Options::%s" % i if key not in Cnf: Cnf[key] = "" apt_pkg.parse_commandline(Cnf, Arguments, sys.argv) Options = Cnf.subtree("Add-User::Options") if Options["help"]: usage() session = DBConn().session() if not keyrings: keyrings = get_active_keyring_paths() cmd = [ "gpg", "--with-colons", "--no-secmem-warning", "--no-auto-check-trustdb", "--with-fingerprint", "--no-default-keyring" ] cmd.extend(utils.gpg_keyring_args(keyrings).split()) cmd.extend(["--list-key", "--", Cnf["Add-User::Options::Key"]]) output = subprocess.check_output(cmd).rstrip() m = re_gpg_fingerprint_colon.search(output) if not m: print(output) utils.fubar( "0x%s: (1) No fingerprint found in gpg output but it returned 0?\n%s" % (Cnf["Add-User::Options::Key"], utils.prefix_multi_line_string(output, " [GPG output:] "))) primary_key = m.group(1) primary_key = primary_key.replace(" ", "") uid = "" if "Add-User::Options::User" in Cnf and Cnf["Add-User::Options::User"]: uid = Cnf["Add-User::Options::User"] name = Cnf["Add-User::Options::User"] else: u = re_user_address.search(output) if not u: print(output) utils.fubar( "0x%s: (2) No userid found in gpg output but it returned 0?\n%s" % (Cnf["Add-User::Options::Key"], utils.prefix_multi_line_string(output, " [GPG output:] "))) uid = u.group(1) n = re_user_name.search(output) name = n.group(1) # Look for all email addresses on the key. emails = [] for line in output.split('\n'): e = re_user_mails.search(line) if not e: continue emails.append(e.group(2)) print("0x%s -> %s <%s> -> %s -> %s" % (Cnf["Add-User::Options::Key"], name, emails[0], uid, primary_key)) prompt = "Add user %s with above data (y/N) ? " % (uid) yn = utils.our_raw_input(prompt).lower() if yn == "y": # Create an account for the user? summary = "" # Now add user to the database. # Note that we provide a session, so we're responsible for committing uidobj = get_or_set_uid(uid, session=session) uid_id = uidobj.uid_id session.commit() # Lets add user to the email-whitelist file if its configured. if "Dinstall::MailWhiteList" in Cnf and Cnf[ "Dinstall::MailWhiteList"] != "": f = utils.open_file(Cnf["Dinstall::MailWhiteList"], "a") for mail in emails: f.write(mail + '\n') f.close() print("Added:\nUid:\t %s (ID: %s)\nMaint:\t %s\nFP:\t %s" % (uid, uid_id, name, primary_key)) # Should we send mail to the newly added user? if Cnf.find_b("Add-User::SendEmail"): mail = name + "<" + emails[0] + ">" Subst = {} Subst["__NEW_MAINTAINER__"] = mail Subst["__UID__"] = uid Subst["__KEYID__"] = Cnf["Add-User::Options::Key"] Subst["__PRIMARY_KEY__"] = primary_key Subst["__FROM_ADDRESS__"] = Cnf["Dinstall::MyEmailAddress"] Subst["__ADMIN_ADDRESS__"] = Cnf["Dinstall::MyAdminAddress"] Subst["__HOSTNAME__"] = Cnf["Dinstall::MyHost"] Subst["__DISTRO__"] = Cnf["Dinstall::MyDistribution"] Subst["__SUMMARY__"] = summary new_add_message = utils.TemplateSubst( Subst, Cnf["Dir::Templates"] + "/add-user.added") utils.send_mail(new_add_message) else: uid = None
def game_over(): answer = utils.our_raw_input("Continue (y/N)? ").lower() if answer != "y": print("Aborted.") sys.exit(1)
def edit_index(new, upload, index): package = new[index]['package'] priority = new[index]["priority"] section = new[index]["section"] ftype = new[index]["type"] done = 0 while not done: print "\t".join([package, priority, section]) answer = "XXX" if ftype != "dsc": prompt = "[B]oth, Priority, Section, Done ? " else: prompt = "[S]ection, Done ? " edit_priority = edit_section = 0 while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.match(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer == 'P': edit_priority = 1 elif answer == 'S': edit_section = 1 elif answer == 'B': edit_priority = edit_section = 1 elif answer == 'D': done = 1 # Edit the priority if edit_priority: readline.set_completer(Priorities.complete) got_priority = 0 while not got_priority: 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 priority = new_priority # Edit the section if edit_section: readline.set_completer(Sections.complete) got_section = 0 while not got_section: 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 section = new_section # Reset the readline completer readline.set_completer(None) new[index]["priority"] = priority new[index]["section"] = section if section.find('/') != -1: component = section.split('/', 1)[0] else: component = 'main' new[index]['component'] = component return new
def action(u, session): global Logger cnf = Config() holding = Holding() # changes["distribution"] may not exist in corner cases # (e.g. unreadable changes files) if not u.pkg.changes.has_key("distribution") or not isinstance(u.pkg.changes["distribution"], dict): u.pkg.changes["distribution"] = {} (summary, short_summary) = u.build_summaries() (prompt, answer) = ("", "XXX") if Options["No-Action"] or Options["Automatic"]: answer = 'S' queuekey = '' pi = u.package_info() try: chg = session.query(DBChange).filter_by(changesname=os.path.basename(u.pkg.changes_file)).one() except NoResultFound as e: chg = None if len(u.rejects) > 0: if u.upload_too_new(): print "SKIP (too new)\n" + pi, prompt = "[S]kip, Quit ?" else: print "REJECT\n" + pi prompt = "[R]eject, Skip, Quit ?" if Options["Automatic"]: answer = 'R' else: # Are we headed for NEW / BYHAND / AUTOBYHAND? # Note that policy queues are no longer handled here qu = determine_target(u) if qu: print "%s for %s\n%s%s" % ( qu.upper(), ", ".join(u.pkg.changes["distribution"].keys()), pi, summary) queuekey = qu[0].upper() if queuekey in "RQSA": queuekey = "D" prompt = "[D]ivert, Skip, Quit ?" else: prompt = "[%s]%s, Skip, Quit ?" % (queuekey, qu[1:].lower()) if Options["Automatic"]: answer = queuekey else: # Does suite have a policy_queue configured divert = False for s in u.pkg.changes["distribution"].keys(): suite = get_suite(s, session) if suite.policy_queue: if not chg or chg.approved_for_id != suite.policy_queue.policy_queue_id: # This routine will check whether the upload is a binary # upload when the source is already in the target suite. If # so, we skip the policy queue, otherwise we go there. divert = package_to_suite(u, suite.suite_name, session=session) if divert: print "%s for %s\n%s%s" % ( suite.policy_queue.queue_name.upper(), ", ".join(u.pkg.changes["distribution"].keys()), pi, summary) queuekey = "P" prompt = "[P]olicy, Skip, Quit ?" policyqueue = suite.policy_queue if Options["Automatic"]: answer = 'P' break if not divert: print "ACCEPT\n" + pi + summary, prompt = "[A]ccept, Skip, Quit ?" if Options["Automatic"]: answer = 'A' while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.match(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer == 'R': os.chdir(u.pkg.directory) u.do_reject(0, pi) elif answer == 'A': if not chg: chg = u.pkg.add_known_changes(holding.holding_dir, session=session, logger=Logger) session.commit() u.accept(summary, short_summary, session) u.check_override() chg.clean_from_queue() session.commit() u.remove() elif answer == 'P': if not chg: chg = u.pkg.add_known_changes(holding.holding_dir, session=session, logger=Logger) package_to_queue(u, summary, short_summary, policyqueue, chg, session) session.commit() u.remove() elif answer == queuekey: if not chg: chg = u.pkg.add_known_changes(holding.holding_dir, session=session, logger=Logger) QueueInfo[qu]["process"](u, summary, short_summary, chg, session) session.commit() u.remove() elif answer == 'Q': byebye() sys.exit(0) session.commit()
def game_over(): answer = utils.our_raw_input("Continue (y/N)? ").lower() if answer != "y": print "Aborted." sys.exit(1)
def check_transitions(transitions): """ Check if the defined transitions still apply and remove those that no longer do. @note: Asks the user for confirmation first unless -a has been set. """ global Cnf to_dump = 0 to_remove = [] info = {} session = DBConn().session() # Now look through all defined transitions for trans in transitions: t = transitions[trans] source = t["source"] expected = t["new"] # Will be an empty list if nothing is in testing. sourceobj = get_source_in_suite(source, "testing", session) info[trans] = get_info(trans, source, expected, t["rm"], t["reason"], t["packages"]) print info[trans] if sourceobj is None: # No package in testing print "Transition source %s not in testing, transition still ongoing." % (source) else: current = sourceobj.version compare = apt_pkg.version_compare(current, expected) if compare < 0: # This is still valid, the current version in database is older than # the new version we wait for print "This transition is still ongoing, we currently have version %s" % (current) else: print "REMOVE: This transition is over, the target package reached testing. REMOVE" print "%s wanted version: %s, has %s" % (source, expected, current) to_remove.append(trans) to_dump = 1 print "-------------------------------------------------------------------------" if to_dump: prompt = "Removing: " for remove in to_remove: prompt += remove prompt += "," prompt += " Commit Changes? (y/N)" answer = "" if Options["no-action"]: answer="n" elif Options["automatic"]: answer="y" else: answer = utils.our_raw_input(prompt).lower() if answer == "": answer = "n" if answer == 'n': print "Not committing changes" sys.exit(0) elif answer == 'y': print "Committing" subst = {} subst['__SUBJECT__'] = "Transitions completed: " + ", ".join(sorted(to_remove)) subst['__TRANSITION_MESSAGE__'] = "The following transitions were removed:\n" for remove in sorted(to_remove): subst['__TRANSITION_MESSAGE__'] += info[remove] + '\n' del transitions[remove] # If we have a mail address configured for transitions, # send a notification subst['__TRANSITION_EMAIL__'] = Cnf.get("Transitions::Notifications", "") if subst['__TRANSITION_EMAIL__'] != "": print "Sending notification to %s" % subst['__TRANSITION_EMAIL__'] subst['__DAK_ADDRESS__'] = Cnf["Dinstall::MyEmailAddress"] subst['__BCC__'] = 'X-DAK: dak transitions' if Cnf.has_key("Dinstall::Bcc"): subst["__BCC__"] += '\nBcc: %s' % Cnf["Dinstall::Bcc"] message = utils.TemplateSubst(subst, os.path.join(Cnf["Dir::Templates"], 'transition.removed')) utils.send_mail(message) edit_file = temp_transitions_file(transitions) write_transitions_from_file(edit_file) print "Done" else: print "WTF are you typing?" sys.exit(0)
def do_new(upload, session): print "NEW\n" files = upload.pkg.files upload.check_files(not Options["No-Action"]) changes = upload.pkg.changes cnf = Config() # Check for a valid distribution upload.check_distributions() # Make a copy of distribution we can happily trample on changes["suite"] = copy.copy(changes["distribution"]) # Try to get an included dsc dsc = None (status, _) = upload.load_dsc() if status: dsc = upload.pkg.dsc # The main NEW processing loop done = 0 new = {} while not done: # Find out what's new new, byhand = determine_new(upload.pkg.changes_file, changes, files, dsc=dsc, session=session, new=new) if not new: break answer = "XXX" if Options["No-Action"] or Options["Automatic"]: answer = 'S' (broken, note) = print_new(new, upload, indexed=0) prompt = "" if not broken and not note: prompt = "Add overrides, " if broken: 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 += "RemOve all notes, Remove note, " prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?" while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.search(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer in ( 'A', 'E', 'M', 'O', 'R' ) and Options["Trainee"]: utils.warn("Trainees can't do that") continue if answer == 'A' and not Options["Trainee"]: try: check_daily_lock() done = add_overrides (new, upload, session) new_accept(upload, Options["No-Action"], session) Logger.log(["NEW ACCEPT: %s" % (upload.pkg.changes_file)]) except CantGetLockError: print "Hello? Operator! Give me the number for 911!" print "Dinstall in the locked area, cant process packages, come back later" elif answer == 'C': check_pkg(upload) elif answer == 'E' and not Options["Trainee"]: new = edit_overrides (new, upload, session) elif answer == 'M' and not Options["Trainee"]: aborted = upload.do_reject(manual=1, reject_message=Options["Manual-Reject"], notes=get_new_comments(changes.get("source", ""), session=session)) if not aborted: upload.pkg.remove_known_changes(session=session) session.commit() Logger.log(["NEW REJECT: %s" % (upload.pkg.changes_file)]) done = 1 elif answer == 'N': edit_note(get_new_comments(changes.get("source", ""), session=session), upload, session, bool(Options["Trainee"])) elif answer == 'P' and not Options["Trainee"]: prod_maintainer(get_new_comments(changes.get("source", ""), session=session), upload) Logger.log(["NEW PROD: %s" % (upload.pkg.changes_file)]) elif answer == 'R' and not Options["Trainee"]: confirm = utils.our_raw_input("Really clear note (y/N)? ").lower() if confirm == "y": for c in get_new_comments(changes.get("source", ""), changes.get("version", ""), session=session): session.delete(c) session.commit() elif answer == 'O' and not Options["Trainee"]: confirm = utils.our_raw_input("Really clear all notes (y/N)? ").lower() if confirm == "y": for c in get_new_comments(changes.get("source", ""), session=session): session.delete(c) session.commit() elif answer == 'S': done = 1 elif answer == 'Q': end() sys.exit(0)
def do_byhand(upload, session): done = 0 while not done: files = upload.pkg.files will_install = True byhand = [] for f in files.keys(): if files[f]["section"] == "byhand": if os.path.exists(f): print "W: %s still present; please process byhand components and try again." % (f) will_install = False else: byhand.append(f) answer = "XXXX" if Options["No-Action"]: answer = "S" if will_install: if Options["Automatic"] and not Options["No-Action"]: answer = 'A' prompt = "[A]ccept, Manual reject, Skip, Quit ?" else: prompt = "Manual reject, [S]kip, Quit ?" while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.search(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer == 'A': dbchg = get_dbchange(upload.pkg.changes_file, session) if dbchg is None: print "Warning: cannot find changes file in database; can't process BYHAND" else: try: check_daily_lock() done = 1 for b in byhand: # Find the file entry in the database found = False for f in dbchg.files: if f.filename == b: found = True f.processed = True break if not found: print "Warning: Couldn't find BYHAND item %s in the database to mark it processed" % b session.commit() Logger.log(["BYHAND ACCEPT: %s" % (upload.pkg.changes_file)]) except CantGetLockError: print "Hello? Operator! Give me the number for 911!" print "Dinstall in the locked area, cant process packages, come back later" elif answer == 'M': aborted = upload.do_reject(manual=1, reject_message=Options["Manual-Reject"], notes=get_new_comments(changes.get("source", ""), session=session)) if not aborted: upload.pkg.remove_known_changes(session=session) session.commit() Logger.log(["BYHAND REJECT: %s" % (upload.pkg.changes_file)]) done = 1 elif answer == 'S': done = 1 elif answer == 'Q': end() sys.exit(0)
def update_db(self): # Ok, try and find the configuration table print("Determining dak database revision ...") cnf = Config() logger = Logger('update-db') modules = [] try: # Build a connect string if "DB::Service" in cnf: connect_str = "service=%s" % cnf["DB::Service"] else: connect_str = "dbname=%s" % (cnf["DB::Name"]) if "DB::Host" in cnf and cnf["DB::Host"] != '': connect_str += " host=%s" % (cnf["DB::Host"]) if "DB::Port" in cnf and cnf["DB::Port"] != '-1': connect_str += " port=%d" % (int(cnf["DB::Port"])) self.db = psycopg2.connect(connect_str) db_role = cnf.get("DB::Role") if db_role: self.db.cursor().execute('SET ROLE "{}"'.format(db_role)) except Exception as e: print("FATAL: Failed connect to database (%s)" % str(e)) sys.exit(1) database_revision = int(self.get_db_rev()) logger.log( ['transaction id before update: %s' % self.get_transaction_id()]) if database_revision == -1: print("dak database schema predates update-db.") print("") print( "This script will attempt to upgrade it to the lastest, but may fail." ) print( "Please make sure you have a database backup handy. If you don't, press Ctrl-C now!" ) print("") print("Continuing in five seconds ...") time.sleep(5) print("") print("Attempting to upgrade pre-zero database to zero") self.update_db_to_zero() database_revision = 0 dbfiles = glob( os.path.join(os.path.dirname(__file__), 'dakdb/update*.py')) required_database_schema = max( map(int, findall('update(\d+).py', " ".join(dbfiles)))) print("dak database schema at %d" % database_revision) print("dak version requires schema %d" % required_database_schema) if database_revision < required_database_schema: print("\nUpdates to be applied:") for i in range(database_revision, required_database_schema): i += 1 dakdb = __import__("dakdb", globals(), locals(), ['update' + str(i)]) update_module = getattr(dakdb, "update" + str(i)) print( "Update %d: %s" % (i, next(s for s in update_module.__doc__.split("\n") if s))) modules.append((update_module, i)) if not Config().find_b("Update-DB::Options::Yes", False): prompt = "\nUpdate database? (y/N) " answer = utils.our_raw_input(prompt) if answer.upper() != 'Y': sys.exit(0) else: print("no updates required") logger.log(["no updates required"]) sys.exit(0) for module in modules: (update_module, i) = module try: update_module.do_update(self) message = "updated database schema from %d to %d" % ( database_revision, i) print(message) logger.log([message]) except DBUpdateError as e: # Seems the update did not work. print("Was unable to update database schema from %d to %d." % (database_revision, i)) print("The error message received was %s" % (e)) logger.log(["DB Schema upgrade failed"]) logger.close() utils.fubar("DB Schema upgrade failed") database_revision += 1 logger.close()
def do_new(upload, upload_copy, handler, session): cnf = Config() run_user_inspect_command(upload, upload_copy) # The main NEW processing loop done = False missing = [] while not done: queuedir = upload.policy_queue.path byhand = upload.byhand missing = handler.missing_overrides(hints=missing) broken = not check_valid(missing, session) changesname = os.path.basename(upload.changes.changesname) print print changesname print "-" * len(changesname) print print " Target: {0}".format(upload.target_suite.suite_name) print " Changed-By: {0}".format(upload.changes.changedby) print #if len(byhand) == 0 and len(missing) == 0: # break if missing: print "NEW\n" for package in missing: if package["type"] == "deb" and package["priority"] == "extra": package["priority"] = "optional" answer = "XXX" if Options["No-Action"] or Options["Automatic"]: answer = 'S' note = print_new(upload, missing, indexed=0, session=session) prompt = "" has_unprocessed_byhand = False for f in byhand: path = os.path.join(queuedir, f.filename) if not f.processed and os.path.exists(path): print "W: {0} still present; please process byhand components and try again".format( f.filename) has_unprocessed_byhand = True if not has_unprocessed_byhand and not broken and not note: if len(missing) == 0: prompt = "Accept, " answer = 'A' else: prompt = "Add overrides, " if broken: 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 += "RemOve all notes, Remove note, " prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?" while prompt.find(answer) == -1: answer = utils.our_raw_input(prompt) m = re_default_answer.search(prompt) if answer == "": answer = m.group(1) answer = answer[:1].upper() if answer in ('A', 'E', 'M', 'O', 'R') and Options["Trainee"]: utils.warn("Trainees can't do that") continue if answer == 'A' and not Options["Trainee"]: add_overrides(missing, upload.target_suite, session) if Config().find_b("Dinstall::BXANotify"): do_bxa_notification(missing, upload, session) handler.accept() done = True Logger.log(["NEW ACCEPT", upload.changes.changesname]) elif answer == 'C': check_pkg(upload, upload_copy, session) elif answer == 'E' and not Options["Trainee"]: missing = edit_overrides(missing, upload, session) elif answer == 'M' and not Options["Trainee"]: reason = Options.get('Manual-Reject', '') + "\n" reason = reason + "\n\n=====\n\n".join([ n.comment for n in get_new_comments(upload.policy_queue, upload.changes.source, session=session) ]) reason = get_reject_reason(reason) if reason is not None: Logger.log(["NEW REJECT", upload.changes.changesname]) handler.reject(reason) done = True elif answer == 'N': if edit_note( get_new_comments(upload.policy_queue, upload.changes.source, session=session), upload, session, bool(Options["Trainee"])) == 0: end() sys.exit(0) elif answer == 'P' and not Options["Trainee"]: if prod_maintainer( get_new_comments(upload.policy_queue, upload.changes.source, session=session), upload) == 0: end() sys.exit(0) Logger.log(["NEW PROD", upload.changes.changesname]) elif answer == 'R' and not Options["Trainee"]: confirm = utils.our_raw_input("Really clear note (y/N)? ").lower() if confirm == "y": for c in get_new_comments(upload.policy_queue, upload.changes.source, upload.changes.version, session=session): session.delete(c) session.commit() elif answer == 'O' and not Options["Trainee"]: confirm = utils.our_raw_input( "Really clear all notes (y/N)? ").lower() if confirm == "y": for c in get_new_comments(upload.policy_queue, upload.changes.source, session=session): session.delete(c) session.commit() elif answer == 'S': done = True elif answer == 'Q': end() sys.exit(0) if handler.get_action(): print "PENDING %s\n" % handler.get_action()