diff --git a/NeoBoot/files/Task.py b/NeoBoot/files/Task.py deleted file mode 100644 index bce5616..0000000 --- a/NeoBoot/files/Task.py +++ /dev/null @@ -1,523 +0,0 @@ -# -*- coding: utf-8 -*- -#from __future__ import print_function -#from Plugins.Extensions.NeoBoot.__init__ import _ -from Tools.CList import CList - -class Job(object): - NOT_STARTED, IN_PROGRESS, FINISHED, FAILED = range(4) - - def __init__(self, name): - self.tasks = [] - self.resident_tasks = [] - self.workspace = '/tmp' - self.current_task = 0 - self.callback = None - self.name = name - self.finished = False - self.end = 100 - self.__progress = 0 - self.weightScale = 1 - self.afterEvent = None - self.state_changed = CList() - self.status = self.NOT_STARTED - self.onSuccess = None - return - - def fromDescription(self, description): - pass - - def createDescription(self): - return None - - def getProgress(self): - if self.current_task == len(self.tasks): - return self.end - t = self.tasks[self.current_task] - jobprogress = t.weighting * t.progress / float(t.end) + sum([ task.weighting for task in self.tasks[:self.current_task] ]) - return int(jobprogress * self.weightScale) - - progress = property(getProgress) - - def getStatustext(self): - return {self.NOT_STARTED: _('Waiting'), - self.IN_PROGRESS: _('In progress'), - self.FINISHED: _('Finished'), - self.FAILED: _('Failed')}[self.status] - - def task_progress_changed_CB(self): - self.state_changed() - - def addTask(self, task): - task.job = self - task.task_progress_changed = self.task_progress_changed_CB - self.tasks.append(task) - - def start(self, callback): - self.callback = callback - self.restart() - - def restart(self): - self.status = self.IN_PROGRESS - self.state_changed() - self.runNext() - sumTaskWeightings = sum([ t.weighting for t in self.tasks ]) or 1 - self.weightScale = self.end / float(sumTaskWeightings) - - def runNext(self): - if self.current_task == len(self.tasks): - if len(self.resident_tasks) == 0: - self.status = self.FINISHED - self.state_changed() - self.callback(self, None, []) - self.callback = None - else: - print 'still waiting for %d resident task(s) %s to finish' % (len(self.resident_tasks), str(self.resident_tasks)) - else: - self.tasks[self.current_task].run(self.taskCallback) - self.state_changed() - return - - def taskCallback(self, task, res, stay_resident = False): - cb_idx = self.tasks.index(task) - if stay_resident: - if cb_idx not in self.resident_tasks: - self.resident_tasks.append(self.current_task) - print 'task going resident:', task - else: - print 'task keeps staying resident:', task - return - if len(res): - print '>>> Error:', res - self.status = self.FAILED - self.state_changed() - self.callback(self, task, res) - if cb_idx != self.current_task: - if cb_idx in self.resident_tasks: - print 'resident task finished:', task - self.resident_tasks.remove(cb_idx) - if res == []: - self.state_changed() - self.current_task += 1 - self.runNext() - - def retry(self): - self.restart() - - def abort(self): - if self.current_task < len(self.tasks): - self.tasks[self.current_task].abort() - for i in self.resident_tasks: - self.tasks[i].abort() - - def cancel(self): - self.abort() - - def __str__(self): - return 'Components.Task.Job name=%s #tasks=%s' % (self.name, len(self.tasks)) - - -class Task(object): - - def __init__(self, job, name): - self.name = name - self.immediate_preconditions = [] - self.global_preconditions = [] - self.postconditions = [] - self.returncode = None - self.initial_input = None - self.job = None - self.end = 100 - self.weighting = 100 - self.__progress = 0 - self.cmd = None - self.cwd = '/tmp' - self.args = [] - self.cmdline = None - self.task_progress_changed = None - self.output_line = '' - job.addTask(self) - self.container = None - return - - def setCommandline(self, cmd, args): - self.cmd = cmd - self.args = args - - def setTool(self, tool): - self.cmd = tool - self.args = [tool] - self.global_preconditions.append(ToolExistsPrecondition()) - self.postconditions.append(ReturncodePostcondition()) - - def setCmdline(self, cmdline): - self.cmdline = cmdline - - def checkPreconditions(self, immediate = False): - not_met = [] - if immediate: - preconditions = self.immediate_preconditions - else: - preconditions = self.global_preconditions - for precondition in preconditions: - if not precondition.check(self): - not_met.append(precondition) - - return not_met - - def _run(self): - if self.cmd is None and self.cmdline is None: - self.finish() - return - else: - from enigma import eConsoleAppContainer - self.container = eConsoleAppContainer() - self.container.appClosed.append(self.processFinished) - self.container.stdoutAvail.append(self.processStdout) - self.container.stderrAvail.append(self.processStderr) - if self.cwd is not None: - self.container.setCWD(self.cwd) - if not self.cmd and self.cmdline: - print 'execute:', self.container.execute(self.cmdline), self.cmdline - else: - print 'execute:', self.container.execute(self.cmd, *self.args), ' '.join(self.args) - if self.initial_input: - self.writeInput(self.initial_input) - return - return - - def run(self, callback): - failed_preconditions = self.checkPreconditions(True) + self.checkPreconditions(False) - if failed_preconditions: - print '[Task] preconditions failed' - callback(self, failed_preconditions) - return - self.callback = callback - try: - self.prepare() - self._run() - except Exception as ex: - print '[Task] exception:', ex - self.postconditions = [FailedPostcondition(ex)] - self.finish() - - def prepare(self): - pass - - def cleanup(self, failed): - pass - - def processStdout(self, data): - self.processOutput(data) - - def processStderr(self, data): - self.processOutput(data) - - def processOutput(self, data): - self.output_line += data - while True: - i = self.output_line.find('\n') - if i == -1: - break - self.processOutputLine(self.output_line[:i + 1]) - self.output_line = self.output_line[i + 1:] - - def processOutputLine(self, line): - print '[Task %s]' % self.name, line[:-1] - - def processFinished(self, returncode): - self.returncode = returncode - self.finish() - - def abort(self): - if self.container: - self.container.kill() - self.finish(aborted=True) - - def finish(self, aborted = False): - self.afterRun() - not_met = [] - if aborted: - not_met.append(AbortedPostcondition()) - else: - for postcondition in self.postconditions: - if not postcondition.check(self): - not_met.append(postcondition) - - self.cleanup(not_met) - self.callback(self, not_met) - - def afterRun(self): - pass - - def writeInput(self, input): - self.container.write(input) - - def getProgress(self): - return self.__progress - - def setProgress(self, progress): - if progress > self.end: - progress = self.end - if progress < 0: - progress = 0 - self.__progress = progress - if self.task_progress_changed: - self.task_progress_changed() - - progress = property(getProgress, setProgress) - - def __str__(self): - return 'Components.Task.Task name=%s' % self.name - - -class LoggingTask(Task): - - def __init__(self, job, name): - Task.__init__(self, job, name) - self.log = [] - - def processOutput(self, data): - print '[%s]' % self.name, data, - self.log.append(data) - - -class PythonTask(Task): - - def _run(self): - from twisted.internet import threads - from enigma import eTimer - self.aborted = False - self.pos = 0 - threads.deferToThread(self.work).addBoth(self.onComplete) - self.timer = eTimer() - self.timer.callback.append(self.onTimer) - self.timer.start(5) - - def work(self): - raise NotImplemented, 'work' - - def abort(self): - self.aborted = True - if self.callback is None: - self.finish(aborted=True) - return - - def onTimer(self): - self.setProgress(self.pos) - - def onComplete(self, result): - self.postconditions.append(FailedPostcondition(result)) - self.timer.stop() - del self.timer - self.finish() - - -class ConditionTask(Task): - - def __init__(self, job, name, timeoutCount = None): - Task.__init__(self, job, name) - self.timeoutCount = timeoutCount - - def _run(self): - self.triggerCount = 0 - - def prepare(self): - from enigma import eTimer - self.timer = eTimer() - self.timer.callback.append(self.trigger) - self.timer.start(1000) - - def cleanup(self, failed): - if hasattr(self, 'timer'): - self.timer.stop() - del self.timer - - def check(self): - return True - - def trigger(self): - self.triggerCount += 1 - try: - if self.timeoutCount is not None and self.triggerCount > self.timeoutCount: - raise Exception, 'Timeout elapsed, sorry' - res = self.check() - except Exception as e: - self.postconditions.append(FailedPostcondition(e)) - res = True - - if res: - self.finish() - return - - -class JobManager: - - def __init__(self): - self.active_jobs = [] - self.failed_jobs = [] - self.job_classes = [] - self.in_background = False - self.visible = False - self.active_job = None - return - - def AddJob(self, job, onSuccess = None, onFail = None): - job.onSuccess = onSuccess - if onFail is None: - job.onFail = self.notifyFailed - else: - job.onFail = onFail - self.active_jobs.append(job) - self.kick() - return - - def kick(self): - if self.active_job is None: - if self.active_jobs: - self.active_job = self.active_jobs.pop(0) - self.active_job.start(self.jobDone) - return - - def notifyFailed(self, job, task, problems): - from Tools import Notifications - from Screens.MessageBox import MessageBox - if problems[0].RECOVERABLE: - Notifications.AddNotificationWithCallback(self.errorCB, MessageBox, _('Error: %s\nRetry?') % problems[0].getErrorMessage(task)) - return True - else: - Notifications.AddNotification(MessageBox, job.name + '\n' + _('Error') + ': %s' % problems[0].getErrorMessage(task), type=MessageBox.TYPE_ERROR) - return False - - def jobDone(self, job, task, problems): - print 'job', job, 'completed with', problems, 'in', task - if problems: - if not job.onFail(job, task, problems): - self.errorCB(False) - else: - self.active_job = None - if job.onSuccess: - job.onSuccess(job) - self.kick() - return - - def popupTaskView(self, job): - if not self.visible: - from Tools import Notifications - from Screens.TaskView import JobView - self.visible = True - Notifications.AddNotification(JobView, job) - - def errorCB(self, answer): - if answer: - print 'retrying job' - self.active_job.retry() - else: - print 'not retrying job.' - self.failed_jobs.append(self.active_job) - self.active_job = None - self.kick() - return - - def getPendingJobs(self): - list = [] - if self.active_job: - list.append(self.active_job) - list += self.active_jobs - return list - - -class Condition: - RECOVERABLE = False - - def getErrorMessage(self, task): - return _('An unknown error occurred!') + ' (%s @ task %s)' % (self.__class__.__name__, task.__class__.__name__) - - -class WorkspaceExistsPrecondition(Condition): - - def check(self, task): - return os.access(task.job.workspace, os.W_OK) - - -class DiskspacePrecondition(Condition): - - def __init__(self, diskspace_required): - self.diskspace_required = diskspace_required - self.diskspace_available = 0 - - def check(self, task): - import os - try: - s = os.statvfs(task.job.workspace) - self.diskspace_available = s.f_bsize * s.f_bavail - return self.diskspace_available >= self.diskspace_required - except OSError: - return False - - def getErrorMessage(self, task): - return _('Not enough disk space. Please free up some disk space and try again. (%d MB required, %d MB available)') % (self.diskspace_required / 1024 / 1024, self.diskspace_available / 1024 / 1024) - - -class ToolExistsPrecondition(Condition): - - def check(self, task): - import os - if task.cmd[0] == '/': - self.realpath = task.cmd - print '[Task.py][ToolExistsPrecondition] WARNING: usage of absolute paths for tasks should be avoided!' - return os.access(self.realpath, os.X_OK) - self.realpath = task.cmd - path = os.environ.get('PATH', '').split(os.pathsep) - path.append(task.cwd + '/') - absolutes = filter(lambda file: os.access(file, os.X_OK), map(lambda directory, file = task.cmd: os.path.join(directory, file), path)) - if absolutes: - self.realpath = absolutes[0] - return True - return False - - def getErrorMessage(self, task): - return _('A required tool (%s) was not found.') % self.realpath - - -class AbortedPostcondition(Condition): - - def getErrorMessage(self, task): - return 'Cancelled upon user request' - - -class ReturncodePostcondition(Condition): - - def check(self, task): - return task.returncode == 0 - - def getErrorMessage(self, task): - if hasattr(task, 'log') and task.log: - log = ''.join(task.log).strip() - log = log.split('\n')[-3:] - log = '\n'.join(log) - return log - else: - return _('Error code') + ': %s' % task.returncode - - -class FailedPostcondition(Condition): - - def __init__(self, exception): - self.exception = exception - - def getErrorMessage(self, task): - if isinstance(self.exception, int): - if hasattr(task, 'log'): - log = ''.join(task.log).strip() - log = log.split('\n')[-4:] - log = '\n'.join(log) - return log - else: - return _('Error code') + ' %s' % self.exception - return str(self.exception) - - def check(self, task): - return self.exception is None or self.exception == 0 - - -job_manager = JobManager() \ No newline at end of file