From 416f19868b92f4ee831a4b8e9891ff666dfa86a6 Mon Sep 17 00:00:00 2001 From: Profpatsch Date: Sat, 9 May 2020 21:04:39 +0200 Subject: pkgs/profpatsch: add exactSource --- pkgs/profpatsch/default.nix | 2 + pkgs/profpatsch/exact-source.nix | 84 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 pkgs/profpatsch/exact-source.nix (limited to 'pkgs') diff --git a/pkgs/profpatsch/default.nix b/pkgs/profpatsch/default.nix index e83cb2d2..08ce4dfc 100644 --- a/pkgs/profpatsch/default.nix +++ b/pkgs/profpatsch/default.nix @@ -17,6 +17,8 @@ let }; in builtins.listToAttrs (builtins.map f xs); + exactSource = import ./exact-source.nix; + # various nix utils and fun experiments nixperiments = let diff --git a/pkgs/profpatsch/exact-source.nix b/pkgs/profpatsch/exact-source.nix new file mode 100644 index 00000000..deb749ca --- /dev/null +++ b/pkgs/profpatsch/exact-source.nix @@ -0,0 +1,84 @@ +# 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 -- cgit 1.4.1