nix-helpers: d72bd0197ba449cab21bfe63c7dc4e3adb48a8d2

     1: # Adding files to the Nix store in a general way turns out to be quite tricky.
     2: # In particular:
     3: #  - Filenames with certain characters (e.g. " " or "'") will cause an error
     4: #    if we try adding them as-is. We can work around this using builtins.path.
     5: #  - Paths which reference things in the Nix store can cause errors when used
     6: #    with functions like builtins.path.
     7: #  - We can use builtins.unsafeDiscardStringContext to avoid errors, but we
     8: #    must ensure that the context is added back in so that dependencies are
     9: #    are built when needed and not garbage collected from under us.
    10: { asPath, hello, lib, runCommand, sanitiseName, writeScript }:
    11: 
    12: with builtins;
    13: with lib;
    14: p:
    15: with rec {
    16:   strP = unsafeDiscardStringContext (toString p);
    17: 
    18:   # Checks whether a path is from the Nix store, since Nix will abort if
    19:   # store paths are referenced in certain ways.
    20:   isStore = x: hasPrefix storeDir (toString x);
    21: 
    22:   # Chops suffices off a store path until it's a top-level entry, e.g.
    23:   #   getRoot "/nix/store/...-foo/bar/baz" -> "/nix/store/...-foo"
    24:   # This way we're guaranteed to avoid filename characters which aren't
    25:   # valid store paths.
    26:   getRoot = x:
    27:     if toString (dirOf x) == toString storeDir then x else getRoot (dirOf x);
    28: 
    29:   # Complements getRoot:
    30:   #   p = "/nix/store/...-foo/bar/baz" -> trunk = "bar/baz"
    31:   trunk = removePrefix "/" (removePrefix (getRoot strP) strP);
    32: 
    33:   # Avoids characters which are incompatible with store paths
    34:   safeName = sanitiseName (baseNameOf strP);
    35: 
    36:   # For store paths, we make a symlink which depends on p's context. By
    37:   # using the root we avoid incompatible characters, without using
    38:   # builtins.path (which Nix complains about if we give it a store path).
    39:   symlink = runCommand safeName {
    40:     inherit trunk;
    41:     root = toString (asPath (getRoot p));
    42:   } ''
    43:     ${if isString p then addContextFrom p "" else ""}
    44:     if [[ -z "$trunk" ]]
    45:     then
    46:       ln -s "$root" "$out"
    47:     else
    48:       ln -s "$root/$trunk" "$out"
    49:     fi
    50:   '';
    51: };
    52: if isStore p then
    53:   symlink
    54: else
    55:   builtins.path {
    56:     name = safeName;
    57:     path = p;
    58:   }

Generated by git2html.