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
58 from daklib.dak_exceptions import CantOpenError
61 Cnf = None #: Configuration, apt_pkg.Configuration
64 projectB = None #: database connection, pgobject
72 ################################################################################
73 ################################################################################
74 ################################################################################
76 def reject (str, prefix="Rejected: "):
79 reject_message += prefix + str + "\n"
83 files = Upload.pkg.files
86 for f in files.keys():
87 # The .orig.tar.gz can disappear out from under us is it's a
88 # duplicate of one in the archive.
89 if not files.has_key(f):
91 # Check that the source still exists
92 if files[f]["type"] == "deb":
93 source_version = files[f]["source version"]
94 source_package = files[f]["source package"]
95 if not Upload.pkg.changes["architecture"].has_key("source") \
96 and not Upload.source_exists(source_package, source_version, Upload.pkg.changes["distribution"].keys()):
97 source_epochless_version = re_no_epoch.sub('', source_version)
98 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
100 for q in ["Accepted", "Embargoed", "Unembargoed"]:
101 if Cnf.has_key("Dir::Queue::%s" % (q)):
102 if os.path.exists(Cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
105 reject("no source found for %s %s (%s)." % (source_package, source_version, f))
107 # Version and file overwrite checks
108 if files[f]["type"] == "deb":
109 reject(Upload.check_binary_against_db(f), "")
110 elif files[f]["type"] == "dsc":
111 reject(Upload.check_source_against_db(f), "")
112 (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(f)
113 reject(reject_msg, "")
115 if reject_message.find("Rejected") != -1:
117 if Options["No-Action"] or Options["Automatic"] or Options["Trainee"]:
120 print "REJECT\n" + reject_message,
121 prompt = "[R]eject, Skip, Quit ?"
123 while prompt.find(answer) == -1:
124 answer = utils.our_raw_input(prompt)
125 m = re_default_answer.match(prompt)
128 answer = answer[:1].upper()
131 Upload.do_reject(0, reject_message)
132 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
142 ################################################################################
144 def indiv_sg_compare (a, b):
145 """Sort by source name, source, version, 'have source', and
146 finally by filename."""
147 # Sort by source version
148 q = apt_pkg.VersionCompare(a["version"], b["version"])
152 # Sort by 'have source'
153 a_has_source = a["architecture"].get("source")
154 b_has_source = b["architecture"].get("source")
155 if a_has_source and not b_has_source:
157 elif b_has_source and not a_has_source:
160 return cmp(a["filename"], b["filename"])
162 ############################################################
164 def sg_compare (a, b):
167 """Sort by have note, source already in database and time of oldest upload."""
169 a_note_state = a["note_state"]
170 b_note_state = b["note_state"]
171 if a_note_state < b_note_state:
173 elif a_note_state > b_note_state:
175 # Sort by source already in database (descending)
176 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
177 if source_in_database:
178 return -source_in_database
180 # Sort by time of oldest upload
181 return cmp(a["oldest"], b["oldest"])
183 def sort_changes(changes_files):
184 """Sort into source groups, then sort each source group by version,
185 have source, filename. Finally, sort the source groups by have
186 note, time of oldest upload of each source upload."""
187 if len(changes_files) == 1:
192 # Read in all the .changes files
193 for filename in changes_files:
195 Upload.pkg.changes_file = filename
198 cache[filename] = copy.copy(Upload.pkg.changes)
199 cache[filename]["filename"] = filename
201 sorted_list.append(filename)
203 # Divide the .changes into per-source groups
205 for filename in cache.keys():
206 source = cache[filename]["source"]
207 if not per_source.has_key(source):
208 per_source[source] = {}
209 per_source[source]["list"] = []
210 per_source[source]["list"].append(cache[filename])
211 # Determine oldest time and have note status for each source group
212 for source in per_source.keys():
213 q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source)
215 per_source[source]["source_in_database"] = len(ql)>0
216 source_list = per_source[source]["list"]
217 first = source_list[0]
218 oldest = os.stat(first["filename"])[stat.ST_MTIME]
220 for d in per_source[source]["list"]:
221 mtime = os.stat(d["filename"])[stat.ST_MTIME]
224 have_note += (database.has_new_comment(d["source"], d["version"]))
225 per_source[source]["oldest"] = oldest
227 per_source[source]["note_state"] = 0; # none
228 elif have_note < len(source_list):
229 per_source[source]["note_state"] = 1; # some
231 per_source[source]["note_state"] = 2; # all
232 per_source[source]["list"].sort(indiv_sg_compare)
233 per_source_items = per_source.items()
234 per_source_items.sort(sg_compare)
235 for i in per_source_items:
236 for j in i[1]["list"]:
237 sorted_list.append(j["filename"])
240 ################################################################################
242 class Section_Completer:
246 q = projectB.query("SELECT section FROM section")
247 for i in q.getresult():
248 self.sections.append(i[0])
250 def complete(self, text, state):
254 for word in self.sections:
256 self.matches.append(word)
258 return self.matches[state]
262 ############################################################
264 class Priority_Completer:
268 q = projectB.query("SELECT priority FROM priority")
269 for i in q.getresult():
270 self.priorities.append(i[0])
272 def complete(self, text, state):
276 for word in self.priorities:
278 self.matches.append(word)
280 return self.matches[state]
284 ################################################################################
286 def print_new (new, indexed, file=sys.stdout):
287 queue.check_valid(new)
290 for pkg in new.keys():
292 section = new[pkg]["section"]
293 priority = new[pkg]["priority"]
294 if new[pkg]["section id"] == -1:
297 if new[pkg]["priority id"] == -1:
301 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
303 line = "%-20s %-20s %-20s" % (pkg, priority, section)
304 line = line.strip()+'\n'
306 note = database.get_new_comments(Upload.pkg.changes.get("source"))
312 ################################################################################
314 def index_range (index):
318 return "1-%s" % (index)
320 ################################################################################
321 ################################################################################
324 # Write the current data to a temporary file
325 (fd, temp_filename) = utils.temp_filename()
326 temp_file = os.fdopen(fd, 'w')
327 print_new (new, 0, temp_file)
329 # Spawn an editor on that file
330 editor = os.environ.get("EDITOR","vi")
331 result = os.system("%s %s" % (editor, temp_filename))
333 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
334 # Read the edited data back in
335 temp_file = utils.open_file(temp_filename)
336 lines = temp_file.readlines()
338 os.unlink(temp_filename)
345 # Pad the list if necessary
346 s[len(s):3] = [None] * (3-len(s))
347 (pkg, priority, section) = s[:3]
348 if not new.has_key(pkg):
349 utils.warn("Ignoring unknown package '%s'" % (pkg))
351 # Strip off any invalid markers, print_new will readd them.
352 if section.endswith("[!]"):
353 section = section[:-3]
354 if priority.endswith("[!]"):
355 priority = priority[:-3]
356 for f in new[pkg]["files"]:
357 Upload.pkg.files[f]["section"] = section
358 Upload.pkg.files[f]["priority"] = priority
359 new[pkg]["section"] = section
360 new[pkg]["priority"] = priority
362 ################################################################################
364 def edit_index (new, index):
365 priority = new[index]["priority"]
366 section = new[index]["section"]
367 ftype = new[index]["type"]
370 print "\t".join([index, priority, section])
374 prompt = "[B]oth, Priority, Section, Done ? "
376 prompt = "[S]ection, Done ? "
377 edit_priority = edit_section = 0
379 while prompt.find(answer) == -1:
380 answer = utils.our_raw_input(prompt)
381 m = re_default_answer.match(prompt)
384 answer = answer[:1].upper()
391 edit_priority = edit_section = 1
397 readline.set_completer(Priorities.complete)
399 while not got_priority:
400 new_priority = utils.our_raw_input("New priority: ").strip()
401 if new_priority not in Priorities.priorities:
402 print "E: '%s' is not a valid priority, try again." % (new_priority)
405 priority = new_priority
409 readline.set_completer(Sections.complete)
411 while not got_section:
412 new_section = utils.our_raw_input("New section: ").strip()
413 if new_section not in Sections.sections:
414 print "E: '%s' is not a valid section, try again." % (new_section)
417 section = new_section
419 # Reset the readline completer
420 readline.set_completer(None)
422 for f in new[index]["files"]:
423 Upload.pkg.files[f]["section"] = section
424 Upload.pkg.files[f]["priority"] = priority
425 new[index]["priority"] = priority
426 new[index]["section"] = section
429 ################################################################################
431 def edit_overrides (new):
442 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
445 while not got_answer:
446 answer = utils.our_raw_input(prompt)
447 if not answer.isdigit():
448 answer = answer[:1].upper()
449 if answer == "E" or answer == "D":
451 elif re_isanum.match (answer):
453 if (answer < 1) or (answer > index):
454 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
463 edit_index (new, new_index[answer])
467 ################################################################################
470 # Write the current data to a temporary file
471 (fd, temp_filename) = utils.temp_filename()
472 temp_file = os.fdopen(fd, 'w')
475 temp_file.write(line)
477 editor = os.environ.get("EDITOR","vi")
480 os.system("%s %s" % (editor, temp_filename))
481 temp_file = utils.open_file(temp_filename)
482 note = temp_file.read().rstrip()
485 print utils.prefix_multi_line_string(note," ")
486 prompt = "[D]one, Edit, Abandon, Quit ?"
488 while prompt.find(answer) == -1:
489 answer = utils.our_raw_input(prompt)
490 m = re_default_answer.search(prompt)
493 answer = answer[:1].upper()
494 os.unlink(temp_filename)
500 database.add_new_comment(Upload.pkg.changes["source"], Upload.pkg.changes["version"], note, utils.whoami())
502 ################################################################################
506 less_fd = os.popen("less -R -", 'w', 0)
507 stdout_fd = sys.stdout
510 changes = utils.parse_changes (Upload.pkg.changes_file)
511 examine_package.display_changes(changes['distribution'], Upload.pkg.changes_file)
512 files = Upload.pkg.files
513 for f in files.keys():
514 if files[f].has_key("new"):
515 ftype = files[f]["type"]
517 examine_package.check_deb(changes['distribution'], f)
519 examine_package.check_dsc(changes['distribution'], f)
521 examine_package.output_package_relations()
522 sys.stdout = stdout_fd
524 if e.errno == errno.EPIPE:
525 utils.warn("[examine_package] Caught EPIPE; skipping.")
529 except KeyboardInterrupt:
530 utils.warn("[examine_package] Caught C-c; skipping.")
533 ################################################################################
535 ## FIXME: horribly Debian specific
537 def do_bxa_notification():
538 files = Upload.pkg.files
540 for f in files.keys():
541 if files[f]["type"] == "deb":
542 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
544 summary += "Package: %s\n" % (control.Find("Package"))
545 summary += "Description: %s\n" % (control.Find("Description"))
546 Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
547 bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
548 utils.send_mail(bxa_mail)
550 ################################################################################
552 def add_overrides (new):
553 changes = Upload.pkg.changes
554 files = Upload.pkg.files
556 projectB.query("BEGIN WORK")
557 for suite in changes["suite"].keys():
558 suite_id = database.get_suite_id(suite)
559 for pkg in new.keys():
560 component_id = database.get_component_id(new[pkg]["component"])
561 type_id = database.get_override_type_id(new[pkg]["type"])
562 priority_id = new[pkg]["priority id"]
563 section_id = new[pkg]["section id"]
564 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))
565 for f in new[pkg]["files"]:
566 if files[f].has_key("new"):
570 projectB.query("COMMIT WORK")
572 if Cnf.FindB("Dinstall::BXANotify"):
573 do_bxa_notification()
575 ################################################################################
577 def prod_maintainer ():
578 # Here we prepare an editor and get them ready to prod...
579 (fd, temp_filename) = utils.temp_filename()
580 editor = os.environ.get("EDITOR","vi")
583 os.system("%s %s" % (editor, temp_filename))
585 prod_message = "".join(f.readlines())
587 print "Prod message:"
588 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
589 prompt = "[P]rod, Edit, Abandon, Quit ?"
591 while prompt.find(answer) == -1:
592 answer = utils.our_raw_input(prompt)
593 m = re_default_answer.search(prompt)
596 answer = answer[:1].upper()
597 os.unlink(temp_filename)
603 # Otherwise, do the proding...
604 user_email_address = utils.whoami() + " <%s>" % (
605 Cnf["Dinstall::MyAdminAddress"])
609 Subst["__FROM_ADDRESS__"] = user_email_address
610 Subst["__PROD_MESSAGE__"] = prod_message
611 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
613 prod_mail_message = utils.TemplateSubst(
614 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
616 # Send the prod mail if appropriate
617 if not Cnf["Dinstall::Options::No-Mail"]:
618 utils.send_mail(prod_mail_message)
620 print "Sent proding message"
622 ################################################################################
626 files = Upload.pkg.files
627 changes = Upload.pkg.changes
629 # Make a copy of distribution we can happily trample on
630 changes["suite"] = copy.copy(changes["distribution"])
632 # Fix up the list of target suites
633 for suite in changes["suite"].keys():
634 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
636 (olderr, newerr) = (database.get_suite_id(suite) == -1,
637 database.get_suite_id(override) == -1)
639 (oinv, newinv) = ("", "")
640 if olderr: oinv = "invalid "
641 if newerr: ninv = "invalid "
642 print "warning: overriding %ssuite %s to %ssuite %s" % (
643 oinv, suite, ninv, override)
644 del changes["suite"][suite]
645 changes["suite"][override] = 1
647 for suite in changes["suite"].keys():
648 suite_id = database.get_suite_id(suite)
650 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
652 # The main NEW processing loop
655 # Find out what's new
656 new = queue.determine_new(changes, files, projectB)
662 if Options["No-Action"] or Options["Automatic"]:
665 (broken, note) = print_new(new, 0)
668 if not broken and not note:
669 prompt = "Add overrides, "
671 print "W: [!] marked entries must be fixed before package can be processed."
673 print "W: note must be removed before package can be processed."
674 prompt += "Remove note, "
676 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
678 while prompt.find(answer) == -1:
679 answer = utils.our_raw_input(prompt)
680 m = re_default_answer.search(prompt)
683 answer = answer[:1].upper()
685 if answer == 'A' and not Options["Trainee"]:
686 done = add_overrides (new)
689 elif answer == 'E' and not Options["Trainee"]:
690 new = edit_overrides (new)
691 elif answer == 'M' and not Options["Trainee"]:
692 aborted = Upload.do_reject(1, Options["Manual-Reject"])
694 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
697 edit_note(database.get_new_comments(changes.get("source", "")))
698 elif answer == 'P' and not Options["Trainee"]:
701 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
703 database.delete_new_comments(changes.get("source"), changes.get("version"))
710 ################################################################################
711 ################################################################################
712 ################################################################################
714 def usage (exit_code=0):
715 print """Usage: dak process-new [OPTION]... [CHANGES]...
716 -a, --automatic automatic run
717 -h, --help show this help and exit.
718 -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new
719 -m, --manual-reject=MSG manual reject with `msg'
720 -n, --no-action don't do anything
721 -t, --trainee FTP Trainee mode
722 -V, --version display the version number and exit"""
725 ################################################################################
728 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
730 Cnf = utils.get_conf()
732 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
733 ('h',"help","Process-New::Options::Help"),
734 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
735 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
736 ('t',"trainee","Process-New::Options::Trainee"),
737 ('n',"no-action","Process-New::Options::No-Action")]
739 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir", "trainee"]:
740 if not Cnf.has_key("Process-New::Options::%s" % (i)):
741 Cnf["Process-New::Options::%s" % (i)] = ""
743 changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
744 if len(changes_files) == 0 and not Cnf.get("Process-New::Options::Comments-Dir",""):
745 changes_files = utils.get_changes_files(Cnf["Dir::Queue::New"])
747 Options = Cnf.SubTree("Process-New::Options")
752 Upload = queue.Upload(Cnf)
754 if not Options["No-Action"]:
756 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
757 except CantOpenError, e:
758 Options["Trainee"] = "Oh yes"
760 projectB = Upload.projectB
762 Sections = Section_Completer()
763 Priorities = Priority_Completer()
764 readline.parse_and_bind("tab: complete")
768 ################################################################################
773 files = Upload.pkg.files
777 for f in files.keys():
778 if files[f]["type"] == "byhand":
779 if os.path.exists(f):
780 print "W: %s still present; please process byhand components and try again." % (f)
786 if Options["No-Action"]:
789 if Options["Automatic"] and not Options["No-Action"]:
791 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
793 prompt = "Manual reject, [S]kip, Quit ?"
795 while prompt.find(answer) == -1:
796 answer = utils.our_raw_input(prompt)
797 m = re_default_answer.search(prompt)
800 answer = answer[:1].upper()
807 Upload.do_reject(1, Options["Manual-Reject"])
808 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
816 ################################################################################
818 def get_accept_lock():
822 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
825 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
828 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
830 print("Unable to get accepted lock (try %d of 10)" % retry)
835 def move_to_dir (dest, perms=0660, changesperms=0664):
836 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
837 file_keys = Upload.pkg.files.keys()
839 utils.move (f, dest, perms=perms)
841 def is_source_in_queue_dir(qdir):
842 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
843 and x.endswith(".changes") ]
844 for entry in entries:
846 u = queue.Upload(Cnf)
847 u.pkg.changes_file = os.path.join(qdir, entry)
849 if not u.pkg.changes["architecture"].has_key("source"):
850 # another binary upload, ignore
852 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
853 # another version, ignore
859 def move_to_holding(suite, queue_dir):
860 print "Moving to %s holding area." % (suite.upper(),)
861 if Options["No-Action"]:
863 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
864 Upload.dump_vars(queue_dir)
865 move_to_dir(queue_dir, perms=0664)
866 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
869 if Options["No-Action"]:
871 (summary, short_summary) = Upload.build_summaries()
872 Upload.accept(summary, short_summary)
873 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
875 def do_accept_stableupdate(suite, q):
876 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
877 if not Upload.pkg.changes["architecture"].has_key("source"):
878 # It is not a sourceful upload. So its source may be either in p-u
879 # holding, in new, in accepted or already installed.
880 if is_source_in_queue_dir(queue_dir):
881 # It's in p-u holding, so move it there.
882 print "Binary-only upload, source in %s." % (q,)
883 move_to_holding(suite, queue_dir)
884 elif Upload.source_exists(Upload.pkg.changes["source"],
885 Upload.pkg.changes["version"]):
886 # dak tells us that there is source available. At time of
887 # writing this means that it is installed, so put it into
889 print "Binary-only upload, source installed."
891 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
892 # The source is in accepted, the binary cleared NEW: accept it.
893 print "Binary-only upload, source in accepted."
895 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
896 # It's in NEW. We expect the source to land in p-u holding
898 print "Binary-only upload, source in new."
899 move_to_holding(suite, queue_dir)
901 # No case applicable. Bail out. Return will cause the upload
904 print "Stable update failed. Source not found."
907 # We are handling a sourceful upload. Move to accepted if currently
908 # in p-u holding and to p-u holding otherwise.
909 if is_source_in_queue_dir(queue_dir):
910 print "Sourceful upload in %s, accepting." % (q,)
913 move_to_holding(suite, queue_dir)
917 if not Options["No-Action"]:
919 (summary, short_summary) = Upload.build_summaries()
921 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
922 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
923 move_to_dir(Cnf["Dir::Queue::Embargoed"])
924 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
925 # Check for override disparities
926 Upload.Subst["__SUMMARY__"] = summary
928 # Stable updates need to be copied to proposed-updates holding
929 # area instead of accepted. Sourceful uploads need to go
930 # to it directly, binaries only if the source has not yet been
932 for suite, q in [("proposed-updates", "ProposedUpdates"),
933 ("oldstable-proposed-updates", "OldProposedUpdates")]:
934 if not Upload.pkg.changes["distribution"].has_key(suite):
936 return do_accept_stableupdate(suite, q)
937 # Just a normal upload, accept it...
940 if not Options["No-Action"]:
941 os.unlink(Cnf["Process-New::AcceptedLockFile"])
943 def check_status(files):
945 for f in files.keys():
946 if files[f]["type"] == "byhand":
948 elif files[f].has_key("new"):
952 def do_pkg(changes_file):
953 Upload.pkg.changes_file = changes_file
956 Upload.update_subst()
957 files = Upload.pkg.files
962 (new, byhand) = check_status(files)
968 (new, byhand) = check_status(files)
970 if not new and not byhand:
973 ################################################################################
976 accept_count = Upload.accept_count
977 accept_bytes = Upload.accept_bytes
983 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
984 Logger.log(["total",accept_count,accept_bytes])
986 if not Options["No-Action"]:
989 ################################################################################
991 def do_comments(dir, opref, npref, line, fn):
992 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
993 lines = open("%s/%s" % (dir, comm)).readlines()
994 if len(lines) == 0 or lines[0] != line + "\n": continue
995 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
996 and x.endswith(".changes") ]
997 changes_files = sort_changes(changes_files)
998 for f in changes_files:
999 f = utils.validate_changes_file_arg(f, 0)
1002 fn(f, "".join(lines[1:]))
1004 if opref != npref and not Options["No-Action"]:
1005 newcomm = npref + comm[len(opref):]
1006 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
1008 ################################################################################
1010 def comment_accept(changes_file, comments):
1011 Upload.pkg.changes_file = changes_file
1013 Upload.update_vars()
1014 Upload.update_subst()
1015 files = Upload.pkg.files
1018 return # dak wants to REJECT, crap
1020 (new, byhand) = check_status(files)
1021 if not new and not byhand:
1024 ################################################################################
1026 def comment_reject(changes_file, comments):
1027 Upload.pkg.changes_file = changes_file
1029 Upload.update_vars()
1030 Upload.update_subst()
1033 pass # dak has its own reasons to reject as well, which is fine
1036 print "REJECT\n" + reject_message,
1037 if not Options["No-Action"]:
1038 Upload.do_reject(0, reject_message)
1039 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1041 ################################################################################
1044 changes_files = init()
1045 if len(changes_files) > 50:
1046 sys.stderr.write("Sorting changes...\n")
1047 changes_files = sort_changes(changes_files)
1049 # Kill me now? **FIXME**
1050 Cnf["Dinstall::Options::No-Mail"] = ""
1051 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1052 if Cnf.has_key("Dinstall::Bcc"):
1053 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1055 Upload.Subst["__BCC__"] = bcc
1057 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1059 if changes_files != []:
1060 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1062 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1063 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1065 for changes_file in changes_files:
1066 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1067 if not changes_file:
1069 print "\n" + changes_file
1070 do_pkg (changes_file)
1074 ################################################################################
1076 if __name__ == '__main__':