diff -up rpm-4.8.0/build/rpmfc.c.psdriver rpm-4.8.0/build/rpmfc.c --- rpm-4.8.0/build/rpmfc.c.psdriver 2010-03-16 10:54:04.000000000 +0200 +++ rpm-4.8.0/build/rpmfc.c 2010-03-16 10:54:04.000000000 +0200 @@ -489,6 +489,7 @@ static const struct rpmfcTokens_s const { " font metrics", RPMFC_WHITE|RPMFC_INCLUDE }, { " font", RPMFC_FONT|RPMFC_INCLUDE }, { " Font", RPMFC_FONT|RPMFC_INCLUDE }, + { "PPD file", RPMFC_PSDRIVER|RPMFC_INCLUDE }, { " commands", RPMFC_SCRIPT|RPMFC_INCLUDE }, { " script", RPMFC_SCRIPT|RPMFC_INCLUDE }, @@ -1185,6 +1186,11 @@ exit: #endif } +static int rpmfcPSDRIVER(rpmfc fc) +{ + return rpmfcHelper(fc, 'P', "psdriver"); +} + static int rpmfcMISC(rpmfc fc) { struct stat st; @@ -1224,6 +1230,7 @@ static const struct rpmfcApplyTbl_s cons RPMFC_PKGCONFIG|RPMFC_LIBTOOL) }, { rpmfcMISC, RPMFC_FONT|RPMFC_TEXT }, { rpmfcSYMLINK, RPMFC_SYMLINK }, + { rpmfcPSDRIVER, RPMFC_PSDRIVER }, { NULL, 0 } }; @@ -1260,6 +1267,10 @@ rpmRC rpmfcApply(rpmfc fc) fc->fcolor->vals[fc->ix] |= RPMFC_PYTHON; } } + /* XXX HACK: get cups driver executables also recognized as psdrivers */ + if (strstr(fc->fn[fc->ix], "/usr/lib/cups/driver/")) { + fc->fcolor->vals[fc->ix] |= RPMFC_PSDRIVER; + } if (fc->fcolor->vals[fc->ix]) for (fcat = rpmfcApplyTable; fcat->func != NULL; fcat++) { @@ -1401,6 +1412,11 @@ rpmRC rpmfcClassify(rpmfc fc, ARGV_t arg else if (rpmFileHasSuffix(s, ".pc")) ftype = "pkgconfig file"; + /* XXX Make cups .drv's to appear as PPD's for now */ + else if (rpmFileHasSuffix(s, ".drv") && + strstr(s, "/usr/share/cups/drv")) + ftype = "PPD file"; + /* XXX skip all files in /dev/ which are (or should be) %dev dummies. */ else if (slen >= fc->brlen+sizeof("/dev/") && rstreqn(s+fc->brlen, "/dev/", sizeof("/dev/")-1)) ftype = ""; diff -up rpm-4.8.0/build/rpmfc.h.psdriver rpm-4.8.0/build/rpmfc.h --- rpm-4.8.0/build/rpmfc.h.psdriver 2009-12-09 15:37:25.000000000 +0200 +++ rpm-4.8.0/build/rpmfc.h 2010-03-16 10:54:04.000000000 +0200 @@ -31,7 +31,8 @@ enum FCOLOR_e { #define RPMFC_ELF (RPMFC_ELF32|RPMFC_ELF64|RPMFC_ELFMIPSN32) /* (1 << 3) leaks into package headers, reserved */ - /* bits 4-6 unused */ + /* bits 4-5 unused */ + RPMFC_PSDRIVER = (1 << 6), RPMFC_OCAML = (1 << 7), RPMFC_PKGCONFIG = (1 << 8), RPMFC_LIBTOOL = (1 << 9), @@ -53,6 +54,7 @@ enum FCOLOR_e { RPMFC_MANPAGE = (7 << 16), RPMFC_TEXT = (8 << 16), RPMFC_DOCUMENT = (9 << 16), + RPMFC_PPD = (10 << 16), RPMFC_ARCHIVE = (1 << 20), RPMFC_COMPRESSED = (1 << 21), diff -up rpm-4.8.0/macros.in.psdriver rpm-4.8.0/macros.in --- rpm-4.8.0/macros.in.psdriver 2010-03-16 10:54:04.000000000 +0200 +++ rpm-4.8.0/macros.in 2010-03-16 10:54:04.000000000 +0200 @@ -504,6 +504,7 @@ print (t)\ %__fontconfig_provides %{_rpmconfigdir}/fontconfig.prov %__desktop_provides %{_rpmconfigdir}/desktop-file.prov +%__psdriver_provides %{_rpmconfigdir}/postscriptdriver.prov %{buildroot} #============================================================================== # ---- Database configuration macros. diff -up rpm-4.8.0/scripts/Makefile.am.psdriver rpm-4.8.0/scripts/Makefile.am --- rpm-4.8.0/scripts/Makefile.am.psdriver 2009-12-07 16:36:49.000000000 +0200 +++ rpm-4.8.0/scripts/Makefile.am 2010-03-16 10:54:04.000000000 +0200 @@ -20,7 +20,8 @@ EXTRA_DIST = \ mono-find-requires mono-find-provides \ ocaml-find-requires.sh ocaml-find-provides.sh \ pkgconfigdeps.sh libtooldeps.sh \ - fontconfig.prov desktop-file.prov + fontconfig.prov desktop-file.prov \ + postscriptdriver.prov rpmconfig_SCRIPTS = \ brp-compress brp-python-bytecompile brp-java-gcjcompile \ @@ -34,6 +35,7 @@ rpmconfig_SCRIPTS = \ pkgconfigdeps.sh libtooldeps.sh \ ocaml-find-requires.sh ocaml-find-provides.sh \ fontconfig.prov desktop-file.prov \ + postscriptdriver.prov \ rpmdb_loadcvt rpmdiff rpm2cpio.sh tcl.req tgpg rpmconfig_DATA = \ diff -up rpm-4.8.0/scripts/Makefile.in.psdriver rpm-4.8.0/scripts/Makefile.in --- rpm-4.8.0/scripts/Makefile.in.psdriver 2010-01-08 10:35:16.000000000 +0200 +++ rpm-4.8.0/scripts/Makefile.in 2010-03-16 10:54:04.000000000 +0200 @@ -317,7 +317,8 @@ EXTRA_DIST = brp-compress brp-python-byt find-php-provides find-php-requires mono-find-requires \ mono-find-provides ocaml-find-requires.sh \ ocaml-find-provides.sh pkgconfigdeps.sh libtooldeps.sh \ - fontconfig.prov desktop-file.prov macros.perl.in macros.php.in \ + fontconfig.prov desktop-file.prov postscriptdriver.prov \ + macros.perl.in macros.php.in \ macros.python.in rpmconfig_SCRIPTS = \ brp-compress brp-python-bytecompile brp-java-gcjcompile \ @@ -331,6 +332,7 @@ rpmconfig_SCRIPTS = \ pkgconfigdeps.sh libtooldeps.sh \ ocaml-find-requires.sh ocaml-find-provides.sh \ fontconfig.prov desktop-file.prov \ + postscriptdriver.prov \ rpmdb_loadcvt rpmdiff rpm2cpio.sh tcl.req tgpg rpmconfig_DATA = rpmdiff.cgi rpm.daily rpm.log rpm.xinetd macros.perl \ diff -up rpm-4.8.0/scripts/postscriptdriver.prov.psdriver rpm-4.8.0/scripts/postscriptdriver.prov --- rpm-4.8.0/scripts/postscriptdriver.prov.psdriver 2010-03-16 10:54:04.000000000 +0200 +++ rpm-4.8.0/scripts/postscriptdriver.prov 2010-03-16 10:54:04.000000000 +0200 @@ -0,0 +1,261 @@ +#!/bin/bash +shopt -s execfail +exec -a "$0" python -- <(tail -n +4 -- "$0") "$@" || exit 0 # -*- 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 () + if key in ["MFG", "MANUFACTURER"]: + mfg = value + elif key in ["MDL", "MODEL"]: + mdl = value + + 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