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
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 files = upload.pkg.files
83 for f in files.keys():
84 # The .orig.tar.gz can disappear out from under us is it's a
85 # duplicate of one in the archive.
86 if not files.has_key(f):
88 # Check that the source still exists
89 if files[f]["type"] == "deb":
90 source_version = files[f]["source version"]
91 source_package = files[f]["source package"]
92 if not upload.pkg.changes["architecture"].has_key("source") \
93 and not upload.source_exists(source_package, source_version, upload.pkg.changes["distribution"].keys()):
94 source_epochless_version = re_no_epoch.sub('', source_version)
95 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
97 for q in ["Accepted", "Embargoed", "Unembargoed", "Newstage"]:
98 if cnf.has_key("Dir::Queue::%s" % (q)):
99 if os.path.exists(cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
102 upload.rejects.append("no source found for %s %s (%s)." % (source_package, source_version, f))
104 # Version and file overwrite checks
105 if files[f]["type"] == "deb":
106 upload.check_binary_against_db(f, session)
107 elif files[f]["type"] == "dsc":
108 upload.check_source_against_db(f, session)
109 upload.check_dsc_against_db(f, session)
111 if len(upload.rejects) > 0:
113 if Options["No-Action"] or Options["Automatic"] or Options["Trainee"]:
116 print "REJECT\n" + upload.rejects.join("\n"),
117 prompt = "[R]eject, Skip, Quit ?"
119 while prompt.find(answer) == -1:
120 answer = utils.our_raw_input(prompt)
121 m = re_default_answer.match(prompt)
124 answer = answer[:1].upper()
127 upload.do_reject(manual=0, reject_message=upload.rejects.join("\n"))
128 os.unlink(upload.pkg.changes_file[:-8]+".dak")
138 ################################################################################
140 def indiv_sg_compare (a, b):
141 """Sort by source name, source, version, 'have source', and
142 finally by filename."""
143 # Sort by source version
144 q = apt_pkg.VersionCompare(a["version"], b["version"])
148 # Sort by 'have source'
149 a_has_source = a["architecture"].get("source")
150 b_has_source = b["architecture"].get("source")
151 if a_has_source and not b_has_source:
153 elif b_has_source and not a_has_source:
156 return cmp(a["filename"], b["filename"])
158 ############################################################
160 def sg_compare (a, b):
163 """Sort by have note, source already in database and time of oldest upload."""
165 a_note_state = a["note_state"]
166 b_note_state = b["note_state"]
167 if a_note_state < b_note_state:
169 elif a_note_state > b_note_state:
171 # Sort by source already in database (descending)
172 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
173 if source_in_database:
174 return -source_in_database
176 # Sort by time of oldest upload
177 return cmp(a["oldest"], b["oldest"])
179 def sort_changes(changes_files, session):
180 """Sort into source groups, then sort each source group by version,
181 have source, filename. Finally, sort the source groups by have
182 note, time of oldest upload of each source upload."""
183 if len(changes_files) == 1:
188 # Read in all the .changes files
189 for filename in changes_files:
192 u.pkg.load_dot_dak(filename)
194 cache[filename] = copy.copy(u.pkg.changes)
195 cache[filename]["filename"] = filename
197 sorted_list.append(filename)
199 # Divide the .changes into per-source groups
201 for filename in cache.keys():
202 source = cache[filename]["source"]
203 if not per_source.has_key(source):
204 per_source[source] = {}
205 per_source[source]["list"] = []
206 per_source[source]["list"].append(cache[filename])
207 # Determine oldest time and have note status for each source group
208 for source in per_source.keys():
209 q = session.query(DBSource).filter_by(source = source).all()
210 per_source[source]["source_in_database"] = len(q)>0
211 source_list = per_source[source]["list"]
212 first = source_list[0]
213 oldest = os.stat(first["filename"])[stat.ST_MTIME]
215 for d in per_source[source]["list"]:
216 mtime = os.stat(d["filename"])[stat.ST_MTIME]
219 have_note += has_new_comment(d["source"], d["version"], session)
220 per_source[source]["oldest"] = oldest
222 per_source[source]["note_state"] = 0; # none
223 elif have_note < len(source_list):
224 per_source[source]["note_state"] = 1; # some
226 per_source[source]["note_state"] = 2; # all
227 per_source[source]["list"].sort(indiv_sg_compare)
228 per_source_items = per_source.items()
229 per_source_items.sort(sg_compare)
230 for i in per_source_items:
231 for j in i[1]["list"]:
232 sorted_list.append(j["filename"])
235 ################################################################################
237 class Section_Completer:
238 def __init__ (self, session):
241 for s, in session.query(Section.section):
242 self.sections.append(s)
244 def complete(self, text, state):
248 for word in self.sections:
250 self.matches.append(word)
252 return self.matches[state]
256 ############################################################
258 class Priority_Completer:
259 def __init__ (self, session):
262 for p, in session.query(Priority.priority):
263 self.priorities.append(p)
265 def complete(self, text, state):
269 for word in self.priorities:
271 self.matches.append(word)
273 return self.matches[state]
277 ################################################################################
279 def print_new (new, upload, indexed, file=sys.stdout):
283 for pkg in new.keys():
285 section = new[pkg]["section"]
286 priority = new[pkg]["priority"]
287 if new[pkg]["section id"] == -1:
290 if new[pkg]["priority id"] == -1:
294 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
296 line = "%-20s %-20s %-20s" % (pkg, priority, section)
297 line = line.strip()+'\n'
299 notes = get_new_comments(upload.pkg.changes.get("source"))
301 print "\nAuthor: %s\nVersion: %s\nTimestamp: %s\n\n%s" \
302 % (note.author, note.version, note.notedate, note.comment)
304 return broken, len(notes) > 0
306 ################################################################################
308 def index_range (index):
312 return "1-%s" % (index)
314 ################################################################################
315 ################################################################################
317 def edit_new (new, upload):
318 # Write the current data to a temporary file
319 (fd, temp_filename) = utils.temp_filename()
320 temp_file = os.fdopen(fd, 'w')
321 print_new (new, upload, indexed=0, file=temp_file)
323 # Spawn an editor on that file
324 editor = os.environ.get("EDITOR","vi")
325 result = os.system("%s %s" % (editor, temp_filename))
327 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
328 # Read the edited data back in
329 temp_file = utils.open_file(temp_filename)
330 lines = temp_file.readlines()
332 os.unlink(temp_filename)
339 # Pad the list if necessary
340 s[len(s):3] = [None] * (3-len(s))
341 (pkg, priority, section) = s[:3]
342 if not new.has_key(pkg):
343 utils.warn("Ignoring unknown package '%s'" % (pkg))
345 # Strip off any invalid markers, print_new will readd them.
346 if section.endswith("[!]"):
347 section = section[:-3]
348 if priority.endswith("[!]"):
349 priority = priority[:-3]
350 for f in new[pkg]["files"]:
351 upload.pkg.files[f]["section"] = section
352 upload.pkg.files[f]["priority"] = priority
353 new[pkg]["section"] = section
354 new[pkg]["priority"] = priority
356 ################################################################################
358 def edit_index (new, upload, index):
359 priority = new[index]["priority"]
360 section = new[index]["section"]
361 ftype = new[index]["type"]
364 print "\t".join([index, priority, section])
368 prompt = "[B]oth, Priority, Section, Done ? "
370 prompt = "[S]ection, Done ? "
371 edit_priority = edit_section = 0
373 while prompt.find(answer) == -1:
374 answer = utils.our_raw_input(prompt)
375 m = re_default_answer.match(prompt)
378 answer = answer[:1].upper()
385 edit_priority = edit_section = 1
391 readline.set_completer(Priorities.complete)
393 while not got_priority:
394 new_priority = utils.our_raw_input("New priority: ").strip()
395 if new_priority not in Priorities.priorities:
396 print "E: '%s' is not a valid priority, try again." % (new_priority)
399 priority = new_priority
403 readline.set_completer(Sections.complete)
405 while not got_section:
406 new_section = utils.our_raw_input("New section: ").strip()
407 if new_section not in Sections.sections:
408 print "E: '%s' is not a valid section, try again." % (new_section)
411 section = new_section
413 # Reset the readline completer
414 readline.set_completer(None)
416 for f in new[index]["files"]:
417 upload.pkg.files[f]["section"] = section
418 upload.pkg.files[f]["priority"] = priority
419 new[index]["priority"] = priority
420 new[index]["section"] = section
423 ################################################################################
425 def edit_overrides (new, upload, session):
429 print_new (new, upload, indexed=1)
436 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
439 while not got_answer:
440 answer = utils.our_raw_input(prompt)
441 if not answer.isdigit():
442 answer = answer[:1].upper()
443 if answer == "E" or answer == "D":
445 elif re_isanum.match (answer):
447 if (answer < 1) or (answer > index):
448 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
453 edit_new(new, upload)
457 edit_index (new, upload, new_index[answer])
461 ################################################################################
463 def edit_note(note, upload, session):
464 # Write the current data to a temporary file
465 (fd, temp_filename) = utils.temp_filename()
466 editor = os.environ.get("EDITOR","vi")
469 os.system("%s %s" % (editor, temp_filename))
470 temp_file = utils.open_file(temp_filename)
471 newnote = temp_file.read().rstrip()
474 print utils.prefix_multi_line_string(newnote," ")
475 prompt = "[D]one, Edit, Abandon, Quit ?"
477 while prompt.find(answer) == -1:
478 answer = utils.our_raw_input(prompt)
479 m = re_default_answer.search(prompt)
482 answer = answer[:1].upper()
483 os.unlink(temp_filename)
490 comment = NewComment()
491 comment.package = upload.pkg.changes["source"]
492 comment.version = upload.pkg.changes["version"]
493 comment.comment = newnote
494 comment.author = utils.whoami()
495 comment.trainee = bool(Options["Trainee"])
499 ################################################################################
501 def check_pkg (upload):
503 less_fd = os.popen("less -R -", 'w', 0)
504 stdout_fd = sys.stdout
507 changes = utils.parse_changes (upload.pkg.changes_file)
508 examine_package.display_changes(changes['distribution'], upload.pkg.changes_file)
509 files = upload.pkg.files
510 for f in files.keys():
511 if files[f].has_key("new"):
512 ftype = files[f]["type"]
514 examine_package.check_deb(changes['distribution'], f)
516 examine_package.check_dsc(changes['distribution'], f)
518 examine_package.output_package_relations()
519 sys.stdout = stdout_fd
521 if e.errno == errno.EPIPE:
522 utils.warn("[examine_package] Caught EPIPE; skipping.")
526 except KeyboardInterrupt:
527 utils.warn("[examine_package] Caught C-c; skipping.")
530 ################################################################################
532 ## FIXME: horribly Debian specific
534 def do_bxa_notification(upload):
535 files = upload.pkg.files
537 for f in files.keys():
538 if files[f]["type"] == "deb":
539 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
541 summary += "Package: %s\n" % (control.Find("Package"))
542 summary += "Description: %s\n" % (control.Find("Description"))
543 upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
544 bxa_mail = utils.TemplateSubst(upload.Subst,Config()["Dir::Templates"]+"/process-new.bxa_notification")
545 utils.send_mail(bxa_mail)
547 ################################################################################
549 def add_overrides (new, upload, session):
550 changes = upload.pkg.changes
551 files = upload.pkg.files
552 srcpkg = changes.get("source")
554 for suite in changes["suite"].keys():
555 suite_id = get_suite(suite).suite_id
556 for pkg in new.keys():
557 component_id = get_component(new[pkg]["component"]).component_id
558 type_id = get_override_type(new[pkg]["type"]).overridetype_id
559 priority_id = new[pkg]["priority id"]
560 section_id = new[pkg]["section id"]
561 Logger.log(["%s overrides" % (srcpkg), suite, new[pkg]["component"], new[pkg]["type"], new[pkg]["priority"], new[pkg]["section"]])
562 session.execute("INSERT INTO override (suite, component, type, package, priority, section, maintainer) VALUES (:sid, :cid, :tid, :pkg, :pid, :sectid, '')",
563 { 'sid': suite_id, 'cid': component_id, 'tid':type_id, 'pkg': pkg, 'pid': priority_id, 'sectid': section_id})
564 for f in new[pkg]["files"]:
565 if files[f].has_key("new"):
571 if Config().FindB("Dinstall::BXANotify"):
572 do_bxa_notification(upload)
574 ################################################################################
576 def prod_maintainer (note, upload):
578 # Here we prepare an editor and get them ready to prod...
579 (fd, temp_filename) = utils.temp_filename()
580 temp_file = os.fdopen(fd, 'w')
583 temp_file.write(line)
585 editor = os.environ.get("EDITOR","vi")
588 os.system("%s %s" % (editor, temp_filename))
589 temp_fh = utils.open_file(temp_filename)
590 prod_message = "".join(temp_fh.readlines())
592 print "Prod message:"
593 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
594 prompt = "[P]rod, Edit, Abandon, Quit ?"
596 while prompt.find(answer) == -1:
597 answer = utils.our_raw_input(prompt)
598 m = re_default_answer.search(prompt)
601 answer = answer[:1].upper()
602 os.unlink(temp_filename)
608 # Otherwise, do the proding...
609 user_email_address = utils.whoami() + " <%s>" % (
610 cnf["Dinstall::MyAdminAddress"])
614 Subst["__FROM_ADDRESS__"] = user_email_address
615 Subst["__PROD_MESSAGE__"] = prod_message
616 Subst["__CC__"] = "Cc: " + cnf["Dinstall::MyEmailAddress"]
618 prod_mail_message = utils.TemplateSubst(
619 Subst,cnf["Dir::Templates"]+"/process-new.prod")
621 # Send the prod mail if appropriate
622 if not cnf["Dinstall::Options::No-Mail"]:
623 utils.send_mail(prod_mail_message)
625 print "Sent proding message"
627 ################################################################################
629 def do_new(upload, session):
631 files = upload.pkg.files
632 changes = upload.pkg.changes
635 # Make a copy of distribution we can happily trample on
636 changes["suite"] = copy.copy(changes["distribution"])
638 # Fix up the list of target suites
639 for suite in changes["suite"].keys():
640 override = cnf.Find("Suite::%s::OverrideSuite" % (suite))
642 (olderr, newerr) = (get_suite(suite, session) == None,
643 get_suite(override, session) == None)
645 (oinv, newinv) = ("", "")
646 if olderr: oinv = "invalid "
647 if newerr: ninv = "invalid "
648 print "warning: overriding %ssuite %s to %ssuite %s" % (
649 oinv, suite, ninv, override)
650 del changes["suite"][suite]
651 changes["suite"][override] = 1
653 for suite in changes["suite"].keys():
654 if get_suite(suite, session) is None:
655 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
657 # The main NEW processing loop
660 # Find out what's new
661 new = determine_new(changes, files)
667 if Options["No-Action"] or Options["Automatic"]:
670 (broken, note) = print_new(new, upload, indexed=0)
673 if not broken and not note:
674 prompt = "Add overrides, "
676 print "W: [!] marked entries must be fixed before package can be processed."
678 print "W: note must be removed before package can be processed."
679 prompt += "RemOve all notes, Remove note, "
681 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
683 while prompt.find(answer) == -1:
684 answer = utils.our_raw_input(prompt)
685 m = re_default_answer.search(prompt)
688 answer = answer[:1].upper()
690 if answer in ( 'A', 'E', 'M', 'O', 'R' ) and Options["Trainee"]:
691 utils.warn("Trainees can't do that")
694 if answer == 'A' and not Options["Trainee"]:
697 done = add_overrides (new, upload, session)
698 Logger.log(["NEW ACCEPT: %s" % (upload.pkg.changes_file)])
699 except CantGetLockError:
700 print "Hello? Operator! Give me the number for 911!"
701 print "Dinstall in the locked area, cant process packages, come back later"
704 elif answer == 'E' and not Options["Trainee"]:
705 new = edit_overrides (new, upload, session)
706 elif answer == 'M' and not Options["Trainee"]:
707 aborted = upload.do_reject(manual=1,
708 reject_message=Options["Manual-Reject"],
709 note=get_new_comments(changes.get("source", ""), session=session))
711 Logger.log(["NEW REJECT: %s" % (upload.pkg.changes_file)])
712 os.unlink(upload.pkg.changes_file[:-8]+".dak")
715 edit_note(get_new_comments(changes.get("source", ""), session=session),
717 elif answer == 'P' and not Options["Trainee"]:
718 prod_maintainer(get_new_comments(changes.get("source", ""), session=session),
720 Logger.log(["NEW PROD: %s" % (upload.pkg.changes_file)])
721 elif answer == 'R' and not Options["Trainee"]:
722 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
724 for c in get_new_comments(changes.get("source", ""), changes.get("version", ""), session=session):
727 elif answer == 'O' and not Options["Trainee"]:
728 confirm = utils.our_raw_input("Really clear all notes (y/N)? ").lower()
730 for c in get_new_comments(changes.get("source", ""), session=session):
740 ################################################################################
741 ################################################################################
742 ################################################################################
744 def usage (exit_code=0):
745 print """Usage: dak process-new [OPTION]... [CHANGES]...
746 -a, --automatic automatic run
747 -h, --help show this help and exit.
748 -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new
749 -m, --manual-reject=MSG manual reject with `msg'
750 -n, --no-action don't do anything
751 -t, --trainee FTP Trainee mode
752 -V, --version display the version number and exit"""
755 ################################################################################
757 def do_byhand(upload, session):
760 files = upload.pkg.files
764 for f in files.keys():
765 if files[f]["type"] == "byhand":
766 if os.path.exists(f):
767 print "W: %s still present; please process byhand components and try again." % (f)
773 if Options["No-Action"]:
776 if Options["Automatic"] and not Options["No-Action"]:
778 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
780 prompt = "Manual reject, [S]kip, Quit ?"
782 while prompt.find(answer) == -1:
783 answer = utils.our_raw_input(prompt)
784 m = re_default_answer.search(prompt)
787 answer = answer[:1].upper()
795 Logger.log(["BYHAND ACCEPT: %s" % (upload.pkg.changes_file)])
796 except CantGetLockError:
797 print "Hello? Operator! Give me the number for 911!"
798 print "Dinstall in the locked area, cant process packages, come back later"
800 Logger.log(["BYHAND REJECT: %s" % (upload.pkg.changes_file)])
801 upload.do_reject(manual=1, reject_message=Options["Manual-Reject"])
802 os.unlink(upload.pkg.changes_file[:-8]+".dak")
803 upload.pkg.remove_known_changes()
811 ################################################################################
813 def check_daily_lock():
815 Raises CantGetLockError if the dinstall daily.lock exists.
820 os.open(cnf["Process-New::DinstallLockFile"],
821 os.O_RDONLY | os.O_CREAT | os.O_EXCL)
823 if e.errno == errno.EEXIST or e.errno == errno.EACCES:
824 raise CantGetLockError
826 os.unlink(cnf["Process-New::DinstallLockFile"])
829 @contextlib.contextmanager
830 def lock_package(package):
832 Lock C{package} so that noone else jumps in processing it.
834 @type package: string
835 @param package: source package name to lock
838 path = os.path.join(Config()["Process-New::LockDir"], package)
840 fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDONLY)
842 if e.errno == errno.EEXIST or e.errno == errno.EACCES:
843 user = pwd.getpwuid(os.stat(path)[stat.ST_UID])[4].split(',')[0].replace('.', '')
844 raise AlreadyLockedError, user
851 # def move_to_dir (upload, dest, perms=0660, changesperms=0664):
852 # utils.move (upload.pkg.changes_file, dest, perms=changesperms)
853 # file_keys = upload.pkg.files.keys()
854 # for f in file_keys:
855 # utils.move (f, dest, perms=perms)
857 # def is_source_in_queue_dir(qdir):
858 # entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
859 # and x.endswith(".changes") ]
860 # for entry in entries:
862 # u = queue.Upload(Cnf)
863 # u.pkg.changes_file = os.path.join(qdir, entry)
865 # if not u.pkg.changes["architecture"].has_key("source"):
866 # # another binary upload, ignore
868 # if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
869 # # another version, ignore
875 # def move_to_holding(suite, queue_dir):
876 # print "Moving to %s holding area." % (suite.upper(),)
877 # if Options["No-Action"]:
879 # Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
880 # Upload.dump_vars(queue_dir)
881 # move_to_dir(queue_dir, perms=0664)
882 # os.unlink(Upload.pkg.changes_file[:-8]+".dak")
885 if Options["No-Action"]:
887 (summary, short_summary) = upload.build_summaries()
888 upload.accept(summary, short_summary, targetdir=Config()["Dir::Queue::Newstage"])
889 os.unlink(upload.pkg.changes_file[:-8]+".dak")
891 # def do_accept_stableupdate(upload,suite, q):
893 # queue_dir = cnf["Dir::Queue::%s" % (q,)]
894 # if not upload.pkg.changes["architecture"].has_key("source"):
895 # # It is not a sourceful upload. So its source may be either in p-u
896 # # holding, in new, in accepted or already installed.
897 # if is_source_in_queue_dir(queue_dir):
898 # # It's in p-u holding, so move it there.
899 # print "Binary-only upload, source in %s." % (q,)
900 # move_to_holding(suite, queue_dir)
901 # elif Upload.source_exists(Upload.pkg.changes["source"],
902 # Upload.pkg.changes["version"]):
903 # # dak tells us that there is source available. At time of
904 # # writing this means that it is installed, so put it into
906 # print "Binary-only upload, source installed."
907 # Logger.log([utils.getusername(), "PUNEW ACCEPT: %s" % (Upload.pkg.changes_file)])
909 # elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
910 # # The source is in accepted, the binary cleared NEW: accept it.
911 # print "Binary-only upload, source in accepted."
912 # Logger.log([utils.getusername(), "PUNEW ACCEPT: %s" % (Upload.pkg.changes_file)])
914 # elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
915 # # It's in NEW. We expect the source to land in p-u holding
917 # print "Binary-only upload, source in new."
918 # move_to_holding(suite, queue_dir)
919 # elif is_source_in_queue_dir(Cnf["Dir::Queue::Newstage"]):
920 # # It's in newstage. Accept into the holding area
921 # print "Binary-only upload, source in newstage."
922 # Logger.log([utils.getusername(), "PUNEW ACCEPT: %s" % (Upload.pkg.changes_file)])
925 # # No case applicable. Bail out. Return will cause the upload
928 # print "Stable update failed. Source not found."
931 # # We are handling a sourceful upload. Move to accepted if currently
932 # # in p-u holding and to p-u holding otherwise.
933 # if is_source_in_queue_dir(queue_dir):
934 # print "Sourceful upload in %s, accepting." % (q,)
937 # move_to_holding(suite, queue_dir)
939 def do_accept(upload):
942 if not Options["No-Action"]:
943 (summary, short_summary) = upload.build_summaries()
944 # if cnf.FindB("Dinstall::SecurityQueueHandling"):
945 # upload.dump_vars(cnf["Dir::Queue::Embargoed"])
946 # move_to_dir(cnf["Dir::Queue::Embargoed"])
947 # upload.queue_build("embargoed", cnf["Dir::Queue::Embargoed"])
948 # # Check for override disparities
949 # upload.Subst["__SUMMARY__"] = summary
951 # Stable updates need to be copied to proposed-updates holding
952 # area instead of accepted. Sourceful uploads need to go
953 # to it directly, binaries only if the source has not yet been
955 for suite, q in [("proposed-updates", "ProposedUpdates"),
956 ("oldstable-proposed-updates", "OldProposedUpdates")]:
957 if not upload.pkg.changes["distribution"].has_key(suite):
959 utils.fubar("stable accept not supported yet")
960 # return do_accept_stableupdate(suite, q)
961 # Just a normal upload, accept it...
964 def check_status(files):
966 for f in files.keys():
967 if files[f]["type"] == "byhand":
969 elif files[f].has_key("new"):
973 def do_pkg(changes_file, session):
975 u.pkg.load_dot_dak(changes_file)
979 bcc = "X-DAK: dak process-new"
980 if cnf.has_key("Dinstall::Bcc"):
981 u.Subst["__BCC__"] = bcc + "\nBcc: %s" % (cnf["Dinstall::Bcc"])
983 u.Subst["__BCC__"] = bcc
988 with lock_package(u.pkg.changes["source"]):
989 if not recheck(u, session):
992 (new, byhand) = check_status(files)
997 do_byhand(u, session)
998 (new, byhand) = check_status(files)
1000 if not new and not byhand:
1004 except CantGetLockError:
1005 print "Hello? Operator! Give me the number for 911!"
1006 print "Dinstall in the locked area, cant process packages, come back later"
1007 except AlreadyLockedError, e:
1008 print "Seems to be locked by %s already, skipping..." % (e)
1010 ################################################################################
1013 accept_count = SummaryStats().accept_count
1014 accept_bytes = SummaryStats().accept_bytes
1018 if accept_count > 1:
1020 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
1021 Logger.log(["total",accept_count,accept_bytes])
1023 if not Options["No-Action"] and not Options["Trainee"]:
1026 ################################################################################
1028 # def do_comments(dir, opref, npref, line, fn):
1029 # for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
1030 # lines = open("%s/%s" % (dir, comm)).readlines()
1031 # if len(lines) == 0 or lines[0] != line + "\n": continue
1032 # changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
1033 # and x.endswith(".changes") ]
1034 # changes_files = sort_changes(changes_files)
1035 # for f in changes_files:
1036 # f = utils.validate_changes_file_arg(f, 0)
1037 # if not f: continue
1039 # fn(f, "".join(lines[1:]))
1041 # if opref != npref and not Options["No-Action"]:
1042 # newcomm = npref + comm[len(opref):]
1043 # os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
1045 # ################################################################################
1047 # def comment_accept(changes_file, comments):
1048 # Upload.pkg.changes_file = changes_file
1049 # Upload.init_vars()
1050 # Upload.update_vars()
1051 # Upload.update_subst()
1052 # files = Upload.pkg.files
1055 # return # dak wants to REJECT, crap
1057 # (new, byhand) = check_status(files)
1058 # if not new and not byhand:
1061 # ################################################################################
1063 # def comment_reject(changes_file, comments):
1064 # Upload.pkg.changes_file = changes_file
1065 # Upload.init_vars()
1066 # Upload.update_vars()
1067 # Upload.update_subst()
1070 # pass # dak has its own reasons to reject as well, which is fine
1073 # print "REJECT\n" + reject_message,
1074 # if not Options["No-Action"]:
1075 # Upload.do_reject(0, reject_message)
1076 # os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1078 ################################################################################
1081 global Options, Logger, Sections, Priorities
1084 session = DBConn().session()
1086 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
1087 ('h',"help","Process-New::Options::Help"),
1088 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
1089 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
1090 ('t',"trainee","Process-New::Options::Trainee"),
1091 ('n',"no-action","Process-New::Options::No-Action")]
1093 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir", "trainee"]:
1094 if not cnf.has_key("Process-New::Options::%s" % (i)):
1095 cnf["Process-New::Options::%s" % (i)] = ""
1097 changes_files = apt_pkg.ParseCommandLine(cnf.Cnf,Arguments,sys.argv)
1098 if len(changes_files) == 0 and not cnf.get("Process-New::Options::Comments-Dir",""):
1099 changes_files = utils.get_changes_files(cnf["Dir::Queue::New"])
1101 Options = cnf.SubTree("Process-New::Options")
1106 if not Options["No-Action"]:
1108 Logger = daklog.Logger(cnf, "process-new")
1109 except CantOpenError, e:
1110 Options["Trainee"] = "True"
1112 Sections = Section_Completer(session)
1113 Priorities = Priority_Completer(session)
1114 readline.parse_and_bind("tab: complete")
1116 if len(changes_files) > 1:
1117 sys.stderr.write("Sorting changes...\n")
1118 changes_files = sort_changes(changes_files, session)
1120 # Kill me now? **FIXME**
1121 cnf["Dinstall::Options::No-Mail"] = ""
1123 # commentsdir = cnf.get("Process-New::Options::Comments-Dir","")
1125 # if changes_files != []:
1126 # sys.stderr.write("Can't specify any changes files if working with comments-dir")
1128 # do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1129 # do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1132 for changes_file in changes_files:
1133 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1134 if not changes_file:
1136 print "\n" + changes_file
1138 do_pkg (changes_file, session)
1142 ################################################################################
1144 if __name__ == '__main__':