]> git.decadent.org.uk Git - dak.git/commitdiff
Merge commit 'djpig/djpig'
authorMark Hymers <mhy@debian.org>
Tue, 27 Oct 2009 10:04:35 +0000 (10:04 +0000)
committerMark Hymers <mhy@debian.org>
Tue, 27 Oct 2009 10:04:35 +0000 (10:04 +0000)
Conflicts:
daklib/dbconn.py

Signed-off-by: Mark Hymers <mhy@debian.org>
1  2 
dak/process_new.py
daklib/dbconn.py

diff --combined dak/process_new.py
index f15a56003f67ae82e5ec347328d94bdae8100125,7e8dd679efc55e160aea97d652ca1b5f8b9444b0..f01f4b91b1278e6549963da4c2fb1359aa2289a6
@@@ -6,6 -6,7 +6,7 @@@
  @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
@@@ -55,40 -56,30 +56,30 @@@ import pw
  import apt_pkg, apt_inst
  import examine_package
  
- from daklib import database
+ from daklib.dbconn import *
+ from daklib.queue import *
  from daklib import daklog
- from daklib import queue
  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
- Cnf = None       #: Configuration, apt_pkg.Configuration
  Options = None
- Upload = None
- projectB = None  #: database connection, pgobject
  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.
          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()):
+             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
                  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):
+                     if cnf.has_key("Dir::Queue::%s" % (q)):
+                         if os.path.exists(cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
                              found = 1
                  if not found:
-                     reject("no source found for %s %s (%s)." % (source_package, source_version, f))
+                     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":
-             reject(Upload.check_binary_against_db(f), "")
+             upload.check_binary_against_db(f, session)
          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"
          if Options["No-Action"] or Options["Automatic"] or Options["Trainee"]:
              answer = 'S'
  
-         print "REJECT\n" + reject_message,
+         print "REJECT\n" + upload.rejects.join("\n"),
          prompt = "[R]eject, Skip, Quit ?"
  
          while prompt.find(answer) == -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
@@@ -186,7 -176,7 +176,7 @@@ def sg_compare (a, b)
      # 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."""
      cache = {}
      # Read in all the .changes files
      for filename in changes_files:
+         u = Upload()
          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)
          per_source[source]["list"].append(cache[filename])
      # Determine oldest time and have note status for each source group
      for source in per_source.keys():
-         q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source)
-         ql = q.getresult()
-         per_source[source]["source_in_database"] = len(ql)>0
+         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]
              mtime = os.stat(d["filename"])[stat.ST_MTIME]
              if mtime < oldest:
                  oldest = mtime
-             have_note += (database.has_new_comment(d["source"], d["version"], True))
+             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
  ################################################################################
  
  class Section_Completer:
-     def __init__ (self):
+     def __init__ (self, session):
          self.sections = []
          self.matches = []
-         q = projectB.query("SELECT section FROM section")
-         for i in q.getresult():
-             self.sections.append(i[0])
+         for s, in session.query(Section.section):
+             self.sections.append(s)
  
      def complete(self, text, state):
          if state == 0:
  ############################################################
  
  class Priority_Completer:
-     def __init__ (self):
+     def __init__ (self, session):
          self.priorities = []
          self.matches = []
-         q = projectB.query("SELECT priority FROM priority")
-         for i in q.getresult():
-             self.priorities.append(i[0])
+         for p, in session.query(Priority.priority):
+             self.priorities.append(p)
  
      def complete(self, text, state):
          if state == 0:
  
  ################################################################################
  
- def print_new (new, indexed, file=sys.stdout):
-     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
          priority = new[pkg]["priority"]
          if new[pkg]["section id"] == -1:
              section += "[!]"
-             broken = 1
+             broken = True
          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)
-     note = database.get_new_comments(Upload.pkg.changes.get("source"))
-     if len(note) > 0:
-         for line in note:
-             print line
-     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
  
  ################################################################################
  
@@@ -326,11 -314,11 +314,11 @@@ def index_range (index)
  ################################################################################
  ################################################################################
  
- def edit_new (new):
+ def edit_new (new, upload):
      # Write the current data to a temporary file
      (fd, temp_filename) = utils.temp_filename()
      temp_file = os.fdopen(fd, 'w')
-     print_new (new, 0, temp_file)
+     print_new (new, upload, indexed=0, file=temp_file)
      temp_file.close()
      # Spawn an editor on that file
      editor = os.environ.get("EDITOR","vi")
              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
  
  ################################################################################
  
- def edit_index (new, index):
+ def edit_index (new, upload, index):
      priority = new[index]["priority"]
      section = new[index]["section"]
      ftype = new[index]["type"]
          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
  
  ################################################################################
  
- def edit_overrides (new):
+ def edit_overrides (new, upload, session):
      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():
                      got_answer = 1
  
          if answer == 'E':
-             edit_new(new)
+             edit_new(new, upload)
          elif answer == 'D':
              done = 1
          else:
-             edit_index (new, new_index[answer])
+             edit_index (new, upload, new_index[answer])
  
      return new
  
  ################################################################################
  
- def edit_note(note):
+ def edit_note(note, upload, session):
      # Write the current data to a temporary file
      (fd, temp_filename) = utils.temp_filename()
      editor = os.environ.get("EDITOR","vi")
          end()
          sys.exit(0)
  
-     database.add_new_comment(Upload.pkg.changes["source"], Upload.pkg.changes["version"], newnote, utils.whoami(), bool(Options["Trainee"]))
+     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
-             changes = utils.parse_changes (Upload.pkg.changes_file)
-             examine_package.display_changes(changes['distribution'], 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"]
  
  ## 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 += "\n"
              summary += "Package: %s\n" % (control.Find("Package"))
              summary += "Description: %s\n" % (control.Find("Description"))
-     Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
-     bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
+     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():
-         suite_id = database.get_suite_id(suite)
+         suite_id = get_suite(suite).suite_id
          for pkg in new.keys():
-             component_id = database.get_component_id(new[pkg]["component"])
-             type_id = 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"]
              Logger.log(["%s overrides" % (srcpkg), suite, new[pkg]["component"], new[pkg]["type"], new[pkg]["priority"], new[pkg]["section"]])
-             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))
+             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]
  
-     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 (note):
+ def prod_maintainer (note, upload):
+     cnf = Config()
      # Here we prepare an editor and get them ready to prod...
      (fd, temp_filename) = utils.temp_filename()
      temp_file = os.fdopen(fd, 'w')
          sys.exit(0)
      # Otherwise, do the proding...
      user_email_address = utils.whoami() + " <%s>" % (
-         Cnf["Dinstall::MyAdminAddress"])
+         cnf["Dinstall::MyAdminAddress"])
  
-     Subst = Upload.Subst
+     Subst = upload.Subst
  
      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 = utils.TemplateSubst(
-         Subst,Cnf["Dir::Templates"]+"/process-new.prod")
+         Subst,cnf["Dir::Templates"]+"/process-new.prod")
  
      # Send the prod mail if appropriate
-     if not Cnf["Dinstall::Options::No-Mail"]:
+     if not cnf["Dinstall::Options::No-Mail"]:
          utils.send_mail(prod_mail_message)
  
      print "Sent proding message"
  
  ################################################################################
  
- def do_new():
+ def do_new(upload, session):
      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():
-         override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
+         override = cnf.Find("Suite::%s::OverrideSuite" % (suite))
          if override:
-             (olderr, newerr) = (database.get_suite_id(suite) == -1,
-               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 "
              changes["suite"][override] = 1
      # Validate suites
      for suite in changes["suite"].keys():
-         suite_id = database.get_suite_id(suite)
-         if suite_id == -1:
+         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
-         new = queue.determine_new(changes, files, projectB)
+         new = determine_new(changes, files)
  
          if not new:
              break
          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:
                  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)
-                 Logger.log([utils.getusername(), "NEW ACCEPT: %s" % (Upload.pkg.changes_file)])
+                 done = add_overrides (new, upload, session)
+                 Logger.log([utils.getusername(), "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()
+             check_pkg(upload)
          elif answer == 'E' and not Options["Trainee"]:
-             new = edit_overrides (new)
+             new = edit_overrides (new, upload, session)
          elif answer == 'M' and not Options["Trainee"]:
-             aborted = Upload.do_reject(manual=1,
+             aborted = upload.do_reject(manual=1,
                                         reject_message=Options["Manual-Reject"],
-                                        note=database.get_new_comments(changes.get("source", "")))
+                                        note=get_new_comments(changes.get("source", ""), session=session))
              if not aborted:
-                 Logger.log([utils.getusername(), "NEW REJECT: %s" % (Upload.pkg.changes_file)])
-                 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
+                 Logger.log([utils.getusername(), "NEW REJECT: %s" % (upload.pkg.changes_file)])
+                 os.unlink(upload.pkg.changes_file[:-8]+".dak")
                  done = 1
          elif answer == 'N':
-             edit_note(database.get_new_comments(changes.get("source", "")))
+             edit_note(get_new_comments(changes.get("source", ""), session=session),
+                       upload, session)
          elif answer == 'P' and not Options["Trainee"]:
-             prod_maintainer(database.get_new_comments(changes.get("source", "")))
-             Logger.log([utils.getusername(), "NEW PROD: %s" % (Upload.pkg.changes_file)])
+             prod_maintainer(get_new_comments(changes.get("source", ""), session=session),
+                             upload)
+             Logger.log([utils.getusername(), "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":
-                 database.delete_new_comments(changes.get("source"), changes.get("version"))
+                 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":
-                 database.delete_all_new_comments(changes.get("source"))
+                 for c in get_new_comments(changes.get("source", ""), session=session):
+                     session.delete(c)
+                 session.commit()
          elif answer == 'S':
              done = 1
          elif answer == 'Q':
@@@ -747,53 -754,10 +754,10 @@@ def usage (exit_code=0)
  
  ################################################################################
  
- def init():
-     global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
-     Cnf = 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"),
-                  ('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)] = ""
-     changes_files = apt_pkg.ParseCommandLine(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"])
-     Options = Cnf.SubTree("Process-New::Options")
-     if Options["Help"]:
-         usage()
-     Upload = queue.Upload(Cnf)
-     if not Options["No-Action"]:
-         try:
-             Logger = Upload.Logger = daklog.Logger(Cnf, "process-new")
-         except CantOpenError, e:
-             Options["Trainee"] = "True"
-     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:
-         files = Upload.pkg.files
+         files = upload.pkg.files
          will_install = 1
          byhand = []
  
                  done = 1
                  for f in byhand:
                      del files[f]
-                 Logger.log([utils.getusername(), "BYHAND ACCEPT: %s" % (Upload.pkg.changes_file)])
+                 Logger.log([utils.getusername(), "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':
-             Logger.log([utils.getusername(), "BYHAND REJECT: %s" % (Upload.pkg.changes_file)])
-             Upload.do_reject(1, Options["Manual-Reject"])
-             os.unlink(Upload.pkg.changes_file[:-8]+".dak")
+             Logger.log([utils.getusername(), "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
@@@ -850,13 -814,15 +814,15 @@@ 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)
+         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"])
+     os.unlink(cnf["Process-New::DinstallLockFile"])
  
  
  @contextlib.contextmanager
@@@ -868,7 -834,7 +834,7 @@@ def lock_package(package)
      @param package: source package name to lock
      """
  
-     path = os.path.join(Cnf["Process-New::LockDir"], package)
+     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:
      finally:
          os.unlink(path)
  
def move_to_dir (dest, perms=0660, changesperms=0664):
    utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
    file_keys = Upload.pkg.files.keys()
-     for f in file_keys:
-         utils.move (f, dest, perms=perms)
- def is_source_in_queue_dir(qdir):
-     entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
-                 and x.endswith(".changes") ]
-     for entry in entries:
-         # read the .dak
-         u = queue.Upload(Cnf)
-         u.pkg.changes_file = 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():
# 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=Cnf["Dir::Queue::Newstage"])
-     os.unlink(Upload.pkg.changes_file[:-8]+".dak")
- def do_accept_stableupdate(suite, q):
-     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():
+     (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"
+     cnf = Config()
      if not Options["No-Action"]:
-         (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:
+         (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):
+             if not upload.pkg.changes["distribution"].has_key(suite):
                  continue
-             return do_accept_stableupdate(suite, q)
+             utils.fubar("stable accept not supported yet")
+ #            return do_accept_stableupdate(suite, q)
          # Just a normal upload, accept it...
-         _accept()
+         _accept(upload)
  
  def check_status(files):
      new = byhand = 0
              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()
+     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
+     files = u.pkg.files
  
      try:
-         with lock_package(Upload.pkg.changes["source"]):
-             if not recheck():
+         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()
+                     do_new(u, session)
                  if byhand:
-                     do_byhand()
+                     do_byhand(u, session)
                  (new, byhand) = check_status(files)
  
              if not new and not byhand:
                  try:
                      check_daily_lock()
-                     do_accept()
+                     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"
@@@ -1048,87 -1024,117 +1024,117 @@@ def end()
  
  ################################################################################
  
- def do_comments(dir, opref, npref, line, fn):
-     for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
-         lines = open("%s/%s" % (dir, comm)).readlines()
-         if len(lines) == 0 or lines[0] != line + "\n": continue
-         changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
-                                 and x.endswith(".changes") ]
-         changes_files = sort_changes(changes_files)
-         for f in changes_files:
-             f = utils.validate_changes_file_arg(f, 0)
-             if not f: continue
-             print "\n" + f
-             fn(f, "".join(lines[1:]))
-         if opref != npref and not Options["No-Action"]:
-             newcomm = npref + comm[len(opref):]
-             os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
+ # def 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"]:
-         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")
-     changes_files = sort_changes(changes_files)
+     changes_files = sort_changes(changes_files, session)
  
      # 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:
              changes_file = utils.validate_changes_file_arg(changes_file, 0)
              if not changes_file:
                  continue
              print "\n" + changes_file
  
-             do_pkg (changes_file)
+             do_pkg (changes_file, session)
  
      end()
  
diff --combined daklib/dbconn.py
index f5a19c1236442360ca57b7b867eed9f24f5f5003,f65c67e447843ab961f368cdb36e1ff28cd5ecd1..8ee9076874d09a0d785924cb4bf3eb891e9b41b9
@@@ -37,14 -37,11 +37,14 @@@ import o
  import psycopg2
  import traceback
  
 +from inspect import getargspec
 +
  from sqlalchemy import create_engine, Table, MetaData, select
  from sqlalchemy.orm import sessionmaker, mapper, relation
  
  # Don't remove this, we re-export the exceptions to scripts which import us
  from sqlalchemy.exc import *
 +from sqlalchemy.orm.exc import NoResultFound
  
  # Only import Config until Queue stuff is changed to store its config
  # in the database
@@@ -58,30 -55,6 +58,30 @@@ __all__ = ['IntegrityError', 'SQLAlchem
  
  ################################################################################
  
 +def session_wrapper(fn):
 +    def wrapped(*args, **kwargs):
 +        private_transaction = False
 +        session = kwargs.get('session')
 +
 +        # No session specified as last argument or in kwargs, create one.
 +        if session is None and len(args) <= len(getargspec(fn)[0]) - 1:
 +            private_transaction = True
 +            kwargs['session'] = DBConn().session()
 +
 +        try:
 +            return fn(*args, **kwargs)
 +        finally:
 +            if private_transaction:
 +                # We created a session; close it.
 +                kwargs['session'].close()
 +
 +    wrapped.__doc__ = fn.__doc__
 +    wrapped.func_name = fn.func_name
 +
 +    return wrapped
 +
 +################################################################################
 +
  class Architecture(object):
      def __init__(self, *args, **kwargs):
          pass
  
  __all__.append('Architecture')
  
 +@session_wrapper
  def get_architecture(architecture, session=None):
      """
      Returns database id for given C{architecture}.
  
      @rtype: Architecture
      @return: Architecture object for the given arch (None if not present)
 -
      """
 -    privatetrans = False
 -
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(Architecture).filter_by(arch_string=architecture)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_architecture')
  
 +@session_wrapper
  def get_architecture_suites(architecture, session=None):
      """
      Returns list of Suite objects for given C{architecture} name
      @rtype: list
      @return: list of Suite objects for the given name (may be empty)
      """
 -    privatetrans = False
 -
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(Suite)
      q = q.join(SuiteArchitecture)
  
      ret = q.all()
  
 -    if privatetrans:
 -        session.close()
 -
      return ret
  
  __all__.append('get_architecture_suites')
@@@ -161,14 -151,13 +161,14 @@@ class Archive(object)
          pass
  
      def __repr__(self):
 -        return '<Archive %s>' % self.name
 +        return '<Archive %s>' % self.archive_name
  
  __all__.append('Archive')
  
 +@session_wrapper
  def get_archive(archive, session=None):
      """
-     returns database id for given c{archive}.
+     returns database id for given C{archive}.
  
      @type archive: string
      @param archive: the name of the arhive
      """
      archive = archive.lower()
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(Archive).filter_by(archive_name=archive)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_archive')
  
@@@ -214,7 -213,6 +214,7 @@@ class DBBinary(object)
  
  __all__.append('DBBinary')
  
 +@session_wrapper
  def get_suites_binary_in(package, session=None):
      """
      Returns list of Suite objects which given C{package} name is in
      @return: list of Suite objects for the given package
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
 -    ret = session.query(Suite).join(BinAssociation).join(DBBinary).filter_by(package=package).all()
 -
 -    session.close()
 -
 -    return ret
 +    return session.query(Suite).join(BinAssociation).join(DBBinary).filter_by(package=package).all()
  
  __all__.append('get_suites_binary_in')
  
 +@session_wrapper
  def get_binary_from_id(id, session=None):
      """
      Returns DBBinary object for given C{id}
      @rtype: DBBinary
      @return: DBBinary object for the given binary (None if not present)
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(DBBinary).filter_by(binary_id=id)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_binary_from_id')
  
 +@session_wrapper
  def get_binaries_from_name(package, version=None, architecture=None, session=None):
      """
      Returns list of DBBinary objects for given C{package} name
      @rtype: list
      @return: list of DBBinary objects for the given name (may be empty)
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(DBBinary).filter_by(package=package)
  
  
      ret = q.all()
  
 -    if privatetrans:
 -        session.close()
 -
      return ret
  
  __all__.append('get_binaries_from_name')
  
 +@session_wrapper
  def get_binaries_from_source_id(source_id, session=None):
      """
      Returns list of DBBinary objects for given C{source_id}
      @rtype: list
      @return: list of DBBinary objects for the given name (may be empty)
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
 -    ret = session.query(DBBinary).filter_by(source_id=source_id).all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
  
 +    return session.query(DBBinary).filter_by(source_id=source_id).all()
  
  __all__.append('get_binaries_from_source_id')
  
 -
 +@session_wrapper
  def get_binary_from_name_suite(package, suitename, session=None):
      ### For dak examine-package
      ### XXX: Doesn't use object API yet
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      sql = """SELECT DISTINCT(b.package), b.version, c.name, su.suite_name
               FROM binaries b, files fi, location l, component c, bin_associations ba, suite su
                 AND su.suite_name=:suitename
            ORDER BY b.version DESC"""
  
 -    ret = session.execute(sql, {'package': package, 'suitename': suitename})
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return session.execute(sql, {'package': package, 'suitename': suitename})
  
  __all__.append('get_binary_from_name_suite')
  
 +@session_wrapper
  def get_binary_components(package, suitename, arch, session=None):
      # Check for packages that have moved from one component to another
      query = """SELECT c.name FROM binaries b, bin_associations ba, suite s, location l, component c, architecture a, files f
  
      vals = {'package': package, 'suitename': suitename, 'arch': arch}
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
 -    ret = session.execute(query, vals)
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return session.execute(query, vals)
  
  __all__.append('get_binary_components')
  
@@@ -374,7 -422,6 +374,7 @@@ class Component(object)
  
  __all__.append('Component')
  
 +@session_wrapper
  def get_component(component, session=None):
      """
      Returns database id for given C{component}.
      """
      component = component.lower()
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(Component).filter_by(component_name=component)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_component')
  
@@@ -441,10 -498,7 +441,10 @@@ def get_or_set_contents_file_id(filenam
          privatetrans = True
  
      q = session.query(ContentFilename).filter_by(filename=filename)
 -    if q.count() < 1:
 +
 +    try:
 +        ret = q.one().cafilename_id
 +    except NoResultFound:
          cf = ContentFilename()
          cf.filename = filename
          session.add(cf)
          else:
              session.flush()
          ret = cf.cafilename_id
 -    else:
 -        ret = q.one().cafilename_id
  
      if privatetrans:
          session.close()
  
  __all__.append('get_or_set_contents_file_id')
  
 +@session_wrapper
  def get_contents(suite, overridetype, section=None, session=None):
      """
      Returns contents for a suite / overridetype combination, limiting
      package, arch_id)
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      # find me all of the contents for a given suite
      contents_q = """SELECT (p.path||'/'||n.file) AS fn,
                              s.section,
  
      contents_q += " ORDER BY fn"
  
 -    ret = session.execute(contents_q, vals)
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return session.execute(contents_q, vals)
  
  __all__.append('get_contents')
  
@@@ -545,10 -610,7 +545,10 @@@ def get_or_set_contents_path_id(filepat
          privatetrans = True
  
      q = session.query(ContentFilepath).filter_by(filepath=filepath)
 -    if q.count() < 1:
 +
 +    try:
 +        ret = q.one().cafilepath_id
 +    except NoResultFound:
          cf = ContentFilepath()
          cf.filepath = filepath
          session.add(cf)
          else:
              session.flush()
          ret = cf.cafilepath_id
 -    else:
 -        ret = q.one().cafilepath_id
  
      if privatetrans:
          session.close()
@@@ -650,7 -714,6 +650,7 @@@ class DSCFile(object)
  
  __all__.append('DSCFile')
  
 +@session_wrapper
  def get_dscfiles(dscfile_id=None, source_id=None, poolfile_id=None, session=None):
      """
      Returns a list of DSCFiles which may be empty
      @return: Possibly empty list of DSCFiles
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(DSCFile)
  
      if dscfile_id is not None:
      if poolfile_id is not None:
          q = q.filter_by(poolfile_id=poolfile_id)
  
 -    ret = q.all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return q.all()
  
  __all__.append('get_dscfiles')
  
@@@ -694,7 -767,6 +694,7 @@@ class PoolFile(object)
  
  __all__.append('PoolFile')
  
 +@session_wrapper
  def check_poolfile(filename, filesize, md5sum, location_id, session=None):
      """
      Returns a tuple:
                      (False, PoolFile object) if file found with size/md5sum mismatch
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(PoolFile).filter_by(filename=filename)
      q = q.join(Location).filter_by(location_id=location_id)
  
      if ret is None:
          ret = (True, obj)
  
 -    if privatetrans:
 -        session.close()
 -
      return ret
  
  __all__.append('check_poolfile')
  
 +@session_wrapper
  def get_poolfile_by_id(file_id, session=None):
      """
      Returns a PoolFile objects or None for the given id
      @return: either the PoolFile object or None
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(PoolFile).filter_by(file_id=file_id)
  
 -    if q.count() > 0:
 -        ret = q.one()
 -    else:
 -        ret = None
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_poolfile_by_id')
  
  
 +@session_wrapper
  def get_poolfile_by_name(filename, location_id=None, session=None):
      """
      Returns an array of PoolFile objects for the given filename and
      @return: array of PoolFile objects
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(PoolFile).filter_by(filename=filename)
  
      if location_id is not None:
          q = q.join(Location).filter_by(location_id=location_id)
  
 -    ret = q.all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return q.all()
  
  __all__.append('get_poolfile_by_name')
  
 +@session_wrapper
  def get_poolfile_like_name(filename, session=None):
      """
      Returns an array of PoolFile objects which are like the given name
      @return: array of PoolFile objects
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      # TODO: There must be a way of properly using bind parameters with %FOO%
      q = session.query(PoolFile).filter(PoolFile.filename.like('%%%s%%' % filename))
  
 -    ret = q.all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return q.all()
  
  __all__.append('get_poolfile_like_name')
  
@@@ -844,10 -951,7 +844,10 @@@ def get_or_set_fingerprint(fpr, session
          privatetrans = True
  
      q = session.query(Fingerprint).filter_by(fingerprint=fpr)
 -    if q.count() < 1:
 +
 +    try:
 +        ret = q.one()
 +    except NoResultFound:
          fingerprint = Fingerprint()
          fingerprint.fingerprint = fpr
          session.add(fingerprint)
          else:
              session.flush()
          ret = fingerprint
 -    else:
 -        ret = q.one()
  
      if privatetrans:
          session.close()
@@@ -922,7 -1028,6 +922,7 @@@ class Location(object)
  
  __all__.append('Location')
  
 +@session_wrapper
  def get_location(location, component=None, archive=None, session=None):
      """
      Returns Location object for the given combination of location, component
      @return: Either a Location object or None if one can't be found
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(Location).filter_by(path=location)
  
      if archive is not None:
      if component is not None:
          q = q.join(Component).filter_by(component_name=component)
  
 -    if q.count() < 1:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_location')
  
@@@ -997,9 -1112,7 +997,9 @@@ def get_or_set_maintainer(name, session
          privatetrans = True
  
      q = session.query(Maintainer).filter_by(name=name)
 -    if q.count() < 1:
 +    try:
 +        ret = q.one()
 +    except NoResultFound:
          maintainer = Maintainer()
          maintainer.name = name
          session.add(maintainer)
          else:
              session.flush()
          ret = maintainer
 -    else:
 -        ret = q.one()
  
      if privatetrans:
          session.close()
@@@ -1052,7 -1167,6 +1052,7 @@@ class NewComment(object)
  
  __all__.append('NewComment')
  
 +@session_wrapper
  def has_new_comment(package, version, session=None):
      """
      Returns true if the given combination of C{package}, C{version} has a comment.
      @return: true/false
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(NewComment)
      q = q.filter_by(package=package)
      q = q.filter_by(version=version)
  
 -    ret = q.count() > 0
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return bool(q.count() > 0)
  
  __all__.append('has_new_comment')
  
 +@session_wrapper
  def get_new_comments(package=None, version=None, comment_id=None, session=None):
      """
      Returns (possibly empty) list of NewComment objects for the given
  
      @rtype: list
      @return: A (possibly empty) list of NewComment objects will be returned
 -
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(NewComment)
      if package is not None: q = q.filter_by(package=package)
      if version is not None: q = q.filter_by(version=version)
      if comment_id is not None: q = q.filter_by(comment_id=comment_id)
  
 -    ret = q.all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return q.all()
  
  __all__.append('get_new_comments')
  
@@@ -1122,7 -1256,6 +1122,7 @@@ class Override(object)
  
  __all__.append('Override')
  
 +@session_wrapper
  def get_override(package, suite=None, component=None, overridetype=None, session=None):
      """
      Returns Override object for the given parameters
  
      @rtype: list
      @return: A (possibly empty) list of Override objects will be returned
 -
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(Override)
      q = q.filter_by(package=package)
          if not isinstance(overridetype, list): overridetype = [overridetype]
          q = q.join(OverrideType).filter(OverrideType.overridetype.in_(overridetype))
  
 -    ret = q.all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return q.all()
  
  __all__.append('get_override')
  
@@@ -1181,7 -1324,6 +1181,7 @@@ class OverrideType(object)
  
  __all__.append('OverrideType')
  
 +@session_wrapper
  def get_override_type(override_type, session=None):
      """
      Returns OverrideType object for given C{override type}.
  
      @rtype: int
      @return: the database id for the given override type
 -
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(OverrideType).filter_by(overridetype=override_type)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_override_type')
  
@@@ -1317,7 -1469,6 +1317,7 @@@ class Priority(object)
  
  __all__.append('Priority')
  
 +@session_wrapper
  def get_priority(priority, session=None):
      """
      Returns Priority object for given C{priority name}.
  
      @rtype: Priority
      @return: Priority object for the given priority
 -
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(Priority).filter_by(priority=priority)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_priority')
  
 +@session_wrapper
  def get_priorities(session=None):
      """
      Returns dictionary of priority names -> id mappings
      @rtype: dictionary
      @return: dictionary of priority names -> id mappings
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      ret = {}
      q = session.query(Priority)
      for x in q.all():
          ret[x.priority] = x.priority_id
  
 -    if privatetrans:
 -        session.close()
 -
      return ret
  
  __all__.append('get_priorities')
@@@ -1429,7 -1596,6 +1429,7 @@@ class Queue(object)
                  # TODO: Move into database as above
                  if conf.FindB("Dinstall::SecurityQueueBuild"):
                      # Copy it since the original won't be readable by www-data
 +                    import utils
                      utils.copy(src, dest)
                  else:
                      # Create a symlink to it
  
  __all__.append('Queue')
  
 +@session_wrapper
  def get_queue(queuename, session=None):
      """
      Returns Queue object for given C{queue name}.
  
      @rtype: Queue
      @return: Queue object for the given queue
 -
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(Queue).filter_by(queue_name=queuename)
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
  
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_queue')
  
@@@ -1524,7 -1698,6 +1524,7 @@@ class QueueBuild(object)
  
  __all__.append('QueueBuild')
  
 +@session_wrapper
  def get_queue_build(filename, suite, session=None):
      """
      Returns QueueBuild object for given C{filename} and C{suite}.
  
      @rtype: Queue
      @return: Queue object for the given queue
 -
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      if isinstance(suite, int):
          q = session.query(QueueBuild).filter_by(filename=filename).filter_by(suite_id=suite)
          q = session.query(QueueBuild).filter_by(filename=filename)
          q = q.join(Suite).filter_by(suite_name=suite)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_queue_build')
  
@@@ -1579,7 -1762,6 +1579,7 @@@ class Section(object)
  
  __all__.append('Section')
  
 +@session_wrapper
  def get_section(section, session=None):
      """
      Returns Section object for given C{section name}.
  
      @rtype: Section
      @return: Section object for the given section name
 -
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(Section).filter_by(section=section)
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
  
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_section')
  
 +@session_wrapper
  def get_sections(session=None):
      """
      Returns dictionary of section names -> id mappings
      @rtype: dictionary
      @return: dictionary of section names -> id mappings
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      ret = {}
      q = session.query(Section)
      for x in q.all():
          ret[x.section] = x.section_id
  
 -    if privatetrans:
 -        session.close()
 -
      return ret
  
  __all__.append('get_sections')
@@@ -1637,7 -1834,6 +1637,7 @@@ class DBSource(object)
  
  __all__.append('DBSource')
  
 +@session_wrapper
  def source_exists(source, source_version, suites = ["any"], session=None):
      """
      Ensure that source exists somewhere in the archive for the binary
  
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      cnf = Config()
      ret = 1
  
          # No source found so return not ok
          ret = 0
  
 -    if privatetrans:
 -        session.close()
 -
      return ret
  
  __all__.append('source_exists')
  
 +@session_wrapper
  def get_suites_source_in(source, session=None):
      """
      Returns list of Suite objects which given C{source} name is in
      @return: list of Suite objects for the given source
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
 -    ret = session.query(Suite).join(SrcAssociation).join(DBSource).filter_by(source=source).all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return session.query(Suite).join(SrcAssociation).join(DBSource).filter_by(source=source).all()
  
  __all__.append('get_suites_source_in')
  
 +@session_wrapper
  def get_sources_from_name(source, version=None, dm_upload_allowed=None, session=None):
      """
      Returns list of DBSource objects for given C{source} name and other parameters
      @rtype: list
      @return: list of DBSource objects for the given name (may be empty)
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(DBSource).filter_by(source=source)
  
      if dm_upload_allowed is not None:
          q = q.filter_by(dm_upload_allowed=dm_upload_allowed)
  
 -    ret = q.all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return q.all()
  
  __all__.append('get_sources_from_name')
  
 +@session_wrapper
  def get_source_in_suite(source, suite, session=None):
      """
      Returns list of DBSource objects for a combination of C{source} and C{suite}.
      @return: the version for I{source} in I{suite}
  
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(SrcAssociation)
      q = q.join('source').filter_by(source=source)
      q = q.join('suite').filter_by(suite_name=suite)
  
 -    if q.count() == 0:
 -        ret =  None
 -    else:
 -        # ???: Maybe we should just return the SrcAssociation object instead
 -        ret = q.one().source
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one().source
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_source_in_suite')
  
@@@ -1860,7 -2090,6 +1860,7 @@@ class Suite(object)
  
  __all__.append('Suite')
  
 +@session_wrapper
  def get_suite_architecture(suite, architecture, session=None):
      """
      Returns a SuiteArchitecture object given C{suite} and ${arch} or None if it
      @return: the SuiteArchitecture object or None
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(SuiteArchitecture)
      q = q.join(Architecture).filter_by(arch_string=architecture)
      q = q.join(Suite).filter_by(suite_name=suite)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_suite_architecture')
  
 +@session_wrapper
  def get_suite(suite, session=None):
      """
      Returns Suite object for given C{suite name}.
      generated if not supplied)
  
      @rtype: Suite
-     @return: Suite object for the requested suite name (None if not presenT)
+     @return: Suite object for the requested suite name (None if not present)
 -
      """
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
  
      q = session.query(Suite).filter_by(suite_name=suite)
  
 -    if q.count() == 0:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_suite')
  
@@@ -1927,7 -2175,6 +1927,7 @@@ class SuiteArchitecture(object)
  
  __all__.append('SuiteArchitecture')
  
 +@session_wrapper
  def get_suite_architectures(suite, skipsrc=False, skipall=False, session=None):
      """
      Returns list of Architecture objects for given C{suite} name
      @return: list of Architecture objects for the given name (may be empty)
      """
  
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(Architecture)
      q = q.join(SuiteArchitecture)
      q = q.join(Suite).filter_by(suite_name=suite)
  
      q = q.order_by('arch_string')
  
 -    ret = q.all()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    return q.all()
  
  __all__.append('get_suite_architectures')
  
@@@ -2044,9 -2301,7 +2044,9 @@@ def get_or_set_uid(uidname, session=Non
  
      q = session.query(Uid).filter_by(uid=uidname)
  
 -    if q.count() < 1:
 +    try:
 +        ret = q.one()
 +    except NoResultFound:
          uid = Uid()
          uid.uid = uidname
          session.add(uid)
          else:
              session.flush()
          ret = uid
 -    else:
 -        ret = q.one()
  
      if privatetrans:
          session.close()
  
  __all__.append('get_or_set_uid')
  
 -
 +@session_wrapper
  def get_uid_from_fingerprint(fpr, session=None):
 -    privatetrans = False
 -    if session is None:
 -        session = DBConn().session()
 -        privatetrans = True
 -
      q = session.query(Uid)
      q = q.join(Fingerprint).filter_by(fingerprint=fpr)
  
 -    if q.count() != 1:
 -        ret = None
 -    else:
 -        ret = q.one()
 -
 -    if privatetrans:
 -        session.close()
 -
 -    return ret
 +    try:
 +        return q.one()
 +    except NoResultFound:
 +        return None
  
  __all__.append('get_uid_from_fingerprint')