about summary refs log tree commit diff
path: root/pkgs/profpatsch/exact-source.nix
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2020-05-09 21:04:39 +0200
committerProfpatsch <mail@profpatsch.de>2020-05-09 21:13:09 +0200
commit416f19868b92f4ee831a4b8e9891ff666dfa86a6 (patch)
tree77df0190737fef700a3d40cc7133023446caaab3 /pkgs/profpatsch/exact-source.nix
parente68a5e04e60cd3bbfda84c10c7bbbfa2321eb54b (diff)
pkgs/profpatsch: add exactSource
Diffstat (limited to 'pkgs/profpatsch/exact-source.nix')
-rw-r--r--pkgs/profpatsch/exact-source.nix84
1 files changed, 84 insertions, 0 deletions
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