* morituri/common/task.py:

* morituri/program/cdrdao.py:
	  Factor out a PopenTask base class.
This commit is contained in:
Thomas Vander Stichele
2012-12-03 22:58:22 +00:00
parent 3a9a939520
commit b8fd3f2931
3 changed files with 136 additions and 91 deletions

View File

@@ -1,3 +1,9 @@
2012-12-03 Thomas Vander Stichele <thomas at apestaart dot org>
* morituri/common/task.py:
* morituri/program/cdrdao.py:
Factor out a PopenTask base class.
2012-12-03 Thomas Vander Stichele <thomas at apestaart dot org>
* morituri/common/program.py:

View File

@@ -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

View File

@@ -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):