]> git.decadent.org.uk Git - dak.git/blob - dak/process_new.py
b8550fd10714bc6c1cba83fc19209a44d423e345
[dak.git] / dak / process_new.py
1 #!/usr/bin/env python
2 # vim:set et ts=4 sw=4:
3
4 """ Handles NEW and BYHAND packages
5
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
11 """
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.
16
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.
21
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
25
26 ################################################################################
27
28 # 23:12|<aj> I will not hush!
29 # 23:12|<elmo> :>
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!!!
42
43 ################################################################################
44
45 from __future__ import with_statement
46
47 import copy
48 import errno
49 import os
50 import readline
51 import stat
52 import sys
53 import time
54 import contextlib
55 import pwd
56 import apt_pkg, apt_inst
57 import examine_package
58
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
67 from daklib.changesutils import *
68
69 # Globals
70 Options = None
71 Logger = None
72
73 Priorities = None
74 Sections = None
75
76 ################################################################################
77 ################################################################################
78 ################################################################################
79
80 def recheck(upload, session):
81 # STU: I'm not sure, but I don't thin kthis is necessary any longer:    upload.recheck(session)
82     if len(upload.rejects) > 0:
83         answer = "XXX"
84         if Options["No-Action"] or Options["Automatic"] or Options["Trainee"]:
85             answer = 'S'
86
87         print "REJECT\n%s" % '\n'.join(upload.rejects)
88         prompt = "[R]eject, Skip, Quit ?"
89
90         while prompt.find(answer) == -1:
91             answer = utils.our_raw_input(prompt)
92             m = re_default_answer.match(prompt)
93             if answer == "":
94                 answer = m.group(1)
95             answer = answer[:1].upper()
96
97         if answer == 'R':
98             upload.do_reject(manual=0, reject_message='\n'.join(upload.rejects))
99             upload.pkg.remove_known_changes(session=session)
100             session.commit()
101             return 0
102         elif answer == 'S':
103             return 0
104         elif answer == 'Q':
105             end()
106             sys.exit(0)
107
108     return 1
109
110 ################################################################################
111
112 class Section_Completer:
113     def __init__ (self, session):
114         self.sections = []
115         self.matches = []
116         for s, in session.query(Section.section):
117             self.sections.append(s)
118
119     def complete(self, text, state):
120         if state == 0:
121             self.matches = []
122             n = len(text)
123             for word in self.sections:
124                 if word[:n] == text:
125                     self.matches.append(word)
126         try:
127             return self.matches[state]
128         except IndexError:
129             return None
130
131 ############################################################
132
133 class Priority_Completer:
134     def __init__ (self, session):
135         self.priorities = []
136         self.matches = []
137         for p, in session.query(Priority.priority):
138             self.priorities.append(p)
139
140     def complete(self, text, state):
141         if state == 0:
142             self.matches = []
143             n = len(text)
144             for word in self.priorities:
145                 if word[:n] == text:
146                     self.matches.append(word)
147         try:
148             return self.matches[state]
149         except IndexError:
150             return None
151
152 ################################################################################
153
154 def print_new (new, upload, indexed, file=sys.stdout):
155     check_valid(new)
156     broken = False
157     index = 0
158     for pkg in new.keys():
159         index += 1
160         section = new[pkg]["section"]
161         priority = new[pkg]["priority"]
162         if new[pkg]["section id"] == -1:
163             section += "[!]"
164             broken = True
165         if new[pkg]["priority id"] == -1:
166             priority += "[!]"
167             broken = True
168         if indexed:
169             line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
170         else:
171             line = "%-20s %-20s %-20s" % (pkg, priority, section)
172         line = line.strip()+'\n'
173         file.write(line)
174     notes = get_new_comments(upload.pkg.changes.get("source"))
175     for note in notes:
176         print "\nAuthor: %s\nVersion: %s\nTimestamp: %s\n\n%s" \
177               % (note.author, note.version, note.notedate, note.comment)
178         print "-" * 72
179     return broken, len(notes) > 0
180
181 ################################################################################
182
183 def index_range (index):
184     if index == 1:
185         return "1"
186     else:
187         return "1-%s" % (index)
188
189 ################################################################################
190 ################################################################################
191
192 def edit_new (new, upload):
193     # Write the current data to a temporary file
194     (fd, temp_filename) = utils.temp_filename()
195     temp_file = os.fdopen(fd, 'w')
196     print_new (new, upload, indexed=0, file=temp_file)
197     temp_file.close()
198     # Spawn an editor on that file
199     editor = os.environ.get("EDITOR","vi")
200     result = os.system("%s %s" % (editor, temp_filename))
201     if result != 0:
202         utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
203     # Read the edited data back in
204     temp_file = utils.open_file(temp_filename)
205     lines = temp_file.readlines()
206     temp_file.close()
207     os.unlink(temp_filename)
208     # Parse the new data
209     for line in lines:
210         line = line.strip()
211         if line == "":
212             continue
213         s = line.split()
214         # Pad the list if necessary
215         s[len(s):3] = [None] * (3-len(s))
216         (pkg, priority, section) = s[:3]
217         if not new.has_key(pkg):
218             utils.warn("Ignoring unknown package '%s'" % (pkg))
219         else:
220             # Strip off any invalid markers, print_new will readd them.
221             if section.endswith("[!]"):
222                 section = section[:-3]
223             if priority.endswith("[!]"):
224                 priority = priority[:-3]
225             for f in new[pkg]["files"]:
226                 upload.pkg.files[f]["section"] = section
227                 upload.pkg.files[f]["priority"] = priority
228             new[pkg]["section"] = section
229             new[pkg]["priority"] = priority
230
231 ################################################################################
232
233 def edit_index (new, upload, index):
234     priority = new[index]["priority"]
235     section = new[index]["section"]
236     ftype = new[index]["type"]
237     done = 0
238     while not done:
239         print "\t".join([index, priority, section])
240
241         answer = "XXX"
242         if ftype != "dsc":
243             prompt = "[B]oth, Priority, Section, Done ? "
244         else:
245             prompt = "[S]ection, Done ? "
246         edit_priority = edit_section = 0
247
248         while prompt.find(answer) == -1:
249             answer = utils.our_raw_input(prompt)
250             m = re_default_answer.match(prompt)
251             if answer == "":
252                 answer = m.group(1)
253             answer = answer[:1].upper()
254
255         if answer == 'P':
256             edit_priority = 1
257         elif answer == 'S':
258             edit_section = 1
259         elif answer == 'B':
260             edit_priority = edit_section = 1
261         elif answer == 'D':
262             done = 1
263
264         # Edit the priority
265         if edit_priority:
266             readline.set_completer(Priorities.complete)
267             got_priority = 0
268             while not got_priority:
269                 new_priority = utils.our_raw_input("New priority: ").strip()
270                 if new_priority not in Priorities.priorities:
271                     print "E: '%s' is not a valid priority, try again." % (new_priority)
272                 else:
273                     got_priority = 1
274                     priority = new_priority
275
276         # Edit the section
277         if edit_section:
278             readline.set_completer(Sections.complete)
279             got_section = 0
280             while not got_section:
281                 new_section = utils.our_raw_input("New section: ").strip()
282                 if new_section not in Sections.sections:
283                     print "E: '%s' is not a valid section, try again." % (new_section)
284                 else:
285                     got_section = 1
286                     section = new_section
287
288         # Reset the readline completer
289         readline.set_completer(None)
290
291     for f in new[index]["files"]:
292         upload.pkg.files[f]["section"] = section
293         upload.pkg.files[f]["priority"] = priority
294     new[index]["priority"] = priority
295     new[index]["section"] = section
296     return new
297
298 ################################################################################
299
300 def edit_overrides (new, upload, session):
301     print
302     done = 0
303     while not done:
304         print_new (new, upload, indexed=1)
305         new_index = {}
306         index = 0
307         for i in new.keys():
308             index += 1
309             new_index[index] = i
310
311         prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
312
313         got_answer = 0
314         while not got_answer:
315             answer = utils.our_raw_input(prompt)
316             if not answer.isdigit():
317                 answer = answer[:1].upper()
318             if answer == "E" or answer == "D":
319                 got_answer = 1
320             elif re_isanum.match (answer):
321                 answer = int(answer)
322                 if (answer < 1) or (answer > index):
323                     print "%s is not a valid index (%s).  Please retry." % (answer, index_range(index))
324                 else:
325                     got_answer = 1
326
327         if answer == 'E':
328             edit_new(new, upload)
329         elif answer == 'D':
330             done = 1
331         else:
332             edit_index (new, upload, new_index[answer])
333
334     return new
335
336 ################################################################################
337
338 def edit_note(note, upload, session):
339     # Write the current data to a temporary file
340     (fd, temp_filename) = utils.temp_filename()
341     editor = os.environ.get("EDITOR","vi")
342     answer = 'E'
343     while answer == 'E':
344         os.system("%s %s" % (editor, temp_filename))
345         temp_file = utils.open_file(temp_filename)
346         newnote = temp_file.read().rstrip()
347         temp_file.close()
348         print "New Note:"
349         print utils.prefix_multi_line_string(newnote,"  ")
350         prompt = "[D]one, Edit, Abandon, Quit ?"
351         answer = "XXX"
352         while prompt.find(answer) == -1:
353             answer = utils.our_raw_input(prompt)
354             m = re_default_answer.search(prompt)
355             if answer == "":
356                 answer = m.group(1)
357             answer = answer[:1].upper()
358     os.unlink(temp_filename)
359     if answer == 'A':
360         return
361     elif answer == 'Q':
362         end()
363         sys.exit(0)
364
365     comment = NewComment()
366     comment.package = upload.pkg.changes["source"]
367     comment.version = upload.pkg.changes["version"]
368     comment.comment = newnote
369     comment.author  = utils.whoami()
370     comment.trainee = bool(Options["Trainee"])
371     session.add(comment)
372     session.commit()
373
374 ################################################################################
375
376 def check_pkg (upload):
377     try:
378         less_fd = os.popen("less -R -", 'w', 0)
379         stdout_fd = sys.stdout
380         try:
381             sys.stdout = less_fd
382             changes = utils.parse_changes (upload.pkg.changes_file)
383             examine_package.display_changes(changes['distribution'], upload.pkg.changes_file)
384             files = upload.pkg.files
385             for f in files.keys():
386                 if files[f].has_key("new"):
387                     ftype = files[f]["type"]
388                     if ftype == "deb":
389                         examine_package.check_deb(changes['distribution'], f)
390                     elif ftype == "dsc":
391                         examine_package.check_dsc(changes['distribution'], f)
392         finally:
393             examine_package.output_package_relations()
394             sys.stdout = stdout_fd
395     except IOError, e:
396         if e.errno == errno.EPIPE:
397             utils.warn("[examine_package] Caught EPIPE; skipping.")
398             pass
399         else:
400             raise
401     except KeyboardInterrupt:
402         utils.warn("[examine_package] Caught C-c; skipping.")
403         pass
404
405 ################################################################################
406
407 ## FIXME: horribly Debian specific
408
409 def do_bxa_notification(upload):
410     files = upload.pkg.files
411     summary = ""
412     for f in files.keys():
413         if files[f]["type"] == "deb":
414             control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
415             summary += "\n"
416             summary += "Package: %s\n" % (control.Find("Package"))
417             summary += "Description: %s\n" % (control.Find("Description"))
418     upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
419     bxa_mail = utils.TemplateSubst(upload.Subst,Config()["Dir::Templates"]+"/process-new.bxa_notification")
420     utils.send_mail(bxa_mail)
421
422 ################################################################################
423
424 def add_overrides (new, upload, session):
425     changes = upload.pkg.changes
426     files = upload.pkg.files
427     srcpkg = changes.get("source")
428
429     for suite in changes["suite"].keys():
430         suite_id = get_suite(suite).suite_id
431         for pkg in new.keys():
432             component_id = get_component(new[pkg]["component"]).component_id
433             type_id = get_override_type(new[pkg]["type"]).overridetype_id
434             priority_id = new[pkg]["priority id"]
435             section_id = new[pkg]["section id"]
436             Logger.log(["%s overrides" % (srcpkg), suite, new[pkg]["component"], new[pkg]["type"], new[pkg]["priority"], new[pkg]["section"]])
437             session.execute("INSERT INTO override (suite, component, type, package, priority, section, maintainer) VALUES (:sid, :cid, :tid, :pkg, :pid, :sectid, '')",
438                             { 'sid': suite_id, 'cid': component_id, 'tid':type_id, 'pkg': pkg, 'pid': priority_id, 'sectid': section_id})
439             for f in new[pkg]["files"]:
440                 if files[f].has_key("new"):
441                     del files[f]["new"]
442             del new[pkg]
443
444     session.commit()
445
446     if Config().FindB("Dinstall::BXANotify"):
447         do_bxa_notification(upload)
448
449 ################################################################################
450
451 def prod_maintainer (note, upload):
452     cnf = Config()
453     # Here we prepare an editor and get them ready to prod...
454     (fd, temp_filename) = utils.temp_filename()
455     temp_file = os.fdopen(fd, 'w')
456     if len(note) > 0:
457         for line in note:
458             temp_file.write(line)
459     temp_file.close()
460     editor = os.environ.get("EDITOR","vi")
461     answer = 'E'
462     while answer == 'E':
463         os.system("%s %s" % (editor, temp_filename))
464         temp_fh = utils.open_file(temp_filename)
465         prod_message = "".join(temp_fh.readlines())
466         temp_fh.close()
467         print "Prod message:"
468         print utils.prefix_multi_line_string(prod_message,"  ",include_blank_lines=1)
469         prompt = "[P]rod, Edit, Abandon, Quit ?"
470         answer = "XXX"
471         while prompt.find(answer) == -1:
472             answer = utils.our_raw_input(prompt)
473             m = re_default_answer.search(prompt)
474             if answer == "":
475                 answer = m.group(1)
476             answer = answer[:1].upper()
477     os.unlink(temp_filename)
478     if answer == 'A':
479         return
480     elif answer == 'Q':
481         end()
482         sys.exit(0)
483     # Otherwise, do the proding...
484     user_email_address = utils.whoami() + " <%s>" % (
485         cnf["Dinstall::MyAdminAddress"])
486
487     Subst = upload.Subst
488
489     Subst["__FROM_ADDRESS__"] = user_email_address
490     Subst["__PROD_MESSAGE__"] = prod_message
491     Subst["__CC__"] = "Cc: " + cnf["Dinstall::MyEmailAddress"]
492
493     prod_mail_message = utils.TemplateSubst(
494         Subst,cnf["Dir::Templates"]+"/process-new.prod")
495
496     # Send the prod mail
497     utils.send_mail(prod_mail_message)
498
499     print "Sent proding message"
500
501 ################################################################################
502
503 def do_new(upload, session):
504     print "NEW\n"
505     files = upload.pkg.files
506     upload.check_files(not Options["No-Action"])
507     changes = upload.pkg.changes
508     cnf = Config()
509
510     # Check for a valid distribution
511     upload.check_distributions()
512
513     # Make a copy of distribution we can happily trample on
514     changes["suite"] = copy.copy(changes["distribution"])
515
516     # The main NEW processing loop
517     done = 0
518     while not done:
519         # Find out what's new
520         new = determine_new(changes, files)
521
522         if not new:
523             break
524
525         answer = "XXX"
526         if Options["No-Action"] or Options["Automatic"]:
527             answer = 'S'
528
529         (broken, note) = print_new(new, upload, indexed=0)
530         prompt = ""
531
532         if not broken and not note:
533             prompt = "Add overrides, "
534         if broken:
535             print "W: [!] marked entries must be fixed before package can be processed."
536         if note:
537             print "W: note must be removed before package can be processed."
538             prompt += "RemOve all notes, Remove note, "
539
540         prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
541
542         while prompt.find(answer) == -1:
543             answer = utils.our_raw_input(prompt)
544             m = re_default_answer.search(prompt)
545             if answer == "":
546                 answer = m.group(1)
547             answer = answer[:1].upper()
548
549         if answer in ( 'A', 'E', 'M', 'O', 'R' ) and Options["Trainee"]:
550             utils.warn("Trainees can't do that")
551             continue
552
553         if answer == 'A' and not Options["Trainee"]:
554             try:
555                 check_daily_lock()
556                 done = add_overrides (new, upload, session)
557                 new_accept(upload, Options["No-Action"], session)
558                 Logger.log(["NEW ACCEPT: %s" % (upload.pkg.changes_file)])
559             except CantGetLockError:
560                 print "Hello? Operator! Give me the number for 911!"
561                 print "Dinstall in the locked area, cant process packages, come back later"
562         elif answer == 'C':
563             check_pkg(upload)
564         elif answer == 'E' and not Options["Trainee"]:
565             new = edit_overrides (new, upload, session)
566         elif answer == 'M' and not Options["Trainee"]:
567             aborted = upload.do_reject(manual=1,
568                                        reject_message=Options["Manual-Reject"],
569                                        notes=get_new_comments(changes.get("source", ""), session=session))
570             if not aborted:
571                 upload.pkg.remove_known_changes(session=session)
572                 session.commit()
573                 Logger.log(["NEW REJECT: %s" % (upload.pkg.changes_file)])
574                 done = 1
575         elif answer == 'N':
576             edit_note(get_new_comments(changes.get("source", ""), session=session),
577                       upload, session)
578         elif answer == 'P' and not Options["Trainee"]:
579             prod_maintainer(get_new_comments(changes.get("source", ""), session=session),
580                             upload)
581             Logger.log(["NEW PROD: %s" % (upload.pkg.changes_file)])
582         elif answer == 'R' and not Options["Trainee"]:
583             confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
584             if confirm == "y":
585                 for c in get_new_comments(changes.get("source", ""), changes.get("version", ""), session=session):
586                     session.delete(c)
587                 session.commit()
588         elif answer == 'O' and not Options["Trainee"]:
589             confirm = utils.our_raw_input("Really clear all notes (y/N)? ").lower()
590             if confirm == "y":
591                 for c in get_new_comments(changes.get("source", ""), session=session):
592                     session.delete(c)
593                 session.commit()
594
595         elif answer == 'S':
596             done = 1
597         elif answer == 'Q':
598             end()
599             sys.exit(0)
600
601 ################################################################################
602 ################################################################################
603 ################################################################################
604
605 def usage (exit_code=0):
606     print """Usage: dak process-new [OPTION]... [CHANGES]...
607   -a, --automatic           automatic run
608   -h, --help                show this help and exit.
609   -m, --manual-reject=MSG   manual reject with `msg'
610   -n, --no-action           don't do anything
611   -t, --trainee             FTP Trainee mode
612   -V, --version             display the version number and exit"""
613     sys.exit(exit_code)
614
615 ################################################################################
616
617 def do_byhand(upload, session):
618     done = 0
619     while not done:
620         files = upload.pkg.files
621         will_install = 1
622         byhand = []
623
624         for f in files.keys():
625             if files[f]["type"] == "byhand":
626                 if os.path.exists(f):
627                     print "W: %s still present; please process byhand components and try again." % (f)
628                     will_install = 0
629                 else:
630                     byhand.append(f)
631
632         answer = "XXXX"
633         if Options["No-Action"]:
634             answer = "S"
635         if will_install:
636             if Options["Automatic"] and not Options["No-Action"]:
637                 answer = 'A'
638             prompt = "[A]ccept, Manual reject, Skip, Quit ?"
639         else:
640             prompt = "Manual reject, [S]kip, Quit ?"
641
642         while prompt.find(answer) == -1:
643             answer = utils.our_raw_input(prompt)
644             m = re_default_answer.search(prompt)
645             if answer == "":
646                 answer = m.group(1)
647             answer = answer[:1].upper()
648
649         if answer == 'A':
650             try:
651                 check_daily_lock()
652                 done = 1
653                 for f in byhand:
654                     del files[f]
655                 Logger.log(["BYHAND ACCEPT: %s" % (upload.pkg.changes_file)])
656             except CantGetLockError:
657                 print "Hello? Operator! Give me the number for 911!"
658                 print "Dinstall in the locked area, cant process packages, come back later"
659         elif answer == 'M':
660             Logger.log(["BYHAND REJECT: %s" % (upload.pkg.changes_file)])
661             upload.do_reject(manual=1, reject_message=Options["Manual-Reject"])
662             upload.pkg.remove_known_changes(session=session)
663             session.commit()
664             done = 1
665         elif answer == 'S':
666             done = 1
667         elif answer == 'Q':
668             end()
669             sys.exit(0)
670
671 ################################################################################
672
673 def check_daily_lock():
674     """
675     Raises CantGetLockError if the dinstall daily.lock exists.
676     """
677
678     cnf = Config()
679     try:
680         os.open(cnf["Process-New::DinstallLockFile"],
681                 os.O_RDONLY | os.O_CREAT | os.O_EXCL)
682     except OSError, e:
683         if e.errno == errno.EEXIST or e.errno == errno.EACCES:
684             raise CantGetLockError
685
686     os.unlink(cnf["Process-New::DinstallLockFile"])
687
688
689 @contextlib.contextmanager
690 def lock_package(package):
691     """
692     Lock C{package} so that noone else jumps in processing it.
693
694     @type package: string
695     @param package: source package name to lock
696     """
697
698     path = os.path.join(Config()["Process-New::LockDir"], package)
699     try:
700         fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDONLY)
701     except OSError, e:
702         if e.errno == errno.EEXIST or e.errno == errno.EACCES:
703             user = pwd.getpwuid(os.stat(path)[stat.ST_UID])[4].split(',')[0].replace('.', '')
704             raise AlreadyLockedError, user
705
706     try:
707         yield fd
708     finally:
709         os.unlink(path)
710
711 class clean_holding(object):
712     def __init__(self,pkg):
713         self.pkg = pkg
714
715     def __enter__(self):
716         pass
717
718     def __exit__(self, type, value, traceback):
719         h = Holding()
720
721         for f in self.pkg.files.keys():
722             if os.path.exists(os.path.join(h.holding_dir, f)):
723                 os.unlink(os.path.join(h.holding_dir, f))
724
725
726 def do_pkg(changes_file, session):
727     new_queue = get_policy_queue('new', session );
728     u = Upload()
729     u.pkg.changes_file = changes_file
730     (u.pkg.changes["fingerprint"], rejects) = utils.check_signature(changes_file)
731     u.load_changes(changes_file)
732     u.pkg.directory = new_queue.path
733     u.update_subst()
734     u.logger = Logger
735     origchanges = os.path.abspath(u.pkg.changes_file)
736
737     cnf = Config()
738     bcc = "X-DAK: dak process-new"
739     if cnf.has_key("Dinstall::Bcc"):
740         u.Subst["__BCC__"] = bcc + "\nBcc: %s" % (cnf["Dinstall::Bcc"])
741     else:
742         u.Subst["__BCC__"] = bcc
743
744     files = u.pkg.files
745     for deb_filename, f in files.items():
746         if deb_filename.endswith(".udeb") or deb_filename.endswith(".deb"):
747             u.binary_file_checks(deb_filename, session)
748             u.check_binary_against_db(deb_filename, session)
749         else:
750             u.source_file_checks(deb_filename, session)
751             u.check_source_against_db(deb_filename, session)
752
753         u.pkg.changes["suite"] = copy.copy(u.pkg.changes["distribution"])
754
755     try:
756         with lock_package(u.pkg.changes["source"]):
757             with clean_holding(u.pkg):
758                 if not recheck(u, session):
759                     return
760
761                 # FIXME: This does need byhand checks added!
762                 new = determine_new(u.pkg.changes, files)
763                 if new:
764                     do_new(u, session)
765                 else:
766                     try:
767                         check_daily_lock()
768                         new_accept(u, Options["No-Action"], session)
769                     except CantGetLockError:
770                         print "Hello? Operator! Give me the number for 911!"
771                         print "Dinstall in the locked area, cant process packages, come back later"
772
773     except AlreadyLockedError, e:
774         print "Seems to be locked by %s already, skipping..." % (e)
775
776 ################################################################################
777
778 def end():
779     accept_count = SummaryStats().accept_count
780     accept_bytes = SummaryStats().accept_bytes
781
782     if accept_count:
783         sets = "set"
784         if accept_count > 1:
785             sets = "sets"
786         sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
787         Logger.log(["total",accept_count,accept_bytes])
788
789     if not Options["No-Action"] and not Options["Trainee"]:
790         Logger.close()
791
792 ################################################################################
793
794 def main():
795     global Options, Logger, Sections, Priorities
796
797     cnf = Config()
798     session = DBConn().session()
799
800     Arguments = [('a',"automatic","Process-New::Options::Automatic"),
801                  ('h',"help","Process-New::Options::Help"),
802                  ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
803                  ('t',"trainee","Process-New::Options::Trainee"),
804                  ('n',"no-action","Process-New::Options::No-Action")]
805
806     for i in ["automatic", "help", "manual-reject", "no-action", "version", "trainee"]:
807         if not cnf.has_key("Process-New::Options::%s" % (i)):
808             cnf["Process-New::Options::%s" % (i)] = ""
809
810     changes_files = apt_pkg.ParseCommandLine(cnf.Cnf,Arguments,sys.argv)
811     if len(changes_files) == 0:
812         new_queue = get_policy_queue('new', session );
813         changes_files = utils.get_changes_files(new_queue.path)
814
815     Options = cnf.SubTree("Process-New::Options")
816
817     if Options["Help"]:
818         usage()
819
820     if not Options["No-Action"]:
821         try:
822             Logger = daklog.Logger(cnf, "process-new")
823         except CantOpenError, e:
824             Options["Trainee"] = "True"
825
826     Sections = Section_Completer(session)
827     Priorities = Priority_Completer(session)
828     readline.parse_and_bind("tab: complete")
829
830     if len(changes_files) > 1:
831         sys.stderr.write("Sorting changes...\n")
832     changes_files = sort_changes(changes_files, session)
833
834     for changes_file in changes_files:
835         changes_file = utils.validate_changes_file_arg(changes_file, 0)
836         if not changes_file:
837             continue
838         print "\n" + changes_file
839
840         do_pkg (changes_file, session)
841
842     end()
843
844 ################################################################################
845
846 if __name__ == '__main__':
847     main()