Changeset 3368
- Timestamp:
- 05/03/08 18:58:40 (17 years ago)
- Location:
- pykota/trunk
- Files:
-
- 2 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/bin/dumpykota
r3295 r3368 22 22 # 23 23 24 """A versatile data dumper for PyKota""" 25 24 26 import sys 25 27 26 28 import pykota.appinit 27 from pykota.utils import * 29 from pykota.utils import run 30 from pykota.commandline import PyKotaOptionParser 28 31 29 32 from pykota.errors import PyKotaCommandLineError 30 33 from pykota.dumper import DumPyKota 31 34 32 __doc__ = N_("""dumpykota v%(__version__)s (c) %(__years__)s %(__author__)s 35 if __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.")) 33 71 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.")) 44 74 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.")) 62 77 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.")) 108 80 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 47 47 class DumPyKota(PyKotaTool) : 48 48 """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"), 60 60 } 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"), 66 66 } 67 67 validfilterkeys = [ "username", … … 75 75 "end", 76 76 ] 77 def main(self, arguments, options, restricted= 1) :77 def main(self, arguments, options, restricted=True) : 78 78 """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 83 82 if datatype not in self.validdatatypes.keys() : 84 raise PyKotaCommandLineError, _("Invalid modifier [%s] for --data command line option, see help.") % datatype83 raise PyKotaCommandLineError, _("Invalid data type '%(datatype)s', see help.") % locals() 85 84 86 orderby = options ["orderby"]85 orderby = options.orderby or [] 87 86 if orderby : 88 87 fields = [f.strip() for f in orderby.split(",")] … … 93 92 orderby.append(field) 94 93 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()) 98 95 99 96 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 : 102 99 self.printInfo(_("Dumping all PyKota's datas forces format to XML, and disables --sum and filters."), "warn") 103 options ["format"] ="xml"104 options ["sum"]= None100 options.format = u"xml" 101 options.sum = None 105 102 else : 106 103 for filterexp in arguments : … … 108 105 try : 109 106 (filterkey, filtervalue) = [part.strip() for part in filterexp.split("=")] 110 filterkey = filterkey. lower()107 filterkey = filterkey.encode("ASCII", "replace").lower() 111 108 if filterkey not in self.validfilterkeys : 112 109 raise ValueError 113 110 except ValueError : 114 raise PyKotaCommandLineError, _("Invalid filter value [%s], see help.") % filterexp111 raise PyKotaCommandLineError, _("Invalid filter value '%(filterexp)s', see help.") % locals() 115 112 else : 116 113 extractonly.update({ filterkey : filtervalue }) 117 114 118 format = options ["format"]115 format = options.format 119 116 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.") % format123 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 : 125 122 raise PyKotaToolError, _("XML output is disabled because the jaxml module is not available.") 126 123 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.") % datatype130 if extractonly.has_key( "start") or extractonly.has_key("end") :131 self.printInfo(_("Invalid filter for the %(datatype)sdata 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") 132 129 try : 133 del extractonly[ "start"]130 del extractonly[u"start"] 134 131 except KeyError : 135 132 pass 136 133 try : 137 del extractonly[ "end"]134 del extractonly[u"end"] 138 135 except KeyError : 139 136 pass … … 141 138 retcode = 0 142 139 nbentries = 0 143 mustclose = 0 144 if options["output"].strip() == "-" : 140 mustclose = False 141 outfname = options.output.strip().encode(sys.getfilesystemencoding()) 142 if outfname == "-" : 145 143 self.outfile = sys.stdout 146 144 else : 147 self.outfile = open(o ptions["output"], "w")148 mustclose = 1149 150 if datatype == "all" :145 self.outfile = open(outfname, "w") 146 mustclose = True 147 148 if datatype == u"all" : 151 149 # NB : order does matter to allow easier or faster restore 152 150 allentries = [] … … 164 162 retcode = self.dumpXml(allentries, neededdatatypes) 165 163 else : 164 datatype = datatype.encode("ASCII") 165 format = format.encode("ASCII") 166 166 entries = getattr(self.storage, "extract%s" % datatype.title())(extractonly, orderby) 167 167 if entries : 168 168 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]) 170 170 171 171 if mustclose : 172 172 self.outfile.close() 173 173 if not nbentries : 174 os.remove(options ["output"])174 os.remove(options.output) 175 175 176 176 return retcode … … 258 258 self.outfile.write("%s\n" % separator.join(line)) 259 259 except IOError, msg : 260 s ys.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") 261 261 return -1 262 262 return 0 … … 291 291 jobdate = DateTime.ISO.ParseDateTime(str(entry[fields["jobdate"]])[:19]) 292 292 gmtoffset = jobdate.gmtoffset() 293 #jobdate = "%s %+03i00" % (jobdate.strftime("%d/%b/%Y:%H:%M:%S"), gmtoffset.hour)294 293 jobdate = "%02i/%s/%04i:%02i:%02i:%02i %+03i%02i" % (jobdate.day, 295 294 months[jobdate.month - 1], … … 305 304 billingcode = entry[fields["billingcode"]] or "-" 306 305 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")) 308 309 return 0 309 310