Changeset 3368

Show
Ignore:
Timestamp:
05/03/08 18:58:40 (12 years ago)
Author:
jerome
Message:

dumpykota now support new style command line options.
TODO : dumpykota.cgi

Location:
pykota/trunk
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/dumpykota

    r3295 r3368  
    2222# 
    2323 
     24"""A versatile data dumper for PyKota""" 
     25 
    2426import sys 
    2527 
    2628import pykota.appinit 
    27 from pykota.utils import * 
     29from pykota.utils import run 
     30from pykota.commandline import PyKotaOptionParser 
    2831 
    2932from pykota.errors import PyKotaCommandLineError 
    3033from pykota.dumper import DumPyKota 
    3134 
    32 __doc__ = N_("""dumpykota v%(__version__)s (c) %(__years__)s %(__author__)s 
     35if __name__ == "__main__" :  
     36    parser = PyKotaOptionParser(description=_("Data Dumper for PyKota."), 
     37                                usage="dumpykota [options] [filterexpr]") 
     38                                 
     39    parser.add_option("-d", "--data",                             
     40                            dest="data", 
     41                            help=_("Select the type of datas to dump. This option is mandatory. Supported data types are : history, payments, billingcodes, users, groups, printers, upquotas, gpquotas, umembers, pmembers, and all. The 'all' value forces the output format to XML.")) 
     42    parser.add_option("-f", "--format",                             
     43                            default="csv", 
     44                            dest="format", 
     45                            help=_("Select the output format, the default being comma separated values. Supported formats are : csv, ssv, tsv, xml and cups. The 'cups' output format only works when dumping the history, and produces CUPS' page_log compatible output.")) 
     46    parser.add_option("-o", "--output",                             
     47                            dest="output", 
     48                            default=u"-", 
     49                            help=_("The name of the file the data dump will be written to. The default value is '-', which tells dumpykota to write the dump to stdout.")) 
     50    parser.add_option("-O", "--orderby",                             
     51                            dest="orderby", 
     52                            help=_("Change the ordering of the output based on a comma separated list of ordering statements. For example '-username,+printername' would sort the output by descending order of user names and ascending order of printer names. Not all expressions are supported, and you should not use this if you don't know the internal structure of PyKota's database." )) 
     53    parser.add_option("-s", "--sum",                             
     54                            dest="sum", 
     55                            action="store_true", 
     56                            default=False, 
     57                            help=_("Summarize the output. Only available when dumping the printing history or the payments.")) 
     58                                 
     59    parser.add_filterexpression("username", _("User's name")) 
     60    parser.add_filterexpression("groupname", _("Users group's name")) 
     61    parser.add_filterexpression("printername", _("Printer's name")) 
     62    parser.add_filterexpression("pgroupname", _("Printers group's name")) 
     63    parser.add_filterexpression("hostname", _("Host's name")) 
     64    parser.add_filterexpression("jobid", _("Job's id")) 
     65    parser.add_filterexpression("billingcode", _("Job's billing code")) 
     66    parser.add_filterexpression("start", _("Job's date of printing")) 
     67    parser.add_filterexpression("end", _("Job's date of printing")) 
     68     
     69    parser.add_example('--unit EURO --output /tmp/invoices.pdf start=now-30',  
     70                       _("This would generate a PDF document containing invoices for all users who have spent some credits last month. Amounts would be in EURO and not VAT information would be included.")) 
    3371 
    34 Dumps PyKota database's content. 
    35  
    36 command line usage : 
    37  
    38   dumpykota [options] [filterexpr] 
    39  
    40 options : 
    41  
    42   -v | --version       Prints dumpykota's version number then exits. 
    43   -h | --help          Prints this message then exits. 
     72    parser.add_example("--data history --format csv >myfile.csv", 
     73                       _("This would dump the whole printing history to stdout in the CSV format, and redirect the output to a file.")) 
    4474   
    45   -d | --data type     Dumps 'type' datas. Allowed types are : 
    46                         
    47                          - history : dumps the jobs history. 
    48                          - users : dumps users. 
    49                          - groups : dumps user groups. 
    50                          - printers : dump printers. 
    51                          - upquotas : dump user quotas. 
    52                          - gpquotas : dump user groups quotas. 
    53                          - payments : dumps user payments. 
    54                          - pmembers : dumps printer groups members. 
    55                          - umembers : dumps user groups members. 
    56                          - billingcodes : dumps billing codes. 
    57                          - all : dumps all PyKota datas. The output format 
    58                                  is always XML in this case. 
    59                           
    60                        NB : the -d | --data command line option    
    61                        is MANDATORY. 
     75    parser.add_example("--data users --format xml -o users.xml", 
     76                       _("This would dump all users into the 'users.xml' file in the XML format.")) 
    6277   
    63   -f | --format fmt    Dumps datas in the 'fmt' format. When not specified, 
    64                        the format is to dump datas in the csv format (comma 
    65                        separated values). All data dumped is between double 
    66                        quotes. Allowed formats are : 
    67                         
    68                          - csv : separate datas with commas 
    69                          - ssv : separate datas with semicolons 
    70                          - tsv : separate datas with tabs 
    71                          - xml : dump data as XML  
    72                          - cups : dump datas in CUPS' page_log format : 
    73                                   ONLY AVAILABLE WITH --data history 
    74                           
    75   -o | --output fname  All datas will be dumped to the file instead of 
    76                        to the standard output. The special '-' filename 
    77                        is the default value and means stdout. 
    78                        WARNING : existing files are truncated ! 
    79  
    80   -O | --orderby exp   Change the ordering or result. 'exp' is a comma 
    81                        separated list of ordering statements, for example 
    82                        '--orderby +username,-printername'. Not all expression 
    83                        values are meaningful, so using this command line  
    84                        switch is not recommanded if you don't know the  
    85                        exact layout of PyKota's database schema. 
    86                         
    87   -s | --sum           Summarize the selected datas. 
    88                            ONLY AVAILABLE WITH --data history or payments 
    89  
    90   Use the filter expressions to extract only parts of the  
    91   datas. Allowed filters are of the form : 
    92                  
    93          key=value 
    94                           
    95   Allowed keys for now are :   
    96                         
    97          username       User's name 
    98          groupname      Users group's name 
    99          printername    Printer's name 
    100          pgroupname     Printers group's name 
    101          hostname       Client's hostname 
    102          jobid          Job's Id 
    103          billingcode    Job's billing code 
    104          start          Job's date of printing 
    105          end            Job's date of printing 
    106           
    107   Dates formatting with 'start' and 'end' filter keys : 
     78    parser.add_example("--data history printername=HP2100 username=jerome", 
     79                       _("This would dump jerome's printing history on printer HP2100.")) 
    10880   
    109     YYYY : year boundaries 
    110     YYYYMM : month boundaries 
    111     YYYYMMDD : day boundaries 
    112     YYYYMMDDhh : hour boundaries 
    113     YYYYMMDDhhmm : minute boundaries 
    114     YYYYMMDDhhmmss : second boundaries 
    115     yesterday[+-NbDays] : yesterday more or less N days (e.g. : yesterday-15) 
    116     today[+-NbDays] : today more or less N days (e.g. : today-15) 
    117     tomorrow[+-NbDays] : tomorrow more or less N days (e.g. : tomorrow-15) 
    118     now[+-NbDays] : now more or less N days (e.g. now-15) 
    119  
    120   'now' and 'today' are not exactly the same since today represents the first 
    121   or last second of the day depending on if it's used in a start= or end= 
    122   date expression. The utility to be able to specify dates in the future is 
    123   a question which remains to be answered :-) 
    124    
    125   Contrary to other PyKota management tools, wildcard characters are not  
    126   expanded, so you can't use them. 
    127    
    128   NB : not all keys are allowed for each data type, so the result may be  
    129   empty if you use a key not available for a particular data type. 
    130    
    131 Examples : 
    132  
    133   $ dumpykota --data history --format csv >myfile.csv 
    134    
    135   This dumps the history in a comma separated values file, for possible 
    136   use in a spreadsheet. 
    137    
    138   $ dumpykota --data users --format xml -o users.xml 
    139    
    140   Dumps all users datas to the users.xml file. 
    141    
    142   $ dumpykota --data history printername=HP2100 username=jerome 
    143    
    144   Dumps the job history for user jerome on printer HP2100 only. 
    145    
    146   $ dumpykota --data history start=200503 end=20050730234615 
    147    
    148   Dumps all jobs printed between March 1st 2005 at midnight and 
    149   July 30th 2005 at 23 hours 46 minutes and 15 secondes included. 
    150 """) 
    151          
    152 if __name__ == "__main__" :  
    153     retcode = 0 
    154     try : 
    155         defaults = { \ 
    156                      "format" : "csv", \ 
    157                      "output" : "-", \ 
    158                    } 
    159         short_options = "vhd:f:o:sO:" 
    160         long_options = ["help", "version", "data=", "format=", "output=", "sum", "orderby="] 
    161          
    162         # Initializes the command line tool 
    163         dumper = DumPyKota(doc=__doc__) 
    164         dumper.deferredInit() 
    165          
    166         # parse and checks the command line 
    167         (options, args) = dumper.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1) 
    168          
    169         # sets long options 
    170         options["help"] = options["h"] or options["help"] 
    171         options["version"] = options["v"] or options["version"] 
    172         options["data"] = options["d"] or options["data"] 
    173         options["format"] = options["f"] or options["format"] or defaults["format"] 
    174         options["output"] = options["o"] or options["output"] or defaults["output"] 
    175         options["sum"] = options["s"] or options["sum"] 
    176         options["orderby"] = options["O"] or options["orderby"] 
    177          
    178         if options["help"] : 
    179             dumper.display_usage_and_quit() 
    180         elif options["version"] : 
    181             dumper.display_version_and_quit() 
    182         elif options["data"] is None :     
    183             raise PyKotaCommandLineError, _("The -d | --data command line option is mandatory, see help.") 
    184         else : 
    185             retcode = dumper.main(args, options) 
    186     except KeyboardInterrupt :         
    187         logerr("\nInterrupted with Ctrl+C !\n") 
    188         retcode = -3 
    189     except PyKotaCommandLineError, msg :     
    190         logerr("%s : %s\n" % (sys.argv[0], msg)) 
    191         retcode = -2 
    192     except SystemExit :         
    193         pass 
    194     except : 
    195         try : 
    196             dumper.crashed("dumpykota failed") 
    197         except :     
    198             crashed("dumpykota failed") 
    199         retcode = -1 
    200  
    201     try : 
    202         dumper.storage.close() 
    203     except (TypeError, NameError, AttributeError) :     
    204         pass 
    205          
    206     sys.exit(retcode)     
     81    parser.add_example("--data history start=200503 end=20050730234615", 
     82                       _("This would dump all jobs printer between March 1st 2008 at midnight and July 30th 2008 at 23 hours 46 minutes and 15 seconds, included.")) 
     83    run(parser, DumPyKota)                    
  • pykota/trunk/pykota/dumper.py

    r3295 r3368  
    4747class DumPyKota(PyKotaTool) :         
    4848    """A class for dumpykota.""" 
    49     validdatatypes = { "history" : N_("History"), 
    50                        "users" : N_("Users"), 
    51                        "groups" : N_("Groups"), 
    52                        "printers" : N_("Printers"), 
    53                        "upquotas" : N_("Users Print Quotas"), 
    54                        "gpquotas" : N_("Users Groups Print Quotas"), 
    55                        "payments" : N_("History of Payments"), 
    56                        "pmembers" : N_("Printers Groups Membership"),  
    57                        "umembers" : N_("Users Groups Membership"), 
    58                        "billingcodes" : N_("Billing Codes"), 
    59                        "all": N_("All"), 
     49    validdatatypes = { u"history" : N_("History"), 
     50                       u"users" : N_("Users"), 
     51                       u"groups" : N_("Groups"), 
     52                       u"printers" : N_("Printers"), 
     53                       u"upquotas" : N_("Users Print Quotas"), 
     54                       u"gpquotas" : N_("Users Groups Print Quotas"), 
     55                       u"payments" : N_("History of Payments"), 
     56                       u"pmembers" : N_("Printers Groups Membership"),  
     57                       u"umembers" : N_("Users Groups Membership"), 
     58                       u"billingcodes" : N_("Billing Codes"), 
     59                       u"all": N_("All"), 
    6060                     } 
    61     validformats = { "csv" : N_("Comma Separated Values"), 
    62                      "ssv" : N_("Semicolon Separated Values"), 
    63                      "tsv" : N_("Tabulation Separated Values"), 
    64                      "xml" : N_("eXtensible Markup Language"), 
    65                      "cups" : N_("CUPS' page_log"), 
     61    validformats = { u"csv" : N_("Comma Separated Values"), 
     62                     u"ssv" : N_("Semicolon Separated Values"), 
     63                     u"tsv" : N_("Tabulation Separated Values"), 
     64                     u"xml" : N_("eXtensible Markup Language"), 
     65                     u"cups" : N_("CUPS' page_log"), 
    6666                   }   
    6767    validfilterkeys = [ "username", 
     
    7575                        "end", 
    7676                      ] 
    77     def main(self, arguments, options, restricted=1) : 
     77    def main(self, arguments, options, restricted=True) : 
    7878        """Print Quota Data Dumper.""" 
    79         if restricted and not self.config.isAdmin : 
    80             raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command.")) 
    81              
    82         datatype = options["data"] 
     79        self.adminOnly(restricted) 
     80             
     81        datatype = options.data 
    8382        if datatype not in self.validdatatypes.keys() : 
    84             raise PyKotaCommandLineError, _("Invalid modifier [%s] for --data command line option, see help.") % datatype 
     83            raise PyKotaCommandLineError, _("Invalid data type '%(datatype)s', see help.") % locals() 
    8584                     
    86         orderby = options["orderby"]              
     85        orderby = options.orderby or [] 
    8786        if orderby : 
    8887            fields = [f.strip() for f in orderby.split(",")] 
     
    9392                    orderby.append(field) 
    9493                else :     
    95                     self.printInfo("Skipping invalid ordering statement '%(field)s'" % locals(), "error")  
    96         else : 
    97             orderby = [] 
     94                    logerr(_("Skipping invalid ordering statement '%(field)s'") % locals()) 
    9895             
    9996        extractonly = {} 
    100         if datatype == "all" :             
    101             if (options["format"] != "xml") or options["sum"] or arguments : 
     97        if datatype == u"all" :             
     98            if (options.format != u"xml") or options.sum or arguments : 
    10299                self.printInfo(_("Dumping all PyKota's datas forces format to XML, and disables --sum and filters."), "warn") 
    103             options["format"] = "xml" 
    104             options["sum"] = None 
     100            options.format = u"xml" 
     101            options.sum = None 
    105102        else :     
    106103            for filterexp in arguments : 
     
    108105                    try : 
    109106                        (filterkey, filtervalue) = [part.strip() for part in filterexp.split("=")] 
    110                         filterkey = filterkey.lower() 
     107                        filterkey = filterkey.encode("ASCII", "replace").lower() 
    111108                        if filterkey not in self.validfilterkeys : 
    112109                            raise ValueError                 
    113110                    except ValueError :     
    114                         raise PyKotaCommandLineError, _("Invalid filter value [%s], see help.") % filterexp 
     111                        raise PyKotaCommandLineError, _("Invalid filter value '%(filterexp)s', see help.") % locals() 
    115112                    else :     
    116113                        extractonly.update({ filterkey : filtervalue }) 
    117114             
    118         format = options["format"] 
     115        format = options.format 
    119116        if (format not in self.validformats.keys()) \ 
    120            or ((format == "cups") \ 
    121               and ((datatype != "history") or options["sum"])) : 
    122             raise PyKotaCommandLineError, _("Invalid modifier [%s] for --format command line option, see help.") % format 
    123              
    124         if (format == "xml") and not hasJAXML : 
     117           or ((format == u"cups") \ 
     118              and ((datatype != u"history") or options.sum)) : 
     119            raise PyKotaCommandLineError, _("Invalid format '%(format)s', see help.") % locals() 
     120             
     121        if (format == u"xml") and not hasJAXML : 
    125122            raise PyKotaToolError, _("XML output is disabled because the jaxml module is not available.") 
    126123             
    127         if datatype not in ("payments", "history") :  
    128             if options["sum"] :  
    129                 raise PyKotaCommandLineError, _("Invalid data type [%s] for --sum command line option, see help.") % datatype 
    130             if extractonly.has_key("start") or extractonly.has_key("end") :     
    131                 self.printInfo(_("Invalid filter for the %(datatype)s data type.") % locals(), "warn") 
     124        if datatype not in (u"payments", u"history") :  
     125            if options.sum :  
     126                raise PyKotaCommandLineError, _("Invalid data type '%(datatype)s' for --sum command line option, see help.") % locals() 
     127            if extractonly.has_key(u"start") or extractonly.has_key(u"end") :     
     128                self.printInfo(_("Invalid filter for the '%(datatype)s' data type.") % locals(), "warn") 
    132129                try : 
    133                     del extractonly["start"] 
     130                    del extractonly[u"start"] 
    134131                except KeyError :     
    135132                    pass 
    136133                try : 
    137                     del extractonly["end"] 
     134                    del extractonly[u"end"] 
    138135                except KeyError :     
    139136                    pass 
     
    141138        retcode = 0 
    142139        nbentries = 0     
    143         mustclose = 0     
    144         if options["output"].strip() == "-" :     
     140        mustclose = False 
     141        outfname = options.output.strip().encode(sys.getfilesystemencoding()) 
     142        if outfname == "-" :     
    145143            self.outfile = sys.stdout 
    146144        else :     
    147             self.outfile = open(options["output"], "w") 
    148             mustclose = 1 
    149              
    150         if datatype == "all" :     
     145            self.outfile = open(outfname, "w") 
     146            mustclose = True 
     147             
     148        if datatype == u"all" :     
    151149            # NB : order does matter to allow easier or faster restore 
    152150            allentries = [] 
     
    164162            retcode = self.dumpXml(allentries, neededdatatypes) 
    165163        else :     
     164            datatype = datatype.encode("ASCII") 
     165            format = format.encode("ASCII") 
    166166            entries = getattr(self.storage, "extract%s" % datatype.title())(extractonly, orderby) 
    167167            if entries : 
    168168                nbentries = len(entries) 
    169                 retcode = getattr(self, "dump%s" % format.title())([self.summarizeDatas(entries, datatype, extractonly, options["sum"])], [datatype]) 
     169                retcode = getattr(self, "dump%s" % format.title())([self.summarizeDatas(entries, datatype, extractonly, options.sum)], [datatype]) 
    170170                 
    171171        if mustclose : 
    172172            self.outfile.close() 
    173173            if not nbentries :  
    174                 os.remove(options["output"]) 
     174                os.remove(options.output) 
    175175             
    176176        return retcode 
     
    258258                    self.outfile.write("%s\n" % separator.join(line)) 
    259259                except IOError, msg :     
    260                     sys.stderr.write("%s : %s\n" % (_("PyKota data dumper failed : I/O error"), msg)) 
     260                    self.printInfo("%s : %s" % (_("PyKota data dumper failed : I/O error"), msg), "error") 
    261261                    return -1 
    262262        return 0         
     
    291291            jobdate = DateTime.ISO.ParseDateTime(str(entry[fields["jobdate"]])[:19]) 
    292292            gmtoffset = jobdate.gmtoffset() 
    293             #jobdate = "%s %+03i00" % (jobdate.strftime("%d/%b/%Y:%H:%M:%S"), gmtoffset.hour) 
    294293            jobdate = "%02i/%s/%04i:%02i:%02i:%02i %+03i%02i" % (jobdate.day, 
    295294                                                                 months[jobdate.month - 1], 
     
    305304            billingcode = entry[fields["billingcode"]] or "-" 
    306305            for pagenum in range(1, jobsize+1) : 
    307                 self.outfile.write("%s %s %s [%s] %s %s %s %s\n" % (printername, username, jobid, jobdate, pagenum, copies, billingcode, hostname)) 
     306                line = "%s %s %s [%s] %s %s %s %s" % (printername, username, jobid, jobdate, pagenum, copies, billingcode, hostname) 
     307                self.outfile.write("%s\n" % line.encode(self.charset,  
     308                                                        "replace")) 
    308309        return 0         
    309310