260 lines
7.0 KiB
Python
Executable File
260 lines
7.0 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
## Copyright (C) 2009, 2010 Red Hat, Inc.
|
|
## Author: Tim Waugh <twaugh@redhat.com>
|
|
|
|
## This program is free software; you can redistribute it and/or modify
|
|
## it under the terms of the GNU General Public License as published by
|
|
## the Free Software Foundation; either version 2 of the License, or
|
|
## (at your option) any later version.
|
|
|
|
## This program is distributed in the hope that it will be useful,
|
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
## GNU General Public License for more details.
|
|
|
|
## You should have received a copy of the GNU General Public License
|
|
## along with this program; if not, write to the Free Software
|
|
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
import sys
|
|
|
|
try:
|
|
import cups
|
|
CAN_EXAMINE_PPDS = True
|
|
except:
|
|
CAN_EXAMINE_PPDS = False
|
|
|
|
from getopt import getopt
|
|
import errno
|
|
import os
|
|
import posix
|
|
import re
|
|
import shlex
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
if len (sys.argv) > 1:
|
|
RPM_BUILD_ROOT = sys.argv[1]
|
|
else:
|
|
RPM_BUILD_ROOT = None
|
|
|
|
class TimedOut(Exception):
|
|
def __init__ (self):
|
|
Exception.__init__ (self, "Timed out")
|
|
|
|
class DeviceIDs:
|
|
def __init__ (self):
|
|
self.ids = dict()
|
|
|
|
def get_dict (self):
|
|
return self.ids
|
|
|
|
def get_tags (self):
|
|
ret = []
|
|
for mfg, mdlset in self.ids.iteritems ():
|
|
mfgl = mfg.lower ().replace (" ", "_")
|
|
for mdl in mdlset:
|
|
mdll = mdl.lower ().replace (" ", "_")
|
|
ret.append ("postscriptdriver(%s;%s;)" % (mfgl,
|
|
mdll))
|
|
|
|
return ret
|
|
|
|
def __add__ (self, other):
|
|
if isinstance(other, DeviceIDs):
|
|
for omfg, omdlset in other.ids.iteritems ():
|
|
try:
|
|
mdlset = self.ids[omfg]
|
|
except KeyError:
|
|
mdlset = set()
|
|
self.ids[omfg] = mdlset
|
|
|
|
mdlset.update (omdlset)
|
|
|
|
return self
|
|
|
|
pieces = other.split (';')
|
|
mfg = mdl = None
|
|
for piece in pieces:
|
|
s = piece.split (":")
|
|
if len (s) != 2:
|
|
continue
|
|
key, value = s
|
|
key = key.upper ().strip ()
|
|
if key in ["MFG", "MANUFACTURER"]:
|
|
mfg = value.strip ()
|
|
elif key in ["MDL", "MODEL"]:
|
|
mdl = value.strip ()
|
|
|
|
if mfg and mdl:
|
|
try:
|
|
mdlset = self.ids[mfg]
|
|
except KeyError:
|
|
mdlset = set()
|
|
self.ids[mfg] = mdlset
|
|
|
|
mdlset.add (mdl)
|
|
|
|
return self
|
|
|
|
class Driver:
|
|
def __init__ (self):
|
|
self.ids = DeviceIDs()
|
|
|
|
def list (self):
|
|
return self.ids
|
|
|
|
class PPDDriver(Driver):
|
|
def __init__ (self, pathname=None):
|
|
Driver.__init__ (self)
|
|
self.pathname = pathname
|
|
|
|
def list (self):
|
|
if self.pathname != None:
|
|
self.examine_file (self.pathname)
|
|
|
|
return Driver.list (self)
|
|
|
|
def examine_file (self, path):
|
|
try:
|
|
ppd = cups.PPD (path)
|
|
except RuntimeError, e:
|
|
# Not a PPD file. Perhaps it's a drv file.
|
|
drv = DrvDriver (path)
|
|
self.ids += drv.list ()
|
|
return
|
|
|
|
attr = ppd.findAttr ('1284DeviceID')
|
|
while attr:
|
|
self.ids += attr.value
|
|
attr = ppd.findNextAttr ('1284DeviceID')
|
|
|
|
class DynamicDriver(Driver):
|
|
def __init__ (self, driver):
|
|
Driver.__init__ (self)
|
|
self.driver = driver
|
|
signal.signal (signal.SIGALRM, self._alarm)
|
|
|
|
def _alarm (self, sig, stack):
|
|
raise TimedOut
|
|
|
|
def list (self):
|
|
signal.alarm (60)
|
|
env = os.environ.copy ()
|
|
if RPM_BUILD_ROOT:
|
|
buildroot = RPM_BUILD_ROOT
|
|
if not buildroot.endswith (os.path.sep):
|
|
buildroot += os.path.sep
|
|
|
|
env["DESTDIR"] = RPM_BUILD_ROOT
|
|
env["LD_LIBRARY_PATH"] = "%susr/lib64:%susr/lib" % (buildroot,
|
|
buildroot)
|
|
|
|
p = subprocess.Popen ([self.driver, "list"],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
env=env)
|
|
try:
|
|
(stdout, stderr) = p.communicate ()
|
|
signal.alarm (0)
|
|
except TimedOut:
|
|
posix.kill (p.pid, signal.SIGKILL)
|
|
raise
|
|
|
|
if stderr:
|
|
print >> sys.stderr, stderr
|
|
|
|
ppds = []
|
|
lines = stdout.split ('\n')
|
|
for line in lines:
|
|
l = shlex.split (line)
|
|
if len (l) < 5:
|
|
continue
|
|
self.ids += l[4]
|
|
|
|
return Driver.list (self)
|
|
|
|
class DrvDriver(PPDDriver):
|
|
def __init__ (self, pathname):
|
|
PPDDriver.__init__ (self)
|
|
self.drv = pathname
|
|
|
|
def _alarm (self, sig, stack):
|
|
raise TimedOut
|
|
|
|
def list (self):
|
|
tmpdir = os.environ.get ("TMPDIR", "/tmp") + os.path.sep
|
|
outputdir = tempfile.mkdtemp (dir=tmpdir)
|
|
|
|
argv = [ "ppdc",
|
|
"-d", outputdir,
|
|
"-I", "/usr/share/cups/ppdc",
|
|
self.drv ]
|
|
|
|
signal.alarm (60)
|
|
try:
|
|
p = subprocess.Popen (argv,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
except OSError:
|
|
# ppdc not available.
|
|
os.rmdir (outputdir)
|
|
return Driver.list (self)
|
|
|
|
try:
|
|
(stdout, stderr) = p.communicate ()
|
|
signal.alarm (0)
|
|
except TimedOut:
|
|
posix.kill (p.pid, signal.SIGKILL)
|
|
raise
|
|
|
|
os.path.walk (outputdir, self.examine_directory, None)
|
|
os.rmdir (outputdir)
|
|
return Driver.list (self)
|
|
|
|
def examine_directory (self, unused, dirname, fnames):
|
|
for fname in fnames:
|
|
path = dirname + os.path.sep + fname
|
|
self.examine_file (path)
|
|
os.unlink (path)
|
|
|
|
class TagBuilder:
|
|
def __init__ (self, filelist=None):
|
|
if filelist == None:
|
|
filelist = sys.stdin
|
|
|
|
paths = map (lambda x: x.rstrip (), filelist.readlines ())
|
|
self.ids = DeviceIDs ()
|
|
|
|
for path in paths:
|
|
if path.find ("/usr/lib/cups/driver/") != -1:
|
|
try:
|
|
self.ids += DynamicDriver (path).list ()
|
|
except TimedOut:
|
|
pass
|
|
except OSError, (e, s):
|
|
if e == errno.EACCES or e == errno.ENOENT:
|
|
# Not executable
|
|
pass
|
|
else:
|
|
raise
|
|
|
|
if CAN_EXAMINE_PPDS:
|
|
for path in paths:
|
|
try:
|
|
self.ids += PPDDriver (path).list ()
|
|
except TimedOut:
|
|
pass
|
|
|
|
def get_tags (self):
|
|
return self.ids.get_tags ()
|
|
|
|
if __name__ == "__main__":
|
|
builder = TagBuilder ()
|
|
tags = builder.get_tags ()
|
|
for tag in tags:
|
|
print tag
|