From b8fd3f2931546e4eb4e088de9f22dd298d5dff8b Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Mon, 3 Dec 2012 22:58:22 +0000 Subject: [PATCH] * morituri/common/task.py: * morituri/program/cdrdao.py: Factor out a PopenTask base class. --- ChangeLog | 6 ++ morituri/common/task.py | 118 +++++++++++++++++++++++++++++++++++++ morituri/program/cdrdao.py | 103 ++++---------------------------- 3 files changed, 136 insertions(+), 91 deletions(-) diff --git a/ChangeLog b/ChangeLog index b065bdb..5082140 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-12-03 Thomas Vander Stichele + + * morituri/common/task.py: + * morituri/program/cdrdao.py: + Factor out a PopenTask base class. + 2012-12-03 Thomas Vander Stichele * morituri/common/program.py: diff --git a/morituri/common/task.py b/morituri/common/task.py index f7744e7..55afffe 100644 --- a/morituri/common/task.py +++ b/morituri/common/task.py @@ -1,6 +1,11 @@ # -*- Mode: Python -*- # vi:si:et:sw=4:sts=4:ts=4 +import os +import signal +import subprocess + +from morituri.extern import asyncsub from morituri.extern.log import log from morituri.extern.task import task, gstreamer @@ -13,3 +18,116 @@ class SyncRunner(log.Loggable, task.SyncRunner): class GstPipelineTask(log.Loggable, gstreamer.GstPipelineTask): pass + + +class PopenTask(log.Loggable, task.Task): + """ + I am a task that runs a command using Popen. + """ + + logCategory = 'PopenTask' + bufsize = 1024 + command = None + + def start(self, runner): + task.Task.start(self, runner) + + try: + self._popen = asyncsub.Popen(self.command, + bufsize=self.bufsize, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, close_fds=True) + except OSError, e: + import errno + if e.errno == errno.ENOENT: + self.commandMissing() + + raise + + self.debug('Started %r with pid %d', self.command, + self._popen.pid) + + self.schedule(1.0, self._read, runner) + + def _read(self, runner): + try: + ret = self._popen.recv() + + if ret: + self.log("read from stdout: %s", ret) + self.readbytesout(ret) + + ret = self._popen.recv_err() + + if ret: + self.log("read from stderr: %s", ret) + self.readbyteserr(ret) + + if self._popen.poll() is None and self.runner: + # not finished yet + self.schedule(1.0, self._read, runner) + return + + self._done() + except Exception, e: + self.debug('exception during _read()') + self.debug(log.getExceptionMessage(e)) + self.setException(e) + self.stop() + + def _done(self): + assert self._popen.returncode is not None, "No returncode" + + if self._popen.returncode >= 0: + self.debug('Return code was %d', self._popen.returncode) + else: + self.debug('Terminated with signal %d', + -self._popen.returncode) + + self.setProgress(1.0) + + if self._popen.returncode != 0: + self.failed() + else: + self.done() + + self.stop() + return + + def abort(self): + self.debug('Aborting, sending SIGTERM to %d', self._popen.pid) + os.kill(self._popen.pid, signal.SIGTERM) + # self.stop() + + def readbytesout(self, bytes): + """ + Called when bytes have been read from stdout. + """ + pass + + def readbyteserr(self, bytes): + """ + Called when bytes have been read from stderr. + """ + pass + + def done(self): + """ + Called when the command completed successfully. + """ + raise NotImplementedError + + def failed(self): + """ + Called when the command failed. + """ + raise NotImplementedError + + + def commandMissing(self): + """ + Called when the command is missing. + """ + pass + + diff --git a/morituri/program/cdrdao.py b/morituri/program/cdrdao.py index 0b1fb7b..eb58a34 100644 --- a/morituri/program/cdrdao.py +++ b/morituri/program/cdrdao.py @@ -23,14 +23,12 @@ import re import os -import signal -import subprocess import tempfile from morituri.common import log, common from morituri.image import toc, table +from morituri.common import task as ctask -from morituri.extern import asyncsub from morituri.extern.task import task @@ -244,7 +242,7 @@ class OutputParser(object, log.Loggable): # FIXME: handle errors -class CDRDAOTask(task.Task): +class CDRDAOTask(ctask.PopenTask): """ I am a task base class that runs CDRDAO. """ @@ -258,97 +256,20 @@ class CDRDAOTask(task.Task): self.debug('creating CDRDAOTask') def start(self, runner): - task.Task.start(self, runner) + self.debug('Starting cdrdao with options %r', self.options) + self.command = ['cdrdao', ] + self.options - bufsize = 1024 - try: - self._popen = asyncsub.Popen(["cdrdao", ] + self.options, - bufsize=bufsize, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) - except OSError, e: - import errno - if e.errno == errno.ENOENT: - raise common.MissingDependencyException('cdrdao') + ctask.PopenTask.start(self, runner) - raise + def commandMissing(self): + raise common.MissingDependencyException('cdrdao') - self.debug('Started cdrdao with pid %d and options %r', - self._popen.pid, self.options) - self.debug('command: cdrdao %s', ' '.join(self.options)) - self.schedule(1.0, self._read, runner) - - def _read(self, runner): - try: - ret = self._popen.recv() - - if ret: - self.log("read from stdout: %s", ret) - self.readbytesout(ret) - - ret = self._popen.recv_err() - - if ret: - self.log("read from stderr: %s", ret) - self.readbyteserr(ret) - - if self._popen.poll() is None and self.runner: - # not finished yet - self.schedule(1.0, self._read, runner) - return - - self._done() - except Exception, e: - self.debug('exception during _read()') - self.debug(log.getExceptionMessage(e)) - self.setException(e) - self.stop() - - def _done(self): - assert self._popen.returncode is not None, "No returncode" - - if self._popen.returncode >= 0: - self.debug('Return code was %d', self._popen.returncode) - else: - self.debug('Terminated with signal %d', - -self._popen.returncode) - - self.setProgress(1.0) - - if self._popen.returncode != 0: - if self.errors: - raise DeviceOpenException("\n".join(self.errors)) - else: - raise ProgramFailedException(self._popen.returncode) - else: - self.done() - - self.stop() - return - - def abort(self): - self.debug('Aborting, sending SIGTERM to %d', self._popen.pid) - os.kill(self._popen.pid, signal.SIGTERM) - # self.stop() - - def readbytesout(self, bytes): - """ - Called when bytes have been read from stdout. - """ - pass - - def readbyteserr(self, bytes): - """ - Called when bytes have been read from stderr. - """ - pass - - def done(self): - """ - Called when cdrdao completed successfully. - """ - raise NotImplementedError + def failed(self): + if self.errors: + raise DeviceOpenException("\n".join(self.errors)) + else: + raise ProgramFailedException(self._popen.returncode) class DiscInfoTask(CDRDAOTask):