about summary refs log blame commit diff
path: root/users/Profpatsch/exactSource.nix
blob: 5c713b5b1c84f1b5389189d4b873de5d2f4cfc93 (plain) (tree)

























































































                                                                                                               
{ ... }:
# SPDX-License-Identifier: MIT
# Created by Graham Christensen
# version from https://github.com/grahamc/mayday/blob/c48f7583e622fe2e695a2a929de34679e5818816/exact-source.nix

let
  # Require that every path specified does exist.
  #
  # By default, Nix won't complain if you refer to a missing file
  # if you don't actually use it:
  #
  #     nix-repl> ./bogus
  #     /home/grahamc/playground/bogus
  #
  #     nix-repl> toString ./bogus
  #     "/home/grahamc/playground/bogus"
  #
  # so in order for this interface to be *exact*, we must
  # specifically require every provided path exists:
  #
  #     nix-repl> "${./bogus}"
  #     error: getting attributes of path
  #     '/home/grahamc/playground/bogus': No such file or
  #     directory
  requireAllPathsExist = paths:
    let
      validation = builtins.map (path: "${path}") paths;
    in
    builtins.deepSeq validation paths;

  # Break down a given path in to a list of all of the path and
  # its parent directories.
  #
  # `builtins.path` / `builtins.filterSource` will ask about
  # a containing directory, and we must say YES otherwise it will
  # not include anything below it.
  #
  # Concretely, convert: "/foo/baz/tux" in to:
  #     [ "/foo/baz/tux" "/foo/baz" "/foo" ]
  recursivelyPopDir = path:
    if path == "/" then [ ]
    else [ path ] ++ (recursivelyPopDir (builtins.dirOf path));

  # Given a list of of strings, dedup the list and return a
  # list of all unique strings.
  #
  # Note: only works on strings ;):
  #
  # First convert [ "foo" "foo" "bar" ] in to:
  #     [
  #       { name = "foo"; value = ""; }
  #       { name = "foo"; value = ""; }
  #       { name = "bar"; value = ""; }
  #     ]
  # then convert that to { "foo" = ""; "bar" = ""; }
  # then get the attribute names, "foo" and "bar".
  dedup = strings:
    let
      name_value_pairs = builtins.map
        (string: { name = string; value = ""; })
        strings;
      attrset_of_strings = builtins.listToAttrs name_value_pairs;
    in
    builtins.attrNames attrset_of_strings;

  exactSource = source_root: paths:
    let
      all_possible_paths =
        let
          # Convert all the paths in to relative paths on disk.
          # ie: stringPaths will contain [ "/home/grahamc/playground/..." ];
          # instead of /nix/store paths.
          string_paths = builtins.map toString
            (requireAllPathsExist paths);

          all_paths_with_duplicates = builtins.concatMap
            recursivelyPopDir
            string_paths;
        in
        dedup all_paths_with_duplicates;

      pathIsSpecified = path:
        builtins.elem path all_possible_paths;
    in
    builtins.path {
      path = source_root;
      filter = (path: _type: pathIsSpecified path);
    };
in
exactSource