+# A Job consists of many "Tasks".
+# A task is the run of an external tool, with proper methods for failure handling
+
+from Tools.CList import CList
+
+class Job:
+ NOT_STARTED, IN_PROGRESS, FINISHED, FAILED = range(4)
+ def __init__(self, name):
+ self.tasks = [ ]
+ self.current_task = 0
+ self.callback = None
+ self.name = name
+ self.finished = False
+
+ self.state_changed = CList()
+
+ self.status = self.NOT_STARTED
+
+ # description is a dict
+ def fromDescription(self, description):
+ pass
+
+ def createDescription(self):
+ return None
+
+ def addTask(self, task):
+ self.tasks.append(task)
+
+ def start(self, callback):
+ assert self.callback is None
+ self.callback = callback
+ self.status = self.IN_PROGRESS
+ self.state_changed()
+ self.runNext()
+
+ def runNext(self):
+ if self.current_task == len(self.tasks):
+ self.callback(self, [])
+ self.status = self.FINISHED
+ self.state_changed()
+ else:
+ self.tasks[self.current_task].run(self.taskCallback)
+ self.state_changed()
+
+ def taskCallback(self, res):
+ if len(res):
+ print ">>> Error:", res
+ self.status = self.FAILED
+ self.state_changed()
+ self.callback(self, res)
+ else:
+ self.current_task += 1
+ self.runNext()
+
+class Task:
+ def __init__(self, name):
+ self.name = name
+ self.workspace = "/tmp"
+ self.immediate_preconditions = [ ]
+ self.global_preconditions = [ ]
+ self.postconditions = [ ]
+ self.returncode = None
+ self.initial_input = None
+
+ self.cmd = None
+ self.args = [ ]
+
+ 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 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, callback):
+ failed_preconditions = self.checkPreconditions(True)
+ if len(failed_preconditions):
+ errback(failed_preconditions)
+ return
+
+ self.callback = callback
+ from enigma import eConsoleAppContainer
+ self.container = eConsoleAppContainer()
+ self.container.appClosed.get().append(self.processFinished)
+ self.container.dataAvail.get().append(self.processOutput)
+
+ assert self.cmd is not None
+ assert len(self.args) >= 1
+
+ print "execute:", self.container.execute(self.cmd, self.args), self.cmd, self.args
+ if self.initial_input:
+ self.writeInput(self.initial_input)
+
+ def prepare(self):
+ pass
+
+ def cleanup(self, failed):
+ pass
+
+ def processOutput(self, data):
+ pass
+
+ def processFinished(self, returncode):
+ self.returncode = returncode
+ self.finish()
+
+ def finish(self):
+ self.afterRun()
+ not_met = [ ]
+ for postcondition in self.postconditions:
+ if not postcondition.check(self):
+ not_met.append(postcondition)
+
+ self.callback(not_met)
+
+ def afterRun(self):
+ pass
+
+ def writeInput(self, input):
+ self.container.write(input)
+
+class JobManager:
+ def __init__(self):
+ self.active_jobs = [ ]
+ self.failed_jobs = [ ]
+ self.job_classes = [ ]
+ self.active_job = None
+
+ def AddJob(self, job):
+ self.active_jobs.append(job)
+ self.kick()
+
+ def kick(self):
+ if self.active_job is None:
+ if len(self.active_jobs):
+ self.active_job = self.active_jobs.pop(0)
+ self.active_job.start(self.jobDone)
+
+ def jobDone(self, job, problems):
+ print "job", job, "completed with", problems
+ if problems:
+ self.failed_jobs.append(self.active_job)
+
+ self.active_job = None
+ self.kick()
+
+# some examples:
+#class PartitionExistsPostcondition:
+# def __init__(self, device):
+# self.device = device
+#
+# def check(self, task):
+# import os
+# return os.access(self.device + "part1", os.F_OK)
+#
+#class CreatePartitionTask(Task):
+# def __init__(self, device):
+# Task.__init__(self, _("Create Partition"))
+# self.device = device
+# self.setTool("/sbin/sfdisk")
+# self.args += ["-f", self.device + "disc"]
+# self.initial_input = "0,\n;\n;\n;\ny\n"
+# self.postconditions.append(PartitionExistsPostcondition(self.device))
+#
+#class CreateFilesystemTask(Task):
+# def __init__(self, device, partition = 1, largefile = True):
+# Task.__init__(self, _("Create Filesystem"))
+# self.setTool("/sbin/mkfs.ext")
+# if largefile:
+# self.args += ["-T", "largefile"]
+# self.args.append("-m0")
+# self.args.append(device + "part%d" % partition)
+#
+#class FilesystemMountTask(Task):
+# def __init__(self, device, partition = 1, filesystem = "ext3"):
+# Task.__init__(self, _("Mounting Filesystem"))
+# self.setTool("/bin/mount")
+# if filesystem is not None:
+# self.args += ["-t", filesystem]
+# self.args.append(device + "part%d" % partition)
+#
+#class DiskspacePrecondition:
+# def __init__(self, diskspace_required):
+# self.diskspace_required = diskspace_required
+#
+# def check(self, task):
+# return getFreeDiskspace(task.workspace) >= self.diskspace_required
+#
+#class ToolExistsPrecondition:
+# def check(self, task):
+# import os
+# return os.access(task.cmd, os.X_OK)
+#
+#class ReturncodePostcondition:
+# def check(self, task):
+# return task.returncode == 0
+#
+#class HDDInitJob(Job):
+# def __init__(self, device):
+# Job.__init__(self, _("Initialize Harddisk"))
+# self.device = device
+# self.fromDescription(self.createDescription())
+#
+# def fromDescription(self, description):
+# self.device = description["device"]
+# self.addTask(CreatePartitionTask(self.device))
+# self.addTask(CreateFilesystemTask(self.device))
+# self.addTask(FilesystemMountTask(self.device))
+#
+# def createDescription(self):
+# return {"device": self.device}
+
+job_manager = JobManager()