nix-helpers: d6fd1b6e411c9f625d63e4da7da862f5647faf30

     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: {
    11:   asPath,
    12:   hello,
    13:   lib,
    14:   runCommand,
    15:   sanitiseName,
    16:   writeScript,
    17: }:
    18: 
    19: with builtins;
    20: with lib;
    21: p:
    22: with rec {
    23:   strP = unsafeDiscardStringContext (toString p);
    24: 
    25:   # Checks whether a path is from the Nix store, since Nix will abort if
    26:   # store paths are referenced in certain ways.
    27:   isStore = x: hasPrefix storeDir (toString x);
    28: 
    29:   # Chops suffices off a store path until it's a top-level entry, e.g.
    30:   #   getRoot "/nix/store/...-foo/bar/baz" -> "/nix/store/...-foo"
    31:   # This way we're guaranteed to avoid filename characters which aren't
    32:   # valid store paths.
    33:   getRoot =
    34:     x: if toString (dirOf x) == toString storeDir then x else getRoot (dirOf x);
    35: 
    36:   # Complements getRoot:
    37:   #   p = "/nix/store/...-foo/bar/baz" -> trunk = "bar/baz"
    38:   trunk = removePrefix "/" (removePrefix (getRoot strP) strP);
    39: 
    40:   # Avoids characters which are incompatible with store paths
    41:   safeName = sanitiseName (baseNameOf strP);
    42: 
    43:   # For store paths, we make a symlink which depends on p's context. By
    44:   # using the root we avoid incompatible characters, without using
    45:   # builtins.path (which Nix complains about if we give it a store path).
    46:   symlink =
    47:     runCommand safeName
    48:       {
    49:         inherit trunk;
    50:         root = toString (asPath (getRoot p));
    51:       }
    52:       ''
    53:         ${if isString p then addContextFrom p "" else ""}
    54:         if [[ -z "$trunk" ]]
    55:         then
    56:           ln -s "$root" "$out"
    57:         else
    58:           ln -s "$root/$trunk" "$out"
    59:         fi
    60:       '';
    61: };
    62: if isStore p then
    63:   symlink
    64: else
    65:   builtins.path {
    66:     name = safeName;
    67:     path = p;
    68:   }

Generated by git2html.