2 # vim:set et ts=4 sw=4:
4 # Handles NEW and BYHAND packages
5 # Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 James Troup <james@nocrew.org>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ################################################################################
23 # 23:12|<aj> I will not hush!
25 # 23:12|<aj> Where there is injustice in the world, I shall be there!
26 # 23:13|<aj> I shall not be silenced!
27 # 23:13|<aj> The world shall know!
28 # 23:13|<aj> The world *must* know!
29 # 23:13|<elmo> oh dear, he's gone back to powerpuff girls... ;-)
30 # 23:13|<aj> yay powerpuff girls!!
31 # 23:13|<aj> buttercup's my favourite, who's yours?
32 # 23:14|<aj> you're backing away from the keyboard right now aren't you?
33 # 23:14|<aj> *AREN'T YOU*?!
34 # 23:15|<aj> I will not be treated like this.
35 # 23:15|<aj> I shall have my revenge.
36 # 23:15|<aj> I SHALL!!!
38 ################################################################################
40 import copy, errno, os, readline, stat, sys, time
41 import apt_pkg, apt_inst
42 import examine_package
43 from daklib import database
44 from daklib import logging
45 from daklib import queue
46 from daklib import utils
47 from daklib.regexes import re_no_epoch, re_default_answer, re_isanum
61 ################################################################################
62 ################################################################################
63 ################################################################################
65 def reject (str, prefix="Rejected: "):
68 reject_message += prefix + str + "\n"
72 files = Upload.pkg.files
75 for f in files.keys():
76 # The .orig.tar.gz can disappear out from under us is it's a
77 # duplicate of one in the archive.
78 if not files.has_key(f):
80 # Check that the source still exists
81 if files[f]["type"] == "deb":
82 source_version = files[f]["source version"]
83 source_package = files[f]["source package"]
84 if not Upload.pkg.changes["architecture"].has_key("source") \
85 and not Upload.source_exists(source_package, source_version, Upload.pkg.changes["distribution"].keys()):
86 source_epochless_version = re_no_epoch.sub('', source_version)
87 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
89 for q in ["Accepted", "Embargoed", "Unembargoed"]:
90 if Cnf.has_key("Dir::Queue::%s" % (q)):
91 if os.path.exists(Cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
94 reject("no source found for %s %s (%s)." % (source_package, source_version, f))
96 # Version and file overwrite checks
97 if files[f]["type"] == "deb":
98 reject(Upload.check_binary_against_db(f), "")
99 elif files[f]["type"] == "dsc":
100 reject(Upload.check_source_against_db(f), "")
101 (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(f)
102 reject(reject_msg, "")
104 if reject_message.find("Rejected") != -1:
106 if Options["No-Action"] or Options["Automatic"]:
109 print "REJECT\n" + reject_message,
110 prompt = "[R]eject, Skip, Quit ?"
112 while prompt.find(answer) == -1:
113 answer = utils.our_raw_input(prompt)
114 m = re_default_answer.match(prompt)
117 answer = answer[:1].upper()
120 Upload.do_reject(0, reject_message)
121 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
131 ################################################################################
133 def indiv_sg_compare (a, b):
134 """Sort by source name, source, version, 'have source', and
135 finally by filename."""
136 # Sort by source version
137 q = apt_pkg.VersionCompare(a["version"], b["version"])
141 # Sort by 'have source'
142 a_has_source = a["architecture"].get("source")
143 b_has_source = b["architecture"].get("source")
144 if a_has_source and not b_has_source:
146 elif b_has_source and not a_has_source:
149 return cmp(a["filename"], b["filename"])
151 ############################################################
153 def sg_compare (a, b):
156 """Sort by have note, source already in database and time of oldest upload."""
158 a_note_state = a["note_state"]
159 b_note_state = b["note_state"]
160 if a_note_state < b_note_state:
162 elif a_note_state > b_note_state:
164 # Sort by source already in database (descending)
165 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
166 if source_in_database:
167 return -source_in_database
169 # Sort by time of oldest upload
170 return cmp(a["oldest"], b["oldest"])
172 def sort_changes(changes_files):
173 """Sort into source groups, then sort each source group by version,
174 have source, filename. Finally, sort the source groups by have
175 note, time of oldest upload of each source upload."""
176 if len(changes_files) == 1:
181 # Read in all the .changes files
182 for filename in changes_files:
184 Upload.pkg.changes_file = filename
187 cache[filename] = copy.copy(Upload.pkg.changes)
188 cache[filename]["filename"] = filename
190 sorted_list.append(filename)
192 # Divide the .changes into per-source groups
194 for filename in cache.keys():
195 source = cache[filename]["source"]
196 if not per_source.has_key(source):
197 per_source[source] = {}
198 per_source[source]["list"] = []
199 per_source[source]["list"].append(cache[filename])
200 # Determine oldest time and have note status for each source group
201 for source in per_source.keys():
202 q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source)
204 per_source[source]["source_in_database"] = len(ql)>0
205 source_list = per_source[source]["list"]
206 first = source_list[0]
207 oldest = os.stat(first["filename"])[stat.ST_MTIME]
209 for d in per_source[source]["list"]:
210 mtime = os.stat(d["filename"])[stat.ST_MTIME]
213 have_note += (d.has_key("process-new note"))
214 per_source[source]["oldest"] = oldest
216 per_source[source]["note_state"] = 0; # none
217 elif have_note < len(source_list):
218 per_source[source]["note_state"] = 1; # some
220 per_source[source]["note_state"] = 2; # all
221 per_source[source]["list"].sort(indiv_sg_compare)
222 per_source_items = per_source.items()
223 per_source_items.sort(sg_compare)
224 for i in per_source_items:
225 for j in i[1]["list"]:
226 sorted_list.append(j["filename"])
229 ################################################################################
231 class Section_Completer:
234 q = projectB.query("SELECT section FROM section")
235 for i in q.getresult():
236 self.sections.append(i[0])
238 def complete(self, text, state):
242 for word in self.sections:
244 self.matches.append(word)
246 return self.matches[state]
250 ############################################################
252 class Priority_Completer:
255 q = projectB.query("SELECT priority FROM priority")
256 for i in q.getresult():
257 self.priorities.append(i[0])
259 def complete(self, text, state):
263 for word in self.priorities:
265 self.matches.append(word)
267 return self.matches[state]
271 ################################################################################
273 def print_new (new, indexed, file=sys.stdout):
274 queue.check_valid(new)
277 for pkg in new.keys():
279 section = new[pkg]["section"]
280 priority = new[pkg]["priority"]
281 if new[pkg]["section id"] == -1:
284 if new[pkg]["priority id"] == -1:
288 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
290 line = "%-20s %-20s %-20s" % (pkg, priority, section)
291 line = line.strip()+'\n'
293 note = Upload.pkg.changes.get("process-new note")
300 ################################################################################
302 def index_range (index):
306 return "1-%s" % (index)
308 ################################################################################
309 ################################################################################
312 # Write the current data to a temporary file
313 (fd, temp_filename) = utils.temp_filename()
314 temp_file = os.fdopen(fd, 'w')
315 print_new (new, 0, temp_file)
317 # Spawn an editor on that file
318 editor = os.environ.get("EDITOR","vi")
319 result = os.system("%s %s" % (editor, temp_filename))
321 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
322 # Read the edited data back in
323 temp_file = utils.open_file(temp_filename)
324 lines = temp_file.readlines()
326 os.unlink(temp_filename)
333 # Pad the list if necessary
334 s[len(s):3] = [None] * (3-len(s))
335 (pkg, priority, section) = s[:3]
336 if not new.has_key(pkg):
337 utils.warn("Ignoring unknown package '%s'" % (pkg))
339 # Strip off any invalid markers, print_new will readd them.
340 if section.endswith("[!]"):
341 section = section[:-3]
342 if priority.endswith("[!]"):
343 priority = priority[:-3]
344 for f in new[pkg]["files"]:
345 Upload.pkg.files[f]["section"] = section
346 Upload.pkg.files[f]["priority"] = priority
347 new[pkg]["section"] = section
348 new[pkg]["priority"] = priority
350 ################################################################################
352 def edit_index (new, index):
353 priority = new[index]["priority"]
354 section = new[index]["section"]
355 ftype = new[index]["type"]
358 print "\t".join([index, priority, section])
362 prompt = "[B]oth, Priority, Section, Done ? "
364 prompt = "[S]ection, Done ? "
365 edit_priority = edit_section = 0
367 while prompt.find(answer) == -1:
368 answer = utils.our_raw_input(prompt)
369 m = re_default_answer.match(prompt)
372 answer = answer[:1].upper()
379 edit_priority = edit_section = 1
385 readline.set_completer(Priorities.complete)
387 while not got_priority:
388 new_priority = utils.our_raw_input("New priority: ").strip()
389 if new_priority not in Priorities.priorities:
390 print "E: '%s' is not a valid priority, try again." % (new_priority)
393 priority = new_priority
397 readline.set_completer(Sections.complete)
399 while not got_section:
400 new_section = utils.our_raw_input("New section: ").strip()
401 if new_section not in Sections.sections:
402 print "E: '%s' is not a valid section, try again." % (new_section)
405 section = new_section
407 # Reset the readline completer
408 readline.set_completer(None)
410 for f in new[index]["files"]:
411 Upload.pkg.files[f]["section"] = section
412 Upload.pkg.files[f]["priority"] = priority
413 new[index]["priority"] = priority
414 new[index]["section"] = section
417 ################################################################################
419 def edit_overrides (new):
430 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
433 while not got_answer:
434 answer = utils.our_raw_input(prompt)
435 if not answer.isdigit():
436 answer = answer[:1].upper()
437 if answer == "E" or answer == "D":
439 elif re_isanum.match (answer):
441 if (answer < 1) or (answer > index):
442 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
451 edit_index (new, new_index[answer])
455 ################################################################################
458 # Write the current data to a temporary file
459 (fd, temp_filename) = utils.temp_filename()
460 temp_file = os.fdopen(temp_filename, 'w')
461 temp_file.write(note)
463 editor = os.environ.get("EDITOR","vi")
466 os.system("%s %s" % (editor, temp_filename))
467 temp_file = utils.open_file(temp_filename)
468 note = temp_file.read().rstrip()
471 print utils.prefix_multi_line_string(note," ")
472 prompt = "[D]one, Edit, Abandon, Quit ?"
474 while prompt.find(answer) == -1:
475 answer = utils.our_raw_input(prompt)
476 m = re_default_answer.search(prompt)
479 answer = answer[:1].upper()
480 os.unlink(temp_filename)
486 Upload.pkg.changes["process-new note"] = note
487 Upload.dump_vars(Cnf["Dir::Queue::New"])
489 ################################################################################
493 less_fd = os.popen("less -R -", 'w', 0)
494 stdout_fd = sys.stdout
497 changes = utils.parse_changes (Upload.pkg.changes_file)
498 examine_package.display_changes(changes['distribution'], Upload.pkg.changes_file)
499 files = Upload.pkg.files
500 for f in files.keys():
501 if files[f].has_key("new"):
502 ftype = files[f]["type"]
504 examine_package.check_deb(changes['distribution'], f)
506 examine_package.check_dsc(changes['distribution'], f)
508 sys.stdout = stdout_fd
510 if e.errno == errno.EPIPE:
511 utils.warn("[examine_package] Caught EPIPE; skipping.")
515 except KeyboardInterrupt:
516 utils.warn("[examine_package] Caught C-c; skipping.")
519 ################################################################################
521 ## FIXME: horribly Debian specific
523 def do_bxa_notification():
524 files = Upload.pkg.files
526 for f in files.keys():
527 if files[f]["type"] == "deb":
528 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
530 summary += "Package: %s\n" % (control.Find("Package"))
531 summary += "Description: %s\n" % (control.Find("Description"))
532 Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
533 bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
534 utils.send_mail(bxa_mail)
536 ################################################################################
538 def add_overrides (new):
539 changes = Upload.pkg.changes
540 files = Upload.pkg.files
542 projectB.query("BEGIN WORK")
543 for suite in changes["suite"].keys():
544 suite_id = database.get_suite_id(suite)
545 for pkg in new.keys():
546 component_id = database.get_component_id(new[pkg]["component"])
547 type_id = database.get_override_type_id(new[pkg]["type"])
548 priority_id = new[pkg]["priority id"]
549 section_id = new[pkg]["section id"]
550 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))
551 for f in new[pkg]["files"]:
552 if files[f].has_key("new"):
556 projectB.query("COMMIT WORK")
558 if Cnf.FindB("Dinstall::BXANotify"):
559 do_bxa_notification()
561 ################################################################################
563 def prod_maintainer ():
564 # Here we prepare an editor and get them ready to prod...
565 (fd, temp_filename) = utils.temp_filename()
566 editor = os.environ.get("EDITOR","vi")
569 os.system("%s %s" % (editor, temp_filename))
571 prod_message = "".join(f.readlines())
573 print "Prod message:"
574 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
575 prompt = "[P]rod, Edit, Abandon, Quit ?"
577 while prompt.find(answer) == -1:
578 answer = utils.our_raw_input(prompt)
579 m = re_default_answer.search(prompt)
582 answer = answer[:1].upper()
583 os.unlink(temp_filename)
589 # Otherwise, do the proding...
590 user_email_address = utils.whoami() + " <%s>" % (
591 Cnf["Dinstall::MyAdminAddress"])
595 Subst["__FROM_ADDRESS__"] = user_email_address
596 Subst["__PROD_MESSAGE__"] = prod_message
597 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
599 prod_mail_message = utils.TemplateSubst(
600 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
602 # Send the prod mail if appropriate
603 if not Cnf["Dinstall::Options::No-Mail"]:
604 utils.send_mail(prod_mail_message)
606 print "Sent proding message"
608 ################################################################################
612 files = Upload.pkg.files
613 changes = Upload.pkg.changes
615 # Make a copy of distribution we can happily trample on
616 changes["suite"] = copy.copy(changes["distribution"])
618 # Fix up the list of target suites
619 for suite in changes["suite"].keys():
620 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
622 (olderr, newerr) = (database.get_suite_id(suite) == -1,
623 database.get_suite_id(override) == -1)
625 (oinv, newinv) = ("", "")
626 if olderr: oinv = "invalid "
627 if newerr: ninv = "invalid "
628 print "warning: overriding %ssuite %s to %ssuite %s" % (
629 oinv, suite, ninv, override)
630 del changes["suite"][suite]
631 changes["suite"][override] = 1
633 for suite in changes["suite"].keys():
634 suite_id = database.get_suite_id(suite)
636 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
638 # The main NEW processing loop
641 # Find out what's new
642 new = queue.determine_new(changes, files, projectB)
648 if Options["No-Action"] or Options["Automatic"]:
651 (broken, note) = print_new(new, 0)
654 if not broken and not note:
655 prompt = "Add overrides, "
657 print "W: [!] marked entries must be fixed before package can be processed."
659 print "W: note must be removed before package can be processed."
660 prompt += "Remove note, "
662 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
664 while prompt.find(answer) == -1:
665 answer = utils.our_raw_input(prompt)
666 m = re_default_answer.search(prompt)
669 answer = answer[:1].upper()
672 done = add_overrides (new)
676 new = edit_overrides (new)
678 aborted = Upload.do_reject(1, Options["Manual-Reject"])
680 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
683 edit_note(changes.get("process-new note", ""))
687 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
689 del changes["process-new note"]
696 ################################################################################
697 ################################################################################
698 ################################################################################
700 def usage (exit_code=0):
701 print """Usage: dak process-new [OPTION]... [CHANGES]...
702 -a, --automatic automatic run
703 -h, --help show this help and exit.
704 -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new
705 -m, --manual-reject=MSG manual reject with `msg'
706 -n, --no-action don't do anything
707 -V, --version display the version number and exit"""
710 ################################################################################
713 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
715 Cnf = utils.get_conf()
717 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
718 ('h',"help","Process-New::Options::Help"),
719 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
720 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
721 ('n',"no-action","Process-New::Options::No-Action")]
723 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir"]:
724 if not Cnf.has_key("Process-New::Options::%s" % (i)):
725 Cnf["Process-New::Options::%s" % (i)] = ""
727 changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
728 Options = Cnf.SubTree("Process-New::Options")
733 Upload = queue.Upload(Cnf)
735 if not Options["No-Action"]:
736 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
738 projectB = Upload.projectB
740 Sections = Section_Completer()
741 Priorities = Priority_Completer()
742 readline.parse_and_bind("tab: complete")
746 ################################################################################
751 files = Upload.pkg.files
755 for f in files.keys():
756 if files[f]["type"] == "byhand":
757 if os.path.exists(f):
758 print "W: %s still present; please process byhand components and try again." % (f)
764 if Options["No-Action"]:
767 if Options["Automatic"] and not Options["No-Action"]:
769 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
771 prompt = "Manual reject, [S]kip, Quit ?"
773 while prompt.find(answer) == -1:
774 answer = utils.our_raw_input(prompt)
775 m = re_default_answer.search(prompt)
778 answer = answer[:1].upper()
785 Upload.do_reject(1, Options["Manual-Reject"])
786 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
794 ################################################################################
796 def get_accept_lock():
800 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
803 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
806 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
808 print("Unable to get accepted lock (try %d of 10)" % retry)
813 def move_to_dir (dest, perms=0660, changesperms=0664):
814 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
815 file_keys = Upload.pkg.files.keys()
817 utils.move (f, dest, perms=perms)
819 def is_source_in_queue_dir(qdir):
820 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
821 and x.endswith(".changes") ]
822 for entry in entries:
824 u = queue.Upload(Cnf)
825 u.pkg.changes_file = os.path.join(qdir, entry)
827 if not u.pkg.changes["architecture"].has_key("source"):
828 # another binary upload, ignore
830 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
831 # another version, ignore
837 def move_to_holding(suite, queue_dir):
838 print "Moving to %s holding area." % (suite.upper(),)
839 if Options["No-Action"]:
841 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
842 Upload.dump_vars(queue_dir)
843 move_to_dir(queue_dir)
844 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
847 if Options["No-Action"]:
849 (summary, short_summary) = Upload.build_summaries()
850 Upload.accept(summary, short_summary)
851 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
853 def do_accept_stableupdate(suite, q):
854 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
855 if not Upload.pkg.changes["architecture"].has_key("source"):
856 # It is not a sourceful upload. So its source may be either in p-u
857 # holding, in new, in accepted or already installed.
858 if is_source_in_queue_dir(queue_dir):
859 # It's in p-u holding, so move it there.
860 print "Binary-only upload, source in %s." % (q,)
861 move_to_holding(suite, queue_dir)
862 elif Upload.source_exists(Upload.pkg.changes["source"],
863 Upload.pkg.changes["version"]):
864 # dak tells us that there is source available. At time of
865 # writing this means that it is installed, so put it into
867 print "Binary-only upload, source installed."
869 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
870 # The source is in accepted, the binary cleared NEW: accept it.
871 print "Binary-only upload, source in accepted."
873 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
874 # It's in NEW. We expect the source to land in p-u holding
876 print "Binary-only upload, source in new."
877 move_to_holding(suite, queue_dir)
879 # No case applicable. Bail out. Return will cause the upload
882 print "Stable update failed. Source not found."
885 # We are handling a sourceful upload. Move to accepted if currently
886 # in p-u holding and to p-u holding otherwise.
887 if is_source_in_queue_dir(queue_dir):
888 print "Sourceful upload in %s, accepting." % (q,)
891 move_to_holding(suite, queue_dir)
895 if not Options["No-Action"]:
897 (summary, short_summary) = Upload.build_summaries()
899 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
900 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
901 move_to_dir(Cnf["Dir::Queue::Embargoed"])
902 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
903 # Check for override disparities
904 Upload.Subst["__SUMMARY__"] = summary
906 # Stable updates need to be copied to proposed-updates holding
907 # area instead of accepted. Sourceful uploads need to go
908 # to it directly, binaries only if the source has not yet been
910 for suite, q in [("proposed-updates", "ProposedUpdates"),
911 ("oldstable-proposed-updates", "OldProposedUpdates")]:
912 if not Upload.pkg.changes["distribution"].has_key(suite):
914 return do_accept_stableupdate(suite, q)
915 # Just a normal upload, accept it...
918 if not Options["No-Action"]:
919 os.unlink(Cnf["Process-New::AcceptedLockFile"])
921 def check_status(files):
923 for f in files.keys():
924 if files[f]["type"] == "byhand":
926 elif files[f].has_key("new"):
930 def do_pkg(changes_file):
931 Upload.pkg.changes_file = changes_file
934 Upload.update_subst()
935 files = Upload.pkg.files
940 (new, byhand) = check_status(files)
946 (new, byhand) = check_status(files)
948 if not new and not byhand:
951 ################################################################################
954 accept_count = Upload.accept_count
955 accept_bytes = Upload.accept_bytes
961 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
962 Logger.log(["total",accept_count,accept_bytes])
964 if not Options["No-Action"]:
967 ################################################################################
969 def do_comments(dir, opref, npref, line, fn):
970 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
971 lines = open("%s/%s" % (dir, comm)).readlines()
972 if len(lines) == 0 or lines[0] != line + "\n": continue
973 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
974 and x.endswith(".changes") ]
975 changes_files = sort_changes(changes_files)
976 for f in changes_files:
977 f = utils.validate_changes_file_arg(f, 0)
980 fn(f, "".join(lines[1:]))
982 if opref != npref and not Options["No-Action"]:
983 newcomm = npref + comm[len(opref):]
984 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
986 ################################################################################
988 def comment_accept(changes_file, comments):
989 Upload.pkg.changes_file = changes_file
992 Upload.update_subst()
993 files = Upload.pkg.files
996 return # dak wants to REJECT, crap
998 (new, byhand) = check_status(files)
999 if not new and not byhand:
1002 ################################################################################
1004 def comment_reject(changes_file, comments):
1005 Upload.pkg.changes_file = changes_file
1007 Upload.update_vars()
1008 Upload.update_subst()
1011 pass # dak has its own reasons to reject as well, which is fine
1014 print "REJECT\n" + reject_message,
1015 if not Options["No-Action"]:
1016 Upload.do_reject(0, reject_message)
1017 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1019 ################################################################################
1022 changes_files = init()
1023 if len(changes_files) > 50:
1024 sys.stderr.write("Sorting changes...\n")
1025 changes_files = sort_changes(changes_files)
1027 # Kill me now? **FIXME**
1028 Cnf["Dinstall::Options::No-Mail"] = ""
1029 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1030 if Cnf.has_key("Dinstall::Bcc"):
1031 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1033 Upload.Subst["__BCC__"] = bcc
1035 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1037 if changes_files != []:
1038 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1040 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1041 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1043 for changes_file in changes_files:
1044 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1045 if not changes_file:
1047 print "\n" + changes_file
1048 do_pkg (changes_file)
1052 ################################################################################
1054 if __name__ == '__main__':