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')
474 temp_file.write(line)
476 editor = os.environ.get("EDITOR","vi")
479 os.system("%s %s" % (editor, temp_filename))
480 temp_file = utils.open_file(temp_filename)
481 note = temp_file.read().rstrip()
484 print utils.prefix_multi_line_string(note," ")
485 prompt = "[D]one, Edit, Abandon, Quit ?"
487 while prompt.find(answer) == -1:
488 answer = utils.our_raw_input(prompt)
489 m = re_default_answer.search(prompt)
492 answer = answer[:1].upper()
493 os.unlink(temp_filename)
499 database.add_new_comment(Upload.pkg.changes["source"], Upload.pkg.changes["version"], note, utils.whoami())
501 ################################################################################
505 less_fd = os.popen("less -R -", 'w', 0)
506 stdout_fd = sys.stdout
509 changes = utils.parse_changes (Upload.pkg.changes_file)
510 examine_package.display_changes(changes['distribution'], Upload.pkg.changes_file)
511 files = Upload.pkg.files
512 for f in files.keys():
513 if files[f].has_key("new"):
514 ftype = files[f]["type"]
516 examine_package.check_deb(changes['distribution'], f)
518 examine_package.check_dsc(changes['distribution'], f)
520 examine_package.output_package_relations()
521 sys.stdout = stdout_fd
523 if e.errno == errno.EPIPE:
524 utils.warn("[examine_package] Caught EPIPE; skipping.")
528 except KeyboardInterrupt:
529 utils.warn("[examine_package] Caught C-c; skipping.")
532 ################################################################################
534 ## FIXME: horribly Debian specific
536 def do_bxa_notification():
537 files = Upload.pkg.files
539 for f in files.keys():
540 if files[f]["type"] == "deb":
541 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
543 summary += "Package: %s\n" % (control.Find("Package"))
544 summary += "Description: %s\n" % (control.Find("Description"))
545 Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
546 bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
547 utils.send_mail(bxa_mail)
549 ################################################################################
551 def add_overrides (new):
552 changes = Upload.pkg.changes
553 files = Upload.pkg.files
555 projectB.query("BEGIN WORK")
556 for suite in changes["suite"].keys():
557 suite_id = database.get_suite_id(suite)
558 for pkg in new.keys():
559 component_id = database.get_component_id(new[pkg]["component"])
560 type_id = database.get_override_type_id(new[pkg]["type"])
561 priority_id = new[pkg]["priority id"]
562 section_id = new[pkg]["section id"]
563 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))
564 for f in new[pkg]["files"]:
565 if files[f].has_key("new"):
569 projectB.query("COMMIT WORK")
571 if Cnf.FindB("Dinstall::BXANotify"):
572 do_bxa_notification()
574 ################################################################################
576 def prod_maintainer ():
577 # Here we prepare an editor and get them ready to prod...
578 (fd, temp_filename) = utils.temp_filename()
579 editor = os.environ.get("EDITOR","vi")
582 os.system("%s %s" % (editor, temp_filename))
584 prod_message = "".join(f.readlines())
586 print "Prod message:"
587 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
588 prompt = "[P]rod, Edit, Abandon, Quit ?"
590 while prompt.find(answer) == -1:
591 answer = utils.our_raw_input(prompt)
592 m = re_default_answer.search(prompt)
595 answer = answer[:1].upper()
596 os.unlink(temp_filename)
602 # Otherwise, do the proding...
603 user_email_address = utils.whoami() + " <%s>" % (
604 Cnf["Dinstall::MyAdminAddress"])
608 Subst["__FROM_ADDRESS__"] = user_email_address
609 Subst["__PROD_MESSAGE__"] = prod_message
610 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
612 prod_mail_message = utils.TemplateSubst(
613 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
615 # Send the prod mail if appropriate
616 if not Cnf["Dinstall::Options::No-Mail"]:
617 utils.send_mail(prod_mail_message)
619 print "Sent proding message"
621 ################################################################################
625 files = Upload.pkg.files
626 changes = Upload.pkg.changes
628 # Make a copy of distribution we can happily trample on
629 changes["suite"] = copy.copy(changes["distribution"])
631 # Fix up the list of target suites
632 for suite in changes["suite"].keys():
633 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
635 (olderr, newerr) = (database.get_suite_id(suite) == -1,
636 database.get_suite_id(override) == -1)
638 (oinv, newinv) = ("", "")
639 if olderr: oinv = "invalid "
640 if newerr: ninv = "invalid "
641 print "warning: overriding %ssuite %s to %ssuite %s" % (
642 oinv, suite, ninv, override)
643 del changes["suite"][suite]
644 changes["suite"][override] = 1
646 for suite in changes["suite"].keys():
647 suite_id = database.get_suite_id(suite)
649 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
651 # The main NEW processing loop
654 # Find out what's new
655 new = queue.determine_new(changes, files, projectB)
661 if Options["No-Action"] or Options["Automatic"]:
664 (broken, note) = print_new(new, 0)
667 if not broken and not note:
668 prompt = "Add overrides, "
670 print "W: [!] marked entries must be fixed before package can be processed."
672 print "W: note must be removed before package can be processed."
673 prompt += "Remove note, "
675 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
677 while prompt.find(answer) == -1:
678 answer = utils.our_raw_input(prompt)
679 m = re_default_answer.search(prompt)
682 answer = answer[:1].upper()
685 done = add_overrides (new)
689 new = edit_overrides (new)
691 aborted = Upload.do_reject(1, Options["Manual-Reject"])
693 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
696 edit_note(database.get_new_comments(changes.get("source", "")))
700 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
702 database.delete_new_comments(changes.get("source"), changes.get("version"))
709 ################################################################################
710 ################################################################################
711 ################################################################################
713 def usage (exit_code=0):
714 print """Usage: dak process-new [OPTION]... [CHANGES]...
715 -a, --automatic automatic run
716 -h, --help show this help and exit.
717 -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new
718 -m, --manual-reject=MSG manual reject with `msg'
719 -n, --no-action don't do anything
720 -V, --version display the version number and exit"""
723 ################################################################################
726 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
728 Cnf = utils.get_conf()
730 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
731 ('h',"help","Process-New::Options::Help"),
732 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
733 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
734 ('n',"no-action","Process-New::Options::No-Action")]
736 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir"]:
737 if not Cnf.has_key("Process-New::Options::%s" % (i)):
738 Cnf["Process-New::Options::%s" % (i)] = ""
740 changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
741 if len(changes_files) == 0 and not Cnf.get("Process-New::Options::Comments-Dir",""):
742 changes_files = utils.get_changes_files(Cnf["Dir::Queue::New"])
744 Options = Cnf.SubTree("Process-New::Options")
749 Upload = queue.Upload(Cnf)
751 if not Options["No-Action"]:
752 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
754 projectB = Upload.projectB
756 Sections = Section_Completer()
757 Priorities = Priority_Completer()
758 readline.parse_and_bind("tab: complete")
762 ################################################################################
767 files = Upload.pkg.files
771 for f in files.keys():
772 if files[f]["type"] == "byhand":
773 if os.path.exists(f):
774 print "W: %s still present; please process byhand components and try again." % (f)
780 if Options["No-Action"]:
783 if Options["Automatic"] and not Options["No-Action"]:
785 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
787 prompt = "Manual reject, [S]kip, Quit ?"
789 while prompt.find(answer) == -1:
790 answer = utils.our_raw_input(prompt)
791 m = re_default_answer.search(prompt)
794 answer = answer[:1].upper()
801 Upload.do_reject(1, Options["Manual-Reject"])
802 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
810 ################################################################################
812 def get_accept_lock():
816 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
819 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
822 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
824 print("Unable to get accepted lock (try %d of 10)" % retry)
829 def move_to_dir (dest, perms=0660, changesperms=0664):
830 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
831 file_keys = Upload.pkg.files.keys()
833 utils.move (f, dest, perms=perms)
835 def is_source_in_queue_dir(qdir):
836 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
837 and x.endswith(".changes") ]
838 for entry in entries:
840 u = queue.Upload(Cnf)
841 u.pkg.changes_file = os.path.join(qdir, entry)
843 if not u.pkg.changes["architecture"].has_key("source"):
844 # another binary upload, ignore
846 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
847 # another version, ignore
853 def move_to_holding(suite, queue_dir):
854 print "Moving to %s holding area." % (suite.upper(),)
855 if Options["No-Action"]:
857 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
858 Upload.dump_vars(queue_dir)
859 move_to_dir(queue_dir, perms=0664)
860 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
863 if Options["No-Action"]:
865 (summary, short_summary) = Upload.build_summaries()
866 Upload.accept(summary, short_summary)
867 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
869 def do_accept_stableupdate(suite, q):
870 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
871 if not Upload.pkg.changes["architecture"].has_key("source"):
872 # It is not a sourceful upload. So its source may be either in p-u
873 # holding, in new, in accepted or already installed.
874 if is_source_in_queue_dir(queue_dir):
875 # It's in p-u holding, so move it there.
876 print "Binary-only upload, source in %s." % (q,)
877 move_to_holding(suite, queue_dir)
878 elif Upload.source_exists(Upload.pkg.changes["source"],
879 Upload.pkg.changes["version"]):
880 # dak tells us that there is source available. At time of
881 # writing this means that it is installed, so put it into
883 print "Binary-only upload, source installed."
885 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
886 # The source is in accepted, the binary cleared NEW: accept it.
887 print "Binary-only upload, source in accepted."
889 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
890 # It's in NEW. We expect the source to land in p-u holding
892 print "Binary-only upload, source in new."
893 move_to_holding(suite, queue_dir)
895 # No case applicable. Bail out. Return will cause the upload
898 print "Stable update failed. Source not found."
901 # We are handling a sourceful upload. Move to accepted if currently
902 # in p-u holding and to p-u holding otherwise.
903 if is_source_in_queue_dir(queue_dir):
904 print "Sourceful upload in %s, accepting." % (q,)
907 move_to_holding(suite, queue_dir)
911 if not Options["No-Action"]:
913 (summary, short_summary) = Upload.build_summaries()
915 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
916 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
917 move_to_dir(Cnf["Dir::Queue::Embargoed"])
918 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
919 # Check for override disparities
920 Upload.Subst["__SUMMARY__"] = summary
922 # Stable updates need to be copied to proposed-updates holding
923 # area instead of accepted. Sourceful uploads need to go
924 # to it directly, binaries only if the source has not yet been
926 for suite, q in [("proposed-updates", "ProposedUpdates"),
927 ("oldstable-proposed-updates", "OldProposedUpdates")]:
928 if not Upload.pkg.changes["distribution"].has_key(suite):
930 return do_accept_stableupdate(suite, q)
931 # Just a normal upload, accept it...
934 if not Options["No-Action"]:
935 os.unlink(Cnf["Process-New::AcceptedLockFile"])
937 def check_status(files):
939 for f in files.keys():
940 if files[f]["type"] == "byhand":
942 elif files[f].has_key("new"):
946 def do_pkg(changes_file):
947 Upload.pkg.changes_file = changes_file
950 Upload.update_subst()
951 files = Upload.pkg.files
956 (new, byhand) = check_status(files)
962 (new, byhand) = check_status(files)
964 if not new and not byhand:
967 ################################################################################
970 accept_count = Upload.accept_count
971 accept_bytes = Upload.accept_bytes
977 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
978 Logger.log(["total",accept_count,accept_bytes])
980 if not Options["No-Action"]:
983 ################################################################################
985 def do_comments(dir, opref, npref, line, fn):
986 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
987 lines = open("%s/%s" % (dir, comm)).readlines()
988 if len(lines) == 0 or lines[0] != line + "\n": continue
989 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
990 and x.endswith(".changes") ]
991 changes_files = sort_changes(changes_files)
992 for f in changes_files:
993 f = utils.validate_changes_file_arg(f, 0)
996 fn(f, "".join(lines[1:]))
998 if opref != npref and not Options["No-Action"]:
999 newcomm = npref + comm[len(opref):]
1000 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
1002 ################################################################################
1004 def comment_accept(changes_file, comments):
1005 Upload.pkg.changes_file = changes_file
1007 Upload.update_vars()
1008 Upload.update_subst()
1009 files = Upload.pkg.files
1012 return # dak wants to REJECT, crap
1014 (new, byhand) = check_status(files)
1015 if not new and not byhand:
1018 ################################################################################
1020 def comment_reject(changes_file, comments):
1021 Upload.pkg.changes_file = changes_file
1023 Upload.update_vars()
1024 Upload.update_subst()
1027 pass # dak has its own reasons to reject as well, which is fine
1030 print "REJECT\n" + reject_message,
1031 if not Options["No-Action"]:
1032 Upload.do_reject(0, reject_message)
1033 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1035 ################################################################################
1038 changes_files = init()
1039 if len(changes_files) > 50:
1040 sys.stderr.write("Sorting changes...\n")
1041 changes_files = sort_changes(changes_files)
1043 # Kill me now? **FIXME**
1044 Cnf["Dinstall::Options::No-Mail"] = ""
1045 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1046 if Cnf.has_key("Dinstall::Bcc"):
1047 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1049 Upload.Subst["__BCC__"] = bcc
1051 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1053 if changes_files != []:
1054 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1056 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1057 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1059 for changes_file in changes_files:
1060 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1061 if not changes_file:
1063 print "\n" + changes_file
1064 do_pkg (changes_file)
1068 ################################################################################
1070 if __name__ == '__main__':