Index: pykota/trunk/bin/pkbcodes
===================================================================
--- pykota/trunk/bin/pkbcodes (revision 3295)
+++ pykota/trunk/bin/pkbcodes (revision 3361)
@@ -22,4 +22,6 @@
 #
 
+"""A billing codes manager for PyKota."""
+
 import os
 import sys
@@ -27,61 +29,10 @@
 
 import pykota.appinit
-from pykota.utils import *
-
+from pykota.utils import run
+from pykota.commandline import PyKotaOptionParser
 from pykota.errors import PyKotaCommandLineError
 from pykota.tool import Percent, PyKotaTool
 from pykota.storage import StorageBillingCode
 
-__doc__ = N_("""pkbcodes v%(__version__)s (c) %(__years__)s %(__author__)s
-
-A billing codes Manager for PyKota.
-
-command line usage :
-
-  pkbcodes [options] code1 code2 code3 ... codeN
-
-options :
-
-  -v | --version       Prints pkbcodes version number then exits.
-  -h | --help          Prints this message then exits.
-  
-  -a | --add           Adds billing codes if they don't exist in PyKota's
-                       database. If they exist, they are modified
-                       unless -s|--skipexisting is also used.
-
-  -d | --delete        Deletes billing codes from PyKota's database.
-                       NB : the history entries with this billing code
-                       are not deleted, voluntarily.
-
-  -D | --description d Adds a textual description to billing codes.
-
-  -l | --list          List informations about the billing codes.
-
-  -r | --reset         Resets the billing codes' balance and page counters
-                       to 0.
-
-  -s | --skipexisting  In combination with the --add option above, tells
-                       pkbcodes to not modify existing billing codes.
-
-  code1 through codeN can contain wildcards if the --add option
-  is not set.
-
-examples :                              
-
-  $ pkbcodes --add -D "My project" myproj
-
-  Will create the myproj billing code with "My project"
-  as the description.
-
-  $ pkbcodes --delete "*"
-
-  This will completely delete all the billing codes, but without
-  removing any matching job from the history. USE WITH CARE ANYWAY !
-  
-  $ pkbcodes --list "my*"
-  
-  This will list all billing codes which name begins with 'my'.
-""")
-        
 class PKBcodes(PyKotaTool) :        
     """A class for a billing codes manager."""
@@ -95,26 +46,35 @@
     def main(self, names, options) :
         """Manage billing codes."""
-        if (not self.config.isAdmin) and (not options["list"]) :
+        if (not self.config.isAdmin) and (options.action != "list") :
             raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
+           
+        islist = (options.action == "list")
+        isadd = (options.action == "add")
+        isdelete = (options.action == "delete")
+        
+        if not names :
+            if isdelete or isadd :
+                raise PyKotaCommandLineError, _("You must specify billing codes on the command line.")
+            names = [u"*"]    
             
-        if not options["list"] :    
+        if not islist :
             percent = Percent(self)
             
-        if not options["add"] :
-            if not options["list"] :
+        if not isadd :
+            if not islist :
                 percent.display("%s..." % _("Extracting datas"))
-            if not names :      # NB : can't happen for --delete because it's catched earlier
+            if not names :
                 names = ["*"]
             billingcodes = self.storage.getMatchingBillingCodes(",".join(names))
             if not billingcodes :
-                if not options["list"] :
+                if not islist :
                     percent.display("\n")
                 raise PyKotaCommandLineError, _("There's no billingcode matching %s") % " ".join(names)
-            if not options["list"] :    
+            if not islist :
                 percent.setSize(len(billingcodes))
                         
-        if options["list"] :
+        if islist :
             for billingcode in billingcodes :
-                print "%s [%s] %s %s %s %.2f %s" % \
+                self.display("%s [%s] %s %s %s %.2f %s\n" % \
                       (billingcode.BillingCode, billingcode.Description, \
                        billingcode.PageCounter, \
@@ -122,31 +82,33 @@
                        _("and"), \
                        billingcode.Balance, \
-                       _("credits"))
-        elif options["delete"] :    
+                       _("credits")))
+        elif isdelete :    
             percent.display("\n%s..." % _("Deletion"))
             self.storage.deleteManyBillingCodes(billingcodes)
             percent.display("\n")
         else :
-            reset = options["reset"]
-            description = options["description"]
+            description = options.description
             if description :
-                description = options["description"].strip()
-            skipexisting = options["skipexisting"]        
+                description = description.strip()
             
             self.storage.beginTransaction()
             try :
-                if options["add"] :    
+                if isadd :    
                     percent.display("%s...\n" % _("Creation"))
                     percent.setSize(len(names))
                     for bname in names :
                         billingcode = StorageBillingCode(self.storage, bname)
-                        self.modifyBillingCode(billingcode, reset, description)
+                        self.modifyBillingCode(billingcode, 
+                                               options.reset, 
+                                               description)
                         oldbillingcode = self.storage.addBillingCode(billingcode)
                         if oldbillingcode is not None :
-                            if skipexisting :
-                                self.logdebug(_("Billing code [%s] already exists, skipping.") % bname)
+                            if options.skipexisting :
+                                self.logdebug(_("Billing code '%(bname)s' already exists, skipping.") % locals())
                             else :    
-                                self.logdebug(_("Billing code [%s] already exists, will be modified.") % bname)
-                                self.modifyBillingCode(oldbillingcode, reset, description)
+                                self.logdebug(_("Billing code '%(bname)s' already exists, will be modified.") % locals())
+                                self.modifyBillingCode(oldbillingcode, 
+                                                       options.reset, 
+                                                       description)
                                 oldbillingcode.save()
                         percent.oneMore()
@@ -154,5 +116,7 @@
                     percent.display("\n%s...\n" % _("Modification"))
                     for billingcode in billingcodes :
-                        self.modifyBillingCode(billingcode, reset, description)
+                        self.modifyBillingCode(billingcode, 
+                                               options.reset, 
+                                               description)
                         billingcode.save()    
                         percent.oneMore()
@@ -163,61 +127,44 @@
                 self.storage.commitTransaction()
                         
-        if not options["list"] :
+        if not islist :
             percent.done()
                      
 if __name__ == "__main__" : 
-    retcode = 0
-    try :
-        short_options = "hvaD:dlrs"
-        long_options = ["help", "version", "add", "description=", "delete", "list", "reset", "skipexisting"]
-        
-        # Initializes the command line tool
-        manager = PKBcodes(doc=__doc__)
-        manager.deferredInit()
-        
-        # parse and checks the command line
-        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
-        
-        # sets long options
-        options["help"] = options["h"] or options["help"]
-        options["version"] = options["v"] or options["version"]
-        options["add"] = options["a"] or options["add"]
-        options["description"] = options["D"] or options["description"]
-        options["delete"] = options["d"] or options["delete"] 
-        options["list"] = options["l"] or options["list"]
-        options["reset"] = options["r"] or options["reset"]
-        options["skipexisting"] = options["s"] or options["skipexisting"]
-        
-        if options["help"] :
-            manager.display_usage_and_quit()
-        elif options["version"] :
-            manager.display_version_and_quit()
-        elif (options["delete"] and (options["add"] or options["reset"] or options["description"])) \
-           or (options["skipexisting"] and not options["add"]) \
-           or (options["list"] and (options["add"] or options["delete"] or options["reset"] or options["description"])) :
-            raise PyKotaCommandLineError, _("incompatible options, see help.")
-        elif (not args) and (options["add"] or options["delete"]) :    
-            raise PyKotaCommandLineError, _("You have to pass billing codes on the command line")
-        else :
-            retcode = manager.main(args, options)
-    except KeyboardInterrupt :        
-        logerr("\nInterrupted with Ctrl+C !\n")
-        retcode = -3
-    except PyKotaCommandLineError, msg :    
-        logerr("%s : %s\n" % (sys.argv[0], msg))
-        retcode = -2
-    except SystemExit :        
-        pass
-    except :
-        try :
-            manager.crashed("pkbcodes failed")
-        except :    
-            crashed("pkbcodes failed")
-        retcode = -1
-
-    try :
-        manager.storage.close()
-    except (TypeError, NameError, AttributeError) :    
-        pass
-        
-    sys.exit(retcode)    
+    parser = PyKotaOptionParser(description=_("A billing codes manager for PyKota."),
+                                usage="pkbcodes [options] code1 code2 ... codeN")
+    parser.add_option("-a", "--add",
+                            action="store_const",
+                            const="add",
+                            dest="action",
+                            help=_("Add new, or modify existing, billing codes."))
+    parser.add_option("-d", "--delete",
+                            action="store_const",
+                            const="delete",
+                            dest="action",
+                            help=_("Deletes billing codes. Matching entries in the printing history are not deleted, on purpose."))
+    parser.add_option("-D", "--description",
+                            dest="description",
+                            help=_("Set a textual description for the specified billing codes."))
+    parser.add_option("-l", "--list",
+                            action="store_const",
+                            const="list",
+                            dest="action",
+                            help=_("Display information about the specified billing codes."))
+    parser.add_option("-r", "--reset",
+                            action="store_true",
+                            dest="reset",
+                            help=_("Reset the page count and amount spent for the specified billing codes."))
+    parser.add_option("-s", "--skipexisting",
+                            action="store_true",
+                            dest="skipexisting",
+                            help=_("If --add is used, ensure that existing billing codes won't be modified."))
+                            
+    parser.add_example('-D "Financial Department" financial',
+                       _("Would create a billing code labelled 'financial' with the specified textual description."))
+    parser.add_example('--delete "fin*"', 
+                       _("Would delete all billing codes which label begins with 'fin'. Matching jobs in the printing history wouldn't be deleted though."))
+    parser.add_example("--list",
+                       _("Would display details about all existing billing codes."))
+                       
+    (options, arguments) = parser.parse_args()
+    run(parser, PKBcodes)                   
