diff options
| author | Mikhail Osipov <m.osipov@corp.mail.ru> | 2013-11-05 12:29:32 +0400 |
|---|---|---|
| committer | Mikhail Osipov <mike.osipov@gmail.com> | 2013-11-05 22:48:08 +0400 |
| commit | 2bb39647a32c51e981070e08c5d3c4a5c2e631e4 (patch) | |
| tree | 92446a3d7956c640eeadf7b754a9bc1b48c3abe9 | |
| parent | 6cb3a8a1828ef2b3c480b6e4988a2421ec47d0c6 (diff) | |
check exceptions for Popen, error handling improved
| -rw-r--r-- | cutter/formats/command.py | 62 | ||||
| -rw-r--r-- | cutter/formats/decoder.py | 36 | ||||
| -rw-r--r-- | cutter/formats/encoder.py | 24 | ||||
| -rw-r--r-- | cutter/formats/wav.py | 3 | ||||
| -rw-r--r-- | cutter/splitter.py | 59 |
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() |
