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 @license: GNU General Public License version 2 or later
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 ################################################################################
27 # 23:12|<aj> I will not hush!
29 # 23:12|<aj> Where there is injustice in the world, I shall be there!
30 # 23:13|<aj> I shall not be silenced!
31 # 23:13|<aj> The world shall know!
32 # 23:13|<aj> The world *must* know!
33 # 23:13|<elmo> oh dear, he's gone back to powerpuff girls... ;-)
34 # 23:13|<aj> yay powerpuff girls!!
35 # 23:13|<aj> buttercup's my favourite, who's yours?
36 # 23:14|<aj> you're backing away from the keyboard right now aren't you?
37 # 23:14|<aj> *AREN'T YOU*?!
38 # 23:15|<aj> I will not be treated like this.
39 # 23:15|<aj> I shall have my revenge.
40 # 23:15|<aj> I SHALL!!!
42 ################################################################################
51 import apt_pkg, apt_inst
52 import examine_package
53 from daklib import database
54 from daklib import logging
55 from daklib import queue
56 from daklib import utils
57 from daklib.regexes import re_no_epoch, re_default_answer, re_isanum
60 Cnf = None #: Configuration, apt_pkg.Configuration
63 projectB = None #: database connection, pgobject
71 ################################################################################
72 ################################################################################
73 ################################################################################
75 def reject (str, prefix="Rejected: "):
78 reject_message += prefix + str + "\n"
82 files = Upload.pkg.files
85 for f in files.keys():
86 # The .orig.tar.gz can disappear out from under us is it's a
87 # duplicate of one in the archive.
88 if not files.has_key(f):
90 # Check that the source still exists
91 if files[f]["type"] == "deb":
92 source_version = files[f]["source version"]
93 source_package = files[f]["source package"]
94 if not Upload.pkg.changes["architecture"].has_key("source") \
95 and not Upload.source_exists(source_package, source_version, Upload.pkg.changes["distribution"].keys()):
96 source_epochless_version = re_no_epoch.sub('', source_version)
97 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
99 for q in ["Accepted", "Embargoed", "Unembargoed"]:
100 if Cnf.has_key("Dir::Queue::%s" % (q)):
101 if os.path.exists(Cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
104 reject("no source found for %s %s (%s)." % (source_package, source_version, f))
106 # Version and file overwrite checks
107 if files[f]["type"] == "deb":
108 reject(Upload.check_binary_against_db(f), "")
109 elif files[f]["type"] == "dsc":
110 reject(Upload.check_source_against_db(f), "")
111 (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(f)
112 reject(reject_msg, "")
114 if reject_message.find("Rejected") != -1:
116 if Options["No-Action"] or Options["Automatic"]:
119 print "REJECT\n" + reject_message,
120 prompt = "[R]eject, Skip, Quit ?"
122 while prompt.find(answer) == -1:
123 answer = utils.our_raw_input(prompt)
124 m = re_default_answer.match(prompt)
127 answer = answer[:1].upper()
130 Upload.do_reject(0, reject_message)
131 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
141 ################################################################################
143 def indiv_sg_compare (a, b):
144 """Sort by source name, source, version, 'have source', and
145 finally by filename."""
146 # Sort by source version
147 q = apt_pkg.VersionCompare(a["version"], b["version"])
151 # Sort by 'have source'
152 a_has_source = a["architecture"].get("source")
153 b_has_source = b["architecture"].get("source")
154 if a_has_source and not b_has_source:
156 elif b_has_source and not a_has_source:
159 return cmp(a["filename"], b["filename"])
161 ############################################################
163 def sg_compare (a, b):
166 """Sort by have note, source already in database and time of oldest upload."""
168 a_note_state = a["note_state"]
169 b_note_state = b["note_state"]
170 if a_note_state < b_note_state:
172 elif a_note_state > b_note_state:
174 # Sort by source already in database (descending)
175 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
176 if source_in_database:
177 return -source_in_database
179 # Sort by time of oldest upload
180 return cmp(a["oldest"], b["oldest"])
182 def sort_changes(changes_files):
183 """Sort into source groups, then sort each source group by version,
184 have source, filename. Finally, sort the source groups by have
185 note, time of oldest upload of each source upload."""
186 if len(changes_files) == 1:
191 # Read in all the .changes files
192 for filename in changes_files:
194 Upload.pkg.changes_file = filename
197 cache[filename] = copy.copy(Upload.pkg.changes)
198 cache[filename]["filename"] = filename
200 sorted_list.append(filename)
202 # Divide the .changes into per-source groups
204 for filename in cache.keys():
205 source = cache[filename]["source"]
206 if not per_source.has_key(source):
207 per_source[source] = {}
208 per_source[source]["list"] = []
209 per_source[source]["list"].append(cache[filename])
210 # Determine oldest time and have note status for each source group
211 for source in per_source.keys():
212 q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source)
214 per_source[source]["source_in_database"] = len(ql)>0
215 source_list = per_source[source]["list"]
216 first = source_list[0]
217 oldest = os.stat(first["filename"])[stat.ST_MTIME]
219 for d in per_source[source]["list"]:
220 mtime = os.stat(d["filename"])[stat.ST_MTIME]
223 have_note += (database.has_new_comment(d["source"], d["version"]))
224 per_source[source]["oldest"] = oldest
226 per_source[source]["note_state"] = 0; # none
227 elif have_note < len(source_list):
228 per_source[source]["note_state"] = 1; # some
230 per_source[source]["note_state"] = 2; # all
231 per_source[source]["list"].sort(indiv_sg_compare)
232 per_source_items = per_source.items()
233 per_source_items.sort(sg_compare)
234 for i in per_source_items:
235 for j in i[1]["list"]:
236 sorted_list.append(j["filename"])
239 ################################################################################
241 class Section_Completer:
245 q = projectB.query("SELECT section FROM section")
246 for i in q.getresult():
247 self.sections.append(i[0])
249 def complete(self, text, state):
253 for word in self.sections:
255 self.matches.append(word)
257 return self.matches[state]
261 ############################################################
263 class Priority_Completer:
267 q = projectB.query("SELECT priority FROM priority")
268 for i in q.getresult():
269 self.priorities.append(i[0])
271 def complete(self, text, state):
275 for word in self.priorities:
277 self.matches.append(word)
279 return self.matches[state]
283 ################################################################################
285 def print_new (new, indexed, file=sys.stdout):
286 queue.check_valid(new)
289 for pkg in new.keys():
291 section = new[pkg]["section"]
292 priority = new[pkg]["priority"]
293 if new[pkg]["section id"] == -1:
296 if new[pkg]["priority id"] == -1:
300 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
302 line = "%-20s %-20s %-20s" % (pkg, priority, section)
303 line = line.strip()+'\n'
305 note = database.get_new_comments(Upload.pkg.changes.get("source"))
311 ################################################################################
313 def index_range (index):
317 return "1-%s" % (index)
319 ################################################################################
320 ################################################################################
323 # Write the current data to a temporary file
324 (fd, temp_filename) = utils.temp_filename()
325 temp_file = os.fdopen(fd, 'w')
326 print_new (new, 0, temp_file)
328 # Spawn an editor on that file
329 editor = os.environ.get("EDITOR","vi")
330 result = os.system("%s %s" % (editor, temp_filename))
332 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
333 # Read the edited data back in
334 temp_file = utils.open_file(temp_filename)
335 lines = temp_file.readlines()
337 os.unlink(temp_filename)
344 # Pad the list if necessary
345 s[len(s):3] = [None] * (3-len(s))
346 (pkg, priority, section) = s[:3]
347 if not new.has_key(pkg):
348 utils.warn("Ignoring unknown package '%s'" % (pkg))
350 # Strip off any invalid markers, print_new will readd them.
351 if section.endswith("[!]"):
352 section = section[:-3]
353 if priority.endswith("[!]"):
354 priority = priority[:-3]
355 for f in new[pkg]["files"]:
356 Upload.pkg.files[f]["section"] = section
357 Upload.pkg.files[f]["priority"] = priority
358 new[pkg]["section"] = section
359 new[pkg]["priority"] = priority
361 ################################################################################
363 def edit_index (new, index):
364 priority = new[index]["priority"]
365 section = new[index]["section"]
366 ftype = new[index]["type"]
369 print "\t".join([index, priority, section])
373 prompt = "[B]oth, Priority, Section, Done ? "
375 prompt = "[S]ection, Done ? "
376 edit_priority = edit_section = 0
378 while prompt.find(answer) == -1:
379 answer = utils.our_raw_input(prompt)
380 m = re_default_answer.match(prompt)
383 answer = answer[:1].upper()
390 edit_priority = edit_section = 1
396 readline.set_completer(Priorities.complete)
398 while not got_priority:
399 new_priority = utils.our_raw_input("New priority: ").strip()
400 if new_priority not in Priorities.priorities:
401 print "E: '%s' is not a valid priority, try again." % (new_priority)
404 priority = new_priority
408 readline.set_completer(Sections.complete)
410 while not got_section:
411 new_section = utils.our_raw_input("New section: ").strip()
412 if new_section not in Sections.sections:
413 print "E: '%s' is not a valid section, try again." % (new_section)
416 section = new_section
418 # Reset the readline completer
419 readline.set_completer(None)
421 for f in new[index]["files"]:
422 Upload.pkg.files[f]["section"] = section
423 Upload.pkg.files[f]["priority"] = priority
424 new[index]["priority"] = priority
425 new[index]["section"] = section
428 ################################################################################
430 def edit_overrides (new):
441 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
444 while not got_answer:
445 answer = utils.our_raw_input(prompt)
446 if not answer.isdigit():
447 answer = answer[:1].upper()
448 if answer == "E" or answer == "D":
450 elif re_isanum.match (answer):
452 if (answer < 1) or (answer > index):
453 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
462 edit_index (new, new_index[answer])
466 ################################################################################
469 # Write the current data to a temporary file
470 (fd, temp_filename) = utils.temp_filename()
471 temp_file = os.fdopen(fd, 'w')
472 temp_file.write(note)
474 editor = os.environ.get("EDITOR","vi")
477 os.system("%s %s" % (editor, temp_filename))
478 temp_file = utils.open_file(temp_filename)
479 note = temp_file.read().rstrip()
482 print utils.prefix_multi_line_string(note," ")
483 prompt = "[D]one, Edit, Abandon, Quit ?"
485 while prompt.find(answer) == -1:
486 answer = utils.our_raw_input(prompt)
487 m = re_default_answer.search(prompt)
490 answer = answer[:1].upper()
491 os.unlink(temp_filename)
497 database.add_new_comment(Upload.pkg.changes["source"], Upload.pkg.changes["version"], note, utils.whoami())
499 ################################################################################
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():
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,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
545 utils.send_mail(bxa_mail)
547 ################################################################################
549 def add_overrides (new):
550 changes = Upload.pkg.changes
551 files = Upload.pkg.files
553 projectB.query("BEGIN WORK")
554 for suite in changes["suite"].keys():
555 suite_id = database.get_suite_id(suite)
556 for pkg in new.keys():
557 component_id = database.get_component_id(new[pkg]["component"])
558 type_id = database.get_override_type_id(new[pkg]["type"])
559 priority_id = new[pkg]["priority id"]
560 section_id = new[pkg]["section id"]
561 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))
562 for f in new[pkg]["files"]:
563 if files[f].has_key("new"):
567 projectB.query("COMMIT WORK")
569 if Cnf.FindB("Dinstall::BXANotify"):
570 do_bxa_notification()
572 ################################################################################
574 def prod_maintainer ():
575 # Here we prepare an editor and get them ready to prod...
576 (fd, temp_filename) = utils.temp_filename()
577 editor = os.environ.get("EDITOR","vi")
580 os.system("%s %s" % (editor, temp_filename))
582 prod_message = "".join(f.readlines())
584 print "Prod message:"
585 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
586 prompt = "[P]rod, Edit, Abandon, Quit ?"
588 while prompt.find(answer) == -1:
589 answer = utils.our_raw_input(prompt)
590 m = re_default_answer.search(prompt)
593 answer = answer[:1].upper()
594 os.unlink(temp_filename)
600 # Otherwise, do the proding...
601 user_email_address = utils.whoami() + " <%s>" % (
602 Cnf["Dinstall::MyAdminAddress"])
606 Subst["__FROM_ADDRESS__"] = user_email_address
607 Subst["__PROD_MESSAGE__"] = prod_message
608 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
610 prod_mail_message = utils.TemplateSubst(
611 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
613 # Send the prod mail if appropriate
614 if not Cnf["Dinstall::Options::No-Mail"]:
615 utils.send_mail(prod_mail_message)
617 print "Sent proding message"
619 ################################################################################
623 files = Upload.pkg.files
624 changes = Upload.pkg.changes
626 # Make a copy of distribution we can happily trample on
627 changes["suite"] = copy.copy(changes["distribution"])
629 # Fix up the list of target suites
630 for suite in changes["suite"].keys():
631 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
633 (olderr, newerr) = (database.get_suite_id(suite) == -1,
634 database.get_suite_id(override) == -1)
636 (oinv, newinv) = ("", "")
637 if olderr: oinv = "invalid "
638 if newerr: ninv = "invalid "
639 print "warning: overriding %ssuite %s to %ssuite %s" % (
640 oinv, suite, ninv, override)
641 del changes["suite"][suite]
642 changes["suite"][override] = 1
644 for suite in changes["suite"].keys():
645 suite_id = database.get_suite_id(suite)
647 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
649 # The main NEW processing loop
652 # Find out what's new
653 new = queue.determine_new(changes, files, projectB)
659 if Options["No-Action"] or Options["Automatic"]:
662 (broken, note) = print_new(new, 0)
665 if not broken and not note:
666 prompt = "Add overrides, "
668 print "W: [!] marked entries must be fixed before package can be processed."
670 print "W: note must be removed before package can be processed."
671 prompt += "Remove note, "
673 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
675 while prompt.find(answer) == -1:
676 answer = utils.our_raw_input(prompt)
677 m = re_default_answer.search(prompt)
680 answer = answer[:1].upper()
683 done = add_overrides (new)
687 new = edit_overrides (new)
689 aborted = Upload.do_reject(1, Options["Manual-Reject"])
691 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
694 edit_note(database.get_new_comments(changes.get("source", "")))
698 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
700 database.delete_new_comments(changes.get("source"), changes.get("version"))
707 ################################################################################
708 ################################################################################
709 ################################################################################
711 def usage (exit_code=0):
712 print """Usage: dak process-new [OPTION]... [CHANGES]...
713 -a, --automatic automatic run
714 -h, --help show this help and exit.
715 -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new
716 -m, --manual-reject=MSG manual reject with `msg'
717 -n, --no-action don't do anything
718 -V, --version display the version number and exit"""
721 ################################################################################
724 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
726 Cnf = utils.get_conf()
728 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
729 ('h',"help","Process-New::Options::Help"),
730 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
731 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
732 ('n',"no-action","Process-New::Options::No-Action")]
734 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir"]:
735 if not Cnf.has_key("Process-New::Options::%s" % (i)):
736 Cnf["Process-New::Options::%s" % (i)] = ""
738 changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
739 if len(changes_files) == 0 and not Cnf.get("Process-New::Options::Comments-Dir",""):
740 changes_files = utils.get_changes_files(Cnf["Dir::Queue::New"])
742 Options = Cnf.SubTree("Process-New::Options")
747 Upload = queue.Upload(Cnf)
749 if not Options["No-Action"]:
750 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
752 projectB = Upload.projectB
754 Sections = Section_Completer()
755 Priorities = Priority_Completer()
756 readline.parse_and_bind("tab: complete")
760 ################################################################################
765 files = Upload.pkg.files
769 for f in files.keys():
770 if files[f]["type"] == "byhand":
771 if os.path.exists(f):
772 print "W: %s still present; please process byhand components and try again." % (f)
778 if Options["No-Action"]:
781 if Options["Automatic"] and not Options["No-Action"]:
783 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
785 prompt = "Manual reject, [S]kip, Quit ?"
787 while prompt.find(answer) == -1:
788 answer = utils.our_raw_input(prompt)
789 m = re_default_answer.search(prompt)
792 answer = answer[:1].upper()
799 Upload.do_reject(1, Options["Manual-Reject"])
800 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
808 ################################################################################
810 def get_accept_lock():
814 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
817 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
820 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
822 print("Unable to get accepted lock (try %d of 10)" % retry)
827 def move_to_dir (dest, perms=0660, changesperms=0664):
828 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
829 file_keys = Upload.pkg.files.keys()
831 utils.move (f, dest, perms=perms)
833 def is_source_in_queue_dir(qdir):
834 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
835 and x.endswith(".changes") ]
836 for entry in entries:
838 u = queue.Upload(Cnf)
839 u.pkg.changes_file = os.path.join(qdir, entry)
841 if not u.pkg.changes["architecture"].has_key("source"):
842 # another binary upload, ignore
844 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
845 # another version, ignore
851 def move_to_holding(suite, queue_dir):
852 print "Moving to %s holding area." % (suite.upper(),)
853 if Options["No-Action"]:
855 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
856 Upload.dump_vars(queue_dir)
857 move_to_dir(queue_dir, perms=0664)
858 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
861 if Options["No-Action"]:
863 (summary, short_summary) = Upload.build_summaries()
864 Upload.accept(summary, short_summary)
865 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
867 def do_accept_stableupdate(suite, q):
868 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
869 if not Upload.pkg.changes["architecture"].has_key("source"):
870 # It is not a sourceful upload. So its source may be either in p-u
871 # holding, in new, in accepted or already installed.
872 if is_source_in_queue_dir(queue_dir):
873 # It's in p-u holding, so move it there.
874 print "Binary-only upload, source in %s." % (q,)
875 move_to_holding(suite, queue_dir)
876 elif Upload.source_exists(Upload.pkg.changes["source"],
877 Upload.pkg.changes["version"]):
878 # dak tells us that there is source available. At time of
879 # writing this means that it is installed, so put it into
881 print "Binary-only upload, source installed."
883 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
884 # The source is in accepted, the binary cleared NEW: accept it.
885 print "Binary-only upload, source in accepted."
887 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
888 # It's in NEW. We expect the source to land in p-u holding
890 print "Binary-only upload, source in new."
891 move_to_holding(suite, queue_dir)
893 # No case applicable. Bail out. Return will cause the upload
896 print "Stable update failed. Source not found."
899 # We are handling a sourceful upload. Move to accepted if currently
900 # in p-u holding and to p-u holding otherwise.
901 if is_source_in_queue_dir(queue_dir):
902 print "Sourceful upload in %s, accepting." % (q,)
905 move_to_holding(suite, queue_dir)
909 if not Options["No-Action"]:
911 (summary, short_summary) = Upload.build_summaries()
913 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
914 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
915 move_to_dir(Cnf["Dir::Queue::Embargoed"])
916 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
917 # Check for override disparities
918 Upload.Subst["__SUMMARY__"] = summary
920 # Stable updates need to be copied to proposed-updates holding
921 # area instead of accepted. Sourceful uploads need to go
922 # to it directly, binaries only if the source has not yet been
924 for suite, q in [("proposed-updates", "ProposedUpdates"),
925 ("oldstable-proposed-updates", "OldProposedUpdates")]:
926 if not Upload.pkg.changes["distribution"].has_key(suite):
928 return do_accept_stableupdate(suite, q)
929 # Just a normal upload, accept it...
932 if not Options["No-Action"]:
933 os.unlink(Cnf["Process-New::AcceptedLockFile"])
935 def check_status(files):
937 for f in files.keys():
938 if files[f]["type"] == "byhand":
940 elif files[f].has_key("new"):
944 def do_pkg(changes_file):
945 Upload.pkg.changes_file = changes_file
948 Upload.update_subst()
949 files = Upload.pkg.files
954 (new, byhand) = check_status(files)
960 (new, byhand) = check_status(files)
962 if not new and not byhand:
965 ################################################################################
968 accept_count = Upload.accept_count
969 accept_bytes = Upload.accept_bytes
975 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
976 Logger.log(["total",accept_count,accept_bytes])
978 if not Options["No-Action"]:
981 ################################################################################
983 def do_comments(dir, opref, npref, line, fn):
984 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
985 lines = open("%s/%s" % (dir, comm)).readlines()
986 if len(lines) == 0 or lines[0] != line + "\n": continue
987 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
988 and x.endswith(".changes") ]
989 changes_files = sort_changes(changes_files)
990 for f in changes_files:
991 f = utils.validate_changes_file_arg(f, 0)
994 fn(f, "".join(lines[1:]))
996 if opref != npref and not Options["No-Action"]:
997 newcomm = npref + comm[len(opref):]
998 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
1000 ################################################################################
1002 def comment_accept(changes_file, comments):
1003 Upload.pkg.changes_file = changes_file
1005 Upload.update_vars()
1006 Upload.update_subst()
1007 files = Upload.pkg.files
1010 return # dak wants to REJECT, crap
1012 (new, byhand) = check_status(files)
1013 if not new and not byhand:
1016 ################################################################################
1018 def comment_reject(changes_file, comments):
1019 Upload.pkg.changes_file = changes_file
1021 Upload.update_vars()
1022 Upload.update_subst()
1025 pass # dak has its own reasons to reject as well, which is fine
1028 print "REJECT\n" + reject_message,
1029 if not Options["No-Action"]:
1030 Upload.do_reject(0, reject_message)
1031 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1033 ################################################################################
1036 changes_files = init()
1037 if len(changes_files) > 50:
1038 sys.stderr.write("Sorting changes...\n")
1039 changes_files = sort_changes(changes_files)
1041 # Kill me now? **FIXME**
1042 Cnf["Dinstall::Options::No-Mail"] = ""
1043 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1044 if Cnf.has_key("Dinstall::Bcc"):
1045 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1047 Upload.Subst["__BCC__"] = bcc
1049 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1051 if changes_files != []:
1052 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1054 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1055 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1057 for changes_file in changes_files:
1058 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1059 if not changes_file:
1061 print "\n" + changes_file
1062 do_pkg (changes_file)
1066 ################################################################################
1068 if __name__ == '__main__':