The string context is the references in a string to derivations. For example, a derivation out path refers to the derivation, and thus any string that interpolates this out path refers to this derivation, too. This is useful because Nix uses it to track derivation dependencies. However, it can sometimes be annoying because functions like builtins.fromJSON does not accept a string with a context:
let
drv = fetchTarball "https://github.com/Lxtharia/minegrub-theme/tarball/main";
str = "\"${drv}\"";
in builtins.fromJSON str
Error
error:
… while calling the 'fromJSON' builtin
at «string»:4:4:
3| str = "\"${drv}\"";
4| in builtins.fromJSON str
| ^
… while evaluating the first argument passed to builtins.fromJSON
error: the string '"/nix/store/ypk21myg6psifx2nn58wn446x0bqa4ng-source"' is not allowed to refer to a store path (such as 'ypk21myg6psifx2nn58wn446x0bqa4ng-source')
In order to do this, one has to convert str to a string that has the same content but does not refer to drv. In other words, we need to clear its context or—by what I would like to call it—“purify” the string. Probably unexpectedly, there is indeed a way to purify a string in Nix!
This PR made it so that builtins.readFile somePath does not refer to drv even if somePath refers to drv, as long as it does not explicitly include the store path of drv. Therefore, builtins.readFile has the capability of purifying a path. We can then devise this way to purify the string str:
- Slice
strinto substrings, each of which does not contain the out path ofdrv. Because the hash part of the store path is 32-character long, making each substring shorter than that is safe enough. - For each substring
s, it still refers todrv, but we can get a purified version bybuiltins.readFile (builtins.toFile "_" s). - Concatenate all the purified substrings to get the purified
str.
let
purify = let maxLength = 31; in str:
let length = builtins.stringLength str; in
if length <= maxLength then
builtins.readFile (builtins.toFile "_" str)
else
"${purify (builtins.substring 0 maxLength str)}${purify (builtins.substring maxLength (length - maxLength) str)}";
drv = fetchTarball "https://github.com/Lxtharia/minegrub-theme/tarball/main";
str = purify "\"${drv}\"";
in builtins.fromJSON str
This gives the result without an error.