Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at python-updates 183 lines 7.6 kB view raw
1fixupOutputHooks+=(_patchPpdFileCommands4fixupOutputHooks) 2 3 4 5# Install a hook for the `fixupPhase`: 6# If the variable `ppdFileCommands` contains a list of 7# executable names, the hook calls `patchPpdFileCommands` 8# on each output's `/share/cups/model` and `/share/ppds` 9# directories in order to replace calls to those executables. 10 11_patchPpdFileCommands4fixupOutputHooks () { 12 [[ -n $ppdFileCommands ]] || return 0 13 if [[ -d $prefix/share/cups/model ]]; then 14 patchPpdFileCommands "$prefix/share/cups/model" $ppdFileCommands 15 fi 16 if [[ -d $prefix/share/ppds ]]; then 17 patchPpdFileCommands "$prefix/share/ppds" $ppdFileCommands 18 fi 19} 20 21 22 23# patchPpdFileCommands PPD-ROOT PROGNAME... 24# 25# Look for ppd files in the directory PPD-ROOT. 26# Descend into subdirectories, even if they are symlinks. 27# However, ignore ppd files that don't belong to the same 28# prefix ($NIX_STORE/$package_name) as PPD-ROOT-DIR does, 29# to avoid stepping into other package's directories. 30# ppd files may be gzipped; if the are, 31# uncompress them, later recompress them. 32# Skip symlinks to ppd files. 33# PPD-ROOT may also be a single ppd file. 34# 35# Look for the PROGNAME executable in outputs and `buildInputs`, 36# then look for PROGNAME invocations in the ppd files, 37# without path or with common paths like `/usr/bin/$PROGNAME`. 38# Replace those invocations with an absolute path to the 39# corresponding executable from the outputs or `buildInputs`. 40# Executables are searched where CUPS would search them, 41# i.e., in `/bin` and `/lib/cups/filter`. 42# 43# As soon as an executable's path is replaced as 44# described above, the package containing the binary 45# is added to the list of propagated build inputs. 46# This ensures the executable's package is still 47# recognized as runtime dependency of the ppd file 48# even if the ppd file is compressed lateron. 49# 50# PROGNAME may not contain spaces or tabs. 51# The function will also likely fail or produce 52# broken results if PROGNAME contains characters that 53# require shell or regex escaping (e.g. a backslash). 54 55patchPpdFileCommands () { 56 57 local bin binnew binold binoldgrep cupspath path ppdroot ppdrootprefix 58 59 # we will store some temporary data here 60 pushd "$(mktemp -d --tmpdir patch-ppd-file-commands.XXXX)" 61 62 # remember the ppd root path 63 [[ "$1" == $NIX_STORE/* ]] # ensure it's a store directory 64 ppdroot=$1 65 shift # now "$@" is the list of binaries 66 ppdrootprefix=${ppdroot%"/${ppdroot#"$NIX_STORE"/*/}"} 67 68 # create `cupspath` (where we should look for binaries), 69 # with these priorities 70 # * outputs of current build before buildInputs 71 # * `/lib/cups/filter' before `/bin` 72 # * add HOST_PATH at end, so we don't miss anything 73 for path in $(getAllOutputNames); do 74 addToSearchPath cupspath "${!path}/lib/cups/filter" 75 addToSearchPath cupspath "${!path}/bin" 76 done 77 for path in ${pkgsHostTarget+"${pkgsHostTarget[@]}"}; do 78 addToSearchPath cupspath "$path/lib/cups/filter" 79 addToSearchPath cupspath "$path/bin" 80 done 81 while read -r -d : path; do 82 addToSearchPath cupspath "$path" 83 done <<< "${HOST_PATH:+"${HOST_PATH}:"}" 84 85 # create list of compressed ppd files 86 # so we can recompress them later 87 find -L "$ppdroot" -type f -iname '*.ppd.gz' '!' -xtype l -print0 > gzipped 88 89 # decompress gzipped ppd files 90 echo "patchPpdFileCommands: decompressing $(grep -cz '^' < gzipped) gzipped ppd file(s) in $ppdroot" 91 xargs -0r -n 64 -P "$NIX_BUILD_CORES" gunzip < gzipped 92 93 # create list of all ppd files to be checked 94 find -L "$ppdroot" -type f -iname '*.ppd' '!' -xtype l -print0 > ppds 95 96 for bin in "$@"; do 97 98 # discover new path 99 binnew=$(PATH=$cupspath '@which@/bin/which' "$bin") 100 echo "patchPpdFileCommands: located binary $binnew" 101 102 # for each binary, we look for the name itself, but 103 # also for a couple of common paths that might be used 104 for binold in {/usr,}/{lib/cups/filter,sbin,bin}/"$bin" "$bin"; do 105 106 # escape regex characters in the old command string 107 binoldgrep=$(sed 's,[]$.*[\^],\\&,g' <<< "$binold") 108 # ...and surround old command with some regex 109 # that singles out shell command invocations 110 # to avoid replacing other strings that might contain the 111 # command name by accident (like "perl" in "perl-script") 112 binoldgrep='\(^\|[;&| '$'\t''"`(]\)'"$binoldgrep"'\($\|[);&| '$'\t''"`<>]\)' 113 # this string is used to *quickly* filter out 114 # unaffected files before the (slower) awk script runs; 115 # note that a similar regex is build in the awk script; 116 # if `binoldgrep` is changed, the awk script should also be checked 117 118 # create list of likely affected files 119 # (might yield exit status != 0 if there are no matches) 120 xargs -0r grep -lZ "$binoldgrep" < ppds > ppds-to-patch || true 121 122 echo "patchPpdFileCommands: $(grep -cz '^' < ppds-to-patch) ppd file(s) contain $binold" 123 124 # actually patch affected ppd files with awk; 125 # this takes some time but can be parallelized; 126 # speed up with LC_ALL=C, https://stackoverflow.com/a/33850386 127 LC_ALL=C xargs -0r -n 64 -P "$NIX_BUILD_CORES" \ 128 awk -i inplace -v old="${binold//\\/\\\\}" -v new="${binnew//\\/\\\\}" -f "@awkscript@" \ 129 < ppds-to-patch 130 131 done 132 133 # create list of affected files 134 xargs -0r grep -lZF "$binnew" < ppds > patched-ppds || true 135 136 echo "patchPpdFileCommands: $(grep -cz '^' < patched-ppds) ppd file(s) patched with $binnew" 137 138 # if the new command is contained in a file, 139 # remember the new path so we can add it to 140 # the list of propagated dependencies later 141 if [[ -s patched-ppds ]]; then 142 printf '%s\0' "${binnew%"/${binnew#"${NIX_STORE}"/*/}"}" >> dependencies 143 fi 144 145 done 146 147 # recompress ppd files that have been decompressed before 148 echo "patchPpdFileCommands: recompressing $(grep -cz '^' < gzipped) gzipped ppd file(s)" 149 # we can't just hand over the paths of the uncompressed files 150 # to gzip as it would add the lower-cased extension ".gz" 151 # even for files where the original was named ".GZ" 152 xargs -0r -n 1 -P "$NIX_BUILD_CORES" \ 153 "$SHELL" -c 'gzip -9nS ".${0##*.}" "${0%.*}"' \ 154 < gzipped 155 156 # enlist dependencies for propagation; 157 # this is needed in case ppd files are compressed later 158 # (Nix won't find dependency paths in compressed files) 159 if [[ -s dependencies ]]; then 160 161 # weed out duplicates from the dependency list first 162 sort -zu dependencies > sorted-dependencies 163 164 mkdir -p "$ppdrootprefix/nix-support" 165 while IFS= read -r -d '' path; do 166 printWords "$path" >> "$ppdrootprefix/nix-support/propagated-build-inputs" 167 # stdenv writes it's own `propagated-build-inputs`, 168 # based on the variable `propagatedBuildInputs`, 169 # but only to one output (`outputDev`). 170 # So we also add our dependencies to that variable. 171 # If our file survives as written above, great! 172 # If stdenv overwrits it, 173 # our dependencies will still be added to the file. 174 # The end result might contain too many 175 # propagated dependencies for multi-output packages, 176 # but never a broken package. 177 appendToVar propagatedBuildInputs "$path" 178 done < sorted-dependencies 179 fi 180 181 popd 182 183}