3 # Handles NEW and BYHAND packages
4 # Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 James Troup <james@nocrew.org>
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 ################################################################################
22 # 23:12|<aj> I will not hush!
24 # 23:12|<aj> Where there is injustice in the world, I shall be there!
25 # 23:13|<aj> I shall not be silenced!
26 # 23:13|<aj> The world shall know!
27 # 23:13|<aj> The world *must* know!
28 # 23:13|<elmo> oh dear, he's gone back to powerpuff girls... ;-)
29 # 23:13|<aj> yay powerpuff girls!!
30 # 23:13|<aj> buttercup's my favourite, who's yours?
31 # 23:14|<aj> you're backing away from the keyboard right now aren't you?
32 # 23:14|<aj> *AREN'T YOU*?!
33 # 23:15|<aj> I will not be treated like this.
34 # 23:15|<aj> I shall have my revenge.
35 # 23:15|<aj> I SHALL!!!
37 ################################################################################
39 import copy, errno, os, readline, stat, sys, time
40 import apt_pkg, apt_inst
41 import examine_package
42 from daklib import database
43 from daklib import logging
44 from daklib import queue
45 from daklib import utils
59 ################################################################################
60 ################################################################################
61 ################################################################################
63 def reject (str, prefix="Rejected: "):
66 reject_message += prefix + str + "\n"
70 files = Upload.pkg.files
73 for f in files.keys():
74 # The .orig.tar.gz can disappear out from under us is it's a
75 # duplicate of one in the archive.
76 if not files.has_key(f):
78 # Check that the source still exists
79 if files[f]["type"] == "deb":
80 source_version = files[f]["source version"]
81 source_package = files[f]["source package"]
82 if not Upload.pkg.changes["architecture"].has_key("source") \
83 and not Upload.source_exists(source_package, source_version, Upload.pkg.changes["distribution"].keys()):
84 source_epochless_version = utils.re_no_epoch.sub('', source_version)
85 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
87 for q in ["Accepted", "Embargoed", "Unembargoed"]:
88 if Cnf.has_key("Dir::Queue::%s" % (q)):
89 if os.path.exists(Cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
92 reject("no source found for %s %s (%s)." % (source_package, source_version, f))
94 # Version and file overwrite checks
95 if files[f]["type"] == "deb":
96 reject(Upload.check_binary_against_db(f))
97 elif files[f]["type"] == "dsc":
98 reject(Upload.check_source_against_db(f))
99 (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(f)
100 reject(reject_msg, "")
102 if reject_message.find("Rejected") != -1:
104 if Options["No-Action"] or Options["Automatic"]:
107 print "REJECT\n" + reject_message,
108 prompt = "[R]eject, Skip, Quit ?"
110 while prompt.find(answer) == -1:
111 answer = utils.our_raw_input(prompt)
112 m = queue.re_default_answer.match(prompt)
115 answer = answer[:1].upper()
118 Upload.do_reject(0, reject_message)
119 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
129 ################################################################################
131 def indiv_sg_compare (a, b):
132 """Sort by source name, source, version, 'have source', and
133 finally by filename."""
134 # Sort by source version
135 q = apt_pkg.VersionCompare(a["version"], b["version"])
139 # Sort by 'have source'
140 a_has_source = a["architecture"].get("source")
141 b_has_source = b["architecture"].get("source")
142 if a_has_source and not b_has_source:
144 elif b_has_source and not a_has_source:
147 return cmp(a["filename"], b["filename"])
149 ############################################################
151 def sg_compare (a, b):
154 """Sort by have note, source already in database and time of oldest upload."""
156 a_note_state = a["note_state"]
157 b_note_state = b["note_state"]
158 if a_note_state < b_note_state:
160 elif a_note_state > b_note_state:
162 # Sort by source already in database (descending)
163 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
164 if source_in_database:
165 return -source_in_database
167 # Sort by time of oldest upload
168 return cmp(a["oldest"], b["oldest"])
170 def sort_changes(changes_files):
171 """Sort into source groups, then sort each source group by version,
172 have source, filename. Finally, sort the source groups by have
173 note, time of oldest upload of each source upload."""
174 if len(changes_files) == 1:
179 # Read in all the .changes files
180 for filename in changes_files:
182 Upload.pkg.changes_file = filename
185 cache[filename] = copy.copy(Upload.pkg.changes)
186 cache[filename]["filename"] = filename
188 sorted_list.append(filename)
190 # Divide the .changes into per-source groups
192 for filename in cache.keys():
193 source = cache[filename]["source"]
194 if not per_source.has_key(source):
195 per_source[source] = {}
196 per_source[source]["list"] = []
197 per_source[source]["list"].append(cache[filename])
198 # Determine oldest time and have note status for each source group
199 for source in per_source.keys():
200 q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source)
202 per_source[source]["source_in_database"] = len(ql)>0
203 source_list = per_source[source]["list"]
204 first = source_list[0]
205 oldest = os.stat(first["filename"])[stat.ST_MTIME]
207 for d in per_source[source]["list"]:
208 mtime = os.stat(d["filename"])[stat.ST_MTIME]
211 have_note += (d.has_key("process-new note"))
212 per_source[source]["oldest"] = oldest
214 per_source[source]["note_state"] = 0; # none
215 elif have_note < len(source_list):
216 per_source[source]["note_state"] = 1; # some
218 per_source[source]["note_state"] = 2; # all
219 per_source[source]["list"].sort(indiv_sg_compare)
220 per_source_items = per_source.items()
221 per_source_items.sort(sg_compare)
222 for i in per_source_items:
223 for j in i[1]["list"]:
224 sorted_list.append(j["filename"])
227 ################################################################################
229 class Section_Completer:
232 q = projectB.query("SELECT section FROM section")
233 for i in q.getresult():
234 self.sections.append(i[0])
236 def complete(self, text, state):
240 for word in self.sections:
242 self.matches.append(word)
244 return self.matches[state]
248 ############################################################
250 class Priority_Completer:
253 q = projectB.query("SELECT priority FROM priority")
254 for i in q.getresult():
255 self.priorities.append(i[0])
257 def complete(self, text, state):
261 for word in self.priorities:
263 self.matches.append(word)
265 return self.matches[state]
269 ################################################################################
271 def print_new (new, indexed, file=sys.stdout):
272 queue.check_valid(new)
275 for pkg in new.keys():
277 section = new[pkg]["section"]
278 priority = new[pkg]["priority"]
279 if new[pkg]["section id"] == -1:
282 if new[pkg]["priority id"] == -1:
286 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
288 line = "%-20s %-20s %-20s" % (pkg, priority, section)
289 line = line.strip()+'\n'
291 note = Upload.pkg.changes.get("process-new note")
298 ################################################################################
300 def index_range (index):
304 return "1-%s" % (index)
306 ################################################################################
307 ################################################################################
310 # Write the current data to a temporary file
311 temp_filename = utils.temp_filename()
312 temp_file = utils.open_file(temp_filename, 'w')
313 print_new (new, 0, temp_file)
315 # Spawn an editor on that file
316 editor = os.environ.get("EDITOR","vi")
317 result = os.system("%s %s" % (editor, temp_filename))
319 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
320 # Read the edited data back in
321 temp_file = utils.open_file(temp_filename)
322 lines = temp_file.readlines()
324 os.unlink(temp_filename)
331 # Pad the list if necessary
332 s[len(s):3] = [None] * (3-len(s))
333 (pkg, priority, section) = s[:3]
334 if not new.has_key(pkg):
335 utils.warn("Ignoring unknown package '%s'" % (pkg))
337 # Strip off any invalid markers, print_new will readd them.
338 if section.endswith("[!]"):
339 section = section[:-3]
340 if priority.endswith("[!]"):
341 priority = priority[:-3]
342 for f in new[pkg]["files"]:
343 Upload.pkg.files[f]["section"] = section
344 Upload.pkg.files[f]["priority"] = priority
345 new[pkg]["section"] = section
346 new[pkg]["priority"] = priority
348 ################################################################################
350 def edit_index (new, index):
351 priority = new[index]["priority"]
352 section = new[index]["section"]
353 ftype = new[index]["type"]
356 print "\t".join([index, priority, section])
360 prompt = "[B]oth, Priority, Section, Done ? "
362 prompt = "[S]ection, Done ? "
363 edit_priority = edit_section = 0
365 while prompt.find(answer) == -1:
366 answer = utils.our_raw_input(prompt)
367 m = queue.re_default_answer.match(prompt)
370 answer = answer[:1].upper()
377 edit_priority = edit_section = 1
383 readline.set_completer(Priorities.complete)
385 while not got_priority:
386 new_priority = utils.our_raw_input("New priority: ").strip()
387 if new_priority not in Priorities.priorities:
388 print "E: '%s' is not a valid priority, try again." % (new_priority)
391 priority = new_priority
395 readline.set_completer(Sections.complete)
397 while not got_section:
398 new_section = utils.our_raw_input("New section: ").strip()
399 if new_section not in Sections.sections:
400 print "E: '%s' is not a valid section, try again." % (new_section)
403 section = new_section
405 # Reset the readline completer
406 readline.set_completer(None)
408 for f in new[index]["files"]:
409 Upload.pkg.files[f]["section"] = section
410 Upload.pkg.files[f]["priority"] = priority
411 new[index]["priority"] = priority
412 new[index]["section"] = section
415 ################################################################################
417 def edit_overrides (new):
428 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
431 while not got_answer:
432 answer = utils.our_raw_input(prompt)
433 if not answer.isdigit():
434 answer = answer[:1].upper()
435 if answer == "E" or answer == "D":
437 elif queue.re_isanum.match (answer):
439 if (answer < 1) or (answer > index):
440 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
449 edit_index (new, new_index[answer])
453 ################################################################################
456 # Write the current data to a temporary file
457 temp_filename = utils.temp_filename()
458 temp_file = utils.open_file(temp_filename, 'w')
459 temp_file.write(note)
461 editor = os.environ.get("EDITOR","vi")
464 os.system("%s %s" % (editor, temp_filename))
465 temp_file = utils.open_file(temp_filename)
466 note = temp_file.read().rstrip()
469 print utils.prefix_multi_line_string(note," ")
470 prompt = "[D]one, Edit, Abandon, Quit ?"
472 while prompt.find(answer) == -1:
473 answer = utils.our_raw_input(prompt)
474 m = queue.re_default_answer.search(prompt)
477 answer = answer[:1].upper()
478 os.unlink(temp_filename)
484 Upload.pkg.changes["process-new note"] = note
485 Upload.dump_vars(Cnf["Dir::Queue::New"])
487 ################################################################################
491 less_fd = os.popen("less -R -", 'w', 0)
492 stdout_fd = sys.stdout
495 examine_package.display_changes(Upload.pkg.changes_file)
496 files = Upload.pkg.files
497 for f in files.keys():
498 if files[f].has_key("new"):
499 ftype = files[f]["type"]
501 examine_package.check_deb(f)
503 examine_package.check_dsc(f)
505 sys.stdout = stdout_fd
507 if e.errno == errno.EPIPE:
508 utils.warn("[examine_package] Caught EPIPE; skipping.")
512 except KeyboardInterrupt:
513 utils.warn("[examine_package] Caught C-c; skipping.")
516 ################################################################################
518 ## FIXME: horribly Debian specific
520 def do_bxa_notification():
521 files = Upload.pkg.files
523 for f in files.keys():
524 if files[f]["type"] == "deb":
525 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
527 summary += "Package: %s\n" % (control.Find("Package"))
528 summary += "Description: %s\n" % (control.Find("Description"))
529 Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
530 bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
531 utils.send_mail(bxa_mail)
533 ################################################################################
535 def add_overrides (new):
536 changes = Upload.pkg.changes
537 files = Upload.pkg.files
539 projectB.query("BEGIN WORK")
540 for suite in changes["suite"].keys():
541 suite_id = database.get_suite_id(suite)
542 for pkg in new.keys():
543 component_id = database.get_component_id(new[pkg]["component"])
544 type_id = database.get_override_type_id(new[pkg]["type"])
545 priority_id = new[pkg]["priority id"]
546 section_id = new[pkg]["section id"]
547 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))
548 for f in new[pkg]["files"]:
549 if files[f].has_key("new"):
553 projectB.query("COMMIT WORK")
555 if Cnf.FindB("Dinstall::BXANotify"):
556 do_bxa_notification()
558 ################################################################################
560 def prod_maintainer ():
561 # Here we prepare an editor and get them ready to prod...
562 temp_filename = utils.temp_filename()
563 editor = os.environ.get("EDITOR","vi")
566 os.system("%s %s" % (editor, temp_filename))
567 f = utils.open_file(temp_filename)
568 prod_message = "".join(f.readlines())
570 print "Prod message:"
571 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
572 prompt = "[P]rod, Edit, Abandon, Quit ?"
574 while prompt.find(answer) == -1:
575 answer = utils.our_raw_input(prompt)
576 m = queue.re_default_answer.search(prompt)
579 answer = answer[:1].upper()
580 os.unlink(temp_filename)
586 # Otherwise, do the proding...
587 user_email_address = utils.whoami() + " <%s>" % (
588 Cnf["Dinstall::MyAdminAddress"])
592 Subst["__FROM_ADDRESS__"] = user_email_address
593 Subst["__PROD_MESSAGE__"] = prod_message
594 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
596 prod_mail_message = utils.TemplateSubst(
597 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
599 # Send the prod mail if appropriate
600 if not Cnf["Dinstall::Options::No-Mail"]:
601 utils.send_mail(prod_mail_message)
603 print "Sent proding message"
605 ################################################################################
609 files = Upload.pkg.files
610 changes = Upload.pkg.changes
612 # Make a copy of distribution we can happily trample on
613 changes["suite"] = copy.copy(changes["distribution"])
615 # Fix up the list of target suites
616 for suite in changes["suite"].keys():
617 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
619 (olderr, newerr) = (database.get_suite_id(suite) == -1,
620 database.get_suite_id(override) == -1)
622 (oinv, newinv) = ("", "")
623 if olderr: oinv = "invalid "
624 if newerr: ninv = "invalid "
625 print "warning: overriding %ssuite %s to %ssuite %s" % (
626 oinv, suite, ninv, override)
627 del changes["suite"][suite]
628 changes["suite"][override] = 1
630 for suite in changes["suite"].keys():
631 suite_id = database.get_suite_id(suite)
633 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
635 # The main NEW processing loop
638 # Find out what's new
639 new = queue.determine_new(changes, files, projectB)
645 if Options["No-Action"] or Options["Automatic"]:
648 (broken, note) = print_new(new, 0)
651 if not broken and not note:
652 prompt = "Add overrides, "
654 print "W: [!] marked entries must be fixed before package can be processed."
656 print "W: note must be removed before package can be processed."
657 prompt += "Remove note, "
659 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
661 while prompt.find(answer) == -1:
662 answer = utils.our_raw_input(prompt)
663 m = queue.re_default_answer.search(prompt)
666 answer = answer[:1].upper()
669 done = add_overrides (new)
673 new = edit_overrides (new)
675 aborted = Upload.do_reject(1, Options["Manual-Reject"])
677 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
680 edit_note(changes.get("process-new note", ""))
684 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
686 del changes["process-new note"]
693 ################################################################################
694 ################################################################################
695 ################################################################################
697 def usage (exit_code=0):
698 print """Usage: dak process-new [OPTION]... [CHANGES]...
699 -a, --automatic automatic run
700 -h, --help show this help and exit.
701 -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new
702 -m, --manual-reject=MSG manual reject with `msg'
703 -n, --no-action don't do anything
704 -V, --version display the version number and exit"""
707 ################################################################################
710 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
712 Cnf = utils.get_conf()
714 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
715 ('h',"help","Process-New::Options::Help"),
716 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
717 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
718 ('n',"no-action","Process-New::Options::No-Action")]
720 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir"]:
721 if not Cnf.has_key("Process-New::Options::%s" % (i)):
722 Cnf["Process-New::Options::%s" % (i)] = ""
724 changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
725 Options = Cnf.SubTree("Process-New::Options")
730 Upload = queue.Upload(Cnf)
732 if not Options["No-Action"]:
733 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
735 projectB = Upload.projectB
737 Sections = Section_Completer()
738 Priorities = Priority_Completer()
739 readline.parse_and_bind("tab: complete")
743 ################################################################################
748 files = Upload.pkg.files
752 for f in files.keys():
753 if files[f]["type"] == "byhand":
754 if os.path.exists(f):
755 print "W: %s still present; please process byhand components and try again." % (f)
761 if Options["No-Action"]:
764 if Options["Automatic"] and not Options["No-Action"]:
766 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
768 prompt = "Manual reject, [S]kip, Quit ?"
770 while prompt.find(answer) == -1:
771 answer = utils.our_raw_input(prompt)
772 m = queue.re_default_answer.search(prompt)
775 answer = answer[:1].upper()
782 Upload.do_reject(1, Options["Manual-Reject"])
783 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
791 ################################################################################
793 def get_accept_lock():
797 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
800 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
803 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
805 print("Unable to get accepted lock (try %d of 10)" % retry)
810 def move_to_dir (dest, perms=0660, changesperms=0664):
811 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
812 file_keys = Upload.pkg.files.keys()
814 utils.move (f, dest, perms=perms)
816 def is_source_in_queue_dir(qdir):
817 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
818 and x.endswith(".changes") ]
819 for entry in entries:
821 u = queue.Upload(Cnf)
822 u.pkg.changes_file = os.path.join(qdir, entry)
824 if not Upload.pkg.changes["architecture"].has_key("source"):
825 # another binary upload, ignore
827 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
828 # another version, ignore
834 def move_to_holding(suite, queue_dir):
835 print "Moving to %s holding area." % (suite.upper(),)
836 if Options["No-Action"]:
838 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
839 Upload.dump_vars(queue_dir)
840 move_to_dir(queue_dir)
841 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
843 def do_accept_stableupdate(suite, q):
844 (summary, short_summary) = Upload.build_summaries()
845 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
846 if not Upload.pkg.changes["architecture"].has_key("source"):
847 # It is not a sourceful upload. So its source may be either in p-u
848 # holding, in new, in accepted or already installed.
849 if is_source_in_queue_dir(queue_dir):
850 # It's in p-u holding, so move it there.
851 print "Binary-only upload, source in %s." % (q,)
852 move_to_holding(suite, queue_dir)
853 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
854 # It's in NEW. We expect the source to land in p-u holding
856 print "Binary-only upload, source in new."
857 move_to_holding(suite, queue_dir)
858 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
859 # The source is in accepted, the binary cleared NEW: accept it.
860 print "Binary-only upload, source in accepted."
861 Upload.accept(summary, short_summary)
862 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
863 elif Upload.source_exists(Upload.pkg.changes["source"],
864 Upload.pkg.changes["version"]):
865 # dak tells us that there is source available. At time of
866 # writing this means that it is installed, so put it into
868 print "Binary-only upload, source installed."
869 Upload.accept(summary, short_summary)
870 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
872 # We are handling a sourceful upload. Move to accepted if currently
873 # in p-u holding and to p-u holding otherwise.
874 if is_source_in_queue_dir(queue_dir):
875 print "Sourceful upload in %s, accepting." % (q,)
876 Upload.accept(summary, short_summary)
877 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
879 move_to_holding(suite, queue_dir)
883 if not Options["No-Action"]:
885 (summary, short_summary) = Upload.build_summaries()
887 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
888 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
889 move_to_dir(Cnf["Dir::Queue::Embargoed"])
890 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
891 # Check for override disparities
892 Upload.Subst["__SUMMARY__"] = summary
894 # Stable updates need to be copied to proposed-updates holding
895 # area instead of accepted. Sourceful uploads need to go
896 # to it directly, binaries only if the source has not yet been
898 for suite, q in [("proposed-updates", "ProposedUpdates"),
899 ("oldstable-proposed-updates", "OldProposedUpdates")]:
900 if not Upload.pkg.changes["distribution"].has_key(suite):
902 return do_accept_stableupdate(suite, q)
903 # Just a normal upload, accept it...
904 Upload.accept(summary, short_summary)
905 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
907 if not Options["No-Action"]:
908 os.unlink(Cnf["Process-New::AcceptedLockFile"])
910 def check_status(files):
912 for f in files.keys():
913 if files[f]["type"] == "byhand":
915 elif files[f].has_key("new"):
919 def do_pkg(changes_file):
920 Upload.pkg.changes_file = changes_file
923 Upload.update_subst()
924 files = Upload.pkg.files
929 (new, byhand) = check_status(files)
935 (new, byhand) = check_status(files)
937 if not new and not byhand:
940 ################################################################################
943 accept_count = Upload.accept_count
944 accept_bytes = Upload.accept_bytes
950 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
951 Logger.log(["total",accept_count,accept_bytes])
953 if not Options["No-Action"]:
956 ################################################################################
958 def do_comments(dir, opref, npref, line, fn):
959 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
960 lines = open("%s/%s" % (dir, comm)).readlines()
961 if len(lines) == 0 or lines[0] != line + "\n": continue
962 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
963 and x.endswith(".changes") ]
964 changes_files = sort_changes(changes_files)
965 for f in changes_files:
966 f = utils.validate_changes_file_arg(f, 0)
969 fn(f, "".join(lines[1:]))
971 if opref != npref and not Options["No-Action"]:
972 newcomm = npref + comm[len(opref):]
973 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
975 ################################################################################
977 def comment_accept(changes_file, comments):
978 Upload.pkg.changes_file = changes_file
981 Upload.update_subst()
982 files = Upload.pkg.files
985 return # dak wants to REJECT, crap
987 (new, byhand) = check_status(files)
988 if not new and not byhand:
991 ################################################################################
993 def comment_reject(changes_file, comments):
994 Upload.pkg.changes_file = changes_file
997 Upload.update_subst()
1000 pass # dak has its own reasons to reject as well, which is fine
1003 print "REJECT\n" + reject_message,
1004 if not Options["No-Action"]:
1005 Upload.do_reject(0, reject_message)
1006 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1008 ################################################################################
1011 changes_files = init()
1012 if len(changes_files) > 50:
1013 sys.stderr.write("Sorting changes...\n")
1014 changes_files = sort_changes(changes_files)
1016 # Kill me now? **FIXME**
1017 Cnf["Dinstall::Options::No-Mail"] = ""
1018 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1019 if Cnf.has_key("Dinstall::Bcc"):
1020 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1022 Upload.Subst["__BCC__"] = bcc
1024 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1026 if changes_files != []:
1027 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1029 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1030 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1032 for changes_file in changes_files:
1033 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1034 if not changes_file:
1036 print "\n" + changes_file
1037 do_pkg (changes_file)
1041 ################################################################################
1043 if __name__ == '__main__':