2 # vim:set et ts=4 sw=4:
4 """ Handles NEW and BYHAND packages
6 @contact: Debian FTP Master <ftpmaster@debian.org>
7 @copyright: 2001, 2002, 2003, 2004, 2005, 2006 James Troup <james@nocrew.org>
8 @copyright: 2009 Joerg Jaspert <joerg@debian.org>
9 @copyright: 2009 Frank Lichtenheld <djpig@debian.org>
10 @license: GNU General Public License version 2 or later
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 ################################################################################
28 # 23:12|<aj> I will not hush!
30 # 23:12|<aj> Where there is injustice in the world, I shall be there!
31 # 23:13|<aj> I shall not be silenced!
32 # 23:13|<aj> The world shall know!
33 # 23:13|<aj> The world *must* know!
34 # 23:13|<elmo> oh dear, he's gone back to powerpuff girls... ;-)
35 # 23:13|<aj> yay powerpuff girls!!
36 # 23:13|<aj> buttercup's my favourite, who's yours?
37 # 23:14|<aj> you're backing away from the keyboard right now aren't you?
38 # 23:14|<aj> *AREN'T YOU*?!
39 # 23:15|<aj> I will not be treated like this.
40 # 23:15|<aj> I shall have my revenge.
41 # 23:15|<aj> I SHALL!!!
43 ################################################################################
45 from __future__ import with_statement
56 import apt_pkg, apt_inst
57 import examine_package
59 from daklib.dbconn import *
60 from daklib.queue import *
61 from daklib import daklog
62 from daklib import utils
63 from daklib.regexes import re_no_epoch, re_default_answer, re_isanum, re_package
64 from daklib.dak_exceptions import CantOpenError, AlreadyLockedError, CantGetLockError
65 from daklib.summarystats import SummaryStats
66 from daklib.config import Config
75 ################################################################################
76 ################################################################################
77 ################################################################################
79 def recheck(upload, session):
80 # STU: I'm not sure, but I don't thin kthis is necessary any longer: upload.recheck(session)
81 if len(upload.rejects) > 0:
83 if Options["No-Action"] or Options["Automatic"] or Options["Trainee"]:
86 print "REJECT\n%s" % '\n'.join(upload.rejects)
87 prompt = "[R]eject, Skip, Quit ?"
89 while prompt.find(answer) == -1:
90 answer = utils.our_raw_input(prompt)
91 m = re_default_answer.match(prompt)
94 answer = answer[:1].upper()
97 upload.do_reject(manual=0, reject_message='\n'.join(upload.rejects))
107 ################################################################################
109 def indiv_sg_compare (a, b):
110 """Sort by source name, source, version, 'have source', and
111 finally by filename."""
112 # Sort by source version
113 q = apt_pkg.VersionCompare(a["version"], b["version"])
117 # Sort by 'have source'
118 a_has_source = a["architecture"].get("source")
119 b_has_source = b["architecture"].get("source")
120 if a_has_source and not b_has_source:
122 elif b_has_source and not a_has_source:
125 return cmp(a["filename"], b["filename"])
127 ############################################################
129 def sg_compare (a, b):
132 """Sort by have note, source already in database and time of oldest upload."""
134 a_note_state = a["note_state"]
135 b_note_state = b["note_state"]
136 if a_note_state < b_note_state:
138 elif a_note_state > b_note_state:
140 # Sort by source already in database (descending)
141 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
142 if source_in_database:
143 return -source_in_database
145 # Sort by time of oldest upload
146 return cmp(a["oldest"], b["oldest"])
148 def sort_changes(changes_files, session):
149 """Sort into source groups, then sort each source group by version,
150 have source, filename. Finally, sort the source groups by have
151 note, time of oldest upload of each source upload."""
152 if len(changes_files) == 1:
157 # Read in all the .changes files
158 for filename in changes_files:
161 u.pkg.changes_file = filename
162 u.load_changes(filename)
164 cache[filename] = copy.copy(u.pkg.changes)
165 cache[filename]["filename"] = filename
167 sorted_list.append(filename)
169 # Divide the .changes into per-source groups
171 for filename in cache.keys():
172 source = cache[filename]["source"]
173 if not per_source.has_key(source):
174 per_source[source] = {}
175 per_source[source]["list"] = []
176 per_source[source]["list"].append(cache[filename])
177 # Determine oldest time and have note status for each source group
178 for source in per_source.keys():
179 q = session.query(DBSource).filter_by(source = source).all()
180 per_source[source]["source_in_database"] = len(q)>0
181 source_list = per_source[source]["list"]
182 first = source_list[0]
183 oldest = os.stat(first["filename"])[stat.ST_MTIME]
185 for d in per_source[source]["list"]:
186 mtime = os.stat(d["filename"])[stat.ST_MTIME]
189 have_note += has_new_comment(d["source"], d["version"], session)
190 per_source[source]["oldest"] = oldest
192 per_source[source]["note_state"] = 0; # none
193 elif have_note < len(source_list):
194 per_source[source]["note_state"] = 1; # some
196 per_source[source]["note_state"] = 2; # all
197 per_source[source]["list"].sort(indiv_sg_compare)
198 per_source_items = per_source.items()
199 per_source_items.sort(sg_compare)
200 for i in per_source_items:
201 for j in i[1]["list"]:
202 sorted_list.append(j["filename"])
205 ################################################################################
207 class Section_Completer:
208 def __init__ (self, session):
211 for s, in session.query(Section.section):
212 self.sections.append(s)
214 def complete(self, text, state):
218 for word in self.sections:
220 self.matches.append(word)
222 return self.matches[state]
226 ############################################################
228 class Priority_Completer:
229 def __init__ (self, session):
232 for p, in session.query(Priority.priority):
233 self.priorities.append(p)
235 def complete(self, text, state):
239 for word in self.priorities:
241 self.matches.append(word)
243 return self.matches[state]
247 ################################################################################
249 def print_new (new, upload, indexed, file=sys.stdout):
253 for pkg in new.keys():
255 section = new[pkg]["section"]
256 priority = new[pkg]["priority"]
257 if new[pkg]["section id"] == -1:
260 if new[pkg]["priority id"] == -1:
264 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
266 line = "%-20s %-20s %-20s" % (pkg, priority, section)
267 line = line.strip()+'\n'
269 notes = get_new_comments(upload.pkg.changes.get("source"))
271 print "\nAuthor: %s\nVersion: %s\nTimestamp: %s\n\n%s" \
272 % (note.author, note.version, note.notedate, note.comment)
274 return broken, len(notes) > 0
276 ################################################################################
278 def index_range (index):
282 return "1-%s" % (index)
284 ################################################################################
285 ################################################################################
287 def edit_new (new, upload):
288 # Write the current data to a temporary file
289 (fd, temp_filename) = utils.temp_filename()
290 temp_file = os.fdopen(fd, 'w')
291 print_new (new, upload, indexed=0, file=temp_file)
293 # Spawn an editor on that file
294 editor = os.environ.get("EDITOR","vi")
295 result = os.system("%s %s" % (editor, temp_filename))
297 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
298 # Read the edited data back in
299 temp_file = utils.open_file(temp_filename)
300 lines = temp_file.readlines()
302 os.unlink(temp_filename)
309 # Pad the list if necessary
310 s[len(s):3] = [None] * (3-len(s))
311 (pkg, priority, section) = s[:3]
312 if not new.has_key(pkg):
313 utils.warn("Ignoring unknown package '%s'" % (pkg))
315 # Strip off any invalid markers, print_new will readd them.
316 if section.endswith("[!]"):
317 section = section[:-3]
318 if priority.endswith("[!]"):
319 priority = priority[:-3]
320 for f in new[pkg]["files"]:
321 upload.pkg.files[f]["section"] = section
322 upload.pkg.files[f]["priority"] = priority
323 new[pkg]["section"] = section
324 new[pkg]["priority"] = priority
326 ################################################################################
328 def edit_index (new, upload, index):
329 priority = new[index]["priority"]
330 section = new[index]["section"]
331 ftype = new[index]["type"]
334 print "\t".join([index, priority, section])
338 prompt = "[B]oth, Priority, Section, Done ? "
340 prompt = "[S]ection, Done ? "
341 edit_priority = edit_section = 0
343 while prompt.find(answer) == -1:
344 answer = utils.our_raw_input(prompt)
345 m = re_default_answer.match(prompt)
348 answer = answer[:1].upper()
355 edit_priority = edit_section = 1
361 readline.set_completer(Priorities.complete)
363 while not got_priority:
364 new_priority = utils.our_raw_input("New priority: ").strip()
365 if new_priority not in Priorities.priorities:
366 print "E: '%s' is not a valid priority, try again." % (new_priority)
369 priority = new_priority
373 readline.set_completer(Sections.complete)
375 while not got_section:
376 new_section = utils.our_raw_input("New section: ").strip()
377 if new_section not in Sections.sections:
378 print "E: '%s' is not a valid section, try again." % (new_section)
381 section = new_section
383 # Reset the readline completer
384 readline.set_completer(None)
386 for f in new[index]["files"]:
387 upload.pkg.files[f]["section"] = section
388 upload.pkg.files[f]["priority"] = priority
389 new[index]["priority"] = priority
390 new[index]["section"] = section
393 ################################################################################
395 def edit_overrides (new, upload, session):
399 print_new (new, upload, indexed=1)
406 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
409 while not got_answer:
410 answer = utils.our_raw_input(prompt)
411 if not answer.isdigit():
412 answer = answer[:1].upper()
413 if answer == "E" or answer == "D":
415 elif re_isanum.match (answer):
417 if (answer < 1) or (answer > index):
418 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
423 edit_new(new, upload)
427 edit_index (new, upload, new_index[answer])
431 ################################################################################
433 def edit_note(note, upload, session):
434 # Write the current data to a temporary file
435 (fd, temp_filename) = utils.temp_filename()
436 editor = os.environ.get("EDITOR","vi")
439 os.system("%s %s" % (editor, temp_filename))
440 temp_file = utils.open_file(temp_filename)
441 newnote = temp_file.read().rstrip()
444 print utils.prefix_multi_line_string(newnote," ")
445 prompt = "[D]one, Edit, Abandon, Quit ?"
447 while prompt.find(answer) == -1:
448 answer = utils.our_raw_input(prompt)
449 m = re_default_answer.search(prompt)
452 answer = answer[:1].upper()
453 os.unlink(temp_filename)
460 comment = NewComment()
461 comment.package = upload.pkg.changes["source"]
462 comment.version = upload.pkg.changes["version"]
463 comment.comment = newnote
464 comment.author = utils.whoami()
465 comment.trainee = bool(Options["Trainee"])
469 ################################################################################
471 def check_pkg (upload):
473 less_fd = os.popen("less -R -", 'w', 0)
474 stdout_fd = sys.stdout
477 changes = utils.parse_changes (upload.pkg.changes_file)
478 examine_package.display_changes(changes['distribution'], upload.pkg.changes_file)
479 files = upload.pkg.files
480 for f in files.keys():
481 if files[f].has_key("new"):
482 ftype = files[f]["type"]
484 examine_package.check_deb(changes['distribution'], f)
486 examine_package.check_dsc(changes['distribution'], f)
488 examine_package.output_package_relations()
489 sys.stdout = stdout_fd
491 if e.errno == errno.EPIPE:
492 utils.warn("[examine_package] Caught EPIPE; skipping.")
496 except KeyboardInterrupt:
497 utils.warn("[examine_package] Caught C-c; skipping.")
500 ################################################################################
502 ## FIXME: horribly Debian specific
504 def do_bxa_notification(upload):
505 files = upload.pkg.files
507 for f in files.keys():
508 if files[f]["type"] == "deb":
509 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
511 summary += "Package: %s\n" % (control.Find("Package"))
512 summary += "Description: %s\n" % (control.Find("Description"))
513 upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
514 bxa_mail = utils.TemplateSubst(upload.Subst,Config()["Dir::Templates"]+"/process-new.bxa_notification")
515 utils.send_mail(bxa_mail)
517 ################################################################################
519 def add_overrides (new, upload, session):
520 changes = upload.pkg.changes
521 files = upload.pkg.files
522 srcpkg = changes.get("source")
524 for suite in changes["suite"].keys():
525 suite_id = get_suite(suite).suite_id
526 for pkg in new.keys():
527 component_id = get_component(new[pkg]["component"]).component_id
528 type_id = get_override_type(new[pkg]["type"]).overridetype_id
529 priority_id = new[pkg]["priority id"]
530 section_id = new[pkg]["section id"]
531 Logger.log(["%s overrides" % (srcpkg), suite, new[pkg]["component"], new[pkg]["type"], new[pkg]["priority"], new[pkg]["section"]])
532 session.execute("INSERT INTO override (suite, component, type, package, priority, section, maintainer) VALUES (:sid, :cid, :tid, :pkg, :pid, :sectid, '')",
533 { 'sid': suite_id, 'cid': component_id, 'tid':type_id, 'pkg': pkg, 'pid': priority_id, 'sectid': section_id})
534 for f in new[pkg]["files"]:
535 if files[f].has_key("new"):
541 if Config().FindB("Dinstall::BXANotify"):
542 do_bxa_notification(upload)
544 ################################################################################
546 def prod_maintainer (note, upload):
548 # Here we prepare an editor and get them ready to prod...
549 (fd, temp_filename) = utils.temp_filename()
550 temp_file = os.fdopen(fd, 'w')
553 temp_file.write(line)
555 editor = os.environ.get("EDITOR","vi")
558 os.system("%s %s" % (editor, temp_filename))
559 temp_fh = utils.open_file(temp_filename)
560 prod_message = "".join(temp_fh.readlines())
562 print "Prod message:"
563 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
564 prompt = "[P]rod, Edit, Abandon, Quit ?"
566 while prompt.find(answer) == -1:
567 answer = utils.our_raw_input(prompt)
568 m = re_default_answer.search(prompt)
571 answer = answer[:1].upper()
572 os.unlink(temp_filename)
578 # Otherwise, do the proding...
579 user_email_address = utils.whoami() + " <%s>" % (
580 cnf["Dinstall::MyAdminAddress"])
584 Subst["__FROM_ADDRESS__"] = user_email_address
585 Subst["__PROD_MESSAGE__"] = prod_message
586 Subst["__CC__"] = "Cc: " + cnf["Dinstall::MyEmailAddress"]
588 prod_mail_message = utils.TemplateSubst(
589 Subst,cnf["Dir::Templates"]+"/process-new.prod")
591 # Send the prod mail if appropriate
592 if not cnf["Dinstall::Options::No-Mail"]:
593 utils.send_mail(prod_mail_message)
595 print "Sent proding message"
597 ################################################################################
599 def do_new(upload, session):
601 files = upload.pkg.files
602 upload.check_files(not Options["No-Action"])
603 changes = upload.pkg.changes
606 # Make a copy of distribution we can happily trample on
607 changes["suite"] = copy.copy(changes["distribution"])
609 # Fix up the list of target suites
610 for suite in changes["suite"].keys():
611 override = cnf.Find("Suite::%s::OverrideSuite" % (suite))
613 (olderr, newerr) = (get_suite(suite, session) == None,
614 get_suite(override, session) == None)
616 (oinv, newinv) = ("", "")
617 if olderr: oinv = "invalid "
618 if newerr: ninv = "invalid "
619 print "warning: overriding %ssuite %s to %ssuite %s" % (
620 oinv, suite, ninv, override)
621 del changes["suite"][suite]
622 changes["suite"][override] = 1
624 for suite in changes["suite"].keys():
625 if get_suite(suite, session) is None:
626 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
628 # The main NEW processing loop
631 # Find out what's new
632 new = determine_new(changes, files)
638 if Options["No-Action"] or Options["Automatic"]:
641 (broken, note) = print_new(new, upload, indexed=0)
644 if not broken and not note:
645 prompt = "Add overrides, "
647 print "W: [!] marked entries must be fixed before package can be processed."
649 print "W: note must be removed before package can be processed."
650 prompt += "RemOve all notes, Remove note, "
652 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
654 while prompt.find(answer) == -1:
655 answer = utils.our_raw_input(prompt)
656 m = re_default_answer.search(prompt)
659 answer = answer[:1].upper()
661 if answer in ( 'A', 'E', 'M', 'O', 'R' ) and Options["Trainee"]:
662 utils.warn("Trainees can't do that")
665 if answer == 'A' and not Options["Trainee"]:
668 done = add_overrides (new, upload, session)
669 Logger.log(["NEW ACCEPT: %s" % (upload.pkg.changes_file)])
670 except CantGetLockError:
671 print "Hello? Operator! Give me the number for 911!"
672 print "Dinstall in the locked area, cant process packages, come back later"
675 elif answer == 'E' and not Options["Trainee"]:
676 new = edit_overrides (new, upload, session)
677 elif answer == 'M' and not Options["Trainee"]:
678 upload.pkg.remove_known_changes()
679 aborted = upload.do_reject(manual=1,
680 reject_message=Options["Manual-Reject"],
681 note=get_new_comments(changes.get("source", ""), session=session))
683 Logger.log(["NEW REJECT: %s" % (upload.pkg.changes_file)])
686 edit_note(get_new_comments(changes.get("source", ""), session=session),
688 elif answer == 'P' and not Options["Trainee"]:
689 prod_maintainer(get_new_comments(changes.get("source", ""), session=session),
691 Logger.log(["NEW PROD: %s" % (upload.pkg.changes_file)])
692 elif answer == 'R' and not Options["Trainee"]:
693 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
695 for c in get_new_comments(changes.get("source", ""), changes.get("version", ""), session=session):
698 elif answer == 'O' and not Options["Trainee"]:
699 confirm = utils.our_raw_input("Really clear all notes (y/N)? ").lower()
701 for c in get_new_comments(changes.get("source", ""), session=session):
711 ################################################################################
712 ################################################################################
713 ################################################################################
715 def usage (exit_code=0):
716 print """Usage: dak process-new [OPTION]... [CHANGES]...
717 -a, --automatic automatic run
718 -h, --help show this help and exit.
719 -m, --manual-reject=MSG manual reject with `msg'
720 -n, --no-action don't do anything
721 -t, --trainee FTP Trainee mode
722 -V, --version display the version number and exit"""
725 ################################################################################
727 def do_byhand(upload, session):
730 files = upload.pkg.files
734 for f in files.keys():
735 if files[f]["type"] == "byhand":
736 if os.path.exists(f):
737 print "W: %s still present; please process byhand components and try again." % (f)
743 if Options["No-Action"]:
746 if Options["Automatic"] and not Options["No-Action"]:
748 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
750 prompt = "Manual reject, [S]kip, Quit ?"
752 while prompt.find(answer) == -1:
753 answer = utils.our_raw_input(prompt)
754 m = re_default_answer.search(prompt)
757 answer = answer[:1].upper()
765 Logger.log(["BYHAND ACCEPT: %s" % (upload.pkg.changes_file)])
766 except CantGetLockError:
767 print "Hello? Operator! Give me the number for 911!"
768 print "Dinstall in the locked area, cant process packages, come back later"
770 Logger.log(["BYHAND REJECT: %s" % (upload.pkg.changes_file)])
771 upload.do_reject(manual=1, reject_message=Options["Manual-Reject"])
779 ################################################################################
781 def check_daily_lock():
783 Raises CantGetLockError if the dinstall daily.lock exists.
788 os.open(cnf["Process-New::DinstallLockFile"],
789 os.O_RDONLY | os.O_CREAT | os.O_EXCL)
791 if e.errno == errno.EEXIST or e.errno == errno.EACCES:
792 raise CantGetLockError
794 os.unlink(cnf["Process-New::DinstallLockFile"])
797 @contextlib.contextmanager
798 def lock_package(package):
800 Lock C{package} so that noone else jumps in processing it.
802 @type package: string
803 @param package: source package name to lock
806 path = os.path.join(Config()["Process-New::LockDir"], package)
808 fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDONLY)
810 if e.errno == errno.EEXIST or e.errno == errno.EACCES:
811 user = pwd.getpwuid(os.stat(path)[stat.ST_UID])[4].split(',')[0].replace('.', '')
812 raise AlreadyLockedError, user
819 def changes_to_newstage(upload, session):
820 """move a changes file to newstage"""
821 newstage = get_policy_queue('newstage', session );
823 # changes.in_queue = newstage
825 chg = session.query(DBChange).filter_by(changesname=os.path.basename(upload.pkg.changes_file)).one()
826 chg.approved_for = newstage.policy_queue_id
829 # update the changes_pending_files row
832 # actually move files
833 upload.move_to_queue(newstage)
835 def _accept(upload, session):
836 if Options["No-Action"]:
838 (summary, short_summary) = upload.build_summaries()
839 # upload.accept(summary, short_summary, targetqueue)
841 changes_to_newstage(upload, session)
843 def do_accept(upload, session):
846 if not Options["No-Action"]:
847 (summary, short_summary) = upload.build_summaries()
849 if cnf.FindB("Dinstall::SecurityQueueHandling"):
850 upload.dump_vars(cnf["Dir::Queue::Embargoed"])
851 upload.move_to_queue(get_policy_queue('embargoed'))
852 upload.queue_build("embargoed", cnf["Dir::Queue::Embargoed"])
853 # Check for override disparities
854 upload.Subst["__SUMMARY__"] = summary
856 # Just a normal upload, accept it...
857 _accept(upload, session)
859 def do_pkg(changes_file, session):
860 new_queue = get_policy_queue('new', session );
862 u.pkg.changes_file = changes_file
863 (u.pkg.changes["fingerprint"], rejects) = utils.check_signature(changes_file)
864 u.load_changes(changes_file)
865 u.pkg.directory = new_queue.path
868 origchanges = os.path.abspath(u.pkg.changes_file)
871 bcc = "X-DAK: dak process-new"
872 if cnf.has_key("Dinstall::Bcc"):
873 u.Subst["__BCC__"] = bcc + "\nBcc: %s" % (cnf["Dinstall::Bcc"])
875 u.Subst["__BCC__"] = bcc
878 for deb_filename, f in files.items():
879 if deb_filename.endswith(".udeb") or deb_filename.endswith(".deb"):
880 u.binary_file_checks(deb_filename, session)
881 u.check_binary_against_db(deb_filename, session)
883 u.source_file_checks(deb_filename, session)
884 u.check_source_against_db(deb_filename, session)
886 u.pkg.changes["suite"] = copy.copy(u.pkg.changes["distribution"])
889 with lock_package(u.pkg.changes["source"]):
890 if not recheck(u, session):
893 # FIXME: This does need byhand checks added!
894 new = determine_new(u.pkg.changes, files)
898 do_accept(u, session)
899 # (new, byhand) = check_status(files)
904 # do_byhand(u, session)
905 # (new, byhand) = check_status(files)
907 # if not new and not byhand:
911 # except CantGetLockError:
912 # print "Hello? Operator! Give me the number for 911!"
913 # print "Dinstall in the locked area, cant process packages, come back later"
914 except AlreadyLockedError, e:
915 print "Seems to be locked by %s already, skipping..." % (e)
917 ################################################################################
920 accept_count = SummaryStats().accept_count
921 accept_bytes = SummaryStats().accept_bytes
927 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
928 Logger.log(["total",accept_count,accept_bytes])
930 if not Options["No-Action"] and not Options["Trainee"]:
933 ################################################################################
936 global Options, Logger, Sections, Priorities
939 session = DBConn().session()
941 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
942 ('h',"help","Process-New::Options::Help"),
943 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
944 ('t',"trainee","Process-New::Options::Trainee"),
945 ('n',"no-action","Process-New::Options::No-Action")]
947 for i in ["automatic", "help", "manual-reject", "no-action", "version", "trainee"]:
948 if not cnf.has_key("Process-New::Options::%s" % (i)):
949 cnf["Process-New::Options::%s" % (i)] = ""
951 changes_files = apt_pkg.ParseCommandLine(cnf.Cnf,Arguments,sys.argv)
952 if len(changes_files) == 0:
953 new_queue = get_policy_queue('new', session );
954 changes_files = utils.get_changes_files(new_queue.path)
956 Options = cnf.SubTree("Process-New::Options")
961 if not Options["No-Action"]:
963 Logger = daklog.Logger(cnf, "process-new")
964 except CantOpenError, e:
965 Options["Trainee"] = "True"
967 Sections = Section_Completer(session)
968 Priorities = Priority_Completer(session)
969 readline.parse_and_bind("tab: complete")
971 if len(changes_files) > 1:
972 sys.stderr.write("Sorting changes...\n")
973 changes_files = sort_changes(changes_files, session)
975 # Kill me now? **FIXME**
976 cnf["Dinstall::Options::No-Mail"] = ""
978 for changes_file in changes_files:
979 changes_file = utils.validate_changes_file_arg(changes_file, 0)
982 print "\n" + changes_file
984 do_pkg (changes_file, session)
988 ################################################################################
990 if __name__ == '__main__':