diff --git a/lib/strings-with-deps.nix b/lib/strings-with-deps.nix index 7b88b018da5786..8f8934d15a2d1f 100644 --- a/lib/strings-with-deps.nix +++ b/lib/strings-with-deps.nix @@ -52,10 +52,101 @@ let in rec { - /* !!! The interface of this function is kind of messed up, since - it's way too overloaded and almost but not quite computes a - topological sort of the depstrings. */ - + /** + Topologically sort a collection of dependent strings. + Only depstrings listed in `arg` and their dependencies will be included in the result. + + ::: {.note} + Doesn't formally fulfill the topological sort definition, but it's good enough for our purpose in nixpkgs. + ::: + + # Inputs + + `predefined` (attribute set) + + : set of depstrings. (String or DepString) + A depstring is itself an attribute set with the following attributes: + - `deps` (list of strings) + - `text` (string) + A depstring can be a simple string if it has no dependencies. + + `arg` (list of strings) + + : Determines which items to include in the result. + + # Type + + ``` + textClosureList :: AttrsOf { deps :: [String], text :: String } -> [String] -> [String] + ``` + + # Examples + :::{.example} + ## `lib.stringsWithDeps.textClosureList` usage example + + ```nix + textClosureList { + a = { + deps = [ "b" "c" "e" ]; + text = "a: depends on b, c and e"; + }; + b = { + deps = [ ]; + text = "b: no dependencies"; + }; + c = { + deps = [ "b" ]; + text = "c: depends on b"; + }; + d = { + deps = [ "c" ]; + text = "d: not being depended on by anything in `arg`"; + }; + e = { + deps = [ "c" ]; + text = "e: depends on c, depended on by a, not in `arg`"; + }; + } [ + "a" + "b" + "c" + ] + => [ + "b: no dependencies" + "c: depends on b" + "e: depends on c, depended on by a, not in `arg`" + "a: depends on b, c and e" + ] + ``` + ::: + + Common real world usages are: + - Ordering the dependent phases of `system.activationScripts` + - Ordering the dependent phases of `system.userActivationScripts` + + :::{.example} + ## `lib.stringsWithDeps.textClosureList` real world example + { + networkSetup = { + text = "Script to setting up network"; + deps = []; + }; + mountFilesystems = { + text = "Mounting filesystems"; + deps = ["networkSetup"]; + }; + startServices = { + text = "Starting services"; + deps = ["mountFilesystems"]; + }; + cleanup = { + text = "Cleaning up temporary files"; + deps = ["mountFilesystems", "startServices"]; + }; + } + ::: + + */ textClosureList = predefined: arg: let f = done: todo: