Something went wrong. Try again.
What happens if I push all of nixpkgs
Something went wrong. Try again.
6.7 kB · 193 lines
Nix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194{ lib, runCommandLocal, replaceDirectDependencies,}:
# Replace some dependencies in the requisites tree of drv, propagating the change all the way up the tree, even within other replacements, 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 rebuilt derivation should be used.# Each old dependency and the corresponding new dependency MUST have the same-length name, and ideally should have close-to-identical directory layout.## Example: safeFirefox = replaceDependencies {# drv = firefox;# replacements = [# {# oldDependency = glibc;# newDependency = glibc.overrideAttrs (oldAttrs: {# patches = oldAttrs.patches ++ [ ./fix-glibc-hole.patch ];# });# }# {# oldDependency = libwebp;# newDependency = libwebp.overrideAttrs (oldAttrs: {# patches = oldAttrs.patches ++ [ ./fix-libwebp-hole.patch ];# });# }# ];# };# This will first rebuild glibc and libwebp with your security patches.# Then it copies over firefox (and all of its dependencies) without rebuilding further.# In particular, the glibc dependency of libwebp will be replaced by the patched version as well.## In rare cases, it is possible for the replacement process to cause breakage (for example due to checksum mismatch).# The cutoffPackages argument can be used to exempt the problematic packages from the replacement process.{ drv, replacements, cutoffPackages ? [ ], verbose ? true,}:
let inherit (builtins) unsafeDiscardStringContext appendContext; inherit (lib) listToAttrs isStorePath readFile attrValues mapAttrs filter hasAttr mapAttrsToList ; inherit (lib.attrsets) mergeAttrsList;
toContextlessString = x: unsafeDiscardStringContext (toString x); warn = if verbose then lib.warn else (x: y: y);
referencesOf = drv: import (runCommandLocal "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 " \"$ref_path\"" fi count=$(($count - 1)) done echo " ];" done < graph echo }) > $out '' ).outPath;
realisation = drv: if isStorePath drv then # Input-addressed and fixed-output derivations have their realisation as outPath. toContextlessString drv else # Floating and deferred derivations have a placeholder outPath. # The realisation can only be obtained by performing an actual build. unsafeDiscardStringContext ( readFile ( runCommandLocal "realisation" { env = { inherit drv; }; } '' echo -n "$drv" > $out '' ) ); rootReferences = referencesOf drv; relevantReplacements = filter ( { oldDependency, newDependency }: if toString oldDependency == toString newDependency then warn "replaceDependencies: attempting to replace dependency ${oldDependency} of ${drv} with itself" # Attempting to replace a dependency by itself is completely useless, and would only lead to infinite recursion. # Hence it must not be attempted to apply this replacement in any case. false else if !hasAttr (realisation oldDependency) rootReferences then warn "replaceDependencies: ${drv} does not depend on ${oldDependency}, so it will not be replaced" # Strictly speaking, another replacement could introduce the dependency. # However, handling this corner case would add significant complexity. # So we just leave it to the user to apply the replacement at the correct place, but show a warning to let them know. false else true ) replacements; targetDerivations = [ drv ] ++ map ({ newDependency, ... }: newDependency) relevantReplacements; referencesMemo = listToAttrs ( map (drv: { name = realisation drv; value = referencesOf drv; }) targetDerivations ); relevantReferences = mergeAttrsList (attrValues referencesMemo); # Make sure a derivation is returned even when no replacements are actually applied. # Yes, even in the stupid edge case where the root derivation itself is replaced. storePathOrKnownTargetDerivationMemo = mapAttrs ( drv: _references: # builtins.storePath does not work in pure evaluation mode, even though it is not impure. # This reimplementation in Nix works as long as the path is already allowed in the evaluation state. # This is always the case here, because all paths come from the closure of the original derivation. appendContext drv { ${drv}.path = true; } ) relevantReferences // listToAttrs ( map (drv: { name = realisation drv; value = drv; }) targetDerivations );
rewriteMemo = # Mind the order of how the three attrsets are merged here. # The order of precedence needs to be "explicitly specified replacements" > "rewrite exclusion (cutoffPackages)" > "rewrite". # So the attrset merge order is the opposite. mapAttrs ( drv: references: let rewrittenReferences = filter (dep: dep != drv && toString rewriteMemo.${dep} != dep) references; rewrites = listToAttrs ( map (reference: { name = reference; value = rewriteMemo.${reference}; }) rewrittenReferences ); in replaceDirectDependencies { drv = storePathOrKnownTargetDerivationMemo.${drv}; replacements = mapAttrsToList (name: value: { oldDependency = name; newDependency = value; }) rewrites; } ) relevantReferences // listToAttrs ( map (drv: { name = realisation drv; value = storePathOrKnownTargetDerivationMemo.${realisation drv}; }) cutoffPackages ) // listToAttrs ( map ( { oldDependency, newDependency }: { name = realisation oldDependency; value = rewriteMemo.${realisation newDependency}; } ) relevantReplacements );inrewriteMemo.${realisation drv}