2 # vim:set et ts=4 sw=4:
4 # Handles NEW and BYHAND packages
5 # Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 James Troup <james@nocrew.org>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ################################################################################
23 # 23:12|<aj> I will not hush!
25 # 23:12|<aj> Where there is injustice in the world, I shall be there!
26 # 23:13|<aj> I shall not be silenced!
27 # 23:13|<aj> The world shall know!
28 # 23:13|<aj> The world *must* know!
29 # 23:13|<elmo> oh dear, he's gone back to powerpuff girls... ;-)
30 # 23:13|<aj> yay powerpuff girls!!
31 # 23:13|<aj> buttercup's my favourite, who's yours?
32 # 23:14|<aj> you're backing away from the keyboard right now aren't you?
33 # 23:14|<aj> *AREN'T YOU*?!
34 # 23:15|<aj> I will not be treated like this.
35 # 23:15|<aj> I shall have my revenge.
36 # 23:15|<aj> I SHALL!!!
38 ################################################################################
40 import copy, errno, os, readline, stat, sys, time
41 import apt_pkg, apt_inst
42 import examine_package
43 from daklib import database
44 from daklib import logging
45 from daklib import queue
46 from daklib import utils
60 ################################################################################
61 ################################################################################
62 ################################################################################
64 def reject (str, prefix="Rejected: "):
67 reject_message += prefix + str + "\n"
71 files = Upload.pkg.files
74 for f in files.keys():
75 # The .orig.tar.gz can disappear out from under us is it's a
76 # duplicate of one in the archive.
77 if not files.has_key(f):
79 # Check that the source still exists
80 if files[f]["type"] == "deb":
81 source_version = files[f]["source version"]
82 source_package = files[f]["source package"]
83 if not Upload.pkg.changes["architecture"].has_key("source") \
84 and not Upload.source_exists(source_package, source_version, Upload.pkg.changes["distribution"].keys()):
85 source_epochless_version = utils.re_no_epoch.sub('', source_version)
86 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
88 for q in ["Accepted", "Embargoed", "Unembargoed"]:
89 if Cnf.has_key("Dir::Queue::%s" % (q)):
90 if os.path.exists(Cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
93 reject("no source found for %s %s (%s)." % (source_package, source_version, f))
95 # Version and file overwrite checks
96 if files[f]["type"] == "deb":
97 reject(Upload.check_binary_against_db(f), "")
98 elif files[f]["type"] == "dsc":
99 reject(Upload.check_source_against_db(f), "")
100 (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(f)
101 reject(reject_msg, "")
103 if reject_message.find("Rejected") != -1:
105 if Options["No-Action"] or Options["Automatic"]:
108 print "REJECT\n" + reject_message,
109 prompt = "[R]eject, Skip, Quit ?"
111 while prompt.find(answer) == -1:
112 answer = utils.our_raw_input(prompt)
113 m = queue.re_default_answer.match(prompt)
116 answer = answer[:1].upper()
119 Upload.do_reject(0, reject_message)
120 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
130 ################################################################################
132 def indiv_sg_compare (a, b):
133 """Sort by source name, source, version, 'have source', and
134 finally by filename."""
135 # Sort by source version
136 q = apt_pkg.VersionCompare(a["version"], b["version"])
140 # Sort by 'have source'
141 a_has_source = a["architecture"].get("source")
142 b_has_source = b["architecture"].get("source")
143 if a_has_source and not b_has_source:
145 elif b_has_source and not a_has_source:
148 return cmp(a["filename"], b["filename"])
150 ############################################################
152 def sg_compare (a, b):
155 """Sort by have note, source already in database and time of oldest upload."""
157 a_note_state = a["note_state"]
158 b_note_state = b["note_state"]
159 if a_note_state < b_note_state:
161 elif a_note_state > b_note_state:
163 # Sort by source already in database (descending)
164 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
165 if source_in_database:
166 return -source_in_database
168 # Sort by time of oldest upload
169 return cmp(a["oldest"], b["oldest"])
171 def sort_changes(changes_files):
172 """Sort into source groups, then sort each source group by version,
173 have source, filename. Finally, sort the source groups by have
174 note, time of oldest upload of each source upload."""
175 if len(changes_files) == 1:
180 # Read in all the .changes files
181 for filename in changes_files:
183 Upload.pkg.changes_file = filename
186 cache[filename] = copy.copy(Upload.pkg.changes)
187 cache[filename]["filename"] = filename
189 sorted_list.append(filename)
191 # Divide the .changes into per-source groups
193 for filename in cache.keys():
194 source = cache[filename]["source"]
195 if not per_source.has_key(source):
196 per_source[source] = {}
197 per_source[source]["list"] = []
198 per_source[source]["list"].append(cache[filename])
199 # Determine oldest time and have note status for each source group
200 for source in per_source.keys():
201 q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source)
203 per_source[source]["source_in_database"] = len(ql)>0
204 source_list = per_source[source]["list"]
205 first = source_list[0]
206 oldest = os.stat(first["filename"])[stat.ST_MTIME]
208 for d in per_source[source]["list"]:
209 mtime = os.stat(d["filename"])[stat.ST_MTIME]
212 have_note += (d.has_key("process-new note"))
213 per_source[source]["oldest"] = oldest
215 per_source[source]["note_state"] = 0; # none
216 elif have_note < len(source_list):
217 per_source[source]["note_state"] = 1; # some
219 per_source[source]["note_state"] = 2; # all
220 per_source[source]["list"].sort(indiv_sg_compare)
221 per_source_items = per_source.items()
222 per_source_items.sort(sg_compare)
223 for i in per_source_items:
224 for j in i[1]["list"]:
225 sorted_list.append(j["filename"])
228 ################################################################################
230 class Section_Completer:
233 q = projectB.query("SELECT section FROM section")
234 for i in q.getresult():
235 self.sections.append(i[0])
237 def complete(self, text, state):
241 for word in self.sections:
243 self.matches.append(word)
245 return self.matches[state]
249 ############################################################
251 class Priority_Completer:
254 q = projectB.query("SELECT priority FROM priority")
255 for i in q.getresult():
256 self.priorities.append(i[0])
258 def complete(self, text, state):
262 for word in self.priorities:
264 self.matches.append(word)
266 return self.matches[state]
270 ################################################################################
272 def print_new (new, indexed, file=sys.stdout):
273 queue.check_valid(new)
276 for pkg in new.keys():
278 section = new[pkg]["section"]
279 priority = new[pkg]["priority"]
280 if new[pkg]["section id"] == -1:
283 if new[pkg]["priority id"] == -1:
287 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
289 line = "%-20s %-20s %-20s" % (pkg, priority, section)
290 line = line.strip()+'\n'
292 note = Upload.pkg.changes.get("process-new note")
299 ################################################################################
301 def index_range (index):
305 return "1-%s" % (index)
307 ################################################################################
308 ################################################################################
311 # Write the current data to a temporary file
312 temp_filename = utils.temp_filename()
313 temp_file = utils.open_file(temp_filename, 'w')
314 print_new (new, 0, temp_file)
316 # Spawn an editor on that file
317 editor = os.environ.get("EDITOR","vi")
318 result = os.system("%s %s" % (editor, temp_filename))
320 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
321 # Read the edited data back in
322 temp_file = utils.open_file(temp_filename)
323 lines = temp_file.readlines()
325 os.unlink(temp_filename)
332 # Pad the list if necessary
333 s[len(s):3] = [None] * (3-len(s))
334 (pkg, priority, section) = s[:3]
335 if not new.has_key(pkg):
336 utils.warn("Ignoring unknown package '%s'" % (pkg))
338 # Strip off any invalid markers, print_new will readd them.
339 if section.endswith("[!]"):
340 section = section[:-3]
341 if priority.endswith("[!]"):
342 priority = priority[:-3]
343 for f in new[pkg]["files"]:
344 Upload.pkg.files[f]["section"] = section
345 Upload.pkg.files[f]["priority"] = priority
346 new[pkg]["section"] = section
347 new[pkg]["priority"] = priority
349 ################################################################################
351 def edit_index (new, index):
352 priority = new[index]["priority"]
353 section = new[index]["section"]
354 ftype = new[index]["type"]
357 print "\t".join([index, priority, section])
361 prompt = "[B]oth, Priority, Section, Done ? "
363 prompt = "[S]ection, Done ? "
364 edit_priority = edit_section = 0
366 while prompt.find(answer) == -1:
367 answer = utils.our_raw_input(prompt)
368 m = queue.re_default_answer.match(prompt)
371 answer = answer[:1].upper()
378 edit_priority = edit_section = 1
384 readline.set_completer(Priorities.complete)
386 while not got_priority:
387 new_priority = utils.our_raw_input("New priority: ").strip()
388 if new_priority not in Priorities.priorities:
389 print "E: '%s' is not a valid priority, try again." % (new_priority)
392 priority = new_priority
396 readline.set_completer(Sections.complete)
398 while not got_section:
399 new_section = utils.our_raw_input("New section: ").strip()
400 if new_section not in Sections.sections:
401 print "E: '%s' is not a valid section, try again." % (new_section)
404 section = new_section
406 # Reset the readline completer
407 readline.set_completer(None)
409 for f in new[index]["files"]:
410 Upload.pkg.files[f]["section"] = section
411 Upload.pkg.files[f]["priority"] = priority
412 new[index]["priority"] = priority
413 new[index]["section"] = section
416 ################################################################################
418 def edit_overrides (new):
429 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
432 while not got_answer:
433 answer = utils.our_raw_input(prompt)
434 if not answer.isdigit():
435 answer = answer[:1].upper()
436 if answer == "E" or answer == "D":
438 elif queue.re_isanum.match (answer):
440 if (answer < 1) or (answer > index):
441 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
450 edit_index (new, new_index[answer])
454 ################################################################################
457 # Write the current data to a temporary file
458 temp_filename = utils.temp_filename()
459 temp_file = utils.open_file(temp_filename, 'w')
460 temp_file.write(note)
462 editor = os.environ.get("EDITOR","vi")
465 os.system("%s %s" % (editor, temp_filename))
466 temp_file = utils.open_file(temp_filename)
467 note = temp_file.read().rstrip()
470 print utils.prefix_multi_line_string(note," ")
471 prompt = "[D]one, Edit, Abandon, Quit ?"
473 while prompt.find(answer) == -1:
474 answer = utils.our_raw_input(prompt)
475 m = queue.re_default_answer.search(prompt)
478 answer = answer[:1].upper()
479 os.unlink(temp_filename)
485 Upload.pkg.changes["process-new note"] = note
486 Upload.dump_vars(Cnf["Dir::Queue::New"])
488 ################################################################################
492 less_fd = os.popen("less -R -", 'w', 0)
493 stdout_fd = sys.stdout
496 examine_package.display_changes(Upload.pkg.changes_file)
497 files = Upload.pkg.files
498 for f in files.keys():
499 if files[f].has_key("new"):
500 ftype = files[f]["type"]
502 examine_package.check_deb(f)
504 examine_package.check_dsc(f)
506 sys.stdout = stdout_fd
508 if e.errno == errno.EPIPE:
509 utils.warn("[examine_package] Caught EPIPE; skipping.")
513 except KeyboardInterrupt:
514 utils.warn("[examine_package] Caught C-c; skipping.")
517 ################################################################################
519 ## FIXME: horribly Debian specific
521 def do_bxa_notification():
522 files = Upload.pkg.files
524 for f in files.keys():
525 if files[f]["type"] == "deb":
526 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
528 summary += "Package: %s\n" % (control.Find("Package"))
529 summary += "Description: %s\n" % (control.Find("Description"))
530 Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
531 bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
532 utils.send_mail(bxa_mail)
534 ################################################################################
536 def add_overrides (new):
537 changes = Upload.pkg.changes
538 files = Upload.pkg.files
540 projectB.query("BEGIN WORK")
541 for suite in changes["suite"].keys():
542 suite_id = database.get_suite_id(suite)
543 for pkg in new.keys():
544 component_id = database.get_component_id(new[pkg]["component"])
545 type_id = database.get_override_type_id(new[pkg]["type"])
546 priority_id = new[pkg]["priority id"]
547 section_id = new[pkg]["section id"]
548 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))
549 for f in new[pkg]["files"]:
550 if files[f].has_key("new"):
554 projectB.query("COMMIT WORK")
556 if Cnf.FindB("Dinstall::BXANotify"):
557 do_bxa_notification()
559 ################################################################################
561 def prod_maintainer ():
562 # Here we prepare an editor and get them ready to prod...
563 temp_filename = utils.temp_filename()
564 editor = os.environ.get("EDITOR","vi")
567 os.system("%s %s" % (editor, temp_filename))
568 f = utils.open_file(temp_filename)
569 prod_message = "".join(f.readlines())
571 print "Prod message:"
572 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
573 prompt = "[P]rod, Edit, Abandon, Quit ?"
575 while prompt.find(answer) == -1:
576 answer = utils.our_raw_input(prompt)
577 m = queue.re_default_answer.search(prompt)
580 answer = answer[:1].upper()
581 os.unlink(temp_filename)
587 # Otherwise, do the proding...
588 user_email_address = utils.whoami() + " <%s>" % (
589 Cnf["Dinstall::MyAdminAddress"])
593 Subst["__FROM_ADDRESS__"] = user_email_address
594 Subst["__PROD_MESSAGE__"] = prod_message
595 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
597 prod_mail_message = utils.TemplateSubst(
598 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
600 # Send the prod mail if appropriate
601 if not Cnf["Dinstall::Options::No-Mail"]:
602 utils.send_mail(prod_mail_message)
604 print "Sent proding message"
606 ################################################################################
610 files = Upload.pkg.files
611 changes = Upload.pkg.changes
613 # Make a copy of distribution we can happily trample on
614 changes["suite"] = copy.copy(changes["distribution"])
616 # Fix up the list of target suites
617 for suite in changes["suite"].keys():
618 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
620 (olderr, newerr) = (database.get_suite_id(suite) == -1,
621 database.get_suite_id(override) == -1)
623 (oinv, newinv) = ("", "")
624 if olderr: oinv = "invalid "
625 if newerr: ninv = "invalid "
626 print "warning: overriding %ssuite %s to %ssuite %s" % (
627 oinv, suite, ninv, override)
628 del changes["suite"][suite]
629 changes["suite"][override] = 1
631 for suite in changes["suite"].keys():
632 suite_id = database.get_suite_id(suite)
634 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
636 # The main NEW processing loop
639 # Find out what's new
640 new = queue.determine_new(changes, files, projectB)
646 if Options["No-Action"] or Options["Automatic"]:
649 (broken, note) = print_new(new, 0)
652 if not broken and not note:
653 prompt = "Add overrides, "
655 print "W: [!] marked entries must be fixed before package can be processed."
657 print "W: note must be removed before package can be processed."
658 prompt += "Remove note, "
660 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
662 while prompt.find(answer) == -1:
663 answer = utils.our_raw_input(prompt)
664 m = queue.re_default_answer.search(prompt)
667 answer = answer[:1].upper()
670 done = add_overrides (new)
674 new = edit_overrides (new)
676 aborted = Upload.do_reject(1, Options["Manual-Reject"])
678 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
681 edit_note(changes.get("process-new note", ""))
685 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
687 del changes["process-new note"]
694 ################################################################################
695 ################################################################################
696 ################################################################################
698 def usage (exit_code=0):
699 print """Usage: dak process-new [OPTION]... [CHANGES]...
700 -a, --automatic automatic run
701 -h, --help show this help and exit.
702 -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new
703 -m, --manual-reject=MSG manual reject with `msg'
704 -n, --no-action don't do anything
705 -V, --version display the version number and exit"""
708 ################################################################################
711 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
713 Cnf = utils.get_conf()
715 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
716 ('h',"help","Process-New::Options::Help"),
717 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
718 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
719 ('n',"no-action","Process-New::Options::No-Action")]
721 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir"]:
722 if not Cnf.has_key("Process-New::Options::%s" % (i)):
723 Cnf["Process-New::Options::%s" % (i)] = ""
725 changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
726 Options = Cnf.SubTree("Process-New::Options")
731 Upload = queue.Upload(Cnf)
733 if not Options["No-Action"]:
734 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
736 projectB = Upload.projectB
738 Sections = Section_Completer()
739 Priorities = Priority_Completer()
740 readline.parse_and_bind("tab: complete")
744 ################################################################################
749 files = Upload.pkg.files
753 for f in files.keys():
754 if files[f]["type"] == "byhand":
755 if os.path.exists(f):
756 print "W: %s still present; please process byhand components and try again." % (f)
762 if Options["No-Action"]:
765 if Options["Automatic"] and not Options["No-Action"]:
767 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
769 prompt = "Manual reject, [S]kip, Quit ?"
771 while prompt.find(answer) == -1:
772 answer = utils.our_raw_input(prompt)
773 m = queue.re_default_answer.search(prompt)
776 answer = answer[:1].upper()
783 Upload.do_reject(1, Options["Manual-Reject"])
784 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
792 ################################################################################
794 def get_accept_lock():
798 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
801 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
804 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
806 print("Unable to get accepted lock (try %d of 10)" % retry)
811 def move_to_dir (dest, perms=0660, changesperms=0664):
812 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
813 file_keys = Upload.pkg.files.keys()
815 utils.move (f, dest, perms=perms)
817 def is_source_in_queue_dir(qdir):
818 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
819 and x.endswith(".changes") ]
820 for entry in entries:
822 u = queue.Upload(Cnf)
823 u.pkg.changes_file = os.path.join(qdir, entry)
825 if not u.pkg.changes["architecture"].has_key("source"):
826 # another binary upload, ignore
828 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
829 # another version, ignore
835 def move_to_holding(suite, queue_dir):
836 print "Moving to %s holding area." % (suite.upper(),)
837 if Options["No-Action"]:
839 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
840 Upload.dump_vars(queue_dir)
841 move_to_dir(queue_dir)
842 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
845 if Options["No-Action"]:
847 (summary, short_summary) = Upload.build_summaries()
848 Upload.accept(summary, short_summary)
849 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
851 def do_accept_stableupdate(suite, q):
852 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
853 if not Upload.pkg.changes["architecture"].has_key("source"):
854 # It is not a sourceful upload. So its source may be either in p-u
855 # holding, in new, in accepted or already installed.
856 if is_source_in_queue_dir(queue_dir):
857 # It's in p-u holding, so move it there.
858 print "Binary-only upload, source in %s." % (q,)
859 move_to_holding(suite, queue_dir)
860 elif Upload.source_exists(Upload.pkg.changes["source"],
861 Upload.pkg.changes["version"]):
862 # dak tells us that there is source available. At time of
863 # writing this means that it is installed, so put it into
865 print "Binary-only upload, source installed."
867 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
868 # The source is in accepted, the binary cleared NEW: accept it.
869 print "Binary-only upload, source in accepted."
871 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
872 # It's in NEW. We expect the source to land in p-u holding
874 print "Binary-only upload, source in new."
875 move_to_holding(suite, queue_dir)
877 # No case applicable. Bail out. Return will cause the upload
880 print "Stable update failed. Source not found."
883 # We are handling a sourceful upload. Move to accepted if currently
884 # in p-u holding and to p-u holding otherwise.
885 if is_source_in_queue_dir(queue_dir):
886 print "Sourceful upload in %s, accepting." % (q,)
889 move_to_holding(suite, queue_dir)
893 if not Options["No-Action"]:
895 (summary, short_summary) = Upload.build_summaries()
897 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
898 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
899 move_to_dir(Cnf["Dir::Queue::Embargoed"])
900 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
901 # Check for override disparities
902 Upload.Subst["__SUMMARY__"] = summary
904 # Stable updates need to be copied to proposed-updates holding
905 # area instead of accepted. Sourceful uploads need to go
906 # to it directly, binaries only if the source has not yet been
908 for suite, q in [("proposed-updates", "ProposedUpdates"),
909 ("oldstable-proposed-updates", "OldProposedUpdates")]:
910 if not Upload.pkg.changes["distribution"].has_key(suite):
912 return do_accept_stableupdate(suite, q)
913 # Just a normal upload, accept it...
916 if not Options["No-Action"]:
917 os.unlink(Cnf["Process-New::AcceptedLockFile"])
919 def check_status(files):
921 for f in files.keys():
922 if files[f]["type"] == "byhand":
924 elif files[f].has_key("new"):
928 def do_pkg(changes_file):
929 Upload.pkg.changes_file = changes_file
932 Upload.update_subst()
933 files = Upload.pkg.files
938 (new, byhand) = check_status(files)
944 (new, byhand) = check_status(files)
946 if not new and not byhand:
949 ################################################################################
952 accept_count = Upload.accept_count
953 accept_bytes = Upload.accept_bytes
959 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
960 Logger.log(["total",accept_count,accept_bytes])
962 if not Options["No-Action"]:
965 ################################################################################
967 def do_comments(dir, opref, npref, line, fn):
968 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
969 lines = open("%s/%s" % (dir, comm)).readlines()
970 if len(lines) == 0 or lines[0] != line + "\n": continue
971 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
972 and x.endswith(".changes") ]
973 changes_files = sort_changes(changes_files)
974 for f in changes_files:
975 f = utils.validate_changes_file_arg(f, 0)
978 fn(f, "".join(lines[1:]))
980 if opref != npref and not Options["No-Action"]:
981 newcomm = npref + comm[len(opref):]
982 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
984 ################################################################################
986 def comment_accept(changes_file, comments):
987 Upload.pkg.changes_file = changes_file
990 Upload.update_subst()
991 files = Upload.pkg.files
994 return # dak wants to REJECT, crap
996 (new, byhand) = check_status(files)
997 if not new and not byhand:
1000 ################################################################################
1002 def comment_reject(changes_file, comments):
1003 Upload.pkg.changes_file = changes_file
1005 Upload.update_vars()
1006 Upload.update_subst()
1009 pass # dak has its own reasons to reject as well, which is fine
1012 print "REJECT\n" + reject_message,
1013 if not Options["No-Action"]:
1014 Upload.do_reject(0, reject_message)
1015 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1017 ################################################################################
1020 changes_files = init()
1021 if len(changes_files) > 50:
1022 sys.stderr.write("Sorting changes...\n")
1023 changes_files = sort_changes(changes_files)
1025 # Kill me now? **FIXME**
1026 Cnf["Dinstall::Options::No-Mail"] = ""
1027 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1028 if Cnf.has_key("Dinstall::Bcc"):
1029 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1031 Upload.Subst["__BCC__"] = bcc
1033 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1035 if changes_files != []:
1036 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1038 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1039 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1041 for changes_file in changes_files:
1042 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1043 if not changes_file:
1045 print "\n" + changes_file
1046 do_pkg (changes_file)
1050 ################################################################################
1052 if __name__ == '__main__':