diff --git a/morituri/common/logcommand.py b/morituri/common/logcommand.py index 32c3afc4..853b2a78 100644 --- a/morituri/common/logcommand.py +++ b/morituri/common/logcommand.py @@ -25,8 +25,24 @@ """ from morituri.extern.command import command -from morituri.common import log +from morituri.common import log, config +import logging +class Lager(): + """ + Provides self.debug() logging facility for existing commands. + Provides self.epilog() formatting command for argparse. + """ + config = config.Config() + def debug(self, format, *args): + kwargs = {} + pass + + def epilog(self): + s = "commands:\n" + for com in sorted(self.subcommands.keys()): + s += " %s %s\n" % (com.ljust(8), self.subcommands[com].summary) + return s class LogCommand(command.Command, log.Loggable): diff --git a/morituri/rip/accurip.py b/morituri/rip/accurip.py index bda12d00..65ef5f58 100644 --- a/morituri/rip/accurip.py +++ b/morituri/rip/accurip.py @@ -87,6 +87,6 @@ def do(self, args): class AccuRip(logcommand.LogCommand): - description = "Handle AccurateRip information." + summary = "handle AccurateRip information" subCommandClasses = [Show, ] diff --git a/morituri/rip/cd.py b/morituri/rip/cd.py index 3939a60a..758ed0a8 100644 --- a/morituri/rip/cd.py +++ b/morituri/rip/cd.py @@ -572,7 +572,7 @@ def writeFile(handle, path, length): class CD(logcommand.LogCommand): - summary = "handle CD's" + summary = "handle CDs" subCommandClasses = [Info, Rip, ] diff --git a/morituri/rip/image.py b/morituri/rip/image.py index 156ec341..087778b4 100644 --- a/morituri/rip/image.py +++ b/morituri/rip/image.py @@ -20,9 +20,13 @@ # You should have received a copy of the GNU General Public License # along with morituri. If not, see . +import argparse import os +import sys -from morituri.common import logcommand, accurip, program +import logging + +from morituri.common import logcommand, accurip, program, config from morituri.image import image from morituri.result import result @@ -99,27 +103,43 @@ def do(self, args): outm3u.close() -class Retag(logcommand.LogCommand): - +class Retag(logcommand.Lager): summary = "retag image files" - - def addOptions(self): - self.parser.add_option('-R', '--release-id', + description = """ +Retags the image from the given .cue files with tags obtained from MusicBrainz. +""" + stdout = sys.stdout + + def __init__(self, argv, prog=None): + parser = argparse.ArgumentParser( + prog=prog, + description=self.description + ) + parser.add_argument('cuefile', nargs='+', action='store', + help="cue file to load rip image from") + parser.add_argument( + '-R', '--release-id', action="store", dest="release_id", - help="MusicBrainz release id to match to (if there are multiple)") - self.parser.add_option('-p', '--prompt', + help="MusicBrainz release id to match to (if there are multiple)" + ) + parser.add_argument( + '-p', '--prompt', action="store_true", dest="prompt", - help="Prompt if there are multiple matching releases") - self.parser.add_option('-c', '--country', + help="Prompt if there are multiple matching releases" + ) + parser.add_argument( + '-c', '--country', action="store", dest="country", - help="Filter releases by country") - + help="Filter releases by country" + ) + self.options = parser.parse_args(argv) + return self.do(self.options.cuefile) def do(self, args): # here to avoid import gst eating our options from morituri.common import encode - prog = program.Program(self.getRootCommand().config, stdout=self.stdout) + prog = program.Program(self.config, stdout=self.stdout) runner = task.SyncRunner() for arg in args: @@ -164,17 +184,24 @@ def do(self, args): print -class Verify(logcommand.LogCommand): - - usage = '[CUEFILE]...' +class Verify(logcommand.Lager): summary = "verify image" - - description = ''' + description = """ Verifies the image from the given .cue files against the AccurateRip database. -''' +""" + + def __init__(self, argv, prog=None): + parser = argparse.ArgumentParser( + prog=prog, + description=self.description + ) + parser.add_argument('cuefile', nargs='+', action='store', + help="cue file to load rip image from") + options = parser.parse_args(argv) + return self.do(options.cuefile) def do(self, args): - prog = program.Program(self.getRootCommand().config) + prog = program.Program(self.config) runner = task.SyncRunner() cache = accurip.AccuCache() @@ -199,14 +226,34 @@ def do(self, args): print "\n".join(prog.getAccurateRipResults()) + "\n" -class Image(logcommand.LogCommand): - +class Image(logcommand.Lager): summary = "handle images" - description = """ Handle disc images. Disc images are described by a .cue file. Disc images can be encoded to another format (for example, to make a compressed encoding), retagged and verified. """ - - subCommandClasses = [Encode, Retag, Verify, ] + subcommands = { + 'verify': Verify, + 'retag': Retag + } + + def __init__(self, argv, prog=None): + parser = argparse.ArgumentParser( + prog=prog, + description=self.description, + epilog=self.epilog(), + formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument('remainder', nargs=argparse.REMAINDER, + help=argparse.SUPPRESS) + opt = parser.parse_args(argv) + if not opt.remainder: + parser.print_help() + sys.exit(0) + if not opt.remainder[0] in self.subcommands: + sys.stderr.write("incorrect subcommand: %s" % opt.remainder[0]) + sys.exit(1) + return self.subcommands[opt.remainder[0]]( + opt.remainder[1:], prog=prog + " " + opt.remainder[0] + ) diff --git a/morituri/rip/main.py b/morituri/rip/main.py index b6f82be3..4a9f086a 100644 --- a/morituri/rip/main.py +++ b/morituri/rip/main.py @@ -1,6 +1,7 @@ # -*- Mode: Python -*- # vi:si:et:sw=4:sts=4:ts=4 +import argparse import os import sys import pkg_resources @@ -22,9 +23,8 @@ def main(): pkg_resources.Environment([directory.data_path('plugins')]) ) map(pkg_resources.working_set.add, distributions) - c = Rip() try: - ret = c.parse(sys.argv[1:]) + ret = Whipper(sys.argv[1:], prog=os.path.basename(sys.argv[0])) except SystemError, e: sys.stderr.write('rip: error: %s\n' % e.args) return 255 @@ -46,15 +46,54 @@ def main(): return 255 raise - except command.CommandError, e: - sys.stderr.write('rip: error: %s\n' % e.output) - return e.status + return ret if ret else 0 - if ret is None: - return 0 - - return ret +class Whipper(logcommand.Lager): + usage = "%prog %command" + description = """whipper is a CD ripping utility focusing on accuracy over speed. +whipper gives you a tree of subcommands to work with. +You can get help on subcommands by using the -h option to the subcommand. +""" + subcommands = { + 'accurip': accurip.AccuRip, + 'cd': cd.CD, + 'debug': debug.Debug, + 'drive': drive.Drive, + 'offset': offset.Offset, + 'image': image.Image + } + + def __init__(self, argv, prog=None): + parser = argparse.ArgumentParser( + prog=prog, + add_help=False, + description=self.description, + epilog=self.epilog(), + formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument('-R', '--record', + action='store_true', dest='record', + help="record API requests for playback") + parser.add_argument('-v', '--version', + action="store_true", dest="version", + help="show version information") + parser.add_argument('-h', '--help', + action="store_true", dest="help", + help="show this help message and exit") + parser.add_argument('remainder', nargs=argparse.REMAINDER, + help=argparse.SUPPRESS) + opt = parser.parse_args(argv) + if opt.help or not opt.remainder: + parser.print_help() + sys.exit(0) + if opt.version: + print "whipper %s" % configure.version + sys.stderr.write("incorrect subcommand: %s" % opt.remainder[0]) + sys.exit(1) + return self.subcommands[opt.remainder[0]]( + opt.remainder[1:], prog=prog + " " + opt.remainder[0] + ) class Rip(logcommand.LogCommand): usage = "%prog %command"