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 ################################################################################
52 import apt_pkg, apt_inst
53 import examine_package
54 from daklib import database
55 from daklib import logging
56 from daklib import queue
57 from daklib import utils
58 from daklib.regexes import re_no_epoch, re_default_answer, re_isanum
59 from daklib.dak_exceptions import CantOpenError, AlreadyLockedError
62 Cnf = None #: Configuration, apt_pkg.Configuration
65 projectB = None #: database connection, pgobject
73 ################################################################################
74 ################################################################################
75 ################################################################################
77 def reject (str, prefix="Rejected: "):
80 reject_message += prefix + str + "\n"
84 files = Upload.pkg.files
87 for f in files.keys():
88 # The .orig.tar.gz can disappear out from under us is it's a
89 # duplicate of one in the archive.
90 if not files.has_key(f):
92 # Check that the source still exists
93 if files[f]["type"] == "deb":
94 source_version = files[f]["source version"]
95 source_package = files[f]["source package"]
96 if not Upload.pkg.changes["architecture"].has_key("source") \
97 and not Upload.source_exists(source_package, source_version, Upload.pkg.changes["distribution"].keys()):
98 source_epochless_version = re_no_epoch.sub('', source_version)
99 dsc_filename = "%s_%s.dsc" % (source_package, source_epochless_version)
101 for q in ["Accepted", "Embargoed", "Unembargoed"]:
102 if Cnf.has_key("Dir::Queue::%s" % (q)):
103 if os.path.exists(Cnf["Dir::Queue::%s" % (q)] + '/' + dsc_filename):
106 reject("no source found for %s %s (%s)." % (source_package, source_version, f))
108 # Version and file overwrite checks
109 if files[f]["type"] == "deb":
110 reject(Upload.check_binary_against_db(f), "")
111 elif files[f]["type"] == "dsc":
112 reject(Upload.check_source_against_db(f), "")
113 (reject_msg, is_in_incoming) = Upload.check_dsc_against_db(f)
114 reject(reject_msg, "")
116 if reject_message.find("Rejected") != -1:
118 if Options["No-Action"] or Options["Automatic"] or Options["Trainee"]:
121 print "REJECT\n" + reject_message,
122 prompt = "[R]eject, Skip, Quit ?"
124 while prompt.find(answer) == -1:
125 answer = utils.our_raw_input(prompt)
126 m = re_default_answer.match(prompt)
129 answer = answer[:1].upper()
132 Upload.do_reject(0, reject_message)
133 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
143 ################################################################################
145 def indiv_sg_compare (a, b):
146 """Sort by source name, source, version, 'have source', and
147 finally by filename."""
148 # Sort by source version
149 q = apt_pkg.VersionCompare(a["version"], b["version"])
153 # Sort by 'have source'
154 a_has_source = a["architecture"].get("source")
155 b_has_source = b["architecture"].get("source")
156 if a_has_source and not b_has_source:
158 elif b_has_source and not a_has_source:
161 return cmp(a["filename"], b["filename"])
163 ############################################################
165 def sg_compare (a, b):
168 """Sort by have note, source already in database and time of oldest upload."""
170 a_note_state = a["note_state"]
171 b_note_state = b["note_state"]
172 if a_note_state < b_note_state:
174 elif a_note_state > b_note_state:
176 # Sort by source already in database (descending)
177 source_in_database = cmp(a["source_in_database"], b["source_in_database"])
178 if source_in_database:
179 return -source_in_database
181 # Sort by time of oldest upload
182 return cmp(a["oldest"], b["oldest"])
184 def sort_changes(changes_files):
185 """Sort into source groups, then sort each source group by version,
186 have source, filename. Finally, sort the source groups by have
187 note, time of oldest upload of each source upload."""
188 if len(changes_files) == 1:
193 # Read in all the .changes files
194 for filename in changes_files:
196 Upload.pkg.changes_file = filename
199 cache[filename] = copy.copy(Upload.pkg.changes)
200 cache[filename]["filename"] = filename
202 sorted_list.append(filename)
204 # Divide the .changes into per-source groups
206 for filename in cache.keys():
207 source = cache[filename]["source"]
208 if not per_source.has_key(source):
209 per_source[source] = {}
210 per_source[source]["list"] = []
211 per_source[source]["list"].append(cache[filename])
212 # Determine oldest time and have note status for each source group
213 for source in per_source.keys():
214 q = projectB.query("SELECT 1 FROM source WHERE source = '%s'" % source)
216 per_source[source]["source_in_database"] = len(ql)>0
217 source_list = per_source[source]["list"]
218 first = source_list[0]
219 oldest = os.stat(first["filename"])[stat.ST_MTIME]
221 for d in per_source[source]["list"]:
222 mtime = os.stat(d["filename"])[stat.ST_MTIME]
225 have_note += (database.has_new_comment(d["source"], d["version"]))
226 per_source[source]["oldest"] = oldest
228 per_source[source]["note_state"] = 0; # none
229 elif have_note < len(source_list):
230 per_source[source]["note_state"] = 1; # some
232 per_source[source]["note_state"] = 2; # all
233 per_source[source]["list"].sort(indiv_sg_compare)
234 per_source_items = per_source.items()
235 per_source_items.sort(sg_compare)
236 for i in per_source_items:
237 for j in i[1]["list"]:
238 sorted_list.append(j["filename"])
241 ################################################################################
243 class Section_Completer:
247 q = projectB.query("SELECT section FROM section")
248 for i in q.getresult():
249 self.sections.append(i[0])
251 def complete(self, text, state):
255 for word in self.sections:
257 self.matches.append(word)
259 return self.matches[state]
263 ############################################################
265 class Priority_Completer:
269 q = projectB.query("SELECT priority FROM priority")
270 for i in q.getresult():
271 self.priorities.append(i[0])
273 def complete(self, text, state):
277 for word in self.priorities:
279 self.matches.append(word)
281 return self.matches[state]
285 ################################################################################
287 def print_new (new, indexed, file=sys.stdout):
288 queue.check_valid(new)
291 for pkg in new.keys():
293 section = new[pkg]["section"]
294 priority = new[pkg]["priority"]
295 if new[pkg]["section id"] == -1:
298 if new[pkg]["priority id"] == -1:
302 line = "(%s): %-20s %-20s %-20s" % (index, pkg, priority, section)
304 line = "%-20s %-20s %-20s" % (pkg, priority, section)
305 line = line.strip()+'\n'
307 note = database.get_new_comments(Upload.pkg.changes.get("source"))
313 ################################################################################
315 def index_range (index):
319 return "1-%s" % (index)
321 ################################################################################
322 ################################################################################
325 # Write the current data to a temporary file
326 (fd, temp_filename) = utils.temp_filename()
327 temp_file = os.fdopen(fd, 'w')
328 print_new (new, 0, temp_file)
330 # Spawn an editor on that file
331 editor = os.environ.get("EDITOR","vi")
332 result = os.system("%s %s" % (editor, temp_filename))
334 utils.fubar ("%s invocation failed for %s." % (editor, temp_filename), result)
335 # Read the edited data back in
336 temp_file = utils.open_file(temp_filename)
337 lines = temp_file.readlines()
339 os.unlink(temp_filename)
346 # Pad the list if necessary
347 s[len(s):3] = [None] * (3-len(s))
348 (pkg, priority, section) = s[:3]
349 if not new.has_key(pkg):
350 utils.warn("Ignoring unknown package '%s'" % (pkg))
352 # Strip off any invalid markers, print_new will readd them.
353 if section.endswith("[!]"):
354 section = section[:-3]
355 if priority.endswith("[!]"):
356 priority = priority[:-3]
357 for f in new[pkg]["files"]:
358 Upload.pkg.files[f]["section"] = section
359 Upload.pkg.files[f]["priority"] = priority
360 new[pkg]["section"] = section
361 new[pkg]["priority"] = priority
363 ################################################################################
365 def edit_index (new, index):
366 priority = new[index]["priority"]
367 section = new[index]["section"]
368 ftype = new[index]["type"]
371 print "\t".join([index, priority, section])
375 prompt = "[B]oth, Priority, Section, Done ? "
377 prompt = "[S]ection, Done ? "
378 edit_priority = edit_section = 0
380 while prompt.find(answer) == -1:
381 answer = utils.our_raw_input(prompt)
382 m = re_default_answer.match(prompt)
385 answer = answer[:1].upper()
392 edit_priority = edit_section = 1
398 readline.set_completer(Priorities.complete)
400 while not got_priority:
401 new_priority = utils.our_raw_input("New priority: ").strip()
402 if new_priority not in Priorities.priorities:
403 print "E: '%s' is not a valid priority, try again." % (new_priority)
406 priority = new_priority
410 readline.set_completer(Sections.complete)
412 while not got_section:
413 new_section = utils.our_raw_input("New section: ").strip()
414 if new_section not in Sections.sections:
415 print "E: '%s' is not a valid section, try again." % (new_section)
418 section = new_section
420 # Reset the readline completer
421 readline.set_completer(None)
423 for f in new[index]["files"]:
424 Upload.pkg.files[f]["section"] = section
425 Upload.pkg.files[f]["priority"] = priority
426 new[index]["priority"] = priority
427 new[index]["section"] = section
430 ################################################################################
432 def edit_overrides (new):
443 prompt = "(%s) edit override <n>, Editor, Done ? " % (index_range(index))
446 while not got_answer:
447 answer = utils.our_raw_input(prompt)
448 if not answer.isdigit():
449 answer = answer[:1].upper()
450 if answer == "E" or answer == "D":
452 elif re_isanum.match (answer):
454 if (answer < 1) or (answer > index):
455 print "%s is not a valid index (%s). Please retry." % (answer, index_range(index))
464 edit_index (new, new_index[answer])
468 ################################################################################
471 # Write the current data to a temporary file
472 (fd, temp_filename) = utils.temp_filename()
473 editor = os.environ.get("EDITOR","vi")
476 os.system("%s %s" % (editor, temp_filename))
477 temp_file = utils.open_file(temp_filename)
478 newnote = temp_file.read().rstrip()
481 print utils.prefix_multi_line_string(newnote," ")
482 prompt = "[D]one, Edit, Abandon, Quit ?"
484 while prompt.find(answer) == -1:
485 answer = utils.our_raw_input(prompt)
486 m = re_default_answer.search(prompt)
489 answer = answer[:1].upper()
490 os.unlink(temp_filename)
496 database.add_new_comment(Upload.pkg.changes["source"], Upload.pkg.changes["version"], newnote, utils.whoami())
498 ################################################################################
502 less_fd = os.popen("less -R -", 'w', 0)
503 stdout_fd = sys.stdout
506 changes = utils.parse_changes (Upload.pkg.changes_file)
507 examine_package.display_changes(changes['distribution'], Upload.pkg.changes_file)
508 files = Upload.pkg.files
509 for f in files.keys():
510 if files[f].has_key("new"):
511 ftype = files[f]["type"]
513 examine_package.check_deb(changes['distribution'], f)
515 examine_package.check_dsc(changes['distribution'], f)
517 examine_package.output_package_relations()
518 sys.stdout = stdout_fd
520 if e.errno == errno.EPIPE:
521 utils.warn("[examine_package] Caught EPIPE; skipping.")
525 except KeyboardInterrupt:
526 utils.warn("[examine_package] Caught C-c; skipping.")
529 ################################################################################
531 ## FIXME: horribly Debian specific
533 def do_bxa_notification():
534 files = Upload.pkg.files
536 for f in files.keys():
537 if files[f]["type"] == "deb":
538 control = apt_pkg.ParseSection(apt_inst.debExtractControl(utils.open_file(f)))
540 summary += "Package: %s\n" % (control.Find("Package"))
541 summary += "Description: %s\n" % (control.Find("Description"))
542 Upload.Subst["__BINARY_DESCRIPTIONS__"] = summary
543 bxa_mail = utils.TemplateSubst(Upload.Subst,Cnf["Dir::Templates"]+"/process-new.bxa_notification")
544 utils.send_mail(bxa_mail)
546 ################################################################################
548 def add_overrides (new):
549 changes = Upload.pkg.changes
550 files = Upload.pkg.files
552 projectB.query("BEGIN WORK")
553 for suite in changes["suite"].keys():
554 suite_id = database.get_suite_id(suite)
555 for pkg in new.keys():
556 component_id = database.get_component_id(new[pkg]["component"])
557 type_id = database.get_override_type_id(new[pkg]["type"])
558 priority_id = new[pkg]["priority id"]
559 section_id = new[pkg]["section id"]
560 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))
561 for f in new[pkg]["files"]:
562 if files[f].has_key("new"):
566 projectB.query("COMMIT WORK")
568 if Cnf.FindB("Dinstall::BXANotify"):
569 do_bxa_notification()
571 ################################################################################
573 def prod_maintainer (note):
574 # Here we prepare an editor and get them ready to prod...
575 (fd, temp_filename) = utils.temp_filename()
576 temp_file = os.fdopen(fd, 'w')
579 temp_file.write(line)
581 editor = os.environ.get("EDITOR","vi")
584 os.system("%s %s" % (editor, temp_filename))
585 temp_fh = utils.open_file(temp_filename)
586 prod_message = "".join(temp_fh.readlines())
588 print "Prod message:"
589 print utils.prefix_multi_line_string(prod_message," ",include_blank_lines=1)
590 prompt = "[P]rod, Edit, Abandon, Quit ?"
592 while prompt.find(answer) == -1:
593 answer = utils.our_raw_input(prompt)
594 m = re_default_answer.search(prompt)
597 answer = answer[:1].upper()
598 os.unlink(temp_filename)
604 # Otherwise, do the proding...
605 user_email_address = utils.whoami() + " <%s>" % (
606 Cnf["Dinstall::MyAdminAddress"])
610 Subst["__FROM_ADDRESS__"] = user_email_address
611 Subst["__PROD_MESSAGE__"] = prod_message
612 Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
614 prod_mail_message = utils.TemplateSubst(
615 Subst,Cnf["Dir::Templates"]+"/process-new.prod")
617 # Send the prod mail if appropriate
618 if not Cnf["Dinstall::Options::No-Mail"]:
619 utils.send_mail(prod_mail_message)
621 print "Sent proding message"
623 ################################################################################
627 files = Upload.pkg.files
628 changes = Upload.pkg.changes
630 # Make a copy of distribution we can happily trample on
631 changes["suite"] = copy.copy(changes["distribution"])
633 # Fix up the list of target suites
634 for suite in changes["suite"].keys():
635 override = Cnf.Find("Suite::%s::OverrideSuite" % (suite))
637 (olderr, newerr) = (database.get_suite_id(suite) == -1,
638 database.get_suite_id(override) == -1)
640 (oinv, newinv) = ("", "")
641 if olderr: oinv = "invalid "
642 if newerr: ninv = "invalid "
643 print "warning: overriding %ssuite %s to %ssuite %s" % (
644 oinv, suite, ninv, override)
645 del changes["suite"][suite]
646 changes["suite"][override] = 1
648 for suite in changes["suite"].keys():
649 suite_id = database.get_suite_id(suite)
651 utils.fubar("%s has invalid suite '%s' (possibly overriden). say wha?" % (changes, suite))
653 # The main NEW processing loop
656 # Find out what's new
657 new = queue.determine_new(changes, files, projectB)
663 if Options["No-Action"] or Options["Automatic"]:
666 (broken, note) = print_new(new, 0)
669 if not broken and not note:
670 prompt = "Add overrides, "
672 print "W: [!] marked entries must be fixed before package can be processed."
674 print "W: note must be removed before package can be processed."
675 prompt += "Remove note, "
677 prompt += "Edit overrides, Check, Manual reject, Note edit, Prod, [S]kip, Quit ?"
679 while prompt.find(answer) == -1:
680 answer = utils.our_raw_input(prompt)
681 m = re_default_answer.search(prompt)
684 answer = answer[:1].upper()
686 if answer == 'A' and not Options["Trainee"]:
687 done = add_overrides (new)
690 elif answer == 'E' and not Options["Trainee"]:
691 new = edit_overrides (new)
692 elif answer == 'M' and not Options["Trainee"]:
693 aborted = Upload.do_reject(manual=1,
694 reject_message=Options["Manual-Reject"],
695 note=database.get_new_comments(changes.get("source", "")))
697 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
700 edit_note(database.get_new_comments(changes.get("source", "")))
701 elif answer == 'P' and not Options["Trainee"]:
702 prod_maintainer(database.get_new_comments(changes.get("source", "")))
704 confirm = utils.our_raw_input("Really clear note (y/N)? ").lower()
706 database.delete_new_comments(changes.get("source"), changes.get("version"))
713 ################################################################################
714 ################################################################################
715 ################################################################################
717 def usage (exit_code=0):
718 print """Usage: dak process-new [OPTION]... [CHANGES]...
719 -a, --automatic automatic run
720 -h, --help show this help and exit.
721 -C, --comments-dir=DIR use DIR as comments-dir, for [o-]p-u-new
722 -m, --manual-reject=MSG manual reject with `msg'
723 -n, --no-action don't do anything
724 -t, --trainee FTP Trainee mode
725 -V, --version display the version number and exit"""
728 ################################################################################
731 global Cnf, Options, Logger, Upload, projectB, Sections, Priorities
733 Cnf = utils.get_conf()
735 Arguments = [('a',"automatic","Process-New::Options::Automatic"),
736 ('h',"help","Process-New::Options::Help"),
737 ('C',"comments-dir","Process-New::Options::Comments-Dir", "HasArg"),
738 ('m',"manual-reject","Process-New::Options::Manual-Reject", "HasArg"),
739 ('t',"trainee","Process-New::Options::Trainee"),
740 ('n',"no-action","Process-New::Options::No-Action")]
742 for i in ["automatic", "help", "manual-reject", "no-action", "version", "comments-dir", "trainee"]:
743 if not Cnf.has_key("Process-New::Options::%s" % (i)):
744 Cnf["Process-New::Options::%s" % (i)] = ""
746 changes_files = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
747 if len(changes_files) == 0 and not Cnf.get("Process-New::Options::Comments-Dir",""):
748 changes_files = utils.get_changes_files(Cnf["Dir::Queue::New"])
750 Options = Cnf.SubTree("Process-New::Options")
755 Upload = queue.Upload(Cnf)
757 if not Options["No-Action"]:
759 Logger = Upload.Logger = logging.Logger(Cnf, "process-new")
760 except CantOpenError, e:
761 Options["Trainee"] = "Oh yes"
763 projectB = Upload.projectB
765 Sections = Section_Completer()
766 Priorities = Priority_Completer()
767 readline.parse_and_bind("tab: complete")
771 ################################################################################
776 files = Upload.pkg.files
780 for f in files.keys():
781 if files[f]["type"] == "byhand":
782 if os.path.exists(f):
783 print "W: %s still present; please process byhand components and try again." % (f)
789 if Options["No-Action"]:
792 if Options["Automatic"] and not Options["No-Action"]:
794 prompt = "[A]ccept, Manual reject, Skip, Quit ?"
796 prompt = "Manual reject, [S]kip, Quit ?"
798 while prompt.find(answer) == -1:
799 answer = utils.our_raw_input(prompt)
800 m = re_default_answer.search(prompt)
803 answer = answer[:1].upper()
810 Upload.do_reject(1, Options["Manual-Reject"])
811 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
819 ################################################################################
821 def get_accept_lock():
825 os.open(Cnf["Process-New::AcceptedLockFile"], os.O_RDONLY | os.O_CREAT | os.O_EXCL)
828 if e.errno == errno.EACCES or e.errno == errno.EEXIST:
831 utils.fubar("Couldn't obtain lock; assuming 'dak process-unchecked' is already running.")
833 print("Unable to get accepted lock (try %d of 10)" % retry)
839 @contextlib.contextmanager
840 def lock_package(package):
842 Lock C{package} so that noone else jumps in processing it.
844 @type package: string
845 @param package: source package name to lock
848 path = os.path.join(Cnf["Process-New::LockDir"], package)
850 fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDONLY)
852 if e.errno == errno.EEXIST or e.errno == errno.EACCES:
853 raise AlreadyLockedError, e.errno
860 def move_to_dir (dest, perms=0660, changesperms=0664):
861 utils.move (Upload.pkg.changes_file, dest, perms=changesperms)
862 file_keys = Upload.pkg.files.keys()
864 utils.move (f, dest, perms=perms)
866 def is_source_in_queue_dir(qdir):
867 entries = [ x for x in os.listdir(qdir) if x.startswith(Upload.pkg.changes["source"])
868 and x.endswith(".changes") ]
869 for entry in entries:
871 u = queue.Upload(Cnf)
872 u.pkg.changes_file = os.path.join(qdir, entry)
874 if not u.pkg.changes["architecture"].has_key("source"):
875 # another binary upload, ignore
877 if Upload.pkg.changes["version"] != u.pkg.changes["version"]:
878 # another version, ignore
884 def move_to_holding(suite, queue_dir):
885 print "Moving to %s holding area." % (suite.upper(),)
886 if Options["No-Action"]:
888 Logger.log(["Moving to %s" % (suite,), Upload.pkg.changes_file])
889 Upload.dump_vars(queue_dir)
890 move_to_dir(queue_dir, perms=0664)
891 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
894 if Options["No-Action"]:
896 (summary, short_summary) = Upload.build_summaries()
897 Upload.accept(summary, short_summary)
898 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
900 def do_accept_stableupdate(suite, q):
901 queue_dir = Cnf["Dir::Queue::%s" % (q,)]
902 if not Upload.pkg.changes["architecture"].has_key("source"):
903 # It is not a sourceful upload. So its source may be either in p-u
904 # holding, in new, in accepted or already installed.
905 if is_source_in_queue_dir(queue_dir):
906 # It's in p-u holding, so move it there.
907 print "Binary-only upload, source in %s." % (q,)
908 move_to_holding(suite, queue_dir)
909 elif Upload.source_exists(Upload.pkg.changes["source"],
910 Upload.pkg.changes["version"]):
911 # dak tells us that there is source available. At time of
912 # writing this means that it is installed, so put it into
914 print "Binary-only upload, source installed."
916 elif is_source_in_queue_dir(Cnf["Dir::Queue::Accepted"]):
917 # The source is in accepted, the binary cleared NEW: accept it.
918 print "Binary-only upload, source in accepted."
920 elif is_source_in_queue_dir(Cnf["Dir::Queue::New"]):
921 # It's in NEW. We expect the source to land in p-u holding
923 print "Binary-only upload, source in new."
924 move_to_holding(suite, queue_dir)
926 # No case applicable. Bail out. Return will cause the upload
929 print "Stable update failed. Source not found."
932 # We are handling a sourceful upload. Move to accepted if currently
933 # in p-u holding and to p-u holding otherwise.
934 if is_source_in_queue_dir(queue_dir):
935 print "Sourceful upload in %s, accepting." % (q,)
938 move_to_holding(suite, queue_dir)
942 if not Options["No-Action"]:
944 (summary, short_summary) = Upload.build_summaries()
946 if Cnf.FindB("Dinstall::SecurityQueueHandling"):
947 Upload.dump_vars(Cnf["Dir::Queue::Embargoed"])
948 move_to_dir(Cnf["Dir::Queue::Embargoed"])
949 Upload.queue_build("embargoed", Cnf["Dir::Queue::Embargoed"])
950 # Check for override disparities
951 Upload.Subst["__SUMMARY__"] = summary
953 # Stable updates need to be copied to proposed-updates holding
954 # area instead of accepted. Sourceful uploads need to go
955 # to it directly, binaries only if the source has not yet been
957 for suite, q in [("proposed-updates", "ProposedUpdates"),
958 ("oldstable-proposed-updates", "OldProposedUpdates")]:
959 if not Upload.pkg.changes["distribution"].has_key(suite):
961 return do_accept_stableupdate(suite, q)
962 # Just a normal upload, accept it...
965 if not Options["No-Action"]:
966 os.unlink(Cnf["Process-New::AcceptedLockFile"])
968 def check_status(files):
970 for f in files.keys():
971 if files[f]["type"] == "byhand":
973 elif files[f].has_key("new"):
977 def do_pkg(changes_file):
978 Upload.pkg.changes_file = changes_file
981 Upload.update_subst()
982 files = Upload.pkg.files
985 with lock_package(Upload.pkg.changes["source"]):
989 (new, byhand) = check_status(files)
995 (new, byhand) = check_status(files)
997 if not new and not byhand:
999 except AlreadyLockedError, e:
1000 print "Seems to be locked already, skipping..."
1002 ################################################################################
1005 accept_count = Upload.accept_count
1006 accept_bytes = Upload.accept_bytes
1010 if accept_count > 1:
1012 sys.stderr.write("Accepted %d package %s, %s.\n" % (accept_count, sets, utils.size_type(int(accept_bytes))))
1013 Logger.log(["total",accept_count,accept_bytes])
1015 if not Options["No-Action"] and not Options["Trainee"]:
1018 ################################################################################
1020 def do_comments(dir, opref, npref, line, fn):
1021 for comm in [ x for x in os.listdir(dir) if x.startswith(opref) ]:
1022 lines = open("%s/%s" % (dir, comm)).readlines()
1023 if len(lines) == 0 or lines[0] != line + "\n": continue
1024 changes_files = [ x for x in os.listdir(".") if x.startswith(comm[7:]+"_")
1025 and x.endswith(".changes") ]
1026 changes_files = sort_changes(changes_files)
1027 for f in changes_files:
1028 f = utils.validate_changes_file_arg(f, 0)
1031 fn(f, "".join(lines[1:]))
1033 if opref != npref and not Options["No-Action"]:
1034 newcomm = npref + comm[len(opref):]
1035 os.rename("%s/%s" % (dir, comm), "%s/%s" % (dir, newcomm))
1037 ################################################################################
1039 def comment_accept(changes_file, comments):
1040 Upload.pkg.changes_file = changes_file
1042 Upload.update_vars()
1043 Upload.update_subst()
1044 files = Upload.pkg.files
1047 return # dak wants to REJECT, crap
1049 (new, byhand) = check_status(files)
1050 if not new and not byhand:
1053 ################################################################################
1055 def comment_reject(changes_file, comments):
1056 Upload.pkg.changes_file = changes_file
1058 Upload.update_vars()
1059 Upload.update_subst()
1062 pass # dak has its own reasons to reject as well, which is fine
1065 print "REJECT\n" + reject_message,
1066 if not Options["No-Action"]:
1067 Upload.do_reject(0, reject_message)
1068 os.unlink(Upload.pkg.changes_file[:-8]+".dak")
1070 ################################################################################
1073 changes_files = init()
1074 if len(changes_files) > 50:
1075 sys.stderr.write("Sorting changes...\n")
1076 changes_files = sort_changes(changes_files)
1078 # Kill me now? **FIXME**
1079 Cnf["Dinstall::Options::No-Mail"] = ""
1080 bcc = "X-DAK: dak process-new\nX-Katie: lisa $Revision: 1.31 $"
1081 if Cnf.has_key("Dinstall::Bcc"):
1082 Upload.Subst["__BCC__"] = bcc + "\nBcc: %s" % (Cnf["Dinstall::Bcc"])
1084 Upload.Subst["__BCC__"] = bcc
1086 commentsdir = Cnf.get("Process-New::Options::Comments-Dir","")
1088 if changes_files != []:
1089 sys.stderr.write("Can't specify any changes files if working with comments-dir")
1091 do_comments(commentsdir, "ACCEPT.", "ACCEPTED.", "OK", comment_accept)
1092 do_comments(commentsdir, "REJECT.", "REJECTED.", "NOTOK", comment_reject)
1094 for changes_file in changes_files:
1095 changes_file = utils.validate_changes_file_arg(changes_file, 0)
1096 if not changes_file:
1098 print "\n" + changes_file
1099 do_pkg (changes_file)
1103 ################################################################################
1105 if __name__ == '__main__':