Package _emerge :: Module CompositeTask
[hide private]

Source Code for Module _emerge.CompositeTask

  1  # Copyright 1999-2012 Gentoo Foundation 
  2  # Distributed under the terms of the GNU General Public License v2 
  3   
  4  from _emerge.AsynchronousTask import AsynchronousTask 
  5  from portage import os 
  6   
7 -class CompositeTask(AsynchronousTask):
8 9 __slots__ = ("scheduler",) + ("_current_task",) 10 11 _TASK_QUEUED = -1 12
13 - def isAlive(self):
14 return self._current_task is not None
15
16 - def _cancel(self):
17 if self._current_task is not None: 18 if self._current_task is self._TASK_QUEUED: 19 self.returncode = 1 20 self._current_task = None 21 else: 22 self._current_task.cancel()
23
24 - def _poll(self):
25 """ 26 This does a loop calling self._current_task.poll() 27 repeatedly as long as the value of self._current_task 28 keeps changing. It calls poll() a maximum of one time 29 for a given self._current_task instance. This is useful 30 since calling poll() on a task can trigger advance to 31 the next task could eventually lead to the returncode 32 being set in cases when polling only a single task would 33 not have the same effect. 34 """ 35 36 prev = None 37 while True: 38 task = self._current_task 39 if task is None or \ 40 task is self._TASK_QUEUED or \ 41 task is prev: 42 # don't poll the same task more than once 43 break 44 task.poll() 45 prev = task 46 47 return self.returncode
48
49 - def _wait(self):
50 51 prev = None 52 while True: 53 task = self._current_task 54 if task is None: 55 # don't wait for the same task more than once 56 break 57 if task is self._TASK_QUEUED: 58 if self.cancelled: 59 self.returncode = 1 60 self._current_task = None 61 break 62 else: 63 while not self._task_queued_wait(): 64 self.scheduler.iteration() 65 if self.returncode is not None: 66 break 67 elif self.cancelled: 68 self.returncode = 1 69 self._current_task = None 70 break 71 else: 72 # try this again with new _current_task value 73 continue 74 if task is prev: 75 if self.returncode is not None: 76 # This is expected if we're being 77 # called from the task's exit listener 78 # after it's been cancelled. 79 break 80 # Before the task.wait() method returned, an exit 81 # listener should have set self._current_task to either 82 # a different task or None. Something is wrong. 83 raise AssertionError("self._current_task has not " + \ 84 "changed since calling wait", self, task) 85 task.wait() 86 prev = task 87 88 return self.returncode
89
90 - def _assert_current(self, task):
91 """ 92 Raises an AssertionError if the given task is not the 93 same one as self._current_task. This can be useful 94 for detecting bugs. 95 """ 96 if task is not self._current_task: 97 raise AssertionError("Unrecognized task: %s" % (task,))
98
99 - def _default_exit(self, task):
100 """ 101 Calls _assert_current() on the given task and then sets the 102 composite returncode attribute if task.returncode != os.EX_OK. 103 If the task failed then self._current_task will be set to None. 104 Subclasses can use this as a generic task exit callback. 105 106 @rtype: int 107 @return: The task.returncode attribute. 108 """ 109 self._assert_current(task) 110 if task.returncode != os.EX_OK: 111 self.returncode = task.returncode 112 self._current_task = None 113 return task.returncode
114
115 - def _final_exit(self, task):
116 """ 117 Assumes that task is the final task of this composite task. 118 Calls _default_exit() and sets self.returncode to the task's 119 returncode and sets self._current_task to None. 120 """ 121 self._default_exit(task) 122 self._current_task = None 123 self.returncode = task.returncode 124 return self.returncode
125
126 - def _default_final_exit(self, task):
127 """ 128 This calls _final_exit() and then wait(). 129 130 Subclasses can use this as a generic final task exit callback. 131 132 """ 133 self._final_exit(task) 134 return self.wait()
135
136 - def _start_task(self, task, exit_handler):
137 """ 138 Register exit handler for the given task, set it 139 as self._current_task, and call task.start(). 140 141 Subclasses can use this as a generic way to start 142 a task. 143 144 """ 145 try: 146 task.scheduler = self.scheduler 147 except AttributeError: 148 pass 149 task.addExitListener(exit_handler) 150 self._current_task = task 151 task.start()
152
153 - def _task_queued(self, task):
156
157 - def _task_queued_start_handler(self, task):
158 self._current_task = task
159
160 - def _task_queued_wait(self):
161 return self._current_task is not self._TASK_QUEUED or \ 162 self.cancelled or self.returncode is not None
163