-
-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the replace-dependency build support function.
The use case is to do a deep replacement of a dependency without rebuilding the entire tree. For example, suppose a security hole is found in glibc and a patch released. Ideally, you'd just rebuild everything, but that takes time, space, and CPU that you might not have, so in the mean time you could build a safe version of, say, firefox with: firefox-safe = replace-dependency { drv = firefox; old-dependency = glibc; new-dependency = patched-glibc; }; Building firefox-safe will rebuild glibc, but only do a simple copy/string replacement on all other dependencies of firefox. On my system (MBP 13" mid-2012), after a new glibc had been build building firefox took around 11 seconds. See the comments in the file for more details.
- Loading branch information
Showing
2 changed files
with
84 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
{ 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: safe-firefox = replace-dependency { | ||
# drv = firefox; | ||
# old-dependency = glibc; | ||
# new-dependency = 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, old-dependency, new-dependency }: | ||
|
||
with lib; | ||
|
||
let | ||
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; | ||
|
||
old-storepath = builtins.storePath (discard old-dependency.outPath); | ||
|
||
references-of = drv: getAttr (discard (toString drv)) references; | ||
|
||
depends-on-old = drv: elem old-storepath (references-of drv) || | ||
any depends-on-old (references-of drv); | ||
|
||
drv-name = drv: | ||
discard (substring 33 (stringLength (builtins.baseNameOf drv)) (builtins.baseNameOf drv)); | ||
|
||
replace-strings = drv: rewritten-drvs: runCommand (drv-name drv) { nixStore = "${nix}/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'" | ||
) rewritten-drvs) | ||
} | $nixStore --restore $out | ||
''; | ||
|
||
fn = { drv, rewritten-drvs }: rewritten-drvs // ( | ||
if depends-on-old drv | ||
then listToAttrs [ { | ||
name = discard (toString drv); | ||
|
||
value = replace-strings drv (rewritten-drvs // (fold (drv: acc: | ||
(fn { inherit drv rewritten-drvs; }) // acc | ||
) {} (references-of drv))); | ||
} ] | ||
else {} | ||
); | ||
in assert (stringLength old-dependency.name == stringLength new-dependency.name); getAttr (discard drv.outPath) (fn { | ||
inherit drv; | ||
rewritten-drvs = listToAttrs [ {name = discard old-dependency.outPath; value = new-dependency;} ]; | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters