From a6d33df32d7ece8f6983ce16304917330751b4f3 Mon Sep 17 00:00:00 2001 From: JTL Date: Mon, 10 Dec 2018 19:24:44 -0800 Subject: [PATCH] asynchronously be able to parse cdrdao output now Add regexes to cdrdao.py --- whipper/program/cdrdao.py | 119 +++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 66 deletions(-) diff --git a/whipper/program/cdrdao.py b/whipper/program/cdrdao.py index 3508a240..2b0ae209 100644 --- a/whipper/program/cdrdao.py +++ b/whipper/program/cdrdao.py @@ -3,6 +3,8 @@ import re import shutil import tempfile +import subprocess +import time from subprocess import Popen, PIPE from whipper.common.common import truncate_filename @@ -15,6 +17,19 @@ CDRDAO = 'cdrdao' +_TRACK_RE = re.compile(r"^Analyzing track (?P[0-9]*) \(AUDIO\): start (?P[0-9]*:[0-9]*:[0-9]*), length (?P[0-9]*:[0-9]*:[0-9]*)") # noqa: E501 +_CRC_RE = re.compile( + r"Found (?P[0-9]*) Q sub-channels with CRC errors") +_BEGIN_CDRDAO_RE = re.compile(r"-"*60) +_LAST_TRACK_RE = re.compile(r"^(?P[0-9]*)") +_LEADOUT_RE = re.compile( + r"^Leadout AUDIO\s*[0-9]\s*[0-9]*:[0-9]*:[0-9]*\([0-9]*\)") + +class ProgressParser: + def parse(self, line): + pass + + class ReadTOC_Task(task.Task): """ Task that reads the TOC of the disc using cdrdao @@ -25,18 +40,20 @@ class ReadTOC_Task(task.Task): def __init__(self, device, fast_toc=False, toc_path=None): """ Read the TOC for 'device'. - @device: path of device - @type device: str - @param fast_toc: use cdrdao fast-toc mode - @type fast_toc: bool - @param toc_path: Where to save the generated table of contents - @type str + @param device: block device to read TOC from + @type device: str + @param fast_toc: If to use fast-toc cdrdao mode + @type fast_toc: bool + @param toc_path: Where to save TOC if wanted. + @type toc_path: str + """ self.device = device self.fast_toc = fast_toc self.toc_path = toc_path - + self._buffer = "" # accumulate characters + def start(self, runner): task.Task.start(self, runner) os.close(self.fd) @@ -80,10 +97,39 @@ def _read(self, runner): # 0 does not give us output before we complete, 1.0 gives us output # too late + + self._start_time = time.time() + self.schedule(1.0, self._read, runner) + + def _read(self, runner): + ret = self._popen.recv_err() + if not ret: + if self._popen.poll() is not None: + self._done() + return self.schedule(0.01, self._read, runner) + return + self._buffer += ret + + # parse buffer into lines if possible, and parse them + if "\n" in self._buffer: + lines = self._buffer.split('\n') + if lines[-1] != "\n": + # last line didn't end yet + self._buffer = lines[-1] + del lines[-1] + else: + self._buffer = "" + for line in lines: + sys.stdout.write("%s\n" % line) + + # 0 does not give us output before we complete, 1.0 gives us output + # too late + self.schedule(0.01, self._read, runner) def _poll(self, runner): + if self._popen.poll() is None: self.schedule(1.0, self._poll, runner) return @@ -108,49 +154,6 @@ def _done(self): self.stop() return -def read_toc(device, fast_toc=False, toc_path=None): - """ - Return cdrdao-generated table of contents for 'device'. - """ - # cdrdao MUST be passed a non-existing filename as its last argument - # to write the TOC to; it does not support writing to stdout or - # overwriting an existing file, nor does linux seem to support - # locking a non-existant file. Thus, this race-condition introducing - # hack is carried from morituri to whipper and will be removed when - # cdrdao is fixed. - fd, tocfile = tempfile.mkstemp(suffix=u'.cdrdao.read-toc.whipper') - os.close(fd) - os.unlink(tocfile) - - cmd = [CDRDAO, 'read-toc'] + (['--fast-toc'] if fast_toc else []) + [ - '--device', device, tocfile] - # PIPE is the closest to >/dev/null we can get - logger.debug("executing %r", cmd) - p = Popen(cmd, stdout=PIPE, stderr=PIPE) - _, stderr = p.communicate() - if p.returncode != 0: - msg = 'cdrdao read-toc failed: return code is non-zero: ' + \ - str(p.returncode) - logger.critical(msg) - # Gracefully handle missing disc - if "ERROR: Unit not ready, giving up." in stderr: - raise EjectError(device, "no disc detected") - raise IOError(msg) - - toc = TocFile(tocfile) - toc.parse() - if toc_path is not None: - t_comp = os.path.abspath(toc_path).split(os.sep) - t_dirn = os.sep.join(t_comp[:-1]) - # If the output path doesn't exist, make it recursively - if not os.path.isdir(t_dirn): - os.makedirs(t_dirn) - t_dst = truncate_filename(os.path.join(t_dirn, t_comp[-1] + '.toc')) - shutil.copy(tocfile, os.path.join(t_dirn, t_dst)) - os.unlink(tocfile) - return toc - - def DetectCdr(device): """ Return whether cdrdao detects a CD-R for 'device'. @@ -163,7 +166,6 @@ def DetectCdr(device): else: return True - def version(): """ Return cdrdao version as a string. @@ -182,21 +184,6 @@ def version(): return None return m.group('version') - -def ReadTOCTask(device): - """ - stopgap morituri-insanity compatibility layer - """ - return read_toc(device, fast_toc=True) - - -def ReadTableTask(device, toc_path=None): - """ - stopgap morituri-insanity compatibility layer - """ - return read_toc(device, toc_path=toc_path) - - def getCDRDAOVersion(): """ stopgap morituri-insanity compatibility layer