cdrdao no-disc ejection & --eject (#93)
* cdrdao: eject empty disc while reading toc
- introduce EjectError
- move {eject,load,unmount}_device to program.utils
* remove duplicated eject
* remove unnecessary ejection
* add --eject option
This commit is contained in:
committed by
JoeLametta
parent
17021a68f2
commit
a1eb3377ea
@@ -34,7 +34,7 @@ from morituri.command.basecommand import BaseCommand
|
||||
from morituri.common import (
|
||||
accurip, common, config, drive, gstreamer, program, task
|
||||
)
|
||||
from morituri.program import cdrdao, cdparanoia
|
||||
from morituri.program import cdrdao, cdparanoia, utils
|
||||
from morituri.result import result
|
||||
|
||||
import logging
|
||||
@@ -108,8 +108,8 @@ class _CD(BaseCommand):
|
||||
self.device = self.options.device
|
||||
sys.stdout.write('Checking device %s\n' % self.device)
|
||||
|
||||
self.program.loadDevice(self.device)
|
||||
self.program.unmountDevice(self.device)
|
||||
utils.load_device(self.device)
|
||||
utils.unmount_device(self.device)
|
||||
|
||||
# first, read the normal TOC, which is fast
|
||||
self.ittoc = self.program.getFastToc(self.runner,
|
||||
@@ -140,8 +140,8 @@ class _CD(BaseCommand):
|
||||
|
||||
# also used by rip cd info
|
||||
if not getattr(self.options, 'unknown', False):
|
||||
if self.eject:
|
||||
self.program.ejectDevice(self.device)
|
||||
logger.critical("unable to retrieve disc metadata, "
|
||||
"--unknown not passed")
|
||||
return -1
|
||||
|
||||
# FIXME ?????
|
||||
@@ -205,8 +205,8 @@ class _CD(BaseCommand):
|
||||
|
||||
self.doCommand()
|
||||
|
||||
if self.eject:
|
||||
self.program.ejectDevice(self.device)
|
||||
if self.options.eject in ('success', 'always'):
|
||||
utils.eject_device(self.device)
|
||||
|
||||
def doCommand(self):
|
||||
pass
|
||||
@@ -587,8 +587,6 @@ Log files will log the path to tracks relative to this directory.
|
||||
# write log file
|
||||
self.program.writeLog(discName, self.logger)
|
||||
|
||||
self.program.ejectDevice(self.device)
|
||||
|
||||
|
||||
class CD(BaseCommand):
|
||||
summary = "handle CDs"
|
||||
|
||||
@@ -12,6 +12,7 @@ from morituri.command import cd, offset, drive, image, accurip, debug
|
||||
from morituri.command.basecommand import BaseCommand
|
||||
from morituri.common import common, directory
|
||||
from morituri.extern.task import task
|
||||
from morituri.program.utils import eject_device
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -26,9 +27,13 @@ def main():
|
||||
)
|
||||
map(pkg_resources.working_set.add, distributions)
|
||||
try:
|
||||
ret = Whipper(sys.argv[1:], os.path.basename(sys.argv[0]), None).do()
|
||||
cmd = Whipper(sys.argv[1:], os.path.basename(sys.argv[0]), None)
|
||||
ret = cmd.do()
|
||||
except SystemError, e:
|
||||
sys.stderr.write('whipper: error: %s\n' % e.args)
|
||||
sys.stderr.write('whipper: error: %s\n' % e)
|
||||
if (type(e) is common.EjectError and
|
||||
cmd.options.eject in ('failure', 'always')):
|
||||
eject_device(e.device)
|
||||
return 255
|
||||
except ImportError, e:
|
||||
raise ImportError(e)
|
||||
@@ -77,6 +82,10 @@ You can get help on subcommands by using the -h option to the subcommand.
|
||||
self.parser.add_argument('-h', '--help',
|
||||
action="store_true", dest="help",
|
||||
help="show this help message and exit")
|
||||
self.parser.add_argument('-e', '--eject',
|
||||
action="store", dest="eject", default="always",
|
||||
choices=('never', 'failure', 'success', 'always'),
|
||||
help="when to eject disc (default: always)")
|
||||
|
||||
def handle_arguments(self):
|
||||
if self.options.help:
|
||||
|
||||
@@ -31,7 +31,7 @@ gobject.threads_init()
|
||||
from morituri.command.basecommand import BaseCommand
|
||||
from morituri.common import accurip, common, config, drive, program
|
||||
from morituri.common import task as ctask
|
||||
from morituri.program import cdrdao, cdparanoia
|
||||
from morituri.program import cdrdao, cdparanoia, utils
|
||||
|
||||
from morituri.extern.task import task
|
||||
|
||||
@@ -88,8 +88,8 @@ CD in the AccurateRip database."""
|
||||
# if necessary, load and unmount
|
||||
sys.stdout.write('Checking device %s\n' % device)
|
||||
|
||||
prog.loadDevice(device)
|
||||
prog.unmountDevice(device)
|
||||
utils.load_device(device)
|
||||
utils.unmount_device(device)
|
||||
|
||||
# first get the Table Of Contents of the CD
|
||||
t = cdrdao.ReadTOCTask(device)
|
||||
|
||||
@@ -39,6 +39,19 @@ WORDS_PER_FRAME = SAMPLES_PER_FRAME * 2
|
||||
BYTES_PER_FRAME = SAMPLES_PER_FRAME * 4
|
||||
|
||||
|
||||
class EjectError(SystemError):
|
||||
"""
|
||||
Possibly ejects the drive in command.main.
|
||||
"""
|
||||
def __init__(self, device, *args):
|
||||
"""
|
||||
args is a tuple used by BaseException.__str__
|
||||
device is the device path to eject
|
||||
"""
|
||||
self.args = args
|
||||
self.device = device
|
||||
|
||||
|
||||
def msfToFrames(msf):
|
||||
"""
|
||||
Converts a string value in MM:SS:FF to frames.
|
||||
|
||||
@@ -90,32 +90,6 @@ class Program:
|
||||
logger.info('Changing to working directory %s' % workingDirectory)
|
||||
os.chdir(workingDirectory)
|
||||
|
||||
def loadDevice(self, device):
|
||||
"""
|
||||
Load the given device.
|
||||
"""
|
||||
os.system('eject -t %s' % device)
|
||||
|
||||
def ejectDevice(self, device):
|
||||
"""
|
||||
Eject the given device.
|
||||
"""
|
||||
os.system('eject %s' % device)
|
||||
|
||||
def unmountDevice(self, device):
|
||||
"""
|
||||
Unmount the given device if it is mounted, as happens with automounted
|
||||
data tracks.
|
||||
|
||||
If the given device is a symlink, the target will be checked.
|
||||
"""
|
||||
device = os.path.realpath(device)
|
||||
logger.debug('possibly unmount real path %r' % device)
|
||||
proc = open('/proc/mounts').read()
|
||||
if device in proc:
|
||||
print 'Device %s is mounted, unmounting' % device
|
||||
os.system('umount %s' % device)
|
||||
|
||||
def getFastToc(self, runner, toc_pickle, device):
|
||||
"""
|
||||
Retrieve the normal TOC table from a toc pickle or the drive.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
from subprocess import check_call, Popen, PIPE, CalledProcessError
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
from morituri.common.common import EjectError
|
||||
from morituri.image.toc import TocFile
|
||||
|
||||
import logging
|
||||
@@ -27,12 +28,18 @@ def read_toc(device, fast_toc=False):
|
||||
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:
|
||||
logger.warning('cdrdao read-toc failed: return code is non-zero: ' +
|
||||
str(e.returncode))
|
||||
raise e
|
||||
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()
|
||||
os.unlink(tocfile)
|
||||
|
||||
35
morituri/program/utils.py
Normal file
35
morituri/program/utils.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def eject_device(device):
|
||||
"""
|
||||
Eject the given device.
|
||||
"""
|
||||
logger.debug("ejecting device %s", device)
|
||||
os.system('eject %s' % device)
|
||||
|
||||
|
||||
def load_device(device):
|
||||
"""
|
||||
Load the given device.
|
||||
"""
|
||||
logger.debug("loading (eject -t) device %s", device)
|
||||
os.system('eject -t %s' % device)
|
||||
|
||||
|
||||
def unmount_device(device):
|
||||
"""
|
||||
Unmount the given device if it is mounted, as happens with automounted
|
||||
data tracks.
|
||||
|
||||
If the given device is a symlink, the target will be checked.
|
||||
"""
|
||||
device = os.path.realpath(device)
|
||||
logger.debug('possibly unmount real path %r' % device)
|
||||
proc = open('/proc/mounts').read()
|
||||
if device in proc:
|
||||
print 'Device %s is mounted, unmounting' % device
|
||||
os.system('umount %s' % device)
|
||||
Reference in New Issue
Block a user