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 @license: GNU General Public License version 2 or later
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 ################################################################################
26 # 23:12|<aj> I will not hush!
28 # 23:12|<aj> Where there is injustice in the world, I shall be there!
29 # 23:13|<aj> I shall not be silenced!
30 # 23:13|<aj> The world shall know!
31 # 23:13|<aj> The world *must* know!
32 # 23:13|<elmo> oh dear, he's gone back to powerpuff girls... ;-)
33 # 23:13|<aj> yay powerpuff girls!!
34 # 23:13|<aj> buttercup's my favourite, who's yours?
35 # 23:14|<aj> you're backing away from the keyboard right now aren't you?
36 # 23:14|<aj> *AREN'T YOU*?!
37 # 23:15|<aj> I will not be treated like this.
38 # 23:15|<aj> I shall have my revenge.
39 # 23:15|<aj> I SHALL!!!
41 ################################################################################
50 import apt_pkg, apt_inst
51 import examine_package
52 from daklib import database
53 from daklib import logging
54 from daklib import queue
55 from daklib import utils
56 from daklib.regexes import re_no_epoch, re_default_answer, re_isanum
59 Cnf = None #: Configuration, apt_pkg.Configuration
62 projectB = None #: database connection, pgobject
70 ################################################################################
71 ################################################################################
72 ################################################################################
74 def reject (str, prefix="Rejected: "):
77 reject_message += prefix + str + "\n"
81 files = Upload.pkg.files
84 for f in files.keys():
85 # The .orig.tar.gz can disappear out from under us is it's a
86 # duplicate of one in the archive.
87 if not files.has_key(f):
89 # Check that the source still exists
90 if files[f]["type"] == "deb":
91 source_version = files[f]["source version"]
92 source_package = files[f]["source package"]
93 if not Upload.pkg.changes["architecture"].has_key("source") \
94 and not Upload.source_exists(source_package, source_version, Upload.pkg.changes["distribution"].keys()):
95 source_epochless_version = re_no_epoch.sub('', source_version)
96 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
98 for q in ["Accepted", "Embargoed", "Unembargoed"]:
99 if Cnf.has_key("Dir::Queue::%s" % (q)):
100 if os.path.exists(Cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
103 reject("no source found for %s %s (%s)." % (source_package, source_version, f))
105 # Version and file overwrite checks
106 if files[f]["type"] == "deb":
107 reject(Upload.check_binary_against_db(f), "")
108 elif files[f]["type"] == "dsc":
109 reject(Upload.check_source_against_db(f), "")
110 (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(f)
111 reject(reject_msg, "")
113 if reject_message.find("Rejected") != -1:
115 if Options["No-Action"] or Options["Automatic"]:
118 print "REJECT\n" + reject_message,
119 prompt = "[R]eject, Skip, Quit ?"
121 while prompt.find(answer) == -1:
122 answer = utils.our_raw_input(prompt)
123 m = re_default_answer.match(prompt)
126 answer = answer[:1].upper()
129 Upload.do_reject(0, reject_message)
130 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
140 ################################################################################
142 def indiv_sg_compare (a, b):
143 """Sort by source name, source, version, 'have source', and
144 finally by filename."""
145 # Sort by source version
146 q = apt_pkg.VersionCompare(a["version"], b["version"])
150 # Sort by 'have source'
151 a_has_source = a["architecture"].get("source")
152 b_has_source = b["architecture"].get("source")
153 if a_has_source and not b_has_source:
155 elif b_has_source and not a_has_source:
158 return cmp(a["filename"], b["filename"])
160 ############################################################
162 def sg_compare (a, b):
165 """Sort by have note, source already in database and time of oldest upload."""
167 a_note_state = a["note_state"]
168 b_note_state = b["note_state"]
169 if a_note_state < b_note_state:
171 elif a_note_state > b_note_state:
173 # Sort by source already in database (descending)
174 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
175 if source_in_database:
176 return -source_in_database
178 # Sort by time of oldest upload
179 return cmp(a["oldest"], b["oldest"])
181 def sort_changes(changes_files):
182 """Sort into source groups, then sort each source group by version,
183 have source, filename. Finally, sort the source groups by have
184 note, time of oldest upload of each source upload."""
185 if len(changes_files) == 1:
190 # Read in all the .changes files
191 for filename in changes_files:
193 Upload.pkg.changes_file = filename
196 cache[filename] = copy.copy(Upload.pkg.changes)
197 cache[filename]["filename"] = filename
199 sorted_list.append(filename)
201 # Divide the .changes into per-source groups
203 for filename in cache.keys():
204 source = cache[filename]["source"]
205 if not per_source.has_key(source):
206 per_source[source] = {}
207 per_source[source]["list"] = []
208 per_source[source]["list"].append(cache[filename])
209 # Determine oldest time and have note status for each source group
210 for source in per_source.keys():
211 q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source)
213 per_source[source]["source_in_database"] = len(ql)>0
214 source_list = per_source[source]["list"]
215 first = source_list[0]
216 oldest = os.stat(first["filename"])[stat.ST_MTIME]
218 for d in per_source[source]["list"]:
219 mtime = os.stat(d["filename"])[stat.ST_MTIME]
222 have_note += (d.has_key("process-new note"))
223 per_source[source]["oldest"] = oldest
225 per_source[source]["note_state"] = 0; # none
226 elif have_note < len(source_list):
227 per_source[source]["note_state"] = 1; # some
229 per_source[source]["note_state"] = 2; # all
230 per_source[source]["list"].sort(indiv_sg_compare)
231 per_source_items = per_source.items()
232 per_source_items.sort(sg_compare)
233 for i in per_source_items:
234 for j in i[1]["list"]:
235 sorted_list.append(j["filename"])
238 ################################################################################
240 class Section_Completer:
244 q = projectB.query("SELECT section FROM section")
245 for i in q.getresult():
246 self.sections.append(i[0])
248 def complete(self, text, state):
252 for word in self.sections:
254 self.matches.append(word)
256 return self.matches[state]
260 ############################################################
262 class Priority_Completer:
266 q = projectB.query("SELECT priority FROM priority")
267 for i in q.getresult():
268 self.priorities.append(i[0])
270 def complete(self, text, state):
274 for word in self.priorities:
276 self.matches.append(word)
278 return self.matches[state]
282 ################################################################################
284 def print_new (new, indexed, file=sys.stdout):
285 queue.check_valid(new)
288 for pkg in new.keys():
290 section = new[pkg]["section"]
291 priority = new[pkg]["priority"]
292 if new[pkg]["section id"] == -1:
295 if new[pkg]["priority id"] == -1:
299 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
301 line = "%-20s %-20s %-20s" % (pkg, priority, section)
302 line = line.strip()+'\n'
304 note = Upload.pkg.changes.get("process-new note")
311 ################################################################################
313 def index_range (index):
317 return "1-%s" % (index)
319 ################################################################################
320 ################################################################################
323 # Write the current data to a temporary file
324 (fd, temp_filename) = utils.temp_filename()
325 temp_file = os.fdopen(fd, 'w')
326 print_new (new, 0, temp_file)
328 # Spawn an editor on that file
329 editor = os.environ.get("EDITOR","vi")
330 result = os.system("%s %s" % (editor, temp_filename))
332 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
333 # Read the edited data back in
334 temp_file = utils.open_file(temp_filename)
335 lines = temp_file.readlines()
337 os.unlink(temp_filename)
344 # Pad the list if necessary
345 s[len(s):3] = [None] * (3-len(s))
346 (pkg, priority, section) = s[:3]
347 if not new.has_key(pkg):
348 utils.warn("Ignoring unknown package '%s'" % (pkg))
350 # Strip off any invalid markers, print_new will readd them.
351 if section.endswith("[!]"):
352 section = section[:-3]
353 if priority.endswith("[!]"):
354 priority = priority[:-3]
355 for f in new[pkg]["files"]:
356 Upload.pkg.files[f]["section"] = section
357 Upload.pkg.files[f]["priority"] = priority
358 new[pkg]["section"] = section
359 new[pkg]["priority"] = priority
361 ################################################################################
363 def edit_index (new, index):
364 priority = new[index]["priority"]
365 section = new[index]["section"]
366 ftype = new[index]["type"]
369 print "\t".join([index, priority, section])
373 prompt = "[B]oth, Priority, Section, Done ? "
375 prompt = "[S]ection, Done ? "
376 edit_priority = edit_section = 0
378 while prompt.find(answer) == -1:
379 answer = utils.our_raw_input(prompt)
380 m = re_default_answer.match(prompt)
383 answer = answer[:1].upper()
390 edit_priority = edit_section = 1
396 readline.set_completer(Priorities.complete)
398 while not got_priority:
399 new_priority = utils.our_raw_input("New priority: ").strip()
400 if new_priority not in Priorities.priorities:
401 print "E: '%s' is not a valid priority, try again." % (new_priority)
404 priority = new_priority
408 readline.set_completer(Sections.complete)
410 while not got_section:
411 new_section = utils.our_raw_input("New section: ").strip()
412 if new_section not in Sections.sections:
413 print "E: '%s' is not a valid section, try again." % (new_section)
416 section = new_section
418 # Reset the readline completer
419 readline.set_completer(None)
421 for f in new[index]["files"]:
422 Upload.pkg.files[f]["section"] = section
423 Upload.pkg.files[f]["priority"] = priority
424 new[index]["priority"] = priority
425 new[index]["section"] = section
428 ################################################################################
430 def edit_overrides (new):
441 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
444 while not got_answer:
445 answer = utils.our_raw_input(prompt)
446 if not answer.isdigit():
447 answer = answer[:1].upper()
448 if answer == "E" or answer == "D":
450 elif re_isanum.match (answer):
452 if (answer < 1) or (answer > index):
453 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
462 edit_index (new, new_index[answer])
466 ################################################################################
469 # Write the current data to a temporary file
470 (fd, temp_filename) = utils.temp_filename()
471 temp_file = os.fdopen(fd, 'w')
472 temp_file.write(note)
474 editor = os.environ.get("EDITOR","vi")
477 os.system("%s %s" % (editor, temp_filename))
478 temp_file = utils.open_file(temp_filename)
479 note = temp_file.read().rstrip()
482 print utils.prefix_multi_line_string(note," ")
483 prompt = "[D]one, Edit, Abandon, Quit ?"
485 while prompt.find(answer) == -1:
486 answer = utils.our_raw_input(prompt)
487 m = re_default_answer.search(prompt)
490 answer = answer[:1].upper()
491 os.unlink(temp_filename)
497 Upload.pkg.changes["process-new note"] = note
498 Upload.dump_vars(Cnf["Dir::Queue::New"])
500 ################################################################################
504 less_fd = os.popen("less -R -", 'w', 0)
505 stdout_fd = sys.stdout
508 changes = utils.parse_changes (Upload.pkg.changes_file)
509 examine_package.display_changes(changes['distribution'], Upload.pkg.changes_file)
510 files = Upload.pkg.files
511 for f in files.keys():
512 if files[f].has_key("new"):
513 ftype = files[f]["type"]
515 examine_package.check_deb(changes['distribution'], f)
517 examine_package.check_dsc(changes['distribution'], f)
519 sys.stdout = stdout_fd
521 if e.errno == errno.EPIPE:
522 utils.warn("[examine_package] Caught EPIPE; skipping.")
526 except KeyboardInterrupt:
527 utils.warn("[examine_package] Caught C-c; skipping.")
530 ################################################################################
532 ## FIXME: horribly Debian specific
534 def do_bxa_notification():
535 files = Upload.pkg.files
537 for f in files.keys():
538 if files[f]["type"] == "deb":
539 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
541 summary += "Package: %s\n" % (control.Find("Package"))
542 summary += "Description: %s\n" % (control.Find("Description"))
543 Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
544 bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
545 utils.send_mail(bxa_mail)
547 ################################################################################
549 def add_overrides (new):
550 changes = Upload.pkg.changes
551 files = Upload.pkg.files
553 projectB.query("BEGIN WORK")
554 for suite in changes["suite"].keys():
555 suite_id = database.get_suite_id(suite)
556 for pkg in new.keys():
557 component_id = database.get_component_id(new[pkg]["component"])
558 type_id = database.get_override_type_id(new[pkg]["type"])
559 priority_id = new[pkg]["priority id"]
560 section_id = new[pkg]["section id"]
561 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))
562 for f in new[pkg]["files"]:
563 if files[f].has_key("new"):
567 projectB.query("COMMIT WORK")
569 if Cnf.FindB("Dinstall::BXANotify"):
570 do_bxa_notification()
572 ################################################################################
574 def prod_maintainer ():
575 # Here we prepare an editor and get them ready to prod...
576 (fd, temp_filename) = utils.temp_filename()
577 editor = os.environ.get("EDITOR","vi")
580 os.system("%s %s" % (editor, temp_filename))
582 prod_message = "".join(f.readlines())
584 print "Prod message:"
585 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
586 prompt = "[P]rod, Edit, Abandon, Quit ?"
588 while prompt.find(answer) == -1:
589 answer = utils.our_raw_input(prompt)
590 m = re_default_answer.search(prompt)
593 answer = answer[:1].upper()
594 os.unlink(temp_filename)
600 # Otherwise, do the proding...
601 user_email_address = utils.whoami() + " <%s>" % (
602 Cnf["Dinstall::MyAdminAddress"])
606 Subst["__FROM_ADDRESS__"] = user_email_address
607 Subst["__PROD_MESSAGE__"] = prod_message
608 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
610 prod_mail_message = utils.TemplateSubst(
611 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
613 # Send the prod mail if appropriate
614 if not Cnf["Dinstall::Options::No-Mail"]:
615 utils.send_mail(prod_mail_message)
617 print "Sent proding message"
619 ################################################################################
623 files = Upload.pkg.files
624 changes = Upload.pkg.changes
626 # Make a copy of distribution we can happily trample on
627 changes["suite"] = copy.copy(changes["distribution"])
629 # Fix up the list of target suites
630 for suite in changes["suite"].keys():
631 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
633 (olderr, newerr) = (database.get_suite_id(suite) == -1,
634 database.get_suite_id(override) == -1)
636 (oinv, newinv) = ("", "")
637 if olderr: oinv = "invalid "
638 if newerr: ninv = "invalid "
639 print "warning: overriding %ssuite %s to %ssuite %s" % (
640 oinv, suite, ninv, override)
641 del changes["suite"][suite]
642 changes["suite"][override] = 1
644 for suite in changes["suite"].keys():
645 suite_id = database.get_suite_id(suite)
647 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
649 # The main NEW processing loop
652 # Find out what's new
653 new = queue.determine_new(changes, files, projectB)
659 if Options["No-Action"] or Options["Automatic"]:
662 (broken, note) = print_new(new, 0)
665 if not broken and not note:
666 prompt = "Add overrides, "
668 print "W: [!] marked entries must be fixed before package can be processed."
670 print "W: note must be removed before package can be processed."
671 prompt += "Remove note, "
673 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
675 while prompt.find(answer) == -1:
676 answer = utils.our_raw_input(prompt)
677 m = re_default_answer.search(prompt)
680 answer = answer[:1].upper()
683 done = add_overrides (new)
687 new = edit_overrides (new)
689 aborted = Upload.do_reject(1, Options["Manual-Reject"])
691 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
694 edit_note(changes.get("process-new note", ""))
698 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
700 del changes["process-new note"]
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 -V, --version display the version number and exit"""
721 ################################################################################
724 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
726 Cnf = utils.get_conf()
728 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
729 ('h',"help","Process-New::Options::Help"),
730 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
731 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
732 ('n',"no-action","Process-New::Options::No-Action")]
734 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir"]:
735 if not Cnf.has_key("Process-New::Options::%s" % (i)):
736 Cnf["Process-New::Options::%s" % (i)] = ""
738 changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
739 if len(changes_files) == 0 and not Cnf.get("Process-New::Options::Comments-Dir",""):
740 changes_files = utils.get_changes_files(Cnf["Dir::Queue::New"])
742 Options = Cnf.SubTree("Process-New::Options")
747 Upload = queue.Upload(Cnf)
749 if not Options["No-Action"]:
750 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
752 projectB = Upload.projectB
754 Sections = Section_Completer()
755 Priorities = Priority_Completer()
756 readline.parse_and_bind("tab: complete")
760 ################################################################################
765 files = Upload.pkg.files
769 for f in files.keys():
770 if files[f]["type"] == "byhand":
771 if os.path.exists(f):
772 print "W: %s still present; please process byhand components and try again." % (f)
778 if Options["No-Action"]:
781 if Options["Automatic"] and not Options["No-Action"]:
783 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
785 prompt = "Manual reject, [S]kip, Quit ?"
787 while prompt.find(answer) == -1:
788 answer = utils.our_raw_input(prompt)
789 m = re_default_answer.search(prompt)
792 answer = answer[:1].upper()
799 Upload.do_reject(1, Options["Manual-Reject"])
800 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
808 ################################################################################
810 def get_accept_lock():
814 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
817 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
820 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
822 print("Unable to get accepted lock (try %d of 10)" % retry)
827 def move_to_dir (dest, perms=0660, changesperms=0664):
828 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
829 file_keys = Upload.pkg.files.keys()
831 utils.move (f, dest, perms=perms)
833 def is_source_in_queue_dir(qdir):
834 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
835 and x.endswith(".changes") ]
836 for entry in entries:
838 u = queue.Upload(Cnf)
839 u.pkg.changes_file = os.path.join(qdir, entry)
841 if not u.pkg.changes["architecture"].has_key("source"):
842 # another binary upload, ignore
844 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
845 # another version, ignore
851 def move_to_holding(suite, queue_dir):
852 print "Moving to %s holding area." % (suite.upper(),)
853 if Options["No-Action"]:
855 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
856 Upload.dump_vars(queue_dir)
857 move_to_dir(queue_dir)
858 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
861 if Options["No-Action"]:
863 (summary, short_summary) = Upload.build_summaries()
864 Upload.accept(summary, short_summary)
865 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
867 def do_accept_stableupdate(suite, q):
868 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
869 if not Upload.pkg.changes["architecture"].has_key("source"):
870 # It is not a sourceful upload. So its source may be either in p-u
871 # holding, in new, in accepted or already installed.
872 if is_source_in_queue_dir(queue_dir):
873 # It's in p-u holding, so move it there.
874 print "Binary-only upload, source in %s." % (q,)
875 move_to_holding(suite, queue_dir)
876 elif Upload.source_exists(Upload.pkg.changes["source"],
877 Upload.pkg.changes["version"]):
878 # dak tells us that there is source available. At time of
879 # writing this means that it is installed, so put it into
881 print "Binary-only upload, source installed."
883 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
884 # The source is in accepted, the binary cleared NEW: accept it.
885 print "Binary-only upload, source in accepted."
887 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
888 # It's in NEW. We expect the source to land in p-u holding
890 print "Binary-only upload, source in new."
891 move_to_holding(suite, queue_dir)
893 # No case applicable. Bail out. Return will cause the upload
896 print "Stable update failed. Source not found."
899 # We are handling a sourceful upload. Move to accepted if currently
900 # in p-u holding and to p-u holding otherwise.
901 if is_source_in_queue_dir(queue_dir):
902 print "Sourceful upload in %s, accepting." % (q,)
905 move_to_holding(suite, queue_dir)
909 if not Options["No-Action"]:
911 (summary, short_summary) = Upload.build_summaries()
913 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
914 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
915 move_to_dir(Cnf["Dir::Queue::Embargoed"])
916 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
917 # Check for override disparities
918 Upload.Subst["__SUMMARY__"] = summary
920 # Stable updates need to be copied to proposed-updates holding
921 # area instead of accepted. Sourceful uploads need to go
922 # to it directly, binaries only if the source has not yet been
924 for suite, q in [("proposed-updates", "ProposedUpdates"),
925 ("oldstable-proposed-updates", "OldProposedUpdates")]:
926 if not Upload.pkg.changes["distribution"].has_key(suite):
928 return do_accept_stableupdate(suite, q)
929 # Just a normal upload, accept it...
932 if not Options["No-Action"]:
933 os.unlink(Cnf["Process-New::AcceptedLockFile"])
935 def check_status(files):
937 for f in files.keys():
938 if files[f]["type"] == "byhand":
940 elif files[f].has_key("new"):
944 def do_pkg(changes_file):
945 Upload.pkg.changes_file = changes_file
948 Upload.update_subst()
949 files = Upload.pkg.files
954 (new, byhand) = check_status(files)
960 (new, byhand) = check_status(files)
962 if not new and not byhand:
965 ################################################################################
968 accept_count = Upload.accept_count
969 accept_bytes = Upload.accept_bytes
975 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
976 Logger.log(["total",accept_count,accept_bytes])
978 if not Options["No-Action"]:
981 ################################################################################
983 def do_comments(dir, opref, npref, line, fn):
984 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
985 lines = open("%s/%s" % (dir, comm)).readlines()
986 if len(lines) == 0 or lines[0] != line + "\n": continue
987 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
988 and x.endswith(".changes") ]
989 changes_files = sort_changes(changes_files)
990 for f in changes_files:
991 f = utils.validate_changes_file_arg(f, 0)
994 fn(f, "".join(lines[1:]))
996 if opref != npref and not Options["No-Action"]:
997 newcomm = npref + comm[len(opref):]
998 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
1000 ################################################################################
1002 def comment_accept(changes_file, comments):
1003 Upload.pkg.changes_file = changes_file
1005 Upload.update_vars()
1006 Upload.update_subst()
1007 files = Upload.pkg.files
1010 return # dak wants to REJECT, crap
1012 (new, byhand) = check_status(files)
1013 if not new and not byhand:
1016 ################################################################################
1018 def comment_reject(changes_file, comments):
1019 Upload.pkg.changes_file = changes_file
1021 Upload.update_vars()
1022 Upload.update_subst()
1025 pass # dak has its own reasons to reject as well, which is fine
1028 print "REJECT\n" + reject_message,
1029 if not Options["No-Action"]:
1030 Upload.do_reject(0, reject_message)
1031 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1033 ################################################################################
1036 changes_files = init()
1037 if len(changes_files) > 50:
1038 sys.stderr.write("Sorting changes...\n")
1039 changes_files = sort_changes(changes_files)
1041 # Kill me now? **FIXME**
1042 Cnf["Dinstall::Options::No-Mail"] = ""
1043 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1044 if Cnf.has_key("Dinstall::Bcc"):
1045 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1047 Upload.Subst["__BCC__"] = bcc
1049 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1051 if changes_files != []:
1052 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1054 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1055 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1057 for changes_file in changes_files:
1058 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1059 if not changes_file:
1061 print "\n" + changes_file
1062 do_pkg (changes_file)
1066 ################################################################################
1068 if __name__ == '__main__':