diff options
author | Alyssa Ross <hi@alyssa.is> | 2019-01-07 02:18:36 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2019-01-07 02:18:47 +0000 |
commit | 36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2 (patch) | |
tree | b3faaf573407b32aa645237a4d16b82778a39a92 /nixpkgs/pkgs/build-support/replace-dependency.nix | |
parent | 4e31070265257dc67d120c27e0f75c2344fdfa9a (diff) | |
parent | abf060725d7614bd3b9f96764262dfbc2f9c2199 (diff) | |
download | nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.gz nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.bz2 nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.lz nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.xz nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.zst nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.zip |
Add 'nixpkgs/' from commit 'abf060725d7614bd3b9f96764262dfbc2f9c2199'
git-subtree-dir: nixpkgs git-subtree-mainline: 4e31070265257dc67d120c27e0f75c2344fdfa9a git-subtree-split: abf060725d7614bd3b9f96764262dfbc2f9c2199
Diffstat (limited to 'nixpkgs/pkgs/build-support/replace-dependency.nix')
-rw-r--r-- | nixpkgs/pkgs/build-support/replace-dependency.nix | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/build-support/replace-dependency.nix b/nixpkgs/pkgs/build-support/replace-dependency.nix new file mode 100644 index 000000000000..15ab50bf3974 --- /dev/null +++ b/nixpkgs/pkgs/build-support/replace-dependency.nix @@ -0,0 +1,83 @@ +{ runCommand, nix, lib }: + +# Replace a single dependency in the requisites tree of drv, propagating +# the change all the way up the tree, without a full rebuild. This can be +# useful, for example, to patch a security hole in libc and still use your +# system safely without rebuilding the world. This should be a short term +# solution, as soon as a rebuild can be done the properly rebuild derivation +# should be used. The old dependency and new dependency MUST have the same-length +# name, and ideally should have close-to-identical directory layout. +# +# Example: safeFirefox = replaceDependency { +# drv = firefox; +# oldDependency = glibc; +# newDependency = overrideDerivation glibc (attrs: { +# patches = attrs.patches ++ [ ./fix-glibc-hole.patch ]; +# }); +# }; +# This will rebuild glibc with your security patch, then copy over firefox +# (and all of its dependencies) without rebuilding further. +{ drv, oldDependency, newDependency, verbose ? true }: + +with lib; + +let + warn = if verbose then builtins.trace else (x: y: y); + references = import (runCommand "references.nix" { exportReferencesGraph = [ "graph" drv ]; } '' + (echo { + while read path + do + echo " \"$path\" = [" + read count + read count + while [ "0" != "$count" ] + do + read ref_path + if [ "$ref_path" != "$path" ] + then + echo " (builtins.storePath $ref_path)" + fi + count=$(($count - 1)) + done + echo " ];" + done < graph + echo }) > $out + '').outPath; + + discard = builtins.unsafeDiscardStringContext; + + oldStorepath = builtins.storePath (discard (toString oldDependency)); + + referencesOf = drv: references.${discard (toString drv)}; + + dependsOnOldMemo = listToAttrs (map + (drv: { name = discard (toString drv); + value = elem oldStorepath (referencesOf drv) || + any dependsOnOld (referencesOf drv); + }) (builtins.attrNames references)); + + dependsOnOld = drv: dependsOnOldMemo.${discard (toString drv)}; + + drvName = drv: + discard (substring 33 (stringLength (builtins.baseNameOf drv)) (builtins.baseNameOf drv)); + + rewriteHashes = drv: hashes: runCommand (drvName drv) { nixStore = "${nix.out}/bin/nix-store"; } '' + $nixStore --dump ${drv} | sed 's|${baseNameOf drv}|'$(basename $out)'|g' | sed -e ${ + concatStringsSep " -e " (mapAttrsToList (name: value: + "'s|${baseNameOf name}|${baseNameOf value}|g'" + ) hashes) + } | $nixStore --restore $out + ''; + + rewrittenDeps = listToAttrs [ {name = discard (toString oldDependency); value = newDependency;} ]; + + rewriteMemo = listToAttrs (map + (drv: { name = discard (toString drv); + value = rewriteHashes (builtins.storePath drv) + (filterAttrs (n: v: builtins.elem (builtins.storePath (discard (toString n))) (referencesOf drv)) rewriteMemo); + }) + (filter dependsOnOld (builtins.attrNames references))) // rewrittenDeps; + + drvHash = discard (toString drv); +in assert (stringLength (drvName (toString oldDependency)) == stringLength (drvName (toString newDependency))); +rewriteMemo.${drvHash} or (warn "replace-dependency.nix: Derivation ${drvHash} does not depend on ${discard (toString oldDependency)}" drv) |