root / pykota / trunk / pykota / accounters / software.py @ 3245

Revision 3245, 6.2 kB (checked in by jerome, 17 years ago)

Now the pykotme command line tool computes size and price based on the preaccounter
define for each printer instead of always using the internal page counter.
IMPORTANT : pykotme.cgi still uses the old behavior.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1# PyKota
2# -*- coding: ISO-8859-15 -*-
3#
4# PyKota - Print Quotas for CUPS and LPRng
5#
6# (c) 2003, 2004, 2005, 2006, 2007 Jerome Alet <alet@librelogiciel.com>
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20#
21# $Id$
22#
23#
24
25import os
26import popen2
27from pykota.accounter import AccounterBase, PyKotaAccounterError
28
29class Accounter(AccounterBase) :
30    def computeJobSize(self) :   
31        """Feeds an external command with our datas to let it compute the job size, and return its value."""
32        if (not self.isPreAccounter) and \
33            (self.filter.accounter.arguments == self.filter.preaccounter.arguments) :
34            # if precomputing has been done and both accounter and preaccounter are
35            # configured the same, no need to launch a second pass since we already
36            # know the result.
37            self.filter.logdebug("Precomputing pass told us that job is %s pages long." % self.filter.softwareJobSize)
38            return self.filter.softwareJobSize   # Optimize : already computed !
39           
40        if self.arguments :
41            self.filter.logdebug("Using external script %s to compute job's size." % self.arguments)
42            return self.withExternalScript()
43        else :   
44            self.filter.logdebug("Using internal parser to compute job's size.")
45            return self.withInternalParser()
46       
47    def withInternalParser(self) :   
48        """Does software accounting through an external script."""
49        jobsize = 0
50        if self.filter.JobSizeBytes :
51            try :
52                from pkpgpdls import analyzer, pdlparser
53            except ImportError :   
54                self.filter.printInfo("pkpgcounter is now distributed separately, please grab it from http://www.pykota.com/software/pkpgcounter", "error")
55                self.filter.printInfo("Precomputed job size will be forced to 0 pages.", "error")
56            else :     
57                infile = open(self.filter.DataFile, "rb")
58                try :
59                    parser = analyzer.PDLAnalyzer(infile)
60                    jobsize = parser.getJobSize()
61                except pdlparser.PDLParserError, msg :   
62                    # Here we just log the failure, but
63                    # we finally ignore it and return 0 since this
64                    # computation is just an indication of what the
65                    # job's size MAY be.
66                    self.filter.printInfo(_("Unable to precompute the job's size with the generic PDL analyzer : %s") % msg, "warn")
67                else :   
68                    try :
69                        if self.filter.InputFile is not None :
70                            # when a filename is passed as an argument, the backend
71                            # must generate the correct number of copies.
72                            jobsize *= self.filter.Copies
73                    except AttributeError : # When not run from the cupspykota backend       
74                        pass
75                infile.close()       
76        return jobsize       
77               
78    def withExternalScript(self) :   
79        """Does software accounting through an external script."""
80        self.filter.printInfo(_("Launching SOFTWARE(%s)...") % self.arguments)
81        MEGABYTE = 1024*1024
82        infile = open(self.filter.DataFile, "rb")
83        child = popen2.Popen4(self.arguments)
84        try :
85            data = infile.read(MEGABYTE)   
86            while data :
87                child.tochild.write(data)
88                data = infile.read(MEGABYTE)
89            child.tochild.flush()
90            child.tochild.close()   
91        except (IOError, OSError), msg :   
92            msg = "%s : %s" % (self.arguments, msg) 
93            self.filter.printInfo(_("Unable to compute job size with accounter %s") % msg)
94        infile.close()
95        pagecounter = None
96        try :
97            answer = child.fromchild.read()
98        except (IOError, OSError), msg :   
99            msg = "%s : %s" % (self.arguments, msg) 
100            self.filter.printInfo(_("Unable to compute job size with accounter %s") % msg)
101        else :   
102            lines = [l.strip() for l in answer.split("\n")]
103            for i in range(len(lines)) : 
104                try :
105                    pagecounter = int(lines[i])
106                except (AttributeError, ValueError) :
107                    self.filter.printInfo(_("Line [%s] skipped in accounter's output. Trying again...") % lines[i])
108                else :   
109                    break
110        child.fromchild.close()
111       
112        try :
113            status = child.wait()
114        except OSError, msg :   
115            self.filter.printInfo(_("Problem while waiting for software accounter pid %s to exit : %s") % (child.pid, msg))
116        else :   
117            if os.WIFEXITED(status) :
118                status = os.WEXITSTATUS(status)
119            self.filter.printInfo(_("Software accounter %s exit code is %s") % (self.arguments, str(status)))
120           
121        if pagecounter is None :   
122            message = _("Unable to compute job size with accounter %s") % self.arguments
123            if self.onerror == "CONTINUE" :
124                self.filter.printInfo(message, "error")
125            else :
126                raise PyKotaAccounterError, message
127        self.filter.logdebug("Software accounter %s said job is %s pages long." % (self.arguments, repr(pagecounter)))
128           
129        pagecounter = pagecounter or 0   
130        if self.filter.InputFile is not None :
131            # when a filename is passed as an argument, the backend
132            # must generate the correct number of copies.
133            pagecounter *= self.filter.Copies
134                       
135        return pagecounter
Note: See TracBrowser for help on using the browser.