From: Fabian Groffen Date: Fri, 18 Jul 2008 09:02:11 +0000 (-0000) Subject: Merged from trunk 11111:11124 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=c3a3e4692aaf96818d6f9684f659c73fc515ebd1;p=portage.git Merged from trunk 11111:11124 | 11112 | Since it's not very interesting, disable the "merges" part | | zmedico | of status display. | | 11113 | Also, don't count "merges" as changes in the status display. | | zmedico | | | 11114 | Initialize JobStatusDisplay.merges since it's not | | zmedico | initialized with the bound properties anymore. | | 11115 | Also, reset "merges" in JobStatusDisplay.reset(). | | zmedico | | | 11116 | When dblink is looping over files for merge/unmerge, | | zmedico | temporarily yield to the scheduler each time a fixed number | | | of files are processed (currently 20). This gives the | | | scheduler an opportunity to service pending poll events. | | | This is implemented with a new | | | PollScheduler._schedule_yield() method which calls poll() | | | exactly once, without blocking, and any services any | | | resulting poll events. | | 11117 | Redirect dblink elog messages from stdout to the log file | | zmedico | when in background mode. This is implemented by adding a new | | | "out" parameter to the portage.elog.e* functions, which can | | | be used to send output to an arbitary file instead of | | | stdout. | | 11118 | If an problem is detected in dblink._security_check(), log | | zmedico | it via elog so that it's properly displayed in the | | | foreground even when in background mode. | | 11119 | Use dblink._eerror() to eliminate duplicate code. | | zmedico | | | 11120 | In dblink._dblink_display_merge(), when in background mode | | zmedico | and no log is available, suppress output when level < | | | logging.WARNING. This hides ">>> Regenerating | | | /etc/ld.so.cache..." messages that appear after postrm when | | | PORT_LOGDIR is unset (the log file if it exists is removed | | | after postrm so there's no place to log the message). | | 11121 | Change package status messages to give more accurate | | zmedico | information about what is happening at a given time: * | | | Change "Emerging" messages to "Building" for ebuilds and | | | "Extracting" for binary packages. * Change "Merging" | | | messages to "Installing" and "Uninstalling". | | 11122 | Add background output redirection and async ebuild phase | | zmedico | support for PackageUninstall (automatic uninstalls that | | | solve blockers). | | 11123 | Suppress counter initialization warning messages in | | zmedico | vardbapi.get_counter_tick_core() in cases when the vdb is | | | empty. This avoids pointless error messages when merging | | | packages into a new root, like when building stage 1. | | 11124 | Fix typo. | | zmedico | | svn path=/main/branches/prefix/; revision=11125 --- diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index e9947fc42..a98754124 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -2864,25 +2864,41 @@ class EbuildMerge(SlotObject): logger.log(" ::: completed emerge (%s of %s) %s to %s" % \ (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root)) -class PackageUninstall(Task): +class PackageUninstall(AsynchronousTask): - __hash__ = Task.__hash__ - __slots__ = ("ldpath_mtimes", "opts", "pkg", "settings") - - def _get_hash_key(self): - hash_key = getattr(self, "_hash_key", None) - if hash_key is None: - self._hash_key = ("PackageUninstall", self.pkg._get_hash_key()) - return self._hash_key + __slots__ = ("ldpath_mtimes", "opts", "pkg", "scheduler", "settings") - def execute(self): + def _start(self): try: unmerge(self.pkg.root_config, self.opts, "unmerge", [self.pkg.cpv], self.ldpath_mtimes, clean_world=0, - raise_on_error=1) + clean_delay=0, raise_on_error=1, scheduler=self.scheduler, + writemsg_level=self._writemsg_level) except UninstallFailure, e: - return e.status - return os.EX_OK + self.returncode = e.status + else: + self.returncode = os.EX_OK + self.wait() + + def _writemsg_level(self, msg, level=0, noiselevel=0): + + log_path = self.settings.get("PORTAGE_LOG_FILE") + background = self.background + + if log_path is None: + if not (background and level < logging.WARNING): + portage.util.writemsg_level(msg, + level=level, noiselevel=noiselevel) + else: + if not background: + portage.util.writemsg_level(msg, + level=level, noiselevel=noiselevel) + + f = open(log_path, 'a') + try: + f.write(msg) + finally: + f.close() class Binpkg(CompositeTask): @@ -3363,15 +3379,22 @@ class MergeListItem(CompositeTask): world_atom = self.world_atom ldpath_mtimes = mtimedb["ldpath"] + action_desc = "Building" + preposition = "for" + if pkg.type_name == "binary": + action_desc = "Extracting" + if not build_opts.pretend: extra_newline = "\n" if self.background: extra_newline = "" portage.writemsg_stdout( - extra_newline + ">>> Emerging (%s of %s) %s to %s\n" % \ - (colorize("MERGE_LIST_PROGRESS", str(pkg_count.curval)), + "%s>>> %s (%s of %s) %s %s %s\n" % \ + (extra_newline, action_desc, + colorize("MERGE_LIST_PROGRESS", str(pkg_count.curval)), colorize("MERGE_LIST_PROGRESS", str(pkg_count.maxval)), - colorize("GOOD", pkg.cpv), pkg.root), noiselevel=-1) + colorize("GOOD", pkg.cpv), preposition, pkg.root), + noiselevel=-1) logger.log(" >>> emerge (%s of %s) %s to %s" % \ (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root)) @@ -3435,10 +3458,12 @@ class MergeListItem(CompositeTask): if not (build_opts.buildpkgonly or \ build_opts.fetchonly or build_opts.pretend): - uninstall = PackageUninstall(ldpath_mtimes=ldpath_mtimes, - opts=self.emerge_opts, pkg=pkg, settings=settings) + uninstall = PackageUninstall(background=self.background, + ldpath_mtimes=ldpath_mtimes, opts=self.emerge_opts, + pkg=pkg, scheduler=scheduler, settings=settings) - retval = uninstall.execute() + uninstall.start() + retval = uninstall.wait() if retval != os.EX_OK: return retval return os.EX_OK @@ -3459,6 +3484,30 @@ class PackageMerge(AsynchronousTask): __slots__ = ("merge",) def _start(self): + + pkg = self.merge.pkg + pkg_count = self.merge.pkg_count + + if pkg.installed: + + action_desc = "Uninstalling" + preposition = "from" + + portage.writemsg_stdout( + ">>> %s %s %s %s\n" % \ + (action_desc, colorize("GOOD", pkg.cpv), + preposition, pkg.root), noiselevel=-1) + + else: + + action_desc = "Installing" + preposition = "to" + + portage.writemsg_stdout( + ">>> %s %s %s %s\n" % \ + (action_desc, colorize("GOOD", pkg.cpv), + preposition, pkg.root), noiselevel=-1) + self.returncode = self.merge.merge() self.wait() @@ -7999,7 +8048,19 @@ class PollSelectAdapter(PollConstants): if timeout is not None: select_args = select_args[:] - select_args.append(timeout) + # Translate poll() timeout args to select() timeout args: + # + # | units | value(s) for indefinite block + # ---------|--------------|------------------------------ + # poll | milliseconds | omitted, negative, or None + # ---------|--------------|------------------------------ + # select | seconds | omitted + # ---------|--------------|------------------------------ + + if timeout is not None and timeout < 0: + timeout = None + if timeout is not None: + select_args.append(timeout / 1000) select_events = select.select(*select_args) poll_events = [] @@ -8186,7 +8247,7 @@ class PollScheduler(object): return True - def _next_poll_event(self): + def _next_poll_event(self, timeout=None): """ Since the _schedule_wait() loop is called by event handlers from _poll_loop(), maintain a central event @@ -8194,7 +8255,7 @@ class PollScheduler(object): poll() call. """ if not self._poll_event_queue: - self._poll_event_queue.extend(self._poll.poll()) + self._poll_event_queue.extend(self._poll.poll(timeout)) return self._poll_event_queue.pop() def _poll_loop(self): @@ -8211,6 +8272,31 @@ class PollScheduler(object): if not event_handled: raise AssertionError("tight loop") + def _schedule_yield(self): + """ + Schedule for a short period of time chosen by the scheduler based + on internal state. Synchronous tasks should call this periodically + in order to allow the scheduler to service pending poll events. The + scheduler will call poll() exactly once, without blocking, and any + resulting poll events will be serviced. + """ + event_handlers = self._poll_event_handlers + events_handled = 0 + + if not event_handlers: + return bool(events_handled) + + if not self._poll_event_queue: + self._poll_event_queue.extend(self._poll.poll(0)) + + while event_handlers and self._poll_event_queue: + f, event = self._next_poll_event() + handler, reg_id = event_handlers[f] + handler(f, event) + events_handled += 1 + + return bool(events_handled) + def _register(self, f, eventmask, handler): """ @rtype: Integer @@ -8352,17 +8438,19 @@ class TaskScheduler(object): class JobStatusDisplay(object): - _bound_properties = ("curval", "merges", "running") + _bound_properties = ("curval", "running") _jobs_column_width = 45 def __init__(self, quiet=False): object.__setattr__(self, "quiet", quiet) object.__setattr__(self, "maxval", 0) + object.__setattr__(self, "merges", 0) object.__setattr__(self, "_changed", False) self.reset() def reset(self): self.maxval = 0 + self.merges = 0 for name in self._bound_properties: object.__setattr__(self, name, 0) @@ -8430,7 +8518,8 @@ class JobStatusDisplay(object): f.pop_style() f.add_literal_data(" running") - if self.merges: + #if self.merges: + if False: f.add_literal_data(", ") f.push_style(number_style) f.add_literal_data(merges_str) @@ -8466,8 +8555,9 @@ class Scheduler(PollScheduler): _fetch_log = EPREFIX + "/var/log/emerge-fetch.log" class _iface_class(SlotObject): - __slots__ = ("dblinkEbuildPhase", "dblinkDisplayMerge", "fetch", - "register", "schedule", "unregister") + __slots__ = ("dblinkEbuildPhase", "dblinkDisplayMerge", + "dblinkElog", "fetch", "register", "schedule", + "scheduleYield", "unregister") class _fetch_iface_class(SlotObject): __slots__ = ("log_file", "schedule") @@ -8535,8 +8625,10 @@ class Scheduler(PollScheduler): self._sched_iface = self._iface_class( dblinkEbuildPhase=self._dblink_ebuild_phase, dblinkDisplayMerge=self._dblink_display_merge, + dblinkElog=self._dblink_elog, fetch=fetch_iface, register=self._register, - schedule=self._schedule_wait, unregister=self._unregister) + schedule=self._schedule_wait, scheduleYield=self._schedule_yield, + unregister=self._unregister) self._task_queues = self._task_queues_class() for k in self._task_queues.allowed_keys: @@ -8728,13 +8820,32 @@ class Scheduler(PollScheduler): finally: f.close() + def _dblink_elog(self, pkg_dblink, phase, func, msgs): + + log_path = pkg_dblink.settings.get("PORTAGE_LOG_FILE") + log_file = None + out = sys.stdout + background = self._max_jobs > 1 + + if background and log_path is not None: + log_file = open(log_path, 'a') + out = log_file + + try: + for msg in msgs: + func(msg, phase=phase, key=pkg_dblink.mycpv, out=out) + finally: + if log_file is not None: + log_file.close() + def _dblink_display_merge(self, pkg_dblink, msg, level=0, noiselevel=0): log_path = pkg_dblink.settings.get("PORTAGE_LOG_FILE") background = self._max_jobs > 1 if log_path is None: - portage.util.writemsg_level(msg, - level=level, noiselevel=noiselevel) + if not (background and level < logging.WARN): + portage.util.writemsg_level(msg, + level=level, noiselevel=noiselevel) else: if not background: portage.util.writemsg_level(msg, @@ -8755,27 +8866,12 @@ class Scheduler(PollScheduler): background = self._max_jobs > 1 log_path = settings.get("PORTAGE_LOG_FILE") - if phase == "preinst": - msg = ">>> Merging %s to %s\n" % (pkg.cpv, pkg.root) - if not background: - portage.writemsg_stdout(msg) - if log_path is not None: - self._append_to_log_path(log_path, msg) - ebuild_phase = EbuildPhase(background=background, pkg=pkg, phase=phase, scheduler=scheduler, settings=settings, tree=pkg_dblink.treetype) ebuild_phase.start() ebuild_phase.wait() - if phase == "postinst" and \ - ebuild_phase.returncode == os.EX_OK: - msg = ">>> %s %s\n" % (pkg.cpv, "merged.") - if not background: - portage.writemsg_stdout(msg) - if log_path is not None: - self._append_to_log_path(log_path, msg) - return ebuild_phase.returncode def _check_manifests(self): @@ -9568,7 +9664,10 @@ class UninstallFailure(portage.exception.PortageException): def unmerge(root_config, myopts, unmerge_action, unmerge_files, ldpath_mtimes, autoclean=0, - clean_world=1, ordered=0, raise_on_error=0): + clean_world=1, clean_delay=1, ordered=0, raise_on_error=0, + scheduler=None, writemsg_level=portage.util.writemsg_level): + + quiet = "--quiet" in myopts settings = root_config.settings sets = root_config.sets vartree = root_config.trees["vartree"] @@ -9925,18 +10024,22 @@ def unmerge(root_config, myopts, unmerge_action, #avoid cluttering the preview printout with stuff that isn't getting unmerged continue if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and cp in syslist: - print colorize("BAD","\a\n\n!!! '%s' is part of your system profile." % cp) - print colorize("WARN","\a!!! Unmerging it may be damaging to your system.\n") - if "--pretend" not in myopts and "--ask" not in myopts: + writemsg_level(colorize("BAD","\a\n\n!!! " + \ + "'%s' is part of your system profile.\n" % cp), + level=logging.WARNING, noiselevel=-1) + writemsg_level(colorize("WARN","\a!!! Unmerging it may " + \ + "be damaging to your system.\n\n"), + level=logging.WARNING, noiselevel=-1) + if clean_delay and "--pretend" not in myopts and "--ask" not in myopts: countdown(int(settings["EMERGE_WARNING_DELAY"]), colorize("UNMERGE_WARN", "Press Ctrl-C to Stop")) - if "--quiet" not in myopts: - print "\n "+bold(cp) + if not quiet: + writemsg_level("\n %s\n" % (bold(cp),), noiselevel=-1) else: - print bold(cp)+": ", + writemsg_level(bold(cp) + ": ", noiselevel=-1) for mytype in ["selected","protected","omitted"]: - if "--quiet" not in myopts: - portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1) + if not quiet: + writemsg_level((mytype + ": ").rjust(14), noiselevel=-1) if pkgmap[x][mytype]: sorted_pkgs = [portage.catpkgsplit(mypkg)[1:] for mypkg in pkgmap[x][mytype]] sorted_pkgs.sort(portage.pkgcmp) @@ -9946,21 +10049,22 @@ def unmerge(root_config, myopts, unmerge_action, else: myversion = ver + "-" + rev if mytype == "selected": - portage.writemsg_stdout( - colorize("UNMERGE_WARN", myversion + " "), noiselevel=-1) + writemsg_level( + colorize("UNMERGE_WARN", myversion + " "), + noiselevel=-1) else: - portage.writemsg_stdout( + writemsg_level( colorize("GOOD", myversion + " "), noiselevel=-1) else: - portage.writemsg_stdout("none ", noiselevel=-1) - if "--quiet" not in myopts: - portage.writemsg_stdout("\n", noiselevel=-1) - if "--quiet" in myopts: - portage.writemsg_stdout("\n", noiselevel=-1) + writemsg_level("none ", noiselevel=-1) + if not quiet: + writemsg_level("\n", noiselevel=-1) + if quiet: + writemsg_level("\n", noiselevel=-1) - portage.writemsg_stdout("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \ + writemsg_level("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \ " packages are slated for removal.\n") - portage.writemsg_stdout(">>> " + colorize("GOOD", "'Protected'") + \ + writemsg_level(">>> " + colorize("GOOD", "'Protected'") + \ " and " + colorize("GOOD", "'omitted'") + \ " packages will not be removed.\n\n") @@ -9976,18 +10080,20 @@ def unmerge(root_config, myopts, unmerge_action, print return 0 #the real unmerging begins, after a short delay.... - if not autoclean: + if clean_delay and not autoclean: countdown(int(settings["CLEAN_DELAY"]), ">>> Unmerging") for x in xrange(len(pkgmap)): for y in pkgmap[x]["selected"]: - print ">>> Unmerging "+y+"..." + writemsg_level(">>> Unmerging "+y+"...\n", noiselevel=-1) emergelog(xterm_titles, "=== Unmerging... ("+y+")") mysplit = y.split("/") #unmerge... retval = portage.unmerge(mysplit[0], mysplit[1], settings["ROOT"], mysettings, unmerge_action not in ["clean","prune"], - vartree=vartree, ldpath_mtimes=ldpath_mtimes) + vartree=vartree, ldpath_mtimes=ldpath_mtimes, + scheduler=scheduler) + if retval != os.EX_OK: emergelog(xterm_titles, " !!! unmerge FAILURE: "+y) if raise_on_error: diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 8aae5b44d..df0a2099b 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -4303,7 +4303,7 @@ def _post_phase_userpriv_perms(mysettings): def _post_src_install_checks(mysettings): _post_src_install_uid_fix(mysettings) global _post_phase_cmds - retval = _spawn_misc_sh(mysettings, post_phase_cmds["install"]) + retval = _spawn_misc_sh(mysettings, _post_phase_cmds["install"]) if retval != os.EX_OK: writemsg("!!! install_qa_check failed; exiting.\n", noiselevel=-1) @@ -5852,9 +5852,10 @@ def merge(mycat, mypkg, pkgloc, infloc, myroot, mysettings, myebuild=None, return mylink.merge(pkgloc, infloc, myroot, myebuild, mydbapi=mydbapi, prev_mtimes=prev_mtimes) -def unmerge(cat, pkg, myroot, mysettings, mytrimworld=1, vartree=None, ldpath_mtimes=None): - mylink = dblink( - cat, pkg, myroot, mysettings, treetype="vartree", vartree=vartree) +def unmerge(cat, pkg, myroot, mysettings, mytrimworld=1, vartree=None, + ldpath_mtimes=None, scheduler=None): + mylink = dblink(cat, pkg, myroot, mysettings, treetype="vartree", + vartree=vartree, scheduler=scheduler) try: mylink.lockdb() if mylink.exists(): diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index aa3e9a013..4a7fc7ad3 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -25,7 +25,6 @@ from portage import listdir, dep_expand, flatten, key_expand, \ abssymlink, movefile, _movefile, bsd_chflags, cpv_getkey from portage.elog import elog_process -from portage.elog.messages import ewarn from portage.elog.filtering import filter_mergephases, filter_unmergephases import os, re, sys, stat, errno, commands, copy, time, subprocess @@ -987,13 +986,16 @@ class vardbapi(dbapi): if counter > max_counter: max_counter = counter + new_vdb = False counter = -1 try: cfile = open(self._counter_path, "r") except EnvironmentError, e: - writemsg("!!! Unable to read COUNTER file: '%s'\n" % \ - self._counter_path, noiselevel=-1) - writemsg("!!! %s\n" % str(e), noiselevel=-1) + new_vdb = not bool(self.cpv_all()) + if not new_vdb: + writemsg("!!! Unable to read COUNTER file: '%s'\n" % \ + self._counter_path, noiselevel=-1) + writemsg("!!! %s\n" % str(e), noiselevel=-1) del e else: try: @@ -1018,7 +1020,7 @@ class vardbapi(dbapi): if counter > max_counter: max_counter = counter - if counter < 0: + if counter < 0 and not new_vdb: writemsg("!!! Initializing COUNTER to " + \ "value of %d\n" % max_counter, noiselevel=-1) @@ -1423,6 +1425,10 @@ class dblink(object): "sym": 5 } + # When looping over files for merge/unmerge, temporarily yield to the + # scheduler each time this many files are processed. + _file_merge_yield_interval = 20 + def __init__(self, cat, pkg, myroot, mysettings, treetype=None, vartree=None, blockers=None, scheduler=None): """ @@ -1851,9 +1857,8 @@ class dblink(object): "pkg_prerm() and pkg_postrm() removal " + \ "phases to be skipped entirely." msg_lines.extend(wrap(msg, 72)) - from portage.elog.messages import eerror - for l in msg_lines: - eerror(l, phase=ebuild_phase, key=self.mycpv) + + self._eerror(ebuild_phase, msg_lines) # process logs created during pre/postrm elog_process(self.mycpv, self.settings, phasefilter=filter_unmergephases) @@ -1915,6 +1920,7 @@ class dblink(object): """ showMessage = self._display_merge + scheduler = self._scheduler if not pkgfiles: showMessage("No package files given... Grabbing a set.\n") @@ -1983,7 +1989,12 @@ class dblink(object): def show_unmerge(zing, desc, file_type, file_name): showMessage("%s %s %s %s\n" % \ (zing, desc.ljust(8), file_type, file_name)) - for objkey in mykeys: + for i, objkey in enumerate(mykeys): + + if scheduler is not None and \ + 0 == i % self._file_merge_yield_interval: + scheduler.scheduleYield() + obj = normalize_path(objkey) file_data = pkgfiles[objkey] file_type = file_data[0] @@ -2360,17 +2371,21 @@ class dblink(object): self.settings.get("COLLISION_IGNORE", "").split()]) showMessage = self._display_merge + scheduler = self._scheduler stopmerge = False - i=0 collisions = [] destroot = normalize_path(destroot).rstrip(os.path.sep) + \ os.path.sep showMessage("%s checking %d files for package collisions\n" % \ (green("*"), len(mycontents))) - for f in mycontents: - i = i + 1 + for i, f in enumerate(mycontents): if i % 1000 == 0: showMessage("%d files checked ...\n" % i) + + if scheduler is not None and \ + 0 == i % self._file_merge_yield_interval: + scheduler.scheduleYield() + dest_path = normalize_path( os.path.join(destroot, f.lstrip(os.path.sep))) try: @@ -2430,13 +2445,19 @@ class dblink(object): return 0 showMessage = self._display_merge + scheduler = self._scheduler file_paths = set() for dblnk in installed_instances: file_paths.update(dblnk.getcontents()) inode_map = {} real_paths = set() - for path in file_paths: + for i, path in enumerate(file_paths): + + if scheduler is not None and \ + 0 == i % self._file_merge_yield_interval: + scheduler.scheduleYield() + try: s = os.lstat(path) except OSError, e: @@ -2463,20 +2484,31 @@ class dblink(object): suspicious_hardlinks.append(path_list) if not suspicious_hardlinks: return 0 - from portage.output import colorize - prefix = colorize("SECURITY_WARN", "*") + " WARNING: " - showMessage(prefix + "suid/sgid file(s) " + \ - "with suspicious hardlink(s):\n", - level=logging.ERROR, noiselevel=-1) + + msg = [] + msg.append("suid/sgid file(s) " + \ + "with suspicious hardlink(s):") + msg.append("") for path_list in suspicious_hardlinks: for path, s in path_list: - showMessage(prefix + " '%s'\n" % path, - level=logging.ERROR, noiselevel=-1) - showMessage(prefix + "See the Gentoo Security Handbook " + \ - "guide for advice on how to proceed.\n", - level=logging.ERROR, noiselevel=-1) + msg.append("\t%s" % path) + msg.append("") + msg.append("See the Gentoo Security Handbook " + \ + "guide for advice on how to proceed.") + + self._eerror("preinst", msg) + return 1 + def _eerror(self, phase, lines): + from portage.elog.messages import eerror as _eerror + if self._scheduler is None: + for l in lines: + _eerror(l, phase=phase, key=self.settings.mycpv) + else: + self._scheduler.dblinkElog(self, + phase, _eerror, lines) + def treewalk(self, srcroot, destroot, inforoot, myebuild, cleanup=0, mydbapi=None, prev_mtimes=None): """ @@ -2514,6 +2546,7 @@ class dblink(object): """ showMessage = self._display_merge + scheduler = self._scheduler srcroot = normalize_path(srcroot).rstrip(os.path.sep) + os.path.sep destroot = normalize_path(destroot).rstrip(os.path.sep) + os.path.sep @@ -2539,10 +2572,8 @@ class dblink(object): if slot is None: slot = "" - from portage.elog.messages import eerror as _eerror def eerror(lines): - for l in lines: - _eerror(l, phase="preinst", key=self.settings.mycpv) + self._eerror("preinst", lines) if slot != self.settings["SLOT"]: showMessage("!!! WARNING: Expected SLOT='%s', got '%s'\n" % \ @@ -2759,8 +2790,6 @@ class dblink(object): self.delete() ensure_dirs(self.dbtmpdir) - scheduler = self._scheduler - # run preinst script if scheduler is None: showMessage(">>> Merging %s to %s\n" % (self.mycpv, destroot)) @@ -2985,6 +3014,7 @@ class dblink(object): """ showMessage = self._display_merge + scheduler = self._scheduler from os.path import sep, join srcroot = normalize_path(srcroot).rstrip(sep) + sep @@ -2998,7 +3028,13 @@ class dblink(object): else: mergelist = stufftomerge offset = "" - for x in mergelist: + + for i, x in enumerate(mergelist): + + if scheduler is not None and \ + 0 == i % self._file_merge_yield_interval: + scheduler.scheduleYield() + mysrc = join(srcroot, offset, x) mydest = join(destroot, offset, x) # myrealdest is mydest without the $ROOT prefix (makes a difference if ROOT!="/") diff --git a/pym/portage/elog/messages.py b/pym/portage/elog/messages.py index ac8d70160..5455e17f4 100644 --- a/pym/portage/elog/messages.py +++ b/pym/portage/elog/messages.py @@ -8,6 +8,7 @@ from portage.const import EBUILD_PHASES from portage.util import writemsg import os +import sys def collect_ebuild_messages(path): """ Collect elog messages generated by the bash logging function stored @@ -66,7 +67,7 @@ def collect_ebuild_messages(path): return logentries _msgbuffer = {} -def _elog_base(level, msg, phase="other", key=None, color=None): +def _elog_base(level, msg, phase="other", key=None, color=None, out=None): """ Backend for the other messaging functions, should not be called directly. """ @@ -75,7 +76,14 @@ def _elog_base(level, msg, phase="other", key=None, color=None): if color == None: color = "GOOD" - print colorize(color, " * ")+msg + + formatted_msg = colorize(color, " * ") + msg + "\n" + + if out is None: + sys.stdout.write(formatted_msg) + else: + out.write(formatted_msg) + if key not in _msgbuffer: _msgbuffer[key] = {} if phase not in _msgbuffer[key]: @@ -108,11 +116,11 @@ _functions = { "einfo": ("INFO", "GOOD"), } def _make_msgfunction(level, color): - def _elog(msg, phase="other", key=None): + def _elog(msg, phase="other", key=None, out=None): """ Display and log a message assigned to the given key/cpv (or unassigned if no key is given). """ - _elog_base(level, msg, phase=phase, key=key, color=color) + _elog_base(level, msg, phase=phase, key=key, color=color, out=out) return _elog import sys