PollScheduler: split out SchedulerInterface
authorZac Medico <zmedico@gentoo.org>
Sun, 7 Oct 2012 18:17:35 +0000 (11:17 -0700)
committerZac Medico <zmedico@gentoo.org>
Sun, 7 Oct 2012 18:51:26 +0000 (11:51 -0700)
pym/_emerge/PollScheduler.py
pym/_emerge/Scheduler.py
pym/portage/util/_async/SchedulerInterface.py [new file with mode: 0644]

index 105943fd485f7a3c0e468e94540d60eedf80b344..8d5c290d7207de0dca56cf5f1f379abd39c59797 100644 (file)
@@ -1,18 +1,12 @@
 # Copyright 1999-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import gzip
-import errno
-
 try:
        import threading
 except ImportError:
        import dummy_threading as threading
 
-from portage import _encodings
-from portage import _unicode_encode
-from portage.util import writemsg_level
-from portage.util.SlotObject import SlotObject
+from portage.util._async.SchedulerInterface import SchedulerInterface
 from portage.util._eventloop.EventLoop import EventLoop
 from portage.util._eventloop.global_event_loop import global_event_loop
 
@@ -23,13 +17,6 @@ class PollScheduler(object):
        # max time between loadavg checks (milliseconds)
        _loadavg_latency = 30000
 
-       class _sched_iface_class(SlotObject):
-               __slots__ = ("IO_ERR", "IO_HUP", "IO_IN", "IO_NVAL", "IO_OUT",
-                       "IO_PRI", "child_watch_add",
-                       "idle_add", "io_add_watch", "iteration",
-                       "output", "run",
-                       "source_remove", "timeout_add")
-
        def __init__(self, main=False, event_loop=None):
                """
                @param main: If True then use global_event_loop(), otherwise use
@@ -49,20 +36,11 @@ class PollScheduler(object):
                        self._event_loop = global_event_loop()
                else:
                        self._event_loop = EventLoop(main=False)
-               self.sched_iface = self._sched_iface_class(
-                       IO_ERR=self._event_loop.IO_ERR,
-                       IO_HUP=self._event_loop.IO_HUP,
-                       IO_IN=self._event_loop.IO_IN,
-                       IO_NVAL=self._event_loop.IO_NVAL,
-                       IO_OUT=self._event_loop.IO_OUT,
-                       IO_PRI=self._event_loop.IO_PRI,
-                       child_watch_add=self._event_loop.child_watch_add,
-                       idle_add=self._event_loop.idle_add,
-                       io_add_watch=self._event_loop.io_add_watch,
-                       iteration=self._event_loop.iteration,
-                       output=self._task_output,
-                       source_remove=self._event_loop.source_remove,
-                       timeout_add=self._event_loop.timeout_add)
+               self.sched_iface = SchedulerInterface(self._event_loop,
+                       is_background=self._is_background)
+
+       def _is_background(self):
+               return self._background
 
        def terminate(self):
                """
@@ -176,47 +154,3 @@ class PollScheduler(object):
                                return False
 
                return True
-
-       def _task_output(self, msg, log_path=None, background=None,
-               level=0, noiselevel=-1):
-               """
-               Output msg to stdout if not self._background. If log_path
-               is not None then append msg to the log (appends with
-               compression if the filename extension of log_path
-               corresponds to a supported compression type).
-               """
-
-               if background is None:
-                       # If the task does not have a local background value
-                       # (like for parallel-fetch), then use the global value.
-                       background = self._background
-
-               msg_shown = False
-               if not background:
-                       writemsg_level(msg, level=level, noiselevel=noiselevel)
-                       msg_shown = True
-
-               if log_path is not None:
-                       try:
-                               f = open(_unicode_encode(log_path,
-                                       encoding=_encodings['fs'], errors='strict'),
-                                       mode='ab')
-                               f_real = f
-                       except IOError as e:
-                               if e.errno not in (errno.ENOENT, errno.ESTALE):
-                                       raise
-                               if not msg_shown:
-                                       writemsg_level(msg, level=level, noiselevel=noiselevel)
-                       else:
-
-                               if log_path.endswith('.gz'):
-                                       # NOTE: The empty filename argument prevents us from
-                                       # triggering a bug in python3 which causes GzipFile
-                                       # to raise AttributeError if fileobj.name is bytes
-                                       # instead of unicode.
-                                       f =  gzip.GzipFile(filename='', mode='ab', fileobj=f)
-
-                               f.write(_unicode_encode(msg))
-                               f.close()
-                               if f_real is not f:
-                                       f_real.close()
index c5779cb9a0a4a216caa2af87d86cc8553a06c348..d64468af0cab09ae38b3b7f93fe279143ca52901 100644 (file)
@@ -28,6 +28,8 @@ from portage._sets import SETPREFIX
 from portage._sets.base import InternalPackageSet
 from portage.util import ensure_dirs, writemsg, writemsg_level
 from portage.util.SlotObject import SlotObject
+from portage.util._async.SchedulerInterface import SchedulerInterface
+from portage.util._eventloop.EventLoop import EventLoop
 from portage.package.ebuild.digestcheck import digestcheck
 from portage.package.ebuild.digestgen import digestgen
 from portage.package.ebuild.doebuild import (_check_temp_dir,
@@ -79,7 +81,7 @@ class Scheduler(PollScheduler):
        _opts_no_self_update = frozenset(["--buildpkgonly",
                "--fetchonly", "--fetch-all-uri", "--pretend"])
 
-       class _iface_class(PollScheduler._sched_iface_class):
+       class _iface_class(SchedulerInterface):
                __slots__ = ("fetch",
                        "scheduleSetup", "scheduleUnpack")
 
@@ -215,11 +217,11 @@ class Scheduler(PollScheduler):
                fetch_iface = self._fetch_iface_class(log_file=self._fetch_log,
                        schedule=self._schedule_fetch)
                self._sched_iface = self._iface_class(
+                       self._event_loop,
+                       is_background=self._is_background,
                        fetch=fetch_iface,
                        scheduleSetup=self._schedule_setup,
-                       scheduleUnpack=self._schedule_unpack,
-                       **dict((k, getattr(self.sched_iface, k))
-                       for k in self.sched_iface.__slots__))
+                       scheduleUnpack=self._schedule_unpack)
 
                self._prefetchers = weakref.WeakValueDictionary()
                self._pkg_queue = []
@@ -767,10 +769,10 @@ class Scheduler(PollScheduler):
 
                failures = 0
 
-               # Use a local PollScheduler instance here, since we don't
+               # Use a local EventLoop instance here, since we don't
                # want tasks here to trigger the usual Scheduler callbacks
                # that handle job scheduling and status display.
-               sched_iface = PollScheduler().sched_iface
+               sched_iface = SchedulerInterface(EventLoop(main=False))
 
                for x in self._mergelist:
                        if not isinstance(x, Package):
diff --git a/pym/portage/util/_async/SchedulerInterface.py b/pym/portage/util/_async/SchedulerInterface.py
new file mode 100644 (file)
index 0000000..731f521
--- /dev/null
@@ -0,0 +1,86 @@
+# Copyright 2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import gzip
+import errno
+
+from portage import _encodings
+from portage import _unicode_encode
+from portage.util import writemsg_level
+from ..SlotObject import SlotObject
+
+class SchedulerInterface(SlotObject):
+
+       __slots__ = ("IO_ERR", "IO_HUP", "IO_IN", "IO_NVAL", "IO_OUT", "IO_PRI",
+               "child_watch_add", "idle_add", "io_add_watch", "iteration",
+               "source_remove", "timeout_add", "_event_loop", "_is_background")
+
+       def __init__(self, event_loop, is_background=None, **kwargs):
+               SlotObject.__init__(self, **kwargs)
+               self._event_loop = event_loop
+               if is_background is None:
+                       is_background = self._return_false
+               self._is_background = is_background
+               self.IO_ERR = event_loop.IO_ERR
+               self.IO_HUP = event_loop.IO_HUP
+               self.IO_IN = event_loop.IO_IN
+               self.IO_NVAL = event_loop.IO_NVAL
+               self.IO_OUT = event_loop.IO_OUT
+               self.IO_PRI = event_loop.IO_PRI
+               self.child_watch_add = event_loop.child_watch_add
+               self.idle_add = event_loop.idle_add
+               self.io_add_watch = event_loop.io_add_watch
+               self.iteration = event_loop.iteration
+               self.source_remove = event_loop.source_remove
+               self.timeout_add = event_loop.timeout_add
+
+       @staticmethod
+       def _return_false():
+               return False
+
+       def output(self, msg, log_path=None, background=None,
+               level=0, noiselevel=-1):
+               """
+               Output msg to stdout if not self._is_background(). If log_path
+               is not None then append msg to the log (appends with
+               compression if the filename extension of log_path corresponds
+               to a supported compression type).
+               """
+
+               global_background = self._is_background()
+               if background is None or global_background:
+                       # Use the global value if the task does not have a local
+                       # background value. For example, parallel-fetch tasks run
+                       # in the background while other tasks concurrently run in
+                       # the foreground.
+                       background = global_background
+
+               msg_shown = False
+               if not background:
+                       writemsg_level(msg, level=level, noiselevel=noiselevel)
+                       msg_shown = True
+
+               if log_path is not None:
+                       try:
+                               f = open(_unicode_encode(log_path,
+                                       encoding=_encodings['fs'], errors='strict'),
+                                       mode='ab')
+                               f_real = f
+                       except IOError as e:
+                               if e.errno not in (errno.ENOENT, errno.ESTALE):
+                                       raise
+                               if not msg_shown:
+                                       writemsg_level(msg, level=level, noiselevel=noiselevel)
+                       else:
+
+                               if log_path.endswith('.gz'):
+                                       # NOTE: The empty filename argument prevents us from
+                                       # triggering a bug in python3 which causes GzipFile
+                                       # to raise AttributeError if fileobj.name is bytes
+                                       # instead of unicode.
+                                       f =  gzip.GzipFile(filename='', mode='ab', fileobj=f)
+
+                               f.write(_unicode_encode(msg))
+                               f.close()
+                               if f_real is not f:
+                                       f_real.close()