summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Osipov <m.osipov@corp.mail.ru>2013-11-05 12:29:32 +0400
committerMikhail Osipov <mike.osipov@gmail.com>2013-11-05 22:48:08 +0400
commit2bb39647a32c51e981070e08c5d3c4a5c2e631e4 (patch)
tree92446a3d7956c640eeadf7b754a9bc1b48c3abe9
parent6cb3a8a1828ef2b3c480b6e4988a2421ec47d0c6 (diff)
check exceptions for Popen, error handling improved
-rw-r--r--cutter/formats/command.py62
-rw-r--r--cutter/formats/decoder.py36
-rw-r--r--cutter/formats/encoder.py24
-rw-r--r--cutter/formats/wav.py3
-rw-r--r--cutter/splitter.py59
5 files changed, 128 insertions, 56 deletions
diff --git a/cutter/formats/command.py b/cutter/formats/command.py
new file mode 100644
index 0000000..72f2e86
--- /dev/null
+++ b/cutter/formats/command.py
@@ -0,0 +1,62 @@
+from .. coding import to_unicode
+
+import subprocess
+import signal
+
+PIPE = subprocess.PIPE
+STDOUT = subprocess.STDOUT
+
+def strsignal(sig):
+ for k, v in signal.__dict__.items():
+ if k.startswith("SIG") and not k.startswith("SIG_"):
+ if v == sig:
+ return k
+
+ return "signal(%d)" % sig
+
+class CommandError(Exception):
+ pass
+
+class Command:
+ def __init__(self, args, stdin=None, stdout=None, stderr=None):
+ self.proc = None
+ self.status = 0
+ self.status_msg = ""
+
+ try:
+ self.proc = subprocess.Popen(args,
+ stdin=stdin, stdout=stdout, stderr=stderr)
+ except OSError as err:
+ self.status = "not started"
+ self.status_msg = err.strerror
+
+ def __getattr__(self, attr):
+ if self.proc is None:
+ raise CommandError("command not started")
+
+ if attr not in ("stdin", "stdout", "stderr"):
+ raise CommandError("unknown attribute '%s'", attr)
+
+ return getattr(self.proc, attr)
+
+ def ready(self):
+ return self.proc is not None
+
+ def get_status(self):
+ return self.status, self.status_msg
+
+ def close(self, msg=""):
+ if self.proc is None:
+ return
+
+ self.status = self.proc.wait()
+ if self.status and self.proc.stderr:
+ self.status_msg = to_unicode(self.proc.stderr.read())
+
+ if msg and not self.status_msg:
+ self.status_msg = msg
+
+ if self.status < 0:
+ self.status = strsignal(-self.status)
+
+ self.proc = None
diff --git a/cutter/formats/decoder.py b/cutter/formats/decoder.py
index 99f2cbe..b57591d 100644
--- a/cutter/formats/decoder.py
+++ b/cutter/formats/decoder.py
@@ -1,8 +1,9 @@
from . handler import *
+from . command import *
+
from .. tools import quote
from .. coding import to_unicode
-import subprocess
import wave
class DecoderError(Exception):
@@ -42,25 +43,20 @@ class Decoder:
return data
def __init__(self, handler, filename, options=None):
- self.reader = None
- self.closed = False
self.handler = handler
args = self.handler.decode(filename)
self.command = " ".join(map(quote, args))
- self.proc = subprocess.Popen(
- args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
- )
+ self.proc = Command(args, stdout=PIPE, stderr=PIPE)
+ if not self.proc.ready():
+ return
try:
self.reader = wave.open(self.proc.stdout, "r")
except Exception as exc:
- self.close()
- if self.status:
- self.status_msg = to_unicode(self.proc.stderr.read())
- else:
- self.status_msg = "wave.open: %s" % exc
+ self.proc.stdout.close()
+ self.proc.close("Exception: wave.open: %s" % repr(exc))
return
self._channels = self.reader.getnchannels()
@@ -68,7 +64,7 @@ class Decoder:
self._sample_rate = self.reader.getframerate()
def ready(self):
- return self.reader is not None
+ return self.proc.ready()
def channels(self):
return self._channels
@@ -111,23 +107,13 @@ class Decoder:
return self.command
def get_status(self):
- return self.status, self.status_msg
+ return self.proc.get_status()
def close(self):
- if self.closed:
- return
-
- if self.reader:
+ if self.proc.ready():
self.reader.close()
-
- if self.proc:
self.proc.stdout.close()
- self.status = self.proc.wait()
- else:
- self.status = 0
-
- self.status_msg = ""
- self.closed = True
+ self.proc.close()
def __del__(self):
self.close()
diff --git a/cutter/formats/encoder.py b/cutter/formats/encoder.py
index 23d0c51..8689de8 100644
--- a/cutter/formats/encoder.py
+++ b/cutter/formats/encoder.py
@@ -1,3 +1,4 @@
+from . command import *
from . handler import *
from .. tools import quote
@@ -52,7 +53,6 @@ class Encoder:
return getattr(self.fileobj, attr)
def __init__(self, handler, reader, filename, options):
- self.closed = False
self.handler = handler
args = self.handler.encode(filename, options, reader.info())
@@ -62,15 +62,20 @@ class Encoder:
self.proc = None
return
- self.proc = subprocess.Popen(args, stdin=subprocess.PIPE)
+ self.proc = Command(args, stdin=PIPE)
+ if not self.proc.ready():
+ return
self.reader = reader
self.stream = self.SafeStream(self.proc.stdin)
self.writer = wave.open(self.stream, "w")
self.writer.setparams(reader.wave_params())
+ def ready(self):
+ return self.proc.ready()
+
def process(self):
- if self.proc is None:
+ if not self.proc.ready():
return
while True:
@@ -83,13 +88,14 @@ class Encoder:
def get_command(self):
return self.command
- def close(self):
- if self.closed or self.proc is None:
- return
+ def get_status(self):
+ return self.proc.get_status()
- self.writer.close()
- self.stream.close()
- self.proc.wait()
+ def close(self):
+ if self.proc and self.proc.ready():
+ self.writer.close()
+ self.stream.close()
+ self.proc.close()
def __del__(self):
self.close()
diff --git a/cutter/formats/wav.py b/cutter/formats/wav.py
index 41e18d9..d614973 100644
--- a/cutter/formats/wav.py
+++ b/cutter/formats/wav.py
@@ -4,6 +4,9 @@ class WavHandler(SoxHandler):
name = "wav"
ext = "wav"
+ def decode(self, filename):
+ return ["cat", filename]
+
def encode(self, path, opt, info):
return self.sox_args(path, opt, info)
diff --git a/cutter/splitter.py b/cutter/splitter.py
index 3109c14..534815b 100644
--- a/cutter/splitter.py
+++ b/cutter/splitter.py
@@ -239,12 +239,11 @@ class Splitter:
path = os.path.join(self.dest, trackname)
printf("copy %s -> %s", quote(file.path), quote(path))
+ printf("\n" if self.opt.dry_run else ": ")
+
if self.opt.dry_run:
- printf("\n")
return
- printf(": ")
-
try:
shutil.copyfile(file.path, path)
except Exception as err:
@@ -255,20 +254,40 @@ class Splitter:
self.tag(track, path)
+ @staticmethod
+ def print_command_error(name, stream):
+ status, msg = stream.get_status()
+
+ cmd = stream.get_command()
+ printerr("%s failed (%s), command: %s", name, status, cmd)
+ for line in msg.split("\n"):
+ if len(line):
+ printf("> %s\n", line)
+
def open_decode(self, path):
stream = formats.decoder_open(path, self.opt)
if stream is None:
printerr("%s: unsupported type", quote(path))
elif not stream.ready():
- printerr("decode failed, command: %s", stream.get_command())
+ self.print_command_error("decode", stream)
+ stream = None
+ else:
+ if self.opt.verbose and self.opt.dry_run:
+ self.print_decode_info(path, stream)
- status, msg = stream.get_status()
- if not len(msg):
- printerr("exit code %d", status)
- else:
- printerr("exit code %d, stderr:\n%s", status, msg)
+ return stream
+
+ def open_encode(self, reader, path):
+ stream = self.encoder.open(reader, path, self.opt)
+ if self.opt.dry_run:
+ if self.opt.verbose:
+ debug("encode: %s", stream.get_command())
+ return stream
+
+ if not stream.ready():
+ self.print_command_error("encode", stream)
stream = None
return stream
@@ -280,9 +299,6 @@ class Splitter:
info.type, info.bits_per_sample, info.sample_rate,
info.channels)
- def print_encode_info(self, stream):
- debug("encode: %s", stream.get_command())
-
@staticmethod
def track_timerange(track):
ts = "%8s -" % msf(track.begin)
@@ -302,10 +318,7 @@ class Splitter:
def split_file(self, file):
stream = self.open_decode(file.path)
if not stream:
- return
-
- if self.opt.verbose and self.opt.dry_run:
- self.print_decode_info(file.path, stream)
+ sys.exit(1)
if file.ntracks() == 1:
if not self.is_need_convert(stream.info()):
@@ -324,19 +337,21 @@ class Splitter:
trackname = self.track_name(track)
path = os.path.join(self.dest, trackname)
- printf("split %s (%s) -> %s", quote(file.path), ts, quote(trackname))
- printf("\n" if self.opt.dry_run else ": ")
-
stream.seek(track.begin)
reader = stream.get_reader(self.track_length(track))
- out = self.encoder.open(reader, path, self.opt)
+ out = self.open_encode(reader, path)
+
+ printf("split %s (%s) -> %s", quote(file.path), ts, quote(trackname))
+ printf("\n" if self.opt.dry_run else ": ")
if self.opt.dry_run:
- if self.opt.verbose:
- self.print_encode_info(out)
continue
+ if out is None:
+ printf("FAILED\n")
+ sys.exit(1)
+
out.process()
out.close()