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 editor = os.environ.get("EDITOR","vi")
475 os.system("%s %s" % (editor, temp_filename))
476 temp_file = utils.open_file(temp_filename)
477 newnote = temp_file.read().rstrip()
480 print utils.prefix_multi_line_string(note," ")
481 prompt = "[D]one, Edit, Abandon, Quit ?"
483 while prompt.find(answer) == -1:
484 answer = utils.our_raw_input(prompt)
485 m = re_default_answer.search(prompt)
488 answer = answer[:1].upper()
489 os.unlink(temp_filename)
495 database.add_new_comment(Upload.pkg.changes["source"], Upload.pkg.changes["version"], note, utils.whoami())
497 ################################################################################
501 less_fd = os.popen("less -R -", 'w', 0)
502 stdout_fd = sys.stdout
505 changes = utils.parse_changes (Upload.pkg.changes_file)
506 examine_package.display_changes(changes['distribution'], Upload.pkg.changes_file)
507 files = Upload.pkg.files
508 for f in files.keys():
509 if files[f].has_key("new"):
510 ftype = files[f]["type"]
512 examine_package.check_deb(changes['distribution'], f)
514 examine_package.check_dsc(changes['distribution'], f)
516 examine_package.output_package_relations()
517 sys.stdout = stdout_fd
519 if e.errno == errno.EPIPE:
520 utils.warn("[examine_package] Caught EPIPE; skipping.")
524 except KeyboardInterrupt:
525 utils.warn("[examine_package] Caught C-c; skipping.")
528 ################################################################################
530 ## FIXME: horribly Debian specific
532 def do_bxa_notification():
533 files = Upload.pkg.files
535 for f in files.keys():
536 if files[f]["type"] == "deb":
537 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
539 summary += "Package: %s\n" % (control.Find("Package"))
540 summary += "Description: %s\n" % (control.Find("Description"))
541 Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
542 bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
543 utils.send_mail(bxa_mail)
545 ################################################################################
547 def add_overrides (new):
548 changes = Upload.pkg.changes
549 files = Upload.pkg.files
551 projectB.query("BEGIN WORK")
552 for suite in changes["suite"].keys():
553 suite_id = database.get_suite_id(suite)
554 for pkg in new.keys():
555 component_id = database.get_component_id(new[pkg]["component"])
556 type_id = database.get_override_type_id(new[pkg]["type"])
557 priority_id = new[pkg]["priority id"]
558 section_id = new[pkg]["section id"]
559 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))
560 for f in new[pkg]["files"]:
561 if files[f].has_key("new"):
565 projectB.query("COMMIT WORK")
567 if Cnf.FindB("Dinstall::BXANotify"):
568 do_bxa_notification()
570 ################################################################################
572 def prod_maintainer ():
573 # Here we prepare an editor and get them ready to prod...
574 (fd, temp_filename) = utils.temp_filename()
575 editor = os.environ.get("EDITOR","vi")
578 os.system("%s %s" % (editor, temp_filename))
580 prod_message = "".join(f.readlines())
582 print "Prod message:"
583 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
584 prompt = "[P]rod, Edit, Abandon, Quit ?"
586 while prompt.find(answer) == -1:
587 answer = utils.our_raw_input(prompt)
588 m = re_default_answer.search(prompt)
591 answer = answer[:1].upper()
592 os.unlink(temp_filename)
598 # Otherwise, do the proding...
599 user_email_address = utils.whoami() + " <%s>" % (
600 Cnf["Dinstall::MyAdminAddress"])
604 Subst["__FROM_ADDRESS__"] = user_email_address
605 Subst["__PROD_MESSAGE__"] = prod_message
606 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
608 prod_mail_message = utils.TemplateSubst(
609 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
611 # Send the prod mail if appropriate
612 if not Cnf["Dinstall::Options::No-Mail"]:
613 utils.send_mail(prod_mail_message)
615 print "Sent proding message"
617 ################################################################################
621 files = Upload.pkg.files
622 changes = Upload.pkg.changes
624 # Make a copy of distribution we can happily trample on
625 changes["suite"] = copy.copy(changes["distribution"])
627 # Fix up the list of target suites
628 for suite in changes["suite"].keys():
629 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
631 (olderr, newerr) = (database.get_suite_id(suite) == -1,
632 database.get_suite_id(override) == -1)
634 (oinv, newinv) = ("", "")
635 if olderr: oinv = "invalid "
636 if newerr: ninv = "invalid "
637 print "warning: overriding %ssuite %s to %ssuite %s" % (
638 oinv, suite, ninv, override)
639 del changes["suite"][suite]
640 changes["suite"][override] = 1
642 for suite in changes["suite"].keys():
643 suite_id = database.get_suite_id(suite)
645 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
647 # The main NEW processing loop
650 # Find out what's new
651 new = queue.determine_new(changes, files, projectB)
657 if Options["No-Action"] or Options["Automatic"]:
660 (broken, note) = print_new(new, 0)
663 if not broken and not note:
664 prompt = "Add overrides, "
666 print "W: [!] marked entries must be fixed before package can be processed."
668 print "W: note must be removed before package can be processed."
669 prompt += "Remove note, "
671 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
673 while prompt.find(answer) == -1:
674 answer = utils.our_raw_input(prompt)
675 m = re_default_answer.search(prompt)
678 answer = answer[:1].upper()
680 if answer == 'A' and not Options["Trainee"]:
681 done = add_overrides (new)
684 elif answer == 'E' and not Options["Trainee"]:
685 new = edit_overrides (new)
686 elif answer == 'M' and not Options["Trainee"]:
687 aborted = Upload.do_reject(manual=1,
688 reject_message=Options["Manual-Reject"],
689 note=database.get_new_comments(changes.get("source", "")))
691 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
694 edit_note(database.get_new_comments(changes.get("source", "")))
695 elif answer == 'P' and not Options["Trainee"]:
696 prod_maintainer(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 -t, --trainee FTP Trainee mode
719 -V, --version display the version number and exit"""
722 ################################################################################
725 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
727 Cnf = utils.get_conf()
729 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
730 ('h',"help","Process-New::Options::Help"),
731 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
732 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
733 ('t',"trainee","Process-New::Options::Trainee"),
734 ('n',"no-action","Process-New::Options::No-Action")]
736 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir", "trainee"]:
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"]:
753 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
754 except CantOpenError, e:
755 Options["Trainee"] = "Oh yes"
757 projectB = Upload.projectB
759 Sections = Section_Completer()
760 Priorities = Priority_Completer()
761 readline.parse_and_bind("tab: complete")
765 ################################################################################
770 files = Upload.pkg.files
774 for f in files.keys():
775 if files[f]["type"] == "byhand":
776 if os.path.exists(f):
777 print "W: %s still present; please process byhand components and try again." % (f)
783 if Options["No-Action"]:
786 if Options["Automatic"] and not Options["No-Action"]:
788 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
790 prompt = "Manual reject, [S]kip, Quit ?"
792 while prompt.find(answer) == -1:
793 answer = utils.our_raw_input(prompt)
794 m = re_default_answer.search(prompt)
797 answer = answer[:1].upper()
804 Upload.do_reject(1, Options["Manual-Reject"])
805 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
813 ################################################################################
815 def get_accept_lock():
819 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
822 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
825 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
827 print("Unable to get accepted lock (try %d of 10)" % retry)
832 def move_to_dir (dest, perms=0660, changesperms=0664):
833 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
834 file_keys = Upload.pkg.files.keys()
836 utils.move (f, dest, perms=perms)
838 def is_source_in_queue_dir(qdir):
839 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
840 and x.endswith(".changes") ]
841 for entry in entries:
843 u = queue.Upload(Cnf)
844 u.pkg.changes_file = os.path.join(qdir, entry)
846 if not u.pkg.changes["architecture"].has_key("source"):
847 # another binary upload, ignore
849 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
850 # another version, ignore
856 def move_to_holding(suite, queue_dir):
857 print "Moving to %s holding area." % (suite.upper(),)
858 if Options["No-Action"]:
860 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
861 Upload.dump_vars(queue_dir)
862 move_to_dir(queue_dir, perms=0664)
863 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
866 if Options["No-Action"]:
868 (summary, short_summary) = Upload.build_summaries()
869 Upload.accept(summary, short_summary)
870 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
872 def do_accept_stableupdate(suite, q):
873 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
874 if not Upload.pkg.changes["architecture"].has_key("source"):
875 # It is not a sourceful upload. So its source may be either in p-u
876 # holding, in new, in accepted or already installed.
877 if is_source_in_queue_dir(queue_dir):
878 # It's in p-u holding, so move it there.
879 print "Binary-only upload, source in %s." % (q,)
880 move_to_holding(suite, queue_dir)
881 elif Upload.source_exists(Upload.pkg.changes["source"],
882 Upload.pkg.changes["version"]):
883 # dak tells us that there is source available. At time of
884 # writing this means that it is installed, so put it into
886 print "Binary-only upload, source installed."
888 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
889 # The source is in accepted, the binary cleared NEW: accept it.
890 print "Binary-only upload, source in accepted."
892 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
893 # It's in NEW. We expect the source to land in p-u holding
895 print "Binary-only upload, source in new."
896 move_to_holding(suite, queue_dir)
898 # No case applicable. Bail out. Return will cause the upload
901 print "Stable update failed. Source not found."
904 # We are handling a sourceful upload. Move to accepted if currently
905 # in p-u holding and to p-u holding otherwise.
906 if is_source_in_queue_dir(queue_dir):
907 print "Sourceful upload in %s, accepting." % (q,)
910 move_to_holding(suite, queue_dir)
914 if not Options["No-Action"]:
916 (summary, short_summary) = Upload.build_summaries()
918 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
919 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
920 move_to_dir(Cnf["Dir::Queue::Embargoed"])
921 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
922 # Check for override disparities
923 Upload.Subst["__SUMMARY__"] = summary
925 # Stable updates need to be copied to proposed-updates holding
926 # area instead of accepted. Sourceful uploads need to go
927 # to it directly, binaries only if the source has not yet been
929 for suite, q in [("proposed-updates", "ProposedUpdates"),
930 ("oldstable-proposed-updates", "OldProposedUpdates")]:
931 if not Upload.pkg.changes["distribution"].has_key(suite):
933 return do_accept_stableupdate(suite, q)
934 # Just a normal upload, accept it...
937 if not Options["No-Action"]:
938 os.unlink(Cnf["Process-New::AcceptedLockFile"])
940 def check_status(files):
942 for f in files.keys():
943 if files[f]["type"] == "byhand":
945 elif files[f].has_key("new"):
949 def do_pkg(changes_file):
950 Upload.pkg.changes_file = changes_file
953 Upload.update_subst()
954 files = Upload.pkg.files
959 (new, byhand) = check_status(files)
965 (new, byhand) = check_status(files)
967 if not new and not byhand:
970 ################################################################################
973 accept_count = Upload.accept_count
974 accept_bytes = Upload.accept_bytes
980 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
981 Logger.log(["total",accept_count,accept_bytes])
983 if not Options["No-Action"] and not Options["Trainee"]:
986 ################################################################################
988 def do_comments(dir, opref, npref, line, fn):
989 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
990 lines = open("%s/%s" % (dir, comm)).readlines()
991 if len(lines) == 0 or lines[0] != line + "\n": continue
992 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
993 and x.endswith(".changes") ]
994 changes_files = sort_changes(changes_files)
995 for f in changes_files:
996 f = utils.validate_changes_file_arg(f, 0)
999 fn(f, "".join(lines[1:]))
1001 if opref != npref and not Options["No-Action"]:
1002 newcomm = npref + comm[len(opref):]
1003 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
1005 ################################################################################
1007 def comment_accept(changes_file, comments):
1008 Upload.pkg.changes_file = changes_file
1010 Upload.update_vars()
1011 Upload.update_subst()
1012 files = Upload.pkg.files
1015 return # dak wants to REJECT, crap
1017 (new, byhand) = check_status(files)
1018 if not new and not byhand:
1021 ################################################################################
1023 def comment_reject(changes_file, comments):
1024 Upload.pkg.changes_file = changes_file
1026 Upload.update_vars()
1027 Upload.update_subst()
1030 pass # dak has its own reasons to reject as well, which is fine
1033 print "REJECT\n" + reject_message,
1034 if not Options["No-Action"]:
1035 Upload.do_reject(0, reject_message)
1036 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1038 ################################################################################
1041 changes_files = init()
1042 if len(changes_files) > 50:
1043 sys.stderr.write("Sorting changes...\n")
1044 changes_files = sort_changes(changes_files)
1046 # Kill me now? **FIXME**
1047 Cnf["Dinstall::Options::No-Mail"] = ""
1048 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1049 if Cnf.has_key("Dinstall::Bcc"):
1050 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1052 Upload.Subst["__BCC__"] = bcc
1054 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1056 if changes_files != []:
1057 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1059 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1060 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1062 for changes_file in changes_files:
1063 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1064 if not changes_file:
1066 print "\n" + changes_file
1067 do_pkg (changes_file)
1071 ################################################################################
1073 if __name__ == '__main__':