changeset 1:979315ed0816

mucho cleanup on optionparser stuff
author Jeff Hammel <jhammel@mozilla.com>
date Mon, 05 Apr 2010 08:55:44 -0700
parents 7301d534bc6c
children fc0dabd2269f
files profilemanager/command.py profilemanager/main.py profilemanager/manager.py setup.py
diffstat 4 files changed, 88 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- 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__)
+
--- 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 <options> command <command-options>'
-    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()
--- 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
--- 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
       """,
       )