]> git.decadent.org.uk Git - dak.git/blobdiff - dak/process_new.py
daklog: Add username in every log line
[dak.git] / dak / process_new.py
old mode 100644 (file)
new mode 100755 (executable)
index 22469ad..1423d70
@@ -1,8 +1,14 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
+# vim:set et ts=4 sw=4:
 
 
-# Handles NEW and BYHAND packages
-# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006  James Troup <james@nocrew.org>
+""" Handles NEW and BYHAND packages
 
 
+@contact: Debian FTP Master <ftpmaster@debian.org>
+@copyright: 2001, 2002, 2003, 2004, 2005, 2006  James Troup <james@nocrew.org>
+@copyright: 2009 Joerg Jaspert <joerg@debian.org>
+@copyright: 2009 Frank Lichtenheld <djpig@debian.org>
+@license: GNU General Public License version 2 or later
+"""
 # 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
 # the Free Software Foundation; either version 2 of the License, or
 # 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
 # the Free Software Foundation; either version 2 of the License, or
 
 ################################################################################
 
 
 ################################################################################
 
-import copy, errno, os, readline, stat, sys, time
+from __future__ import with_statement
+
+import copy
+import errno
+import os
+import readline
+import stat
+import sys
+import time
+import contextlib
+import pwd
 import apt_pkg, apt_inst
 import examine_package
 import apt_pkg, apt_inst
 import examine_package
-import daklib.database
-import daklib.logging
-import daklib.queue
-import daklib.utils
+
+from daklib.dbconn import *
+from daklib.queue import *
+from daklib import daklog
+from daklib import utils
+from daklib.regexes import re_no_epoch, re_default_answer, re_isanum
+from daklib.dak_exceptions import CantOpenError, AlreadyLockedError, CantGetLockError
+from daklib.summarystats import SummaryStats
+from daklib.config import Config
 
 # Globals
 
 # Globals
-Cnf = None
 Options = None
 Options = None
-Upload = None
-projectB = None
 Logger = None
 
 Priorities = None
 Sections = None
 
 Logger = None
 
 Priorities = None
 Sections = None
 
-reject_message = ""
-
 ################################################################################
 ################################################################################
 ################################################################################
 
 ################################################################################
 ################################################################################
 ################################################################################
 
-def reject (str, prefix="Rejected: "):
-    global reject_message
-    if str:
-        reject_message += prefix + str + "\n"
-
-def recheck():
-    global reject_message
-    files = Upload.pkg.files
-    reject_message = ""
+def recheck(upload, session):
+    files = upload.pkg.files
 
 
+    cnf = Config()
     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.
     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.
@@ -79,44 +89,43 @@ def recheck():
         if files[f]["type"] == "deb":
             source_version = files[f]["source version"]
             source_package = files[f]["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 = daklib.utils.re_no_epoch.sub('', source_version)
+            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 = re_no_epoch.sub('', source_version)
                 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
                 found = 0
                 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
                 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):
+                for q in ["Accepted", "Embargoed", "Unembargoed", "Newstage"]:
+                    if cnf.has_key("Dir::Queue::%s" % (q)):
+                        if os.path.exists(cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
                             found = 1
                 if not found:
                             found = 1
                 if not found:
-                    reject("no source found for %s %s (%s)." % (source_package, source_version, f))
+                    upload.rejects.append("no source found for %s %s (%s)." % (source_package, source_version, f))
 
         # Version and file overwrite checks
         if files[f]["type"] == "deb":
 
         # Version and file overwrite checks
         if files[f]["type"] == "deb":
-            reject(Upload.check_binary_against_db(f))
+            upload.check_binary_against_db(f, session)
         elif files[f]["type"] == "dsc":
         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, "")
+            upload.check_source_against_db(f, session)
+            upload.check_dsc_against_db(f, session)
 
 
-    if reject_message.find("Rejected") != -1:
+    if len(upload.rejects) > 0:
         answer = "XXX"
         answer = "XXX"
-        if Options["No-Action"] or Options["Automatic"]:
+        if Options["No-Action"] or Options["Automatic"] or Options["Trainee"]:
             answer = 'S'
 
             answer = 'S'
 
-        print "REJECT\n" + reject_message,
+        print "REJECT\n" + upload.rejects.join("\n"),
         prompt = "[R]eject, Skip, Quit ?"
 
         while prompt.find(answer) == -1:
         prompt = "[R]eject, Skip, Quit ?"
 
         while prompt.find(answer) == -1:
-            answer = daklib.utils.our_raw_input(prompt)
-            m = daklib.queue.re_default_answer.match(prompt)
+            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':
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
 
         if answer == 'R':
-            Upload.do_reject(0, reject_message)
-            os.unlink(Upload.pkg.changes_file[:-8]+".dak")
+            upload.do_reject(manual=0, reject_message=upload.rejects.join("\n"))
+            os.unlink(upload.pkg.changes_file[:-8]+".dak")
             return 0
         elif answer == 'S':
             return 0
             return 0
         elif answer == 'S':
             return 0
@@ -151,7 +160,7 @@ def indiv_sg_compare (a, b):
 def sg_compare (a, b):
     a = a[1]
     b = b[1]
 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"]
     # Sort by have note
     a_note_state = a["note_state"]
     b_note_state = b["note_state"]
@@ -159,11 +168,15 @@ def sg_compare (a, b):
         return -1
     elif a_note_state > b_note_state:
         return 1
         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"])
 
 
     # Sort by time of oldest upload
     return cmp(a["oldest"], b["oldest"])
 
-def sort_changes(changes_files):
+def sort_changes(changes_files, session):
     """Sort into source groups, then sort each source group by version,
     have source, filename.  Finally, sort the source groups by have
     note, time of oldest upload of each source upload."""
     """Sort into source groups, then sort each source group by version,
     have source, filename.  Finally, sort the source groups by have
     note, time of oldest upload of each source upload."""
@@ -174,11 +187,11 @@ def sort_changes(changes_files):
     cache = {}
     # Read in all the .changes files
     for filename in changes_files:
     cache = {}
     # Read in all the .changes files
     for filename in changes_files:
+        u = Upload()
         try:
         try:
-            Upload.pkg.changes_file = filename
-            Upload.init_vars()
-            Upload.update_vars()
-            cache[filename] = copy.copy(Upload.pkg.changes)
+            u.pkg.load_dot_dak(filename)
+            u.update_subst()
+            cache[filename] = copy.copy(u.pkg.changes)
             cache[filename]["filename"] = filename
         except:
             sorted_list.append(filename)
             cache[filename]["filename"] = filename
         except:
             sorted_list.append(filename)
@@ -193,6 +206,8 @@ 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():
         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 = session.query(DBSource).filter_by(source = source).all()
+        per_source[source]["source_in_database"] = len(q)>0
         source_list = per_source[source]["list"]
         first = source_list[0]
         oldest = os.stat(first["filename"])[stat.ST_MTIME]
         source_list = per_source[source]["list"]
         first = source_list[0]
         oldest = os.stat(first["filename"])[stat.ST_MTIME]
@@ -201,7 +216,7 @@ def sort_changes(changes_files):
             mtime = os.stat(d["filename"])[stat.ST_MTIME]
             if mtime < oldest:
                 oldest = mtime
             mtime = os.stat(d["filename"])[stat.ST_MTIME]
             if mtime < oldest:
                 oldest = mtime
-            have_note += (d.has_key("process-new note"))
+            have_note += has_new_comment(d["source"], d["version"], session)
         per_source[source]["oldest"] = oldest
         if not have_note:
             per_source[source]["note_state"] = 0; # none
         per_source[source]["oldest"] = oldest
         if not have_note:
             per_source[source]["note_state"] = 0; # none
@@ -220,11 +235,11 @@ def sort_changes(changes_files):
 ################################################################################
 
 class Section_Completer:
 ################################################################################
 
 class Section_Completer:
-    def __init__ (self):
+    def __init__ (self, session):
         self.sections = []
         self.sections = []
-        q = projectB.query("SELECT section FROM section")
-        for i in q.getresult():
-            self.sections.append(i[0])
+        self.matches = []
+        for s, in session.query(Section.section):
+            self.sections.append(s)
 
     def complete(self, text, state):
         if state == 0:
 
     def complete(self, text, state):
         if state == 0:
@@ -241,11 +256,11 @@ class Section_Completer:
 ############################################################
 
 class Priority_Completer:
 ############################################################
 
 class Priority_Completer:
-    def __init__ (self):
+    def __init__ (self, session):
         self.priorities = []
         self.priorities = []
-        q = projectB.query("SELECT priority FROM priority")
-        for i in q.getresult():
-            self.priorities.append(i[0])
+        self.matches = []
+        for p, in session.query(Priority.priority):
+            self.priorities.append(p)
 
     def complete(self, text, state):
         if state == 0:
 
     def complete(self, text, state):
         if state == 0:
@@ -261,9 +276,9 @@ class Priority_Completer:
 
 ################################################################################
 
 
 ################################################################################
 
-def print_new (new, indexed, file=sys.stdout):
-    daklib.queue.check_valid(new)
-    broken = 0
+def print_new (new, upload, indexed, file=sys.stdout):
+    check_valid(new)
+    broken = False
     index = 0
     for pkg in new.keys():
         index += 1
     index = 0
     for pkg in new.keys():
         index += 1
@@ -271,22 +286,22 @@ def print_new (new, indexed, file=sys.stdout):
         priority = new[pkg]["priority"]
         if new[pkg]["section id"] == -1:
             section += "[!]"
         priority = new[pkg]["priority"]
         if new[pkg]["section id"] == -1:
             section += "[!]"
-            broken = 1
+            broken = True
         if new[pkg]["priority id"] == -1:
             priority += "[!]"
         if new[pkg]["priority id"] == -1:
             priority += "[!]"
-            broken = 1
+            broken = True
         if indexed:
             line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
         else:
             line = "%-20s %-20s %-20s" % (pkg, priority, section)
         line = line.strip()+'\n'
         file.write(line)
         if indexed:
             line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
         else:
             line = "%-20s %-20s %-20s" % (pkg, priority, section)
         line = line.strip()+'\n'
         file.write(line)
-    note = Upload.pkg.changes.get("process-new note")
-    if note:
-        print "*"*75
-        print note
-        print "*"*75
-    return broken, note
+    notes = get_new_comments(upload.pkg.changes.get("source"))
+    for note in notes:
+        print "\nAuthor: %s\nVersion: %s\nTimestamp: %s\n\n%s" \
+              % (note.author, note.version, note.notedate, note.comment)
+        print "-" * 72
+    return broken, len(notes) > 0
 
 ################################################################################
 
 
 ################################################################################
 
@@ -299,19 +314,19 @@ def index_range (index):
 ################################################################################
 ################################################################################
 
 ################################################################################
 ################################################################################
 
-def edit_new (new):
+def edit_new (new, upload):
     # Write the current data to a temporary file
     # Write the current data to a temporary file
-    temp_filename = daklib.utils.temp_filename()
-    temp_file = daklib.utils.open_file(temp_filename, 'w')
-    print_new (new, 0, temp_file)
+    (fd, temp_filename) = utils.temp_filename()
+    temp_file = os.fdopen(fd, 'w')
+    print_new (new, upload, indexed=0, file=temp_file)
     temp_file.close()
     # Spawn an editor on that file
     editor = os.environ.get("EDITOR","vi")
     result = os.system("%s %s" % (editor, temp_filename))
     if result != 0:
     temp_file.close()
     # Spawn an editor on that file
     editor = os.environ.get("EDITOR","vi")
     result = os.system("%s %s" % (editor, temp_filename))
     if result != 0:
-        daklib.utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
+        utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
     # Read the edited data back in
     # Read the edited data back in
-    temp_file = daklib.utils.open_file(temp_filename)
+    temp_file = utils.open_file(temp_filename)
     lines = temp_file.readlines()
     temp_file.close()
     os.unlink(temp_filename)
     lines = temp_file.readlines()
     temp_file.close()
     os.unlink(temp_filename)
@@ -325,7 +340,7 @@ def edit_new (new):
         s[len(s):3] = [None] * (3-len(s))
         (pkg, priority, section) = s[:3]
         if not new.has_key(pkg):
         s[len(s):3] = [None] * (3-len(s))
         (pkg, priority, section) = s[:3]
         if not new.has_key(pkg):
-            daklib.utils.warn("Ignoring unknown package '%s'" % (pkg))
+            utils.warn("Ignoring unknown package '%s'" % (pkg))
         else:
             # Strip off any invalid markers, print_new will readd them.
             if section.endswith("[!]"):
         else:
             # Strip off any invalid markers, print_new will readd them.
             if section.endswith("[!]"):
@@ -333,14 +348,14 @@ def edit_new (new):
             if priority.endswith("[!]"):
                 priority = priority[:-3]
             for f in new[pkg]["files"]:
             if priority.endswith("[!]"):
                 priority = priority[:-3]
             for f in new[pkg]["files"]:
-                Upload.pkg.files[f]["section"] = section
-                Upload.pkg.files[f]["priority"] = priority
+                upload.pkg.files[f]["section"] = section
+                upload.pkg.files[f]["priority"] = priority
             new[pkg]["section"] = section
             new[pkg]["priority"] = priority
 
 ################################################################################
 
             new[pkg]["section"] = section
             new[pkg]["priority"] = priority
 
 ################################################################################
 
-def edit_index (new, index):
+def edit_index (new, upload, index):
     priority = new[index]["priority"]
     section = new[index]["section"]
     ftype = new[index]["type"]
     priority = new[index]["priority"]
     section = new[index]["section"]
     ftype = new[index]["type"]
@@ -356,8 +371,8 @@ def edit_index (new, index):
         edit_priority = edit_section = 0
 
         while prompt.find(answer) == -1:
         edit_priority = edit_section = 0
 
         while prompt.find(answer) == -1:
-            answer = daklib.utils.our_raw_input(prompt)
-            m = daklib.queue.re_default_answer.match(prompt)
+            answer = utils.our_raw_input(prompt)
+            m = re_default_answer.match(prompt)
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
@@ -376,7 +391,7 @@ def edit_index (new, index):
             readline.set_completer(Priorities.complete)
             got_priority = 0
             while not got_priority:
             readline.set_completer(Priorities.complete)
             got_priority = 0
             while not got_priority:
-                new_priority = daklib.utils.our_raw_input("New priority: ").strip()
+                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:
                 if new_priority not in Priorities.priorities:
                     print "E: '%s' is not a valid priority, try again." % (new_priority)
                 else:
@@ -388,7 +403,7 @@ def edit_index (new, index):
             readline.set_completer(Sections.complete)
             got_section = 0
             while not got_section:
             readline.set_completer(Sections.complete)
             got_section = 0
             while not got_section:
-                new_section = daklib.utils.our_raw_input("New section: ").strip()
+                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:
                 if new_section not in Sections.sections:
                     print "E: '%s' is not a valid section, try again." % (new_section)
                 else:
@@ -399,19 +414,19 @@ def edit_index (new, index):
         readline.set_completer(None)
 
     for f in new[index]["files"]:
         readline.set_completer(None)
 
     for f in new[index]["files"]:
-        Upload.pkg.files[f]["section"] = section
-        Upload.pkg.files[f]["priority"] = priority
+        upload.pkg.files[f]["section"] = section
+        upload.pkg.files[f]["priority"] = priority
     new[index]["priority"] = priority
     new[index]["section"] = section
     return new
 
 ################################################################################
 
     new[index]["priority"] = priority
     new[index]["section"] = section
     return new
 
 ################################################################################
 
-def edit_overrides (new):
+def edit_overrides (new, upload, session):
     print
     done = 0
     while not done:
     print
     done = 0
     while not done:
-        print_new (new, 1)
+        print_new (new, upload, indexed=1)
         new_index = {}
         index = 0
         for i in new.keys():
         new_index = {}
         index = 0
         for i in new.keys():
@@ -422,12 +437,12 @@ def edit_overrides (new):
 
         got_answer = 0
         while not got_answer:
 
         got_answer = 0
         while not got_answer:
-            answer = daklib.utils.our_raw_input(prompt)
+            answer = utils.our_raw_input(prompt)
             if not answer.isdigit():
                 answer = answer[:1].upper()
             if answer == "E" or answer == "D":
                 got_answer = 1
             if not answer.isdigit():
                 answer = answer[:1].upper()
             if answer == "E" or answer == "D":
                 got_answer = 1
-            elif daklib.queue.re_isanum.match (answer):
+            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))
                 answer = int(answer)
                 if (answer < 1) or (answer > index):
                     print "%s is not a valid index (%s).  Please retry." % (answer, index_range(index))
@@ -435,36 +450,33 @@ def edit_overrides (new):
                     got_answer = 1
 
         if answer == 'E':
                     got_answer = 1
 
         if answer == 'E':
-            edit_new(new)
+            edit_new(new, upload)
         elif answer == 'D':
             done = 1
         else:
         elif answer == 'D':
             done = 1
         else:
-            edit_index (new, new_index[answer])
+            edit_index (new, upload, new_index[answer])
 
     return new
 
 ################################################################################
 
 
     return new
 
 ################################################################################
 
-def edit_note(note):
+def edit_note(note, upload, session):
     # Write the current data to a temporary file
     # Write the current data to a temporary file
-    temp_filename = daklib.utils.temp_filename()
-    temp_file = daklib.utils.open_file(temp_filename, 'w')
-    temp_file.write(note)
-    temp_file.close()
+    (fd, temp_filename) = utils.temp_filename()
     editor = os.environ.get("EDITOR","vi")
     answer = 'E'
     while answer == 'E':
         os.system("%s %s" % (editor, temp_filename))
     editor = os.environ.get("EDITOR","vi")
     answer = 'E'
     while answer == 'E':
         os.system("%s %s" % (editor, temp_filename))
-        temp_file = daklib.utils.open_file(temp_filename)
-        note = temp_file.read().rstrip()
+        temp_file = utils.open_file(temp_filename)
+        newnote = temp_file.read().rstrip()
         temp_file.close()
         temp_file.close()
-        print "Note:"
-        print daklib.utils.prefix_multi_line_string(note,"  ")
+        print "New Note:"
+        print utils.prefix_multi_line_string(newnote,"  ")
         prompt = "[D]one, Edit, Abandon, Quit ?"
         answer = "XXX"
         while prompt.find(answer) == -1:
         prompt = "[D]one, Edit, Abandon, Quit ?"
         answer = "XXX"
         while prompt.find(answer) == -1:
-            answer = daklib.utils.our_raw_input(prompt)
-            m = daklib.queue.re_default_answer.search(prompt)
+            answer = utils.our_raw_input(prompt)
+            m = re_default_answer.search(prompt)
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
@@ -474,143 +486,161 @@ def edit_note(note):
     elif answer == 'Q':
         end()
         sys.exit(0)
     elif answer == 'Q':
         end()
         sys.exit(0)
-    Upload.pkg.changes["process-new note"] = note
-    Upload.dump_vars(Cnf["Dir::Queue::New"])
+
+    comment = NewComment()
+    comment.package = upload.pkg.changes["source"]
+    comment.version = upload.pkg.changes["version"]
+    comment.comment = newnote
+    comment.author  = utils.whoami()
+    comment.trainee = bool(Options["Trainee"])
+    session.add(comment)
+    session.commit()
 
 ################################################################################
 
 
 ################################################################################
 
-def check_pkg ():
+def check_pkg (upload):
     try:
         less_fd = os.popen("less -R -", 'w', 0)
         stdout_fd = sys.stdout
         try:
             sys.stdout = less_fd
     try:
         less_fd = os.popen("less -R -", 'w', 0)
         stdout_fd = sys.stdout
         try:
             sys.stdout = less_fd
-            examine_package.display_changes(Upload.pkg.changes_file)
-            files = Upload.pkg.files
+            changes = utils.parse_changes (upload.pkg.changes_file)
+            examine_package.display_changes(changes['distribution'], upload.pkg.changes_file)
+            files = upload.pkg.files
             for f in files.keys():
                 if files[f].has_key("new"):
                     ftype = files[f]["type"]
                     if ftype == "deb":
             for f in files.keys():
                 if files[f].has_key("new"):
                     ftype = files[f]["type"]
                     if ftype == "deb":
-                        examine_package.check_deb(f)
+                        examine_package.check_deb(changes['distribution'], f)
                     elif ftype == "dsc":
                     elif ftype == "dsc":
-                        examine_package.check_dsc(f)
+                        examine_package.check_dsc(changes['distribution'], f)
         finally:
         finally:
+            examine_package.output_package_relations()
             sys.stdout = stdout_fd
     except IOError, e:
         if e.errno == errno.EPIPE:
             sys.stdout = stdout_fd
     except IOError, e:
         if e.errno == errno.EPIPE:
-            daklib.utils.warn("[examine_package] Caught EPIPE; skipping.")
+            utils.warn("[examine_package] Caught EPIPE; skipping.")
             pass
         else:
             raise
     except KeyboardInterrupt:
             pass
         else:
             raise
     except KeyboardInterrupt:
-        daklib.utils.warn("[examine_package] Caught C-c; skipping.")
+        utils.warn("[examine_package] Caught C-c; skipping.")
         pass
 
 ################################################################################
 
 ## FIXME: horribly Debian specific
 
         pass
 
 ################################################################################
 
 ## FIXME: horribly Debian specific
 
-def do_bxa_notification():
-    files = Upload.pkg.files
+def do_bxa_notification(upload):
+    files = upload.pkg.files
     summary = ""
     for f in files.keys():
         if files[f]["type"] == "deb":
     summary = ""
     for f in files.keys():
         if files[f]["type"] == "deb":
-            control = apt_pkg.ParseSection(apt_inst.debExtractControl(daklib.utils.open_file(f)))
+            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"))
             summary += "\n"
             summary += "Package: %s\n" % (control.Find("Package"))
             summary += "Description: %s\n" % (control.Find("Description"))
-    Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
-    bxa_mail = daklib.utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
-    daklib.utils.send_mail(bxa_mail)
+    upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
+    bxa_mail = utils.TemplateSubst(upload.Subst,Config()["Dir::Templates"]+"/process-new.bxa_notification")
+    utils.send_mail(bxa_mail)
 
 ################################################################################
 
 
 ################################################################################
 
-def add_overrides (new):
-    changes = Upload.pkg.changes
-    files = Upload.pkg.files
+def add_overrides (new, upload, session):
+    changes = upload.pkg.changes
+    files = upload.pkg.files
+    srcpkg = changes.get("source")
 
 
-    projectB.query("BEGIN WORK")
     for suite in changes["suite"].keys():
     for suite in changes["suite"].keys():
-        suite_id = daklib.database.get_suite_id(suite)
+        suite_id = get_suite(suite).suite_id
         for pkg in new.keys():
         for pkg in new.keys():
-            component_id = daklib.database.get_component_id(new[pkg]["component"])
-            type_id = daklib.database.get_override_type_id(new[pkg]["type"])
+            component_id = get_component(new[pkg]["component"]).component_id
+            type_id = get_override_type(new[pkg]["type"]).overridetype_id
             priority_id = new[pkg]["priority id"]
             section_id = new[pkg]["section id"]
             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))
+            Logger.log(["%s overrides" % (srcpkg), suite, new[pkg]["component"], new[pkg]["type"], new[pkg]["priority"], new[pkg]["section"]])
+            session.execute("INSERT INTO override (suite, component, type, package, priority, section, maintainer) VALUES (:sid, :cid, :tid, :pkg, :pid, :sectid, '')",
+                            { 'sid': suite_id, 'cid': component_id, 'tid':type_id, 'pkg': pkg, 'pid': priority_id, 'sectid': section_id})
             for f in new[pkg]["files"]:
                 if files[f].has_key("new"):
                     del files[f]["new"]
             del new[pkg]
 
             for f in new[pkg]["files"]:
                 if files[f].has_key("new"):
                     del files[f]["new"]
             del new[pkg]
 
-    projectB.query("COMMIT WORK")
+    session.commit()
 
 
-    if Cnf.FindB("Dinstall::BXANotify"):
-        do_bxa_notification()
+    if Config().FindB("Dinstall::BXANotify"):
+        do_bxa_notification(upload)
 
 ################################################################################
 
 
 ################################################################################
 
-def prod_maintainer ():
+def prod_maintainer (note, upload):
+    cnf = Config()
     # Here we prepare an editor and get them ready to prod...
     # Here we prepare an editor and get them ready to prod...
-    temp_filename = daklib.utils.temp_filename()
+    (fd, temp_filename) = utils.temp_filename()
+    temp_file = os.fdopen(fd, 'w')
+    if len(note) > 0:
+        for line in note:
+            temp_file.write(line)
+    temp_file.close()
     editor = os.environ.get("EDITOR","vi")
     answer = 'E'
     while answer == 'E':
         os.system("%s %s" % (editor, temp_filename))
     editor = os.environ.get("EDITOR","vi")
     answer = 'E'
     while answer == 'E':
         os.system("%s %s" % (editor, temp_filename))
-        f = daklib.utils.open_file(temp_filename)
-        prod_message = "".join(f.readlines())
-        f.close()
+        temp_fh = utils.open_file(temp_filename)
+        prod_message = "".join(temp_fh.readlines())
+        temp_fh.close()
         print "Prod message:"
         print "Prod message:"
-        print daklib.utils.prefix_multi_line_string(prod_message,"  ",include_blank_lines=1)
+        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:
         prompt = "[P]rod, Edit, Abandon, Quit ?"
         answer = "XXX"
         while prompt.find(answer) == -1:
-            answer = daklib.utils.our_raw_input(prompt)
-            m = daklib.queue.re_default_answer.search(prompt)
+            answer = utils.our_raw_input(prompt)
+            m = re_default_answer.search(prompt)
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
-        os.unlink(temp_filename)
-        if answer == 'A':
-            return
-        elif answer == 'Q':
-            end()
-            sys.exit(0)
+    os.unlink(temp_filename)
+    if answer == 'A':
+        return
+    elif answer == 'Q':
+        end()
+        sys.exit(0)
     # Otherwise, do the proding...
     # Otherwise, do the proding...
-    user_email_address = daklib.utils.whoami() + " <%s>" % (
-        Cnf["Dinstall::MyAdminAddress"])
+    user_email_address = utils.whoami() + " <%s>" % (
+        cnf["Dinstall::MyAdminAddress"])
 
 
-    Subst = Upload.Subst
+    Subst = upload.Subst
 
     Subst["__FROM_ADDRESS__"] = user_email_address
     Subst["__PROD_MESSAGE__"] = prod_message
 
     Subst["__FROM_ADDRESS__"] = user_email_address
     Subst["__PROD_MESSAGE__"] = prod_message
-    Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
+    Subst["__CC__"] = "Cc: " + cnf["Dinstall::MyEmailAddress"]
 
 
-    prod_mail_message = daklib.utils.TemplateSubst(
-        Subst,Cnf["Dir::Templates"]+"/process-new.prod")
+    prod_mail_message = utils.TemplateSubst(
+        Subst,cnf["Dir::Templates"]+"/process-new.prod")
 
     # Send the prod mail if appropriate
 
     # Send the prod mail if appropriate
-    if not Cnf["Dinstall::Options::No-Mail"]:
-        daklib.utils.send_mail(prod_mail_message)
+    if not cnf["Dinstall::Options::No-Mail"]:
+        utils.send_mail(prod_mail_message)
 
     print "Sent proding message"
 
 ################################################################################
 
 
     print "Sent proding message"
 
 ################################################################################
 
-def do_new():
+def do_new(upload, session):
     print "NEW\n"
     print "NEW\n"
-    files = Upload.pkg.files
-    changes = Upload.pkg.changes
+    files = upload.pkg.files
+    changes = upload.pkg.changes
+    cnf = Config()
 
     # Make a copy of distribution we can happily trample on
     changes["suite"] = copy.copy(changes["distribution"])
 
     # Fix up the list of target suites
     for suite in changes["suite"].keys():
 
     # Make a copy of distribution we can happily trample on
     changes["suite"] = copy.copy(changes["distribution"])
 
     # Fix up the list of target suites
     for suite in changes["suite"].keys():
-        override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
+        override = cnf.Find("Suite::%s::OverrideSuite" % (suite))
         if override:
         if override:
-            (olderr, newerr) = (daklib.database.get_suite_id(suite) == -1,
-              daklib.database.get_suite_id(override) == -1)
+            (olderr, newerr) = (get_suite(suite, session) == None,
+                                get_suite(override, session) == None)
             if olderr or newerr:
                 (oinv, newinv) = ("", "")
                 if olderr: oinv = "invalid "
             if olderr or newerr:
                 (oinv, newinv) = ("", "")
                 if olderr: oinv = "invalid "
@@ -621,15 +651,14 @@ def do_new():
             changes["suite"][override] = 1
     # Validate suites
     for suite in changes["suite"].keys():
             changes["suite"][override] = 1
     # Validate suites
     for suite in changes["suite"].keys():
-        suite_id = daklib.database.get_suite_id(suite)
-        if suite_id == -1:
-            daklib.utils.fubar("%s has invalid suite '%s' (possibly overriden).  say wha?" % (changes, suite))
+        if get_suite(suite, session) is None:
+            utils.fubar("%s has invalid suite '%s' (possibly overriden).  say wha?" % (changes, suite))
 
     # The main NEW processing loop
     done = 0
     while not done:
         # Find out what's new
 
     # The main NEW processing loop
     done = 0
     while not done:
         # Find out what's new
-        new = daklib.queue.determine_new(changes, files, projectB)
+        new = determine_new(changes, files)
 
         if not new:
             break
 
         if not new:
             break
@@ -638,7 +667,7 @@ def do_new():
         if Options["No-Action"] or Options["Automatic"]:
             answer = 'S'
 
         if Options["No-Action"] or Options["Automatic"]:
             answer = 'S'
 
-        (broken, note) = print_new(new, 0)
+        (broken, note) = print_new(new, upload, indexed=0)
         prompt = ""
 
         if not broken and not note:
         prompt = ""
 
         if not broken and not note:
@@ -647,36 +676,61 @@ 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."
             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 note, "
+            prompt += "RemOve all notes, Remove note, "
 
         prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
 
         while prompt.find(answer) == -1:
 
         prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
 
         while prompt.find(answer) == -1:
-            answer = daklib.utils.our_raw_input(prompt)
-            m = daklib.queue.re_default_answer.search(prompt)
+            answer = utils.our_raw_input(prompt)
+            m = re_default_answer.search(prompt)
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
 
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
 
-        if answer == 'A':
-            done = add_overrides (new)
+        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)
+                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':
         elif answer == 'C':
-            check_pkg()
-        elif answer == 'E':
-            new = edit_overrides (new)
-        elif answer == 'M':
-            aborted = Upload.do_reject(1, Options["Manual-Reject"])
+            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"],
+                                       note=get_new_comments(changes.get("source", ""), session=session))
             if not aborted:
             if not aborted:
-                os.unlink(Upload.pkg.changes_file[:-8]+".dak")
+                Logger.log(["NEW REJECT: %s" % (upload.pkg.changes_file)])
+                os.unlink(upload.pkg.changes_file[:-8]+".dak")
                 done = 1
         elif answer == 'N':
                 done = 1
         elif answer == 'N':
-            edit_note(changes.get("process-new note", ""))
-        elif answer == 'P':
-            prod_maintainer()
-        elif answer == 'R':
-            confirm = daklib.utils.our_raw_input("Really clear note (y/N)? ").lower()
+            edit_note(get_new_comments(changes.get("source", ""), session=session),
+                      upload, session)
+        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":
             if confirm == "y":
-                del changes["process-new note"]
+                for c in get_new_comments(changes.get("source", ""), session=session):
+                    session.delete(c)
+                session.commit()
+
         elif answer == 'S':
             done = 1
         elif answer == 'Q':
         elif answer == 'S':
             done = 1
         elif answer == 'Q':
@@ -694,51 +748,16 @@ def usage (exit_code=0):
   -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
   -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
+  -t, --trainee             FTP Trainee mode
   -V, --version             display the version number and exit"""
     sys.exit(exit_code)
 
 ################################################################################
 
   -V, --version             display the version number and exit"""
     sys.exit(exit_code)
 
 ################################################################################
 
-def init():
-    global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
-
-    Cnf = daklib.utils.get_conf()
-
-    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", "comments-dir"]:
-        if not Cnf.has_key("Process-New::Options::%s" % (i)):
-            Cnf["Process-New::Options::%s" % (i)] = ""
-
-    changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
-    Options = Cnf.SubTree("Process-New::Options")
-
-    if Options["Help"]:
-        usage()
-
-    Upload = daklib.queue.Upload(Cnf)
-
-    if not Options["No-Action"]:
-        Logger = Upload.Logger = daklib.logging.Logger(Cnf, "process-new")
-
-    projectB = Upload.projectB
-
-    Sections = Section_Completer()
-    Priorities = Priority_Completer()
-    readline.parse_and_bind("tab: complete")
-
-    return changes_files
-
-################################################################################
-
-def do_byhand():
+def do_byhand(upload, session):
     done = 0
     while not done:
     done = 0
     while not done:
-        files = Upload.pkg.files
+        files = upload.pkg.files
         will_install = 1
         byhand = []
 
         will_install = 1
         byhand = []
 
@@ -761,19 +780,26 @@ def do_byhand():
             prompt = "Manual reject, [S]kip, Quit ?"
 
         while prompt.find(answer) == -1:
             prompt = "Manual reject, [S]kip, Quit ?"
 
         while prompt.find(answer) == -1:
-            answer = daklib.utils.our_raw_input(prompt)
-            m = daklib.queue.re_default_answer.search(prompt)
+            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':
             if answer == "":
                 answer = m.group(1)
             answer = answer[:1].upper()
 
         if answer == 'A':
-            done = 1
-            for f in byhand:
-                del files[f]
+            try:
+                check_daily_lock()
+                done = 1
+                for f in byhand:
+                    del files[f]
+                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':
         elif answer == 'M':
-            Upload.do_reject(1, Options["Manual-Reject"])
-            os.unlink(Upload.pkg.changes_file[:-8]+".dak")
+            Logger.log(["BYHAND REJECT: %s" % (upload.pkg.changes_file)])
+            upload.do_reject(manual=1, reject_message=Options["Manual-Reject"])
+            os.unlink(upload.pkg.changes_file[:-8]+".dak")
             done = 1
         elif answer == 'S':
             done = 1
             done = 1
         elif answer == 'S':
             done = 1
@@ -783,44 +809,156 @@ def do_byhand():
 
 ################################################################################
 
 
 ################################################################################
 
-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):
-                    daklib.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):
-    daklib.utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
-    file_keys = Upload.pkg.files.keys()
-    for f in file_keys:
-        daklib.utils.move (f, dest, perms=perms)
-
-def do_accept():
+def check_daily_lock():
+    """
+    Raises CantGetLockError if the dinstall daily.lock exists.
+    """
+
+    cnf = Config()
+    try:
+        os.open(cnf["Process-New::DinstallLockFile"],
+                os.O_RDONLY | os.O_CREAT | os.O_EXCL)
+    except OSError, e:
+        if e.errno == errno.EEXIST or e.errno == errno.EACCES:
+            raise CantGetLockError
+
+    os.unlink(cnf["Process-New::DinstallLockFile"])
+
+
+@contextlib.contextmanager
+def lock_package(package):
+    """
+    Lock C{package} so that noone else jumps in processing it.
+
+    @type package: string
+    @param package: source package name to lock
+    """
+
+    path = os.path.join(Config()["Process-New::LockDir"], package)
+    try:
+        fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDONLY)
+    except OSError, e:
+        if e.errno == errno.EEXIST or e.errno == errno.EACCES:
+            user = pwd.getpwuid(os.stat(path)[stat.ST_UID])[4].split(',')[0].replace('.', '')
+            raise AlreadyLockedError, user
+
+    try:
+        yield fd
+    finally:
+        os.unlink(path)
+
+# def move_to_dir (upload, 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 = os.path.join(qdir, entry)
+#         u.update_vars()
+#         if not u.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, perms=0664)
+#     os.unlink(Upload.pkg.changes_file[:-8]+".dak")
+
+def _accept(upload):
+    if Options["No-Action"]:
+        return
+    (summary, short_summary) = upload.build_summaries()
+    upload.accept(summary, short_summary, targetdir=Config()["Dir::Queue::Newstage"])
+    os.unlink(upload.pkg.changes_file[:-8]+".dak")
+
+# def do_accept_stableupdate(upload,suite, q):
+#     cnf = Config()
+#     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 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."
+#             Logger.log([utils.getusername(), "PUNEW ACCEPT: %s" % (Upload.pkg.changes_file)])
+#             _accept()
+#         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."
+#             Logger.log([utils.getusername(), "PUNEW ACCEPT: %s" % (Upload.pkg.changes_file)])
+#             _accept()
+#         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::Newstage"]):
+#             # It's in newstage.  Accept into the holding area
+#             print "Binary-only upload, source in newstage."
+#             Logger.log([utils.getusername(), "PUNEW ACCEPT: %s" % (Upload.pkg.changes_file)])
+#             _accept()
+#         else:
+#             # No case applicable.  Bail out.  Return will cause the upload
+#             # to be skipped.
+#             print "ERROR"
+#             print "Stable update failed.  Source not found."
+#             return
+#     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,)
+#             _accept()
+#         else:
+#             move_to_holding(suite, queue_dir)
+
+def do_accept(upload):
     print "ACCEPT"
     print "ACCEPT"
+    cnf = Config()
     if not Options["No-Action"]:
     if not Options["No-Action"]:
-        get_accept_lock()
-        (summary, short_summary) = Upload.build_summaries()
-    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:
-        Upload.accept(summary, short_summary)
-        os.unlink(Upload.pkg.changes_file[:-8]+".dak")
-    os.unlink(Cnf["Process-New::AcceptedLockFile"])
+        (summary, short_summary) = upload.build_summaries()
+#     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
+            utils.fubar("stable accept not supported yet")
+#            return do_accept_stableupdate(suite, q)
+        # Just a normal upload, accept it...
+        _accept(upload)
 
 def check_status(files):
     new = byhand = 0
 
 def check_status(files):
     new = byhand = 0
@@ -831,125 +969,172 @@ def check_status(files):
             new = 1
     return (new, byhand)
 
             new = 1
     return (new, byhand)
 
-def do_pkg(changes_file):
-    Upload.pkg.changes_file = changes_file
-    Upload.init_vars()
-    Upload.update_vars()
-    Upload.update_subst()
-    files = Upload.pkg.files
+def do_pkg(changes_file, session):
+    u = Upload()
+    u.pkg.load_dot_dak(changes_file)
+    u.update_subst()
 
 
-    if not recheck():
-        return
+    cnf = Config()
+    bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
+    if cnf.has_key("Dinstall::Bcc"):
+        u.Subst["__BCC__"] = bcc + "\nBcc: %s" % (cnf["Dinstall::Bcc"])
+    else:
+        u.Subst["__BCC__"] = bcc
 
 
-    (new, byhand) = check_status(files)
-    if new or byhand:
-        if new:
-            do_new()
-        if byhand:
-            do_byhand()
-        (new, byhand) = check_status(files)
+    files = u.pkg.files
 
 
-    if not new and not byhand:
-        do_accept()
+    try:
+        with lock_package(u.pkg.changes["source"]):
+            if not recheck(u, session):
+                return
+
+            (new, byhand) = check_status(files)
+            if new or byhand:
+                if new:
+                    do_new(u, session)
+                if byhand:
+                    do_byhand(u, session)
+                (new, byhand) = check_status(files)
+
+            if not new and not byhand:
+                try:
+                    check_daily_lock()
+                    do_accept(u)
+                except CantGetLockError:
+                    print "Hello? Operator! Give me the number for 911!"
+                    print "Dinstall in the locked area, cant process packages, come back later"
+    except AlreadyLockedError, e:
+        print "Seems to be locked by %s already, skipping..." % (e)
 
 ################################################################################
 
 def end():
 
 ################################################################################
 
 def end():
-    accept_count = Upload.accept_count
-    accept_bytes = Upload.accept_bytes
+    accept_count = SummaryStats().accept_count
+    accept_bytes = SummaryStats().accept_bytes
 
     if accept_count:
         sets = "set"
         if accept_count > 1:
             sets = "sets"
 
     if accept_count:
         sets = "set"
         if accept_count > 1:
             sets = "sets"
-        sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, daklib.utils.size_type(int(accept_bytes))))
+        sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
         Logger.log(["total",accept_count,accept_bytes])
 
         Logger.log(["total",accept_count,accept_bytes])
 
-    if not Options["No-Action"]:
+    if not Options["No-Action"] and not Options["Trainee"]:
         Logger.close()
 
 ################################################################################
 
         Logger.close()
 
 ################################################################################
 
-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 = daklib.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 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 comment_accept(changes_file, comments):
-    Upload.pkg.changes_file = changes_file
-    Upload.init_vars()
-    Upload.update_vars()
-    Upload.update_subst()
-    files = Upload.pkg.files
+def main():
+    global Options, Logger, Sections, Priorities
 
 
-    if not recheck():
-        return # dak wants to REJECT, crap
+    cnf = Config()
+    session = DBConn().session()
 
 
-    (new, byhand) = check_status(files)
-    if not new and not byhand:
-        do_accept()
+    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"),
+                 ('t',"trainee","Process-New::Options::Trainee"),
+                 ('n',"no-action","Process-New::Options::No-Action")]
 
 
-################################################################################
+    for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir", "trainee"]:
+        if not cnf.has_key("Process-New::Options::%s" % (i)):
+            cnf["Process-New::Options::%s" % (i)] = ""
 
 
-def comment_reject(changes_file, comments):
-    Upload.pkg.changes_file = changes_file
-    Upload.init_vars()
-    Upload.update_vars()
-    Upload.update_subst()
+    changes_files = apt_pkg.ParseCommandLine(cnf.Cnf,Arguments,sys.argv)
+    if len(changes_files) == 0 and not cnf.get("Process-New::Options::Comments-Dir",""):
+        changes_files = utils.get_changes_files(cnf["Dir::Queue::New"])
 
 
-    if not recheck():
-        pass # dak has its own reasons to reject as well, which is fine
+    Options = cnf.SubTree("Process-New::Options")
+
+    if Options["Help"]:
+        usage()
 
 
-    reject(comments)
-    print "REJECT\n" + reject_message,
     if not Options["No-Action"]:
     if not Options["No-Action"]:
-        Upload.do_reject(0, reject_message)
-        os.unlink(Upload.pkg.changes_file[:-8]+".dak")
+        try:
+            Logger = daklog.Logger(cnf, "process-new")
+        except CantOpenError, e:
+            Options["Trainee"] = "True"
 
 
-################################################################################
+    Sections = Section_Completer(session)
+    Priorities = Priority_Completer(session)
+    readline.parse_and_bind("tab: complete")
 
 
-def main():
-    changes_files = init()
-    if len(changes_files) > 50:
+    if len(changes_files) > 1:
         sys.stderr.write("Sorting changes...\n")
         sys.stderr.write("Sorting changes...\n")
-    changes_files = sort_changes(changes_files)
+    changes_files = sort_changes(changes_files, session)
 
     # Kill me now? **FIXME**
 
     # Kill me now? **FIXME**
-    Cnf["Dinstall::Options::No-Mail"] = ""
-    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
-
-    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:
+    cnf["Dinstall::Options::No-Mail"] = ""
+
+#     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:
+    if True:
         for changes_file in changes_files:
         for changes_file in changes_files:
-            changes_file = daklib.utils.validate_changes_file_arg(changes_file, 0)
+            changes_file = utils.validate_changes_file_arg(changes_file, 0)
             if not changes_file:
                 continue
             print "\n" + changes_file
             if not changes_file:
                 continue
             print "\n" + changes_file
-            do_pkg (changes_file)
+
+            do_pkg (changes_file, session)
 
     end()
 
 
     end()