diff --git a/morituri/common/program.py b/morituri/common/program.py
index 83fa1ab..3bc8400 100644
--- a/morituri/common/program.py
+++ b/morituri/common/program.py
@@ -126,26 +126,14 @@ class Program(log.Loggable):
ptoc = cache.Persister(toc_pickle or None)
if not ptoc.object:
- tries = 0
- while True:
- tries += 1
- t = cdrdao.ReadTOCTask(device=device)
- try:
- function(runner, t)
- break
- except:
- if tries > 3:
- raise
- self.debug('failed to read TOC after %d tries, retrying' % tries)
-
- version = t.tasks[1].parser.version
from pkg_resources import parse_version as V
- # we've built a cdrdao 1.2.3rc2 modified package with the patch
- if V(version) < V('1.2.3rc2p1'):
+ version = cdrdao.getCDRDAOVersion()
+ if V(version) < V('1.2.3rc2'):
self.stdout.write('Warning: cdrdao older than 1.2.3 has a '
'pre-gap length bug.\n'
'See http://sourceforge.net/tracker/?func=detail'
'&aid=604751&group_id=2171&atid=102171\n')
+ t = cdrdao.ReadTOCTask(device)
ptoc.persist(t.table)
toc = ptoc.object
assert toc.hasTOC()
@@ -173,8 +161,7 @@ class Program(log.Loggable):
self.debug('getTable: cddbdiscid %s, mbdiscid %s not in cache for offset %s, '
'reading table' % (
cddbdiscid, mbdiscid, offset))
- t = cdrdao.ReadTableTask(device=device)
- runner.run(t)
+ t = cdrdao.ReadTableTask(device)
itable = t.table
tdict[offset] = itable
ptable.persist(tdict)
diff --git a/morituri/program/cdrdao.py b/morituri/program/cdrdao.py
index c6fba64..95ba4f6 100644
--- a/morituri/program/cdrdao.py
+++ b/morituri/program/cdrdao.py
@@ -1,522 +1,73 @@
-# -*- Mode: Python; test-case-name:morituri.test.test_program_cdrdao -*-
-# vi:si:et:sw=4:sts=4:ts=4
-
-# Morituri - for those about to RIP
-
-# Copyright (C) 2009 Thomas Vander Stichele
-
-# This file is part of morituri.
-#
-# morituri is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# morituri is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with morituri. If not, see .
-
-
-import re
+import logging
import os
+import re
import tempfile
+from subprocess import check_call, Popen, PIPE, CalledProcessError
-from morituri.common import log, common
-from morituri.image import toc, table
-from morituri.common import task as ctask
+from morituri.image.toc import TocFile
-from morituri.extern.task import task
+CDRDAO = 'cdrdao'
-
-class ProgramError(Exception):
+def read_toc(device, fast_toc=False):
"""
- The program had a fatal error.
+ 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)
- def __init__(self, errorMessage):
- self.args = (errorMessage, )
- self.errorMessage = errorMessage
+ cmd = [CDRDAO, 'read-toc'] + (['--fast-toc'] if fast_toc else []) + [
+ '--device', device, tocfile]
+ # PIPE is the closest to >/dev/null we can get
+ try:
+ check_call(cmd, stdout=PIPE, stderr=PIPE)
+ except CalledProcessError, e:
+ logging.warning('cdrdao read-toc failed: return code is non-zero: ' +
+ str(e.returncode))
+ raise e
+ toc = TocFile(tocfile)
+ toc.parse()
+ os.unlink(tocfile)
+ return toc
-states = ['START', 'TRACK', 'LEADOUT', 'DONE']
-
-_VERSION_RE = re.compile(r'^Cdrdao version (?P.*) - \(C\)')
-
-_ANALYZING_RE = re.compile(r'^Analyzing track (?P