diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml index b731b8b72a3d..02cb2dd9ccd1 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml @@ -643,6 +643,15 @@ maintainer to update the package. + + + ppd files in pkgs.cups-drv-rastertosag-gdi + are now gzipped. If you refer to such a ppd file with its path + (e.g. via + hardware.printers.ensurePrinters) + you will need to append .gz to the path. + + xow package removed along with the diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md index 0f0e3c7a2e55..43abb40b8a04 100644 --- a/nixos/doc/manual/release-notes/rl-2211.section.md +++ b/nixos/doc/manual/release-notes/rl-2211.section.md @@ -210,6 +210,8 @@ Available as [services.patroni](options.html#opt-services.patroni.enable). - riak package removed along with `services.riak` module, due to lack of maintainer to update the package. +- ppd files in `pkgs.cups-drv-rastertosag-gdi` are now gzipped. If you refer to such a ppd file with its path (e.g. via [hardware.printers.ensurePrinters](options.html#opt-hardware.printers.ensurePrinters)) you will need to append `.gz` to the path. + - xow package removed along with the `hardware.xow` module, due to the project being deprecated in favor of `xone`, which is available via the `hardware.xone` module. - dd-agent package removed along with the `services.dd-agent` module, due to the project being deprecated in favor of `datadog-agent`, which is available via the `services.datadog-agent` module. diff --git a/pkgs/build-support/setup-hooks/patch-ppd-files/default.nix b/pkgs/build-support/setup-hooks/patch-ppd-files/default.nix new file mode 100644 index 000000000000..b3c7b19f3732 --- /dev/null +++ b/pkgs/build-support/setup-hooks/patch-ppd-files/default.nix @@ -0,0 +1,25 @@ +{ lib +, makeSetupHook +, which +, callPackage +}: + +let + patchPpdFilesHook = makeSetupHook + { + name = "patch-ppd-files"; + substitutions.which = lib.attrsets.getBin which; + substitutions.awkscript = ./patch-ppd-lines.awk; + } + ./patch-ppd-hook.sh; +in + +patchPpdFilesHook.overrideAttrs ( + lib.trivial.flip + lib.attrsets.recursiveUpdate + { + passthru.tests.test = callPackage ./test.nix {}; + meta.description = "setup hook to patch executable paths in ppd files"; + meta.maintainers = [ lib.maintainers.yarny ]; + } +) diff --git a/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-hook.sh b/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-hook.sh new file mode 100644 index 000000000000..a450ecd7f963 --- /dev/null +++ b/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-hook.sh @@ -0,0 +1,183 @@ +fixupOutputHooks+=(_patchPpdFileCommands4fixupOutputHooks) + + + +# Install a hook for the `fixupPhase`: +# If the variable `ppdFileCommands` contains a list of +# executable names, the hook calls `patchPpdFileCommands` +# on each output's `/share/cups/model` and `/share/ppds` +# directories in order to replace calls to those executables. + +_patchPpdFileCommands4fixupOutputHooks () { + [[ -n $ppdFileCommands ]] || return 0 + if [[ -d $prefix/share/cups/model ]]; then + patchPpdFileCommands "$prefix/share/cups/model" $ppdFileCommands + fi + if [[ -d $prefix/share/ppds ]]; then + patchPpdFileCommands "$prefix/share/ppds" $ppdFileCommands + fi +} + + + +# patchPpdFileCommands PPD-ROOT PROGNAME... +# +# Look for ppd files in the directory PPD-ROOT. +# Descend into subdirectories, even if they are symlinks. +# However, ignore ppd files that don't belong to the same +# prefix ($NIX_STORE/$package_name) as PPD-ROOT-DIR does, +# to avoid stepping into other package's directories. +# ppd files may be gzipped; if the are, +# uncompress them, later recompress them. +# Skip symlinks to ppd files. +# PPD-ROOT may also be a single ppd file. +# +# Look for the PROGNAME executable in outputs and `buildInputs`, +# then look for PROGNAME invocations in the ppd files, +# without path or with common paths like `/usr/bin/$PROGNAME`. +# Replace those invocations with an absolute path to the +# corresponding executable from the outputs or `buildInputs`. +# Executables are searched where CUPS would search them, +# i.e., in `/bin` and `/lib/cups/filter`. +# +# As soon as an executable's path is replaced as +# described above, the package containing the binary +# is added to the list of propagated build inputs. +# This ensures the executable's package is still +# recognized as runtime dependency of the ppd file +# even if the ppd file is compressed lateron. +# +# PROGNAME may not contain spaces or tabs. +# The function will also likely fail or produce +# broken results if PROGNAME contains characters that +# require shell or regex escaping (e.g. a backslash). + +patchPpdFileCommands () { + + local bin binnew binold binoldgrep cupspath path ppdroot ppdrootprefix + + # we will store some temporary data here + pushd "$(mktemp -d --tmpdir patch-ppd-file-commands.XXXX)" + + # remember the ppd root path + [[ "$1" == $NIX_STORE/* ]] # ensure it's a store directory + ppdroot=$1 + shift # now "$@" is the list of binaries + ppdrootprefix=${ppdroot%"/${ppdroot#"$NIX_STORE"/*/}"} + + # create `cupspath` (where we should look for binaries), + # with these priorities + # * outputs of current build before buildInputs + # * `/lib/cups/filter' before `/bin` + # * add HOST_PATH at end, so we don't miss anything + for path in $outputs; do + addToSearchPath cupspath "${!path}/lib/cups/filter" + addToSearchPath cupspath "${!path}/bin" + done + for path in ${pkgsHostTarget+"${pkgsHostTarget[@]}"}; do + addToSearchPath cupspath "$path/lib/cups/filter" + addToSearchPath cupspath "$path/bin" + done + while read -r -d : path; do + addToSearchPath cupspath "$path" + done <<< "${HOST_PATH:+"${HOST_PATH}:"}" + + # create list of compressed ppd files + # so we can recompress them later + find -L "$ppdroot" -type f -iname '*.ppd.gz' '!' -xtype l -print0 > gzipped + + # decompress gzipped ppd files + echo "patchPpdFileCommands: decompressing $(grep -cz '^' < gzipped) gzipped ppd file(s) in $ppdroot" + xargs -0r -n 64 -P "$NIX_BUILD_CORES" gunzip < gzipped + + # create list of all ppd files to be checked + find -L "$ppdroot" -type f -iname '*.ppd' '!' -xtype l -print0 > ppds + + for bin in "$@"; do + + # discover new path + binnew=$(PATH=$cupspath '@which@/bin/which' "$bin") + echo "patchPpdFileCommands: located binary $binnew" + + # for each binary, we look for the name itself, but + # also for a couple of common paths that might be used + for binold in {/usr,}/{lib/cups/filter,sbin,bin}/"$bin" "$bin"; do + + # escape regex characters in the old command string + binoldgrep=$(sed 's,[]$.*[\^],\\&,g' <<< "$binold") + # ...and surround old command with some regex + # that singles out shell command invocations + # to avoid replacing other strings that might contain the + # command name by accident (like "perl" in "perl-script") + binoldgrep='\(^\|[;&| '$'\t''"`(]\)'"$binoldgrep"'\($\|[);&| '$'\t''"`<>]\)' + # this string is used to *quickly* filter out + # unaffected files before the (slower) awk script runs; + # note that a similar regex is build in the awk script; + # if `binoldgrep` is changed, the awk script should also be checked + + # create list of likely affected files + # (might yield exit status != 0 if there are no matches) + xargs -0r grep -lZ "$binoldgrep" < ppds > ppds-to-patch || true + + echo "patchPpdFileCommands: $(grep -cz '^' < ppds-to-patch) ppd file(s) contain $binold" + + # actually patch affected ppd files with awk; + # this takes some time but can be parallelized; + # speed up with LC_ALL=C, https://stackoverflow.com/a/33850386 + LC_ALL=C xargs -0r -n 64 -P "$NIX_BUILD_CORES" \ + awk -i inplace -v old="${binold//\\/\\\\}" -v new="${binnew//\\/\\\\}" -f "@awkscript@" \ + < ppds-to-patch + + done + + # create list of affected files + xargs -0r grep -lZF "$binnew" < ppds > patched-ppds || true + + echo "patchPpdFileCommands: $(grep -cz '^' < patched-ppds) ppd file(s) patched with $binnew" + + # if the new command is contained in a file, + # remember the new path so we can add it to + # the list of propagated dependencies later + if [[ -s patched-ppds ]]; then + printf '%s\0' "${binnew%"/${binnew#"${NIX_STORE}"/*/}"}" >> dependencies + fi + + done + + # recompress ppd files that have been decompressed before + echo "patchPpdFileCommands: recompressing $(grep -cz '^' < gzipped) gzipped ppd file(s)" + # we can't just hand over the paths of the uncompressed files + # to gzip as it would add the lower-cased extension ".gz" + # even for files where the original was named ".GZ" + xargs -0r -n 1 -P "$NIX_BUILD_CORES" \ + "$SHELL" -c 'gzip -9nS ".${0##*.}" "${0%.*}"' \ + < gzipped + + # enlist dependencies for propagation; + # this is needed in case ppd files are compressed later + # (Nix won't find dependency paths in compressed files) + if [[ -s dependencies ]]; then + + # weed out duplicates from the dependency list first + sort -zu dependencies > sorted-dependencies + + mkdir -p "$ppdrootprefix/nix-support" + while IFS= read -r -d '' path; do + printWords "$path" >> "$ppdrootprefix/nix-support/propagated-build-inputs" + # stdenv writes it's own `propagated-build-inputs`, + # based on the variable `propagatedBuildInputs`, + # but only to one output (`outputDev`). + # So we also add our dependencies to that variable. + # If our file survives as written above, great! + # If stdenv overwrits it, + # our dependencies will still be added to the file. + # The end result might contain too many + # propagated dependencies for multi-output packages, + # but never a broken package. + propagatedBuildInputs+=("$path") + done < sorted-dependencies + fi + + popd + +} diff --git a/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-lines.awk b/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-lines.awk new file mode 100644 index 000000000000..ddb9171fff32 --- /dev/null +++ b/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-lines.awk @@ -0,0 +1,50 @@ +BEGIN { + + # ppd file keys are separated from their values by a colon, + # but "options" may reside between the key name and the colon; + # options are separated from the key by spaces + # (we also permit tabs to be on the safe side) + FS = "[: \t]"; + + # escape regex characters in the old and new command strings + gsub(/[]\\.^$(){}|*+?[]/, "\\\\&", old); + gsub(/\\/, "\\\\&", new); + # ...and surround old command with some regex + # that singles out shell command invocations + # to avoid replacing other strings that might contain the + # command name by accident (like "perl" in "perl-script") + new = "\\1" new "\\2"; + old = "(^|[;&| \\t\"`(])" old "($|[);&| \\t\"`<>])"; + # note that a similar regex is build in the shell script to + # filter out unaffected files before this awk script is called; + # if the regex here is changed, the shell script should also be checked + + # list of PPD keys that contain executable names or scripts, see + # https://refspecs.linuxfoundation.org/LSB_4.0.0/LSB-Printing/LSB-Printing/ppdext.html + # https://www.cups.org/doc/spec-ppd.html + cmds["*APAutoSetupTool"] = ""; + cmds["*APPrinterLowInkTool"] = ""; + cmds["*FoomaticRIPCommandLine"] = ""; + cmds["*FoomaticRIPPostPipe"] = ""; + cmds["*cupsFilter"] = ""; + cmds["*cupsFilter2"] = ""; + cmds["*cupsPreFilter"] = ""; + +} + +# since comments always start with "*%", +# this mechanism also properly recognizes (and ignores) them + +{ + + # if the current line starts a new key, + # check if it is a command-containing key; + # also reset the `isCmd` flag if a new file begins + if ($0 ~ /^\*/ || FNR == 1) { isCmd = ($1 in cmds) } + + # replace commands if the current keys might contain commands + if (isCmd) { $0 = gensub(old, new, "g") } + + print + +} diff --git a/pkgs/build-support/setup-hooks/patch-ppd-files/test.nix b/pkgs/build-support/setup-hooks/patch-ppd-files/test.nix new file mode 100644 index 000000000000..4f2996b23510 --- /dev/null +++ b/pkgs/build-support/setup-hooks/patch-ppd-files/test.nix @@ -0,0 +1,40 @@ +{ substituteAll +, diffutils +, stdenv +, patchPpdFilesHook +}: + +let + input = substituteAll { + src = ./test.ppd; + keep = "cmp"; + patch = "cmp"; + pathkeep = "/bin/cmp"; + pathpatch = "/bin/cmp"; + }; + + output = substituteAll { + src = ./test.ppd; + keep = "cmp"; + patch = "${diffutils}/bin/cmp"; + pathkeep = "/bin/cmp"; + pathpatch = "${diffutils}/bin/cmp"; + }; +in + +stdenv.mkDerivation { + name = "${patchPpdFilesHook.name}-test"; + buildInputs = [ diffutils ]; + nativeBuildInputs = [ diffutils patchPpdFilesHook ]; + dontUnpack = true; + dontInstall = true; + ppdFileCommands = [ "cmp" ]; + preFixup = '' + install -D "${input}" "${placeholder "out"}/share/cups/model/test.ppd" + install -D "${input}" "${placeholder "out"}/share/ppds/test.ppd" + ''; + postFixup = '' + diff --color --report-identical-files "${output}" "${placeholder "out"}/share/cups/model/test.ppd" + diff --color --report-identical-files "${output}" "${placeholder "out"}/share/ppds/test.ppd" + ''; +} diff --git a/pkgs/build-support/setup-hooks/patch-ppd-files/test.ppd b/pkgs/build-support/setup-hooks/patch-ppd-files/test.ppd new file mode 100644 index 000000000000..d0ca11ccfe6d --- /dev/null +++ b/pkgs/build-support/setup-hooks/patch-ppd-files/test.ppd @@ -0,0 +1,22 @@ +*% This comment: might look like a command @keep@ +*% but it should be left untouched +*SomeKey: do not replace this @keep@ +*APAutoSetupTool: do replace this @patch@ +*FoomaticRIPCommandLine: "patch also @patch@ +in a multi-line command @patch@ +and another line @patch@ +*SomeKey: "stop patching on new non-command key @keep@ +and remember the key in the next line @keep@" +*cupsFilter option: recognize keys with options @patch@ +*cupsFilter : handle strange spacing;@patch@ +*cupsFilter : handle tabulator @patch@ +*cupsFilter: patch common paths @pathpatch@ +*cupsFilter: patch quoted commands "@patch@" +*cupsFilter: patch commands in subshell (@patch@) +*cupsFilter: patch commands in subshell `@pathpatch@` +*cupsFilter: keep uncommon paths /fancy/@pathkeep@ +*cupsFilter: keep entangled commands-@keep@ +*cupsFilter: keep entangled commands\@keep@ +*cupsFilter: keep entangled commands @keep@() +*cupsFilter: keep entangled commands @pathkeep@-cmd +*%cupsFilter: This comment should also be left as is @pathkeep@ diff --git a/pkgs/misc/cups/drivers/cups-drv-rastertosag-gdi/default.nix b/pkgs/misc/cups/drivers/cups-drv-rastertosag-gdi/default.nix index d49143655459..4f1ad6c9911e 100644 --- a/pkgs/misc/cups/drivers/cups-drv-rastertosag-gdi/default.nix +++ b/pkgs/misc/cups/drivers/cups-drv-rastertosag-gdi/default.nix @@ -3,6 +3,7 @@ , fetchpatch , cups , python3Packages +, patchPpdFilesHook }: python3Packages.buildPythonApplication rec { @@ -20,9 +21,9 @@ python3Packages.buildPythonApplication rec { }) ]; format = "other"; - nativeBuildInputs = [ (lib.getBin cups) ]; + nativeBuildInputs = [ (lib.getBin cups) patchPpdFilesHook ]; # The source image also brings pre-built ppd files, - # be we prefer to generate from source where possible, so + # but we prefer to generate from source where possible, so # the following line generates ppd files from the drv file. postBuild = '' ppdc -v -d . -I "${cups}/share/cups/ppdc" rastertosag-gdi.drv @@ -35,6 +36,10 @@ python3Packages.buildPythonApplication rec { ln -vst "${placeholder "out"}/lib/cups/filter/" "${placeholder "out"}/bin/rastertosag-gdi" runHook postInstall ''; + ppdFileCommands = [ "rastertosag-gdi" ]; + postFixup = '' + gzip -9nv "${placeholder "out"}/share/cups/model/rastertosag-gdi"/*.ppd + ''; meta = { description = "CUPS driver for Ricoh Aficio SP 1000S and SP 1100S printers"; downloadPage = "https://www.openprinting.org/download/printing/rastertosag-gdi/"; diff --git a/pkgs/misc/cups/drivers/foomatic-db-engine/default.nix b/pkgs/misc/cups/drivers/foomatic-db-engine/default.nix new file mode 100644 index 000000000000..b5e107ebf37f --- /dev/null +++ b/pkgs/misc/cups/drivers/foomatic-db-engine/default.nix @@ -0,0 +1,94 @@ +{ lib +, perlPackages +, fetchFromGitHub +, withCupsAccess ? false # needed to access local cups server +, cups +, cups-filters +, curl +, withSocketAccess ? false # needed to access network printers +, netcat-gnu +, withSMBAccess ? false # needed to access SMB-connected printers +, samba +, autoconf +, automake +, file +, makeWrapper +}: + +perlPackages.buildPerlPackage { + pname = "foomatic-db-engine"; + version = "unstable-2022-05-03"; + + src = fetchFromGitHub { + # there is also a daily snapshot at the `downloadPage`, + # but it gets deleted quickly and would provoke 404 errors + owner = "OpenPrinting"; + repo = "foomatic-db-engine"; + rev = "2e6f14b54748fa121a4d2e3d480010e10b070c5a"; + hash = "sha256-m7FQTxWmawbtm24h8UqznGKXgX41JhOtyyFMRwEhm5k="; + }; + + outputs = [ "out" ]; + + propagatedBuildInputs = [ + perlPackages.Clone + perlPackages.DBI + perlPackages.XMLLibXML + ]; + + buildInputs = + # provide some "cups-*" commands to `foomatic-{configure,printjob}` + # so that they can manage a local cups server (add queues, add jobs...) + lib.optionals withCupsAccess [ cups cups-filters curl ] + # the commands `foomatic-{configure,getpjloptions}` need + # netcat if they are used to query or alter a network + # printer via AppSocket/HP JetDirect protocol + ++ lib.optional withSocketAccess netcat-gnu + # `foomatic-configure` can be used to access printers that are + # shared via the SMB protocol, but it needs the `smbclient` binary + ++ lib.optional withSMBAccess samba + ; + + nativeBuildInputs = [ autoconf automake file makeWrapper ]; + + # sed-substitute indirection is more robust against + # characters in paths that might need escaping + prePatch = '' + sed -Ei 's|^(S?BINSEARCHPATH=).+$|\1"@PATH@"|g' configure.ac + substituteInPlace configure.ac --subst-var PATH + touch Makefile.PL # `buildPerlPackage` fails unless this exists + ''; + + preConfigure = '' + ./make_configure + ''; + + configureFlags = [ + "--sysconfdir=${placeholder "out"}/etc" + "LIBDIR=${placeholder "out"}/share/foomatic" + "PERLPREFIX=${placeholder "out"}" + ]; + + postFixup = '' + for bin in "${placeholder "out"}/bin"/*; do + test '!' -L "$bin" || continue # skip symlink + wrapProgram "$bin" --set PERL5LIB "$PERL5LIB" + done + ''; + + doCheck = false; # no tests, would fail + + meta = { + description = "OpenPrinting printer support database engine"; + downloadPage = "https://www.openprinting.org/download/foomatic/"; + homepage = "https://openprinting.github.io/projects/02-foomatic/"; + license = lib.licenses.gpl2Only; + maintainers = [ lib.maintainers.yarny ]; + longDescription = '' + Foomatic's database engine generates PPD files + from the data in Foomatic's XML database. + It also contains scripts to directly + generate print queues and handle jobs. + ''; + }; +} diff --git a/pkgs/misc/cups/drivers/foomatic-db-nonfree/default.nix b/pkgs/misc/cups/drivers/foomatic-db-nonfree/default.nix new file mode 100644 index 000000000000..1c38ae38b98a --- /dev/null +++ b/pkgs/misc/cups/drivers/foomatic-db-nonfree/default.nix @@ -0,0 +1,86 @@ +{ lib +, stdenv +, fetchFromGitHub +, autoconf +, automake +, perl +}: + +stdenv.mkDerivation { + pname = "foomatic-db-nonfree"; + version = "unstable-2015-06-05"; + + src = fetchFromGitHub { + # there is also a daily snapshot at the `downloadPage`, + # but it gets deleted quickly and would provoke 404 errors + owner = "OpenPrinting"; + repo = "foomatic-db-nonfree"; + rev = "6ddae02ac89240c019f8b5026cfe70e30fd2b3db"; + hash = "sha256-cRZH0CXg03FEqUJdxaNnPVXjf8+ct86PjhL59WQbw60="; + }; + + nativeBuildInputs = [ autoconf automake perl ]; + + # sed-substitute indirection is more robust against + # characters in paths that might need escaping + postPatch = '' + sed -Ei -e 's|^(S?BINSEARCHPATH=).+$|\1"@PATH@"|g' \ + -e 's|^(DATASEARCHPATH=).+$|\1"@DATA@"|g' configure.ac + substituteInPlace configure.ac \ + --subst-var PATH \ + --subst-var-by DATA "${placeholder "out"}/share" + ''; + + preConfigure = '' + mkdir -p "${placeholder "out"}/share/foomatic/db/source" + ./make_configure + ''; + + # make ppd files available to cups, + # use a package-specific subdirectory to avoid + # conflicts with other ppd-containing packages + postInstall = '' + if ! [[ -d "${placeholder "out"}/share/foomatic/db/source/PPD" ]]; then + echo "failed to create share/foomatic/db/source/PPD" + exit 1 + fi + mkdir -p "${placeholder "out"}/share/cups/model" + ln -s "${placeholder "out"}/share/foomatic/db/source/PPD" \ + "${placeholder "out"}/share/cups/model/foomatic-db-nonfree" + ''; + + # we might patch ppd file commands with `patchPpdFilesHook`, + # but the only command "rastertophaser6100" isn't packaged yet + + # compress ppd files + postFixup = '' + echo 'compressing ppd files' + find -H "${placeholder "out"}/share/cups/model/foomatic-db-nonfree" -type f -iname '*.ppd' -print0 \ + | xargs -0r -n 64 -P "$NIX_BUILD_CORES" gzip -9n + ''; + + meta = { + description = "OpenPrinting printer support database (unfree content)"; + downloadPage = "https://www.openprinting.org/download/foomatic/"; + homepage = "https://openprinting.github.io/projects/02-foomatic/"; + license = lib.licenses.unfree; + maintainers = [ lib.maintainers.yarny ]; + # list printer manufacturers here so people + # searching for ppd files can find this package + longDescription = '' + The collected knowledge about printers, + drivers, and driver options in XML files, + used by `foomatic-db-engine` to generate PPD files. + This is a package of PPD and Foomatic XML files + that may have restrictions that keep them + from being used on a variety of machines + for licensing and other non-technical reasons. + The XML files in this package enable `foomatic-db-ppds` + to create about 120 additional PPD files, for printer from + Dell, Genicom, Lexmark, Oce, Tektronix and Xerox. + Besides the XML files, this package contains + about 130 PPD files, for printers from + Dell, Genicom, Lexmark, Oce and Xerox. + ''; + }; +} diff --git a/pkgs/misc/cups/drivers/foomatic-db-ppds/default.nix b/pkgs/misc/cups/drivers/foomatic-db-ppds/default.nix new file mode 100644 index 000000000000..bdc1e0a9b5fe --- /dev/null +++ b/pkgs/misc/cups/drivers/foomatic-db-ppds/default.nix @@ -0,0 +1,122 @@ +{ lib +, foomatic-db +, foomatic-db-nonfree +, buildEnv +, foomatic-db-engine +, stdenv +, cups-filters +, ghostscript +, netpbm +, perl +, psutils +, patchPpdFilesHook +, withNonfreeDb ? false # include foomatic-db-nonfree ppd files +}: + +let + foomatic-db-packages = [ foomatic-db ] ++ + lib.lists.optional withNonfreeDb foomatic-db-nonfree; + + foomatic-db-combined = buildEnv { + name = "foomatic-db-combined"; + paths = foomatic-db-packages; + pathsToLink = [ "/share/foomatic" ]; + # `foomatic-db-combined` is a nativeBuildInput of `foomatic-db-ppds`. + # The setup hook defined here helps scripts in + # `foomatic-db-engine` to find the database. + postBuild = '' + mkdir -p "${placeholder "out"}"/{etc/cups,nix-support} + cat >> "${placeholder "out"}/nix-support/setup-hook" << eof + export FOOMATICDB="${placeholder "out"}/share/foomatic" + eof + ''; + }; + + # the effective license is `free` if all database + # packages have free licenses, `unfree` otherwise + isFree = lib.trivial.pipe foomatic-db-packages [ + (lib.lists.map (lib.attrsets.attrByPath [ "meta" "license" ] lib.licenses.unfree)) + (lib.lists.all (lib.attrsets.attrByPath [ "free" ] true)) + ]; +in + +stdenv.mkDerivation { + pname = "foomatic-db-ppds"; + # the effective version is simply the + # highest version of all database packages + version = lib.trivial.pipe foomatic-db-packages [ + (lib.lists.map (lib.attrsets.getAttr "version")) + (lib.lists.sort lib.strings.versionOlder) + lib.lists.reverseList + lib.lists.head + ]; + + buildInputs = [ + cups-filters + ghostscript + netpbm + perl + psutils + ]; + + nativeBuildInputs = [ + foomatic-db-combined + foomatic-db-engine + patchPpdFilesHook + ]; + + dontUnpack = true; + + installPhase = '' + runHook preInstall + mkdir -p "${placeholder "out"}/share/cups/model" + foomatic-compiledb -j "$NIX_BUILD_CORES" -d "${placeholder "out"}/share/cups/model/foomatic-db-ppds" + runHook postInstall + ''; + + # Comments indicate the respective + # package the command is contained in. + ppdFileCommands = [ + "cat" "echo" # coreutils + "foomatic-rip" # cups-filters or foomatic-filters + "gs" # ghostscript + "pnmflip" "pnmgamma" "pnmnoraw" # netpbm + "perl" # perl + "psresize" # psutils + # These commands aren't packaged yet. + # ppd files using these likely won't work. + #"c2050" "c2070" "cjet" "lm1100" + #"pbm2l2030" "pbm2lwxl" "rastertophaser6100" + ]; + + # compress ppd files + postFixup = '' + echo 'compressing ppd files' + find -H "${placeholder "out"}/share/cups/model/foomatic-db-ppds" -type f -iname '*.ppd' -print0 \ + | xargs -0r -n 64 -P "$NIX_BUILD_CORES" gzip -9n + ''; + + meta = { + description = "OpenPrinting ppd files"; + homepage = "https://openprinting.github.io/projects/02-foomatic/"; + license = if isFree then lib.licenses.free else lib.licenses.unfree; + maintainers = [ lib.maintainers.yarny ]; + # list printer manufacturers here so people + # searching for ppd files can find this package + longDescription = '' + All PPD files available in + OpenPrinting's Foomatic database. + This package contains about 8,800 PPD files, + for printers from + Alps, Anitech, Apollo, Apple, Avery, Brother, Canon, + Citizen, CItoh, Compaq, DEC, Dell, Dymo-CoStar, Epson, + Fujitsu, FujiXerox, Generic, Genicom, Gestetner, + Heidelberg, Hitachi, HP, IBM, Imagen, Imagistics, + InfoPrint, Infotec, Kodak, KONICAMINOLTA, Kyocera, Lanier, + Lexmark, Minolta, MinoltaQMS, Mitsubishi, NEC, NRG, Oce, + Oki, Olivetti, Panasonic, PCPI, Pentax, QMS, Raven, Ricoh, + Samsung, Savin, Seiko, Sharp, SiPix, Sony, Star, Tally, + Tektronix, TexasInstruments, Toshiba, Xante and Xerox. + ''; + }; +} diff --git a/pkgs/misc/cups/drivers/foomatic-db/default.nix b/pkgs/misc/cups/drivers/foomatic-db/default.nix new file mode 100644 index 000000000000..dd76fb1ee05b --- /dev/null +++ b/pkgs/misc/cups/drivers/foomatic-db/default.nix @@ -0,0 +1,102 @@ +{ lib +, stdenv +, fetchFromGitHub +, cups +, cups-filters +, ghostscript +, gnused +, perl +, autoconf +, automake +, patchPpdFilesHook +}: + +stdenv.mkDerivation { + pname = "foomatic-db"; + version = "unstable-2022-10-03"; + + src = fetchFromGitHub { + # there is also a daily snapshot at the `downloadPage`, + # but it gets deleted quickly and would provoke 404 errors + owner = "OpenPrinting"; + repo = "foomatic-db"; + rev = "2a3c4d1bf7eadc42f936ce8989c1dd2973ea9669"; + hash = "sha256-in0/j1nAQvM0NowBIBx3jj5WVMPIfZAeAk1SkuA3tjA="; + }; + + buildInputs = [ cups cups-filters ghostscript gnused perl ]; + + nativeBuildInputs = [ autoconf automake patchPpdFilesHook perl ]; + + # sed-substitute indirection is more robust + # against characters in paths that might need escaping + postPatch = '' + sed -Ei -e 's|^(S?BINSEARCHPATH=).+$|\1"@PATH@"|g' \ + -e 's|^(DATASEARCHPATH=).+$|\1"@DATA@"|g' configure.ac + substituteInPlace configure.ac \ + --subst-var PATH \ + --subst-var-by DATA "${placeholder "out"}/share" + ''; + + preConfigure = '' + mkdir -p "${placeholder "out"}/share/foomatic/db/source" + ./make_configure + ''; + + # don't let the intaller gzip ppd files as we would + # have to unzip them later in order to patch them + configureFlags = [ "--disable-gzip-ppds" ]; + + # make ppd files available to cups, + # use a package-specific subdirectory to avoid + # conflicts with other ppd-containing packages + postInstall = '' + if ! [[ -d "${placeholder "out"}/share/foomatic/db/source/PPD" ]]; then + echo "failed to create share/foomatic/db/source/PPD" + exit 1 + fi + mkdir -p "${placeholder "out"}/share/cups/model" + ln -s "${placeholder "out"}/share/foomatic/db/source/PPD" \ + "${placeholder "out"}/share/cups/model/foomatic-db" + ''; + + # Comments indicate the respective + # package the command is contained in. + ppdFileCommands = [ + "cat" "date" "printf" # coreutils + "rastertohp" # cups + "foomatic-rip" # cups-filters or foomatic-filters + "gs" # ghostscript + "sed" # gnused + "perl" # perl + ]; + + # compress ppd files + postFixup = '' + echo 'compressing ppd files' + find -H "${placeholder "out"}/share/cups/model/foomatic-db" -type f -iname '*.ppd' -print0 \ + | xargs -0r -n 64 -P "$NIX_BUILD_CORES" gzip -9n + ''; + + meta = { + description = "OpenPrinting printer support database (free content)"; + downloadPage = "https://www.openprinting.org/download/foomatic/"; + homepage = "https://openprinting.github.io/projects/02-foomatic/"; + license = lib.licenses.free; # mostly GPL and MIT, see README in source dir + maintainers = [ lib.maintainers.yarny ]; + # list printer manufacturers here so people + # searching for ppd files can find this package + longDescription = '' + The collected knowledge about printers, + drivers, and driver options in XML files, + used by `foomatic-db-engine` to generate PPD files. + PPD files generated from the XML files in this package + are contained in the package 'foomatic-db-ppds'. + Besides the XML files, this package contains + about 6,600 PPD files, for printers from + Brother, Canon, Epson, Gestetner, HP, InfoPrint, + Infotec, KONICA_MINOLTA, Kyocera, Lanier, Lexmark, NRG, + Oce, Oki, Ricoh, Samsung, Savin, Sharp, Toshiba and Utax. + ''; + }; +} diff --git a/pkgs/misc/cups/drivers/kyocera/default.nix b/pkgs/misc/cups/drivers/kyocera/default.nix index 28b2a1281761..0a560e3188f6 100644 --- a/pkgs/misc/cups/drivers/kyocera/default.nix +++ b/pkgs/misc/cups/drivers/kyocera/default.nix @@ -1,4 +1,9 @@ -{ stdenv, lib, fetchzip, cups }: +{ lib +, stdenv +, cups +, fetchzip +, patchPpdFilesHook +}: let platform = @@ -23,7 +28,11 @@ stdenv.mkDerivation { sha256 = "0z1pbgidkibv4j21z0ys8cq1lafc6687syqa07qij2qd8zp15wiz"; }; + nativeBuildInputs = [ patchPpdFilesHook ]; + installPhase = '' + runHook preInstall + tar -xvf ${platform}/Global/English.tar.gz install -Dm755 English/rastertokpsl $out/lib/cups/filter/rastertokpsl patchelf \ @@ -33,13 +42,13 @@ stdenv.mkDerivation { mkdir -p $out/share/cups/model/Kyocera cd English - for i in *.ppd; do - sed -i $i -e \ - "s,/usr/lib/cups/filter/rastertokpsl,$out/lib/cups/filter/rastertokpsl,g" - cp $i $out/share/cups/model/Kyocera - done; + cp *.ppd $out/share/cups/model/Kyocera + + runHook postInstall ''; + ppdFileCommands = [ "rastertokpsl" ]; + meta = with lib; { description = "CUPS drivers for several Kyocera FS-{1020,1025,1040,1060,1120,1125} printers"; homepage = "https://www.kyoceradocumentsolutions.ru/index/service_support/download_center.false.driver.FS1040._.EN.html#"; diff --git a/pkgs/misc/cups/drivers/samsung/1.00.36/default.nix b/pkgs/misc/cups/drivers/samsung/1.00.36/default.nix index fac3dfccba62..47700265231f 100644 --- a/pkgs/misc/cups/drivers/samsung/1.00.36/default.nix +++ b/pkgs/misc/cups/drivers/samsung/1.00.36/default.nix @@ -23,6 +23,7 @@ in stdenv.mkDerivation rec { ]; installPhase = '' + runHook preInstall mkdir -p $out/bin cp -R ${arch}/{gettext,pstosecps,rastertospl,smfpnetdiscovery,usbresetter} $out/bin @@ -82,6 +83,8 @@ in stdenv.mkDerivation rec { cd $out/share/cups ln -s ../ppd . ln -s ppd model + + runHook postInstall ''; preFixup = '' diff --git a/pkgs/misc/cups/drivers/samsung/1.00.37.nix b/pkgs/misc/cups/drivers/samsung/1.00.37.nix index 0aab52eac5da..59a210e6f534 100644 --- a/pkgs/misc/cups/drivers/samsung/1.00.37.nix +++ b/pkgs/misc/cups/drivers/samsung/1.00.37.nix @@ -22,6 +22,7 @@ in stdenv.mkDerivation rec { ]; installPhase = '' + runHook preInstall mkdir -p $out/bin cp -R ${arch}/{gettext,pstosecps,rastertospl,smfpnetdiscovery,usbresetter} $out/bin @@ -65,6 +66,8 @@ in stdenv.mkDerivation rec { cd $out/share/cups ln -s ../ppd . ln -s ppd model + + runHook postInstall ''; preFixup = '' diff --git a/pkgs/misc/cups/drivers/samsung/4.01.17.nix b/pkgs/misc/cups/drivers/samsung/4.01.17.nix index 12cfcde82f76..334703017478 100644 --- a/pkgs/misc/cups/drivers/samsung/4.01.17.nix +++ b/pkgs/misc/cups/drivers/samsung/4.01.17.nix @@ -11,7 +11,13 @@ # } # (This advice was tested on the 1st November 2016.) -{ lib, stdenv, fetchurl, cups, libusb-compat-0_1 }: +{ lib +, stdenv +, cups +, libusb-compat-0_1 +, fetchurl +, patchPpdFilesHook +}: # Do not bump lightly! Visit # to see what will break when upgrading. Consider a new versioned attribute. @@ -28,10 +34,14 @@ in stdenv.mkDerivation rec { sha256 = "1vv3pzvqpg1dq3xjr8161x2yp3v7ca75vil56ranhw5pkjwq66x0"; }; + nativeBuildInputs = [ patchPpdFilesHook ]; + dontPatchELF = true; dontStrip = true; installPhase = '' + runHook preInstall + cd Linux/${installationPath} mkdir -p $out/lib/cups/{backend,filter} install -Dm755 mfp $out/lib/cups/backend/ @@ -63,15 +73,18 @@ in stdenv.mkDerivation rec { mkdir -p $out/share/cups/model/samsung cd - cd ../noarch/at_opt/share/ppd - for i in *.ppd; do - sed -i $i -e \ - "s,pstosecps,$out/lib/cups/filter/pstosecps,g; \ - s,pstospl,$out/lib/cups/filter/pstospl,g; \ - s,rastertospl,$out/lib/cups/filter/rastertospl,g" - done; cp -r ./* $out/share/cups/model/samsung + + runHook postInstall ''; + ppdFileCommands = [ + "pstosecps" + "pstospl" + "pstosplc" + "rastertospl" + ]; + meta = with lib; { description = "Samsung's Linux printing drivers; includes binaries without source code"; homepage = "http://www.samsung.com/"; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 9708553e8e71..1965a7216afa 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -1076,6 +1076,8 @@ with pkgs; { name = "validate-pkg-config"; deps = [ findutils pkg-config ]; } ../build-support/setup-hooks/validate-pkg-config.sh; + patchPpdFilesHook = callPackage ../build-support/setup-hooks/patch-ppd-files {}; + #package writers writers = callPackage ../build-support/writers {}; @@ -36360,6 +36362,12 @@ with pkgs; epson-workforce-635-nx625-series = callPackage ../misc/drivers/epson-workforce-635-nx625-series { }; + foomatic-db = callPackage ../misc/cups/drivers/foomatic-db {}; + foomatic-db-engine = callPackage ../misc/cups/drivers/foomatic-db-engine {}; + foomatic-db-nonfree = callPackage ../misc/cups/drivers/foomatic-db-nonfree {}; + foomatic-db-ppds = callPackage ../misc/cups/drivers/foomatic-db-ppds {}; + foomatic-db-ppds-withNonfreeDb = callPackage ../misc/cups/drivers/foomatic-db-ppds { withNonfreeDb = true; }; + gutenprint = callPackage ../misc/drivers/gutenprint { }; gutenprintBin = callPackage ../misc/drivers/gutenprint/bin.nix { };