# HG changeset patch # User Jeff Hammel # Date 1270482944 25200 # Node ID 979315ed0816c64cf8677f4a15c5a1bf735f86df # Parent 7301d534bc6ca5081db6014e314ec9ae5c83c4fd mucho cleanup on optionparser stuff diff -r 7301d534bc6c -r 979315ed0816 profilemanager/command.py --- a/profilemanager/command.py Sun Apr 04 18:49:55 2010 -0400 +++ b/profilemanager/command.py Mon Apr 05 08:55:44 2010 -0700 @@ -41,10 +41,6 @@ retval.append('[options]') return ' '.join(retval) -def list_commands(): - for command in sorted(commands.keys()): - print '%s %s' % (command, commandargs2str(command)) - print '\n%s\n' % commands[command]['doc'] def doc2arghelp(docstring, decoration='-', delimeter=':'): """ @@ -96,3 +92,73 @@ return parser +class CommandParser(OptionParser): + def __init__(self, commands, description=None, setup=None): + usage = '%prog [options] command [command-options]' + OptionParser.__init__(self, description=description) + for _command in commands: + command(_command) + self.disable_interspersed_args() + self.setup = setup + + def print_help(self): + OptionParser.print_help(self) + # short descriptions for commands + command_descriptions = [dict(name=i, + description=commands[i]['doc'].strip().split('\n',1)[0]) + for i in sorted(commands.keys())] + max_len = max([len(i['name']) for i in command_descriptions]) + description = "Commands: \n%s" % ('\n'.join([' %s%s %s' % (description['name'], ' ' * (max_len - len(description['name'])), description['description']) + for description in command_descriptions])) + + print + print description + + def parse(self, args=sys.argv[1:]): + """global parse step""" + + self.options, args = self.parse_args(args) + + # help/sanity check -- should probably be separated + if not len(args): + self.print_help() + sys.exit(0) + if args[0] == 'help': + if len(args) == 2: + if args[1] in commands: + name = args[1] + commandparser = command2parser(name) + commandparser.print_help() + else: + self.error("No command '%s'" % args[1]) + else: + self.print_help() + sys.exit(0) + command = args[0] + if command not in commands: + self.error("No command '%s'" % command) + return command, args[1:] + + def invoke(self, args=sys.argv[1:]): + """ + invoke + """ + + # parse + name, args = self.parse(args) + + # setup + _object = self.setup(self, self.options) + + # command specific args + command = commands[name] + commandparser = command2parser(name) + command_options, command_args = commandparser.parse_args(args) + if len(command_args) < len(command['args']): + commandparser.error("Not enough arguments given") + if len(command_args) != len(command['args']) and not command['varargs']: + commandparser.error("Too many arguments given") + + # invoke the command + getattr(_object, name)(*command_args, **command_options.__dict__) + diff -r 7301d534bc6c -r 979315ed0816 profilemanager/main.py --- a/profilemanager/main.py Sun Apr 04 18:49:55 2010 -0400 +++ b/profilemanager/main.py Mon Apr 05 08:55:44 2010 -0700 @@ -4,73 +4,28 @@ import sys from manager import ProfileManager -from optparse import OptionGroup -from optparse import OptionParser -from command import commands, commandargs2str, command2parser - -# could go in commands -def print_help(parser): - parser.print_help() - # short descriptions for commands - command_descriptions = [dict(name=i, - description = commands[i]['doc'].strip().split('\n',1)[0]) - for i in sorted(commands.keys())] - max_len = max([len(i['name']) for i in command_descriptions]) - description = "Commands: \n%s" % ('\n'.join([' %s%s %s' % (description['name'], ' ' * (max_len - len(description['name'])), description['description']) - for description in command_descriptions])) - - print - print description - -def main(args=sys.argv[1:]): +from command import CommandParser - # global option parsing - usage = '%prog command ' - parser = OptionParser(usage, description='run `%prog help` to display commands') - parser.add_option('-c', '--config', dest='config', - help="specify a profile.ini [default: $HOME/.mozilla/firefox/profiles.ini]") - parser.disable_interspersed_args() - options, args = parser.parse_args(args) - - # help/sanity check -- should probably be separated - if not len(args): - print_help(parser) - sys.exit(0) - if args[0] == 'help': - if len(args) == 2: - if args[1] in commands: - name = args[1] - commandparser = command2parser(name) - commandparser.print_help() - else: - parser.error("No command '%s'" % args[1]) - else: - print_help(parser) - sys.exit(0) - command = args[0] - if command not in commands: - parser.error("No command '%s'" % command) - - # XXX to move it its own method -- this is the only program-specific code +def create_profilemanager(parser, options): + """create the profile manager from parsed arguments""" if options.config is None: # XXX unix-specific options.config = os.path.join(os.environ['HOME'], '.mozilla/firefox/profiles.ini') if not os.path.exists(options.config): parser.error('%s does not exist' % options.config) - manager = ProfileManager(options.config) + return ProfileManager(options.config) + +def main(args=sys.argv[1:]): - # command specific args - name = args[0] - command = commands[name] - commandparser = command2parser(name) - command_options, command_args = commandparser.parse_args(args[1:]) - if len(command_args) < len(command['args']): - commandparser.error("Not enough arguments given") - if len(command_args) != len(command['args']) and not command['varargs']: - commandparser.error("Too many arguments given") - - # invoke the command - getattr(manager, name)(*command_args, **command_options.__dict__) + # global option parsing + commands = [ ProfileManager.clone, + ProfileManager.backup, + ProfileManager.restore, + ProfileManager.merge ] + parser = CommandParser(commands, setup=create_profilemanager) + parser.add_option('-c', '--config', dest='config', + help="specify a profile.ini [default: $HOME/.mozilla/firefox/profiles.ini]") + parser.invoke(args) if __name__ == '__main__': main() diff -r 7301d534bc6c -r 979315ed0816 profilemanager/manager.py --- a/profilemanager/manager.py Sun Apr 04 18:49:55 2010 -0400 +++ b/profilemanager/manager.py Mon Apr 05 08:55:44 2010 -0700 @@ -24,7 +24,6 @@ ### (public) API - @command def clone(self, source, dest): """ clones the profile `source` and output to `dest` @@ -33,7 +32,7 @@ dest_path = self.path(dest) # fs path to back up to shutil.copytree(src_path, backup, symlinks=False) - @command + def backup(self, profile, dest=None): """ backup the profile @@ -48,7 +47,6 @@ # `Backup=$(profile)s.$(datestamp)s.bak` # to self.profiles - @command def restore(self, profile, date=None, delete=False): """ restore the profile from a backup @@ -60,7 +58,6 @@ # delete the backup pass - @command def merge(self, *profiles): """merge a set of profiles (not trivial!)""" raise NotImplementedError diff -r 7301d534bc6c -r 979315ed0816 setup.py --- a/setup.py Sun Apr 04 18:49:55 2010 -0400 +++ b/setup.py Mon Apr 05 08:55:44 2010 -0700 @@ -13,7 +13,7 @@ author='Jeff Hammel', author_email='jhammel@mozilla.com', url='', - license='', + license='MPL', packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), include_package_data=True, zip_safe=False, @@ -23,6 +23,6 @@ entry_points=""" # -*- Entry points: -*- [console_scripts] - ProfileManager = profilemanager.main:main + profile-manager = profilemanager.main:main """, )