root / pykota / trunk / bin / edpykota @ 2655

Revision 2655, 30.3 kB (checked in by jerome, 18 years ago)

Now outputs a message explaining that the treatment could be long.
For today, it's easier than really improving speed ;-)

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# PyKota Print Quota Editor
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003, 2004, 2005, 2006 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22#
23# $Id$
24#
25#
26
27import sys
28import os
29import pwd
30import grp
31from pykota.tool import PyKotaTool, PyKotaToolError, PyKotaCommandLineError, crashed, N_
32from pykota.config import PyKotaConfigError
33from pykota.storage import PyKotaStorageError
34
35__doc__ = N_("""edpykota v%(__version__)s (c) %(__years__)s %(__author__)s
36
37A Print Quota editor for PyKota.
38
39command line usage :
40
41  edpykota [options] user1 user2 ... userN
42 
43  edpykota [options] group1 group2 ... groupN
44
45options :
46
47  -v | --version       Prints edpykota's version number then exits.
48  -h | --help          Prints this message then exits.
49 
50  -a | --add           Adds users and/or printers if they don't
51                       exist on the Quota Storage Server.
52                       
53  -d | --delete        Deletes users/groups from the quota storage.
54                       Printers are never deleted.
55                       
56  -c | --charge p[,j]  Sets the price per page and per job to charge
57                       for a particular printer. Job price is optional.
58                       If both are to be set, separate them with a comma.
59                       Floating point values are allowed.
60                       
61  -o | --overcharge f  Sets the overcharging factor applied to the user
62                       when computing the cost of a print job. Positive or
63                       negative floating point values are allowed,
64                       this allows you to do some really creative
65                       things like giving money to an user whenever
66                       he prints. The number of pages in a print job
67                       is not modified by this coefficient, only the
68                       cost of the job for a particular user.
69                       Only users have a coefficient.
70 
71  -i | --ingroups g1[,g2...]  Puts the users into each of the groups
72                              listed, separated by commas. The groups
73                              must already exist in the Quota Storage.
74 
75  -u | --users         Edit users print quotas, this is the default.
76 
77  -P | --printer p     Edit quotas on printer p only. Actually p can
78                       use wildcards characters to select only
79                       some printers. The default value is *, meaning
80                       all printers.
81                       You can specify several names or wildcards,
82                       by separating them with commas.
83 
84  -G | --pgroups pg1[,pg2...] Adds the printer(s) to the printer groups
85                       pg1, pg2, etc... which must already exist.
86                       A printer group is just like a normal printer,
87                       only that it is usually unknown from the printing
88                       system. Create printer groups exactly the same
89                       way that you create printers, then add other
90                       printers to them with this option.
91                       Accounting is done on a printer and on all
92                       the printer groups it belongs to, quota checking
93                       is done on a printer and on all the printer groups
94                       it belongs to.
95 
96  -g | --groups        Edit users groups print quotas instead of users.
97                         
98  -p | --prototype u|g Uses user u or group g as a prototype to set
99                       print quotas
100                       
101  -n | --noquota       Sets both soft and hard limits to None for a
102                       particular print quota entry.
103                       This is NOT the same as --limitby noquota
104                       which acts on ALL print quota entries for a
105                       particular user.
106 
107  -r | --reset         Resets the actual page counter for the user
108                       or group to zero on the specified printers.
109                       The life time page counter is kept unchanged.
110                       
111  -R | --hardreset     Resets the actual and life time page counters
112                       for the user or group to zero on the specified
113                       printers. This is a shortcut for '--used 0'.
114                       
115  -l | --limitby l     Choose if the user/group is limited in printing                     
116                       by its account balance or by its page quota.
117                       The default value is 'quota'. Allowed values
118                       are 'quota' 'balance' 'noquota' 'noprint' 
119                       and 'nochange' :
120                       
121                         - quota : limit by number of pages per printer.
122                         - balance : limit by number of credits in account.
123                         - noquota : no limit, accounting still done.
124                         - nochange : no limit, accounting not done.
125                         - noprint : printing is denied.
126                       NB : nochange and noprint are not supported for groups.
127                       
128  -b | --balance b     Sets the user's account balance to b.                     
129                       Account balance may be increase or decreased
130                       if b is prefixed with + or -.
131                       WARNING : when decreasing account balance,
132                       the total paid so far by the user is decreased
133                       too.
134                       Groups don't have a real balance, but the
135                       sum of their users' account balance.
136                       
137  -C | --comment txt   Defines some informational text to be associated
138                       with a change to an user's account balance.
139                       Only meaningful if -b | --balance is also used.
140                       
141  -S | --softlimit sl  Sets the quota soft limit to sl pages.                       
142 
143  -H | --hardlimit hl  Sets the quota hard limit to hl pages.
144 
145  -I | --increase v    Increase both Soft and Hard limits by the value
146                       of v. You can prefix v with + or -, if no sign is
147                       used, + is assumed.
148
149  -U | --used usage    Sets the pagecounters for the user to usage pages;
150                       useful for migrating users from a different system
151                       where they have already used some pages. Actual
152                       and Life Time page counters may be increased or decreased
153                       if usage is prefixed with + or -.
154                       WARNING : BOTH page counters are modified in all cases,
155                       so be careful.
156                       NB : if 'usage' equals '0', then the action taken is
157                       the same as if --hardreset was used.
158
159  user1 through userN and group1 through groupN can use wildcards
160  if the --add option is not set.
161 
162examples :                             
163
164  $ edpykota --add -p jerome john paul george ringo/ringo@example.com
165 
166  This will add users john, paul, george and ringo to the quota
167  database, and set their print quotas to the same values than user
168  jerome. User jerome must already exist.
169  User ringo's email address will also be set to 'ringo@example.com'
170 
171  $ edpykota --printer lp -S 50 -H 60 jerome
172 
173  This will set jerome's print quota on the lp printer to a soft limit
174  of 50 pages, and a hard limit of 60 pages. If either user jerome or
175  printer lp doesn't exist on the Quota Storage Server then nothing is done.
176
177  $ edpykota --add --printer lp --ingroups coders,it -S 50 -H 60 jerome
178 
179  Same as above, but if either user jerome or printer lp doesn't exist
180  on the Quota Storage Server they are automatically added. Also
181  user jerome is put into the groups "coders" and "it" which must
182  already exist in the Quota Storage.
183           
184  $ edpykota -g -S 500 -H 550 financial support           
185 
186  This will set print quota soft limit to 500 pages and hard limit
187  to 550 pages for groups financial and support on all printers.
188 
189  $ edpykota --reset jerome "jo*"
190 
191  This will reset jerome's page counter to zero on all printers, as
192  well as every user whose name begins with 'jo'.
193  Their life time page counter on each printer will be kept unchanged.
194  You can also reset the life time page counters by using the
195  --hardreset | -R command line option.
196 
197  $ edpykota --printer hpcolor --noquota jerome
198 
199  This will tell PyKota to not limit jerome when printing on the
200  hpcolor printer. All his jobs will be allowed on this printer, but
201  accounting of the pages he prints will still be kept.
202  Print Quotas for jerome on other printers are unchanged.
203 
204  $ edpykota --limitby balance jerome
205 
206  This will tell PyKota to limit jerome by his account's balance
207  when printing.
208 
209  $ edpykota --balance +10.0 jerome
210 
211  This will increase jerome's account balance by 10.0 (in your
212  own currency). You can decrease the account balance with a
213  dash prefix, and set it to a fixed amount with no prefix.
214 
215  $ edpykota --delete jerome rachel
216 
217  This will completely delete jerome and rachel from the Quota Storage
218  database. All their quotas and jobs will be deleted too.
219 
220  $ edpykota --printer lp --charge 0.1
221 
222  This will set the page price for printer lp to 0.1. Job price
223  will not be changed.
224 
225  $ edpykota --printer hplj1,hplj2 --pgroups Laser,HP
226 
227  This will put printers hplj1 and hplj2 in printers groups Laser and HP.
228  When printing either on hplj1 or hplj2, print quota will also be
229  checked and accounted for on virtual printers Laser and HP.
230 
231  $ edpykota --overcharge 2.5 poorstudent
232 
233  This will overcharge the poorstudent user by a factor of 2.5.
234 
235  $ edpykota --overcharge -1 jerome
236 
237  User jerome will actually earn money whenever he prints.
238 
239  $ edpykota --overcharge 0 boss
240 
241  User boss can print at will, it won't cost him anything because the
242  cost of each print job will be multiplied by zero before charging
243  his account.
244""") 
245       
246class EdPyKota(PyKotaTool) :       
247    """A class for edpykota."""
248    def main(self, names, options) :
249        """Edit user or group quotas."""
250        if not self.config.isAdmin :
251            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
252       
253        suffix = (options["groups"] and "Group") or "User"       
254       
255        softlimit = hardlimit = None
256       
257        limitby = options["limitby"]
258        if limitby :
259            limitby = limitby.strip().lower()
260        if limitby :
261            if limitby not in ('quota', 'balance', 'noquota', \
262                                        'noprint', 'nochange') :
263                raise PyKotaCommandLineError, _("Invalid limitby value %s") % options["limitby"]
264            if limitby in ('noquota', 'nochange') :   
265                options["noquota"] = 1
266            if (limitby in ('nochange', 'noprint')) and options["groups"] :   
267                raise PyKotaCommandLineError, _("Invalid limitby value %s") % options["limitby"]
268
269        used = options["used"]
270        if used :
271            used = used.strip()
272            try :
273                int(used)
274            except ValueError :
275                raise PyKotaCommandLineError, _("Invalid used value %s.") % used
276               
277        increase = options["increase"]
278        if increase :
279            try :
280                increase = int(increase.strip())
281            except ValueError :
282                raise PyKotaCommandLineError, _("Invalid increase value %s.") % increase
283
284        if not options["noquota"] :
285            if options["softlimit"] :
286                try :
287                    softlimit = int(options["softlimit"].strip())
288                    if softlimit < 0 :
289                        raise ValueError
290                except ValueError :   
291                    raise PyKotaCommandLineError, _("Invalid softlimit value %s.") % options["softlimit"]
292            if options["hardlimit"] :
293                try :
294                    hardlimit = int(options["hardlimit"].strip())
295                    if hardlimit < 0 :
296                        raise ValueError
297                except ValueError :   
298                    raise PyKotaCommandLineError, _("Invalid hardlimit value %s.") % options["hardlimit"]
299            if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) :       
300                # error, exchange them
301                self.printInfo(_("Hard limit %i is less than soft limit %i, values will be exchanged.") % (hardlimit, softlimit))
302                (softlimit, hardlimit) = (hardlimit, softlimit)
303           
304        overcharge = options["overcharge"]
305        if overcharge :
306            try :
307                overcharge = float(overcharge.strip())
308            except (ValueError, AttributeError) :   
309                raise PyKotaCommandLineError, _("Invalid overcharge value %s") % options["overcharge"]
310               
311        balance = options["balance"]
312        if balance :
313            balance = balance.strip()
314            try :
315                balancevalue = float(balance)
316            except ValueError :   
317                raise PyKotaCommandLineError, _("Invalid balance value %s") % options["balance"]
318           
319        if options["charge"] :
320            try :
321                charges = [float(part) for part in options["charge"].split(',', 1)]
322            except ValueError :   
323                raise PyKotaCommandLineError, _("Invalid charge amount value %s") % options["charge"]
324            else :   
325                if len(charges) > 2 :
326                    charges = charges[:2]
327                if len(charges) != 2 :
328                    charges = [charges[0], None]
329                   
330        if options["ingroups"] :   
331            groupnames = [gname.strip() for gname in options["ingroups"].split(',')]
332        else :   
333            groupnames = []
334           
335        rejectunknown = self.config.getRejectUnknown()   
336        printeradded = 0
337        printers = self.storage.getMatchingPrinters(options["printer"])
338        if not printers :
339            pname = options["printer"]
340            if options["add"] and pname :
341                if self.isValidName(pname) :
342                    printers = [ self.storage.addPrinter(pname) ]
343                    if printers[0].Exists :
344                        printeradded = 1
345                    else :   
346                        raise PyKotaToolError, _("Impossible to add printer %s") % pname
347                else :   
348                    raise PyKotaCommandLineError, _("Invalid printer name %s") % pname
349            else :
350                raise PyKotaCommandLineError, _("There's no printer matching %s") % pname
351        if not names :   
352            if options["delete"] :   
353                raise PyKotaCommandLineError, _("You have to pass user or group names on the command line")
354            else :
355                names = getattr(self.storage, "getAll%ssNames" % suffix)() # all users or groups
356               
357        printersgroups = []       
358        if options["pgroups"] :       
359            printersgroups = self.storage.getMatchingPrinters(options["pgroups"])
360           
361        if options["prototype"] :   
362            protoentry = getattr(self.storage, "get%s" % suffix)(options["prototype"])
363            if not protoentry.Exists :
364                raise PyKotaCommandLineError, _("Prototype object %s not found in Quota Storage.") % protoentry.Name
365            else :   
366                limitby = protoentry.LimitBy
367                balancevalue = protoentry.AccountBalance
368                if balancevalue is not None :
369                    balance = str(abs(balancevalue))
370                else :   
371                    balance = None
372                overcharge = getattr(protoentry, "OverCharge", None)
373           
374        sys.stdout.write(_("Managing print quotas... (this may take a lot of time)"))
375        sys.stdout.flush()
376        missingusers = {}
377        missinggroups = {}   
378        todelete = {}   
379        changed = {} # tracks changes made at the user/group level
380        for printer in printers :
381            for pgroup in printersgroups :
382                pgroup.addPrinterToGroup(printer)   
383               
384            if options["charge"] :
385                (perpage, perjob) = charges
386                printer.setPrices(perpage, perjob)   
387               
388            if options["prototype"] :
389                protoquota = getattr(self.storage, "get%sPQuota" % suffix)(protoentry, printer)
390                if not protoquota.Exists :
391                    self.printInfo(_("Prototype %s not found in Quota Storage for printer %s.") % (protoentry.Name, printer.Name))
392                else :   
393                    (softlimit, hardlimit) = (protoquota.SoftLimit, protoquota.HardLimit)
394                   
395            if not options["noquota"] :   
396                if hardlimit is None :   
397                    hardlimit = softlimit
398                    if hardlimit is not None :
399                        self.printInfo(_("Undefined hard limit set to soft limit (%s) on printer %s.") % (str(hardlimit), printer.Name))
400                if softlimit is None :   
401                    softlimit = hardlimit
402                    if softlimit is not None :
403                        self.printInfo(_("Undefined soft limit set to hard limit (%s) on printer %s.") % (str(softlimit), printer.Name))
404                       
405            if options["add"] :   
406                allentries = []   
407                for name in names :
408                    email = ""
409                    if not options["groups"] :
410                        splitname = name.split('/', 1)     # username/email
411                        if len(splitname) == 1 :
412                            splitname.append("")
413                        (name, email) = splitname
414                        if email and (email.count('@') != 1) :
415                            self.printInfo(_("Invalid email address %s") % email)
416                            email = ""
417                    entry = getattr(self.storage, "get%s" % suffix)(name)
418                    if email and not options["groups"] :
419                        entry.Email = email
420                    entrypquota = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer)
421                    allentries.append((entry, entrypquota))
422            else :   
423                allentries = getattr(self.storage, "getPrinter%ssAndQuotas" % suffix)(printer, names)
424               
425            # TODO : do this only once !!!   
426            allnames = [entry.Name for (entry, dummy) in allentries]
427            for name in names :   
428                if not self.matchString(name, allnames) :
429                    if options["groups"] :
430                        missinggroups[name] = 1
431                    else :   
432                        missingusers[name] = 1
433               
434            for (entry, entrypquota) in allentries :
435                if not changed.has_key(entry.Name) :
436                    changed[entry.Name] = {}
437                    if not options["groups"] :
438                        changed[entry.Name]["ingroups"] = []
439                       
440                if not entry.Exists :       
441                    # not found
442                    if options["add"] :
443                        # In case we want to add something, it is crucial
444                        # that we DON'T check with the system accounts files
445                        # like /etc/passwd because users may be defined
446                        # only remotely
447                        if self.isValidName(entry.Name) :
448                            reject = 0
449                            if rejectunknown :
450                                if options["groups"] :
451                                    try :
452                                        grp.getgrnam(entry.Name)
453                                    except KeyError :   
454                                        self.printInfo(_("Unknown group %s") % entry.Name, "error")
455                                        reject = 1
456                                else :   
457                                    try :
458                                        pwd.getpwnam(entry.Name)
459                                    except KeyError :   
460                                        self.printInfo(_("Unknown user %s") % entry.Name, "error")
461                                        reject = 1
462                            if not reject :       
463                                entry = getattr(self.storage, "add%s" % suffix)(entry)
464                        else :   
465                            if options["groups"] :
466                                self.printInfo(_("Invalid group name %s") % entry.Name)
467                            else :   
468                                self.printInfo(_("Invalid user name %s") % entry.Name)
469                    else :
470                        if options["groups"] :
471                            missinggroups[entry.Name] = 1
472                        else :   
473                            missingusers[entry.Name] = 1
474                elif options["delete"] :               
475                    todelete[entry.Name] = entry
476                               
477                if entry.Exists and (not entrypquota.Exists) :
478                    # not found
479                    if options["add"] :
480                        entrypquota = getattr(self.storage, "add%sPQuota" % suffix)(entry, printer)
481                       
482                if not entrypquota.Exists :     
483                    self.printInfo(_("Quota not found for object %s on printer %s.") % (entry.Name, printer.Name))
484                else :   
485                    if options["noquota"] or options["prototype"] \
486                       or ((softlimit is not None) and (hardlimit is not None)) :
487                        entrypquota.setLimits(softlimit, hardlimit)
488                    if increase :
489                       if (entrypquota.SoftLimit is None) \
490                           or (entrypquota.HardLimit is None) :
491                           self.printInfo(_("You can't increase limits by %s when no limit is set.") % increase, "error")
492                       else :
493                           newsoft = entrypquota.SoftLimit + increase         
494                           newhard = entrypquota.HardLimit + increase         
495                           if (newsoft >= 0) and (newhard >= 0) :
496                               entrypquota.setLimits(newsoft, newhard)
497                           else :   
498                               self.printInfo(_("You can't set negative limits."), "error")
499                    if limitby :
500                        if changed[entry.Name].get("limitby") is None :
501                            entry.setLimitBy(limitby)
502                            changed[entry.Name]["limitby"] = limitby
503                   
504                    if options["reset"] :
505                        entrypquota.reset()
506                       
507                    if options["hardreset"] :   
508                        entrypquota.hardreset()
509                       
510                    if not options["groups"] :
511                        if used :
512                            entrypquota.setUsage(used)
513                           
514                        if overcharge is not None :   
515                            if changed[entry.Name].get("overcharge") is None :
516                                entry.setOverChargeFactor(overcharge)
517                                changed[entry.Name]["overcharge"] = overcharge
518                               
519                        if balance :
520                            if changed[entry.Name].get("balance") is None :
521                                if balance.startswith("+") or balance.startswith("-") :
522                                    newbalance = float(entry.AccountBalance or 0.0) + balancevalue
523                                    newlifetimepaid = float(entry.LifeTimePaid or 0.0) + balancevalue
524                                    entry.setAccountBalance(newbalance, newlifetimepaid, options["comment"])
525                                else :
526                                    diff = balancevalue - float(entry.AccountBalance or 0.0)
527                                    newlifetimepaid = float(entry.LifeTimePaid or 0.0) + diff
528                                    entry.setAccountBalance(balancevalue, newlifetimepaid, options["comment"])
529                                changed[entry.Name]["balance"] = balance
530                               
531                        for groupname in groupnames :       
532                            # not executed if option --ingroups is not used
533                            if groupname not in changed[entry.Name]["ingroups"] :
534                                group = self.storage.getGroup(groupname)
535                                if group.Exists :
536                                    self.storage.addUserToGroup(entry, group)
537                                    changed[entry.Name]["ingroups"].append(groupname)
538                                else :
539                                    self.printInfo(_("Group %s not found in the PyKota Storage.") % groupname)
540                       
541        # Now outputs the list of nonexistent users and groups               
542        for name in missingusers.keys() :
543            self.printInfo(_("Nonexistent user %s or missing print quota entry.") % name, level="warn")
544        for name in missinggroups.keys() :
545            self.printInfo(_("Nonexistent group %s or missing print quota entry.") % name, level="warn")
546       
547        # Now delete what has to be deleted               
548        for (name, entry) in todelete.items() :               
549            entry.delete()
550        sys.stdout.write("\nDone.\n")   
551                     
552if __name__ == "__main__" : 
553    retcode = 0
554    try :
555        defaults = { \
556                     "printer" : "*", \
557                     "comment" : "", \
558                   }
559        short_options = "vhdo:c:C:l:b:i:naugrp:P:S:H:G:RU:I:"
560        long_options = ["help", "version", "comment=", \
561                        "overcharge=", "charge=", "delete", "limitby=", \
562                        "balance=", "ingroups=", "noquota", "add", "users", \
563                        "groups", "reset", "hardreset", "prototype=", \
564                        "printer=", "softlimit=", "hardlimit=", "pgroups=", \
565                        "increase=", "used="]
566       
567        # Initializes the command line tool
568        editor = EdPyKota(doc=__doc__)
569        editor.deferredInit()
570       
571        # parse and checks the command line
572        (options, args) = editor.parseCommandline(sys.argv[1:], short_options, long_options)
573       
574        # sets long options
575        options["help"] = options["h"] or options["help"]
576        options["version"] = options["v"] or options["version"]
577        options["add"] = options["a"] or options["add"]
578        options["users"] = options["u"] or options["users"]
579        options["groups"] = options["g"] or options["groups"]
580        options["prototype"] = options["p"] or options["prototype"]
581        options["printer"] = options["P"] or options["printer"] or defaults["printer"]
582        options["softlimit"] = options["S"] or options["softlimit"]
583        options["hardlimit"] = options["H"] or options["hardlimit"] 
584        options["reset"] = options["r"] or options["reset"] 
585        options["noquota"] = options["n"] or options["noquota"]
586        options["limitby"] = options["l"] or options["limitby"]
587        options["balance"] = options["b"] or options["balance"] 
588        options["delete"] = options["d"] or options["delete"] 
589        options["ingroups"] = options["i"] or options["ingroups"]
590        options["charge"] = options["c"] or options["charge"]
591        options["pgroups"] = options["G"] or options["pgroups"]
592        options["hardreset"] = options["R"] or options["hardreset"] 
593        options["used"] = options["U"] or options["used"]
594        options["overcharge"] = options["o"] or options["overcharge"]
595        options["comment"] = options["C"] or options["comment"] or defaults["comment"]
596        options["increase"] = options["I"] or options["increase"]
597       
598        if options["help"] :
599            editor.display_usage_and_quit()
600        elif options["version"] :
601            editor.display_version_and_quit()
602        elif options["users"] and options["groups"] :   
603            raise PyKotaCommandLineError, _("incompatible options, see help.")
604        elif (options["add"] or options["prototype"]) and options["delete"] :   
605            raise PyKotaCommandLineError, _("incompatible options, see help.")
606        elif (options["reset"] or options["hardreset"] or options["limitby"] or options["used"] or options["balance"] or options["overcharge"] or options["softlimit"] or options["hardlimit"]) and options["prototype"] :
607            raise PyKotaCommandLineError, _("incompatible options, see help.")
608        elif options["noquota"] and (options["prototype"] or options["hardlimit"] or options["softlimit"]) :
609            raise PyKotaCommandLineError, _("incompatible options, see help.")
610        elif options["groups"] and (options["balance"] or options["ingroups"] or options["used"] or options["overcharge"]) :
611            raise PyKotaCommandLineError, _("incompatible options, see help.")
612        elif options["comment"] and not options["balance"] :   
613            raise PyKotaCommandLineError, _("incompatible options, see help.")
614        else :
615            retcode = editor.main(args, options)
616    except KeyboardInterrupt :       
617        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
618        retcode = -3
619    except PyKotaCommandLineError, msg :     
620        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
621        retcode = -2
622    except SystemExit :       
623        pass
624    except :
625        try :
626            editor.crashed("edpykota failed")
627        except :   
628            crashed("edpykota failed")
629        retcode = -1
630
631    try :
632        editor.storage.close()
633    except (TypeError, NameError, AttributeError) :   
634        pass
635       
636    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.