91 lines
2.7 KiB
Nix
91 lines
2.7 KiB
Nix
|
{ ... }:
|
||
|
# 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
|