diff options
Diffstat (limited to 'home-manager/modules/lib')
-rw-r--r-- | home-manager/modules/lib/dag.nix | 124 | ||||
-rw-r--r-- | home-manager/modules/lib/default.nix | 23 | ||||
-rw-r--r-- | home-manager/modules/lib/file-type.nix | 102 | ||||
-rw-r--r-- | home-manager/modules/lib/shell.nix | 11 | ||||
-rw-r--r-- | home-manager/modules/lib/strings.nix | 27 | ||||
-rw-r--r-- | home-manager/modules/lib/types.nix | 28 | ||||
-rw-r--r-- | home-manager/modules/lib/zsh.nix | 28 |
7 files changed, 343 insertions, 0 deletions
diff --git a/home-manager/modules/lib/dag.nix b/home-manager/modules/lib/dag.nix new file mode 100644 index 00000000000..535dec35ad4 --- /dev/null +++ b/home-manager/modules/lib/dag.nix @@ -0,0 +1,124 @@ +# A generalization of Nixpkgs's `strings-with-deps.nix`. +# +# The main differences from the Nixpkgs version are +# +# - not specific to strings, i.e., any payload is OK, +# +# - the addition of the function `dagEntryBefore` indicating a +# "wanted by" relationship. + +{ lib }: + +with lib; + +rec { + + emptyDag = {}; + + isDag = dag: + let + isEntry = e: (e ? data) && (e ? after) && (e ? before); + in + builtins.isAttrs dag && all (x: x) (mapAttrsToList (n: isEntry) dag); + + # Takes an attribute set containing entries built by + # dagEntryAnywhere, dagEntryAfter, and dagEntryBefore to a + # topologically sorted list of entries. + # + # Internally this function uses the `toposort` function in + # `<nixpkgs/lib/lists.nix>` and its value is accordingly. + # + # Specifically, the result on success is + # + # { result = [{name = ?; data = ?;} …] } + # + # For example + # + # nix-repl> dagTopoSort { + # a = dagEntryAnywhere "1"; + # b = dagEntryAfter ["a" "c"] "2"; + # c = dagEntryBefore ["d"] "3"; + # d = dagEntryBefore ["e"] "4"; + # e = dagEntryAnywhere "5"; + # } == { + # result = [ + # { data = "1"; name = "a"; } + # { data = "3"; name = "c"; } + # { data = "2"; name = "b"; } + # { data = "4"; name = "d"; } + # { data = "5"; name = "e"; } + # ]; + # } + # true + # + # And the result on error is + # + # { + # cycle = [ {after = ?; name = ?; data = ?} … ]; + # loops = [ {after = ?; name = ?; data = ?} … ]; + # } + # + # For example + # + # nix-repl> dagTopoSort { + # a = dagEntryAnywhere "1"; + # b = dagEntryAfter ["a" "c"] "2"; + # c = dagEntryAfter ["d"] "3"; + # d = dagEntryAfter ["b"] "4"; + # e = dagEntryAnywhere "5"; + # } == { + # cycle = [ + # { after = ["a" "c"]; data = "2"; name = "b"; } + # { after = ["d"]; data = "3"; name = "c"; } + # { after = ["b"]; data = "4"; name = "d"; } + # ]; + # loops = [ + # { after = ["a" "c"]; data = "2"; name = "b"; } + # ]; + # } == {} + # true + dagTopoSort = dag: + let + dagBefore = dag: name: + mapAttrsToList (n: v: n) ( + filterAttrs (n: v: any (a: a == name) v.before) dag + ); + normalizedDag = + mapAttrs (n: v: { + name = n; + data = v.data; + after = v.after ++ dagBefore dag n; + }) dag; + before = a: b: any (c: a.name == c) b.after; + sorted = toposort before (mapAttrsToList (n: v: v) normalizedDag); + in + if sorted ? result then + { result = map (v: { inherit (v) name data; }) sorted.result; } + else + sorted; + + # Applies a function to each element of the given DAG. + dagMap = f: dag: mapAttrs (n: v: v // { data = f n v.data; }) dag; + + # Create a DAG entry with no particular dependency information. + dagEntryAnywhere = data: { + inherit data; + before = []; + after = []; + }; + + dagEntryBetween = before: after: data: { + inherit data before after; + }; + + dagEntryAfter = after: data: { + inherit data after; + before = []; + }; + + dagEntryBefore = before: data: { + inherit data before; + after = []; + }; + +} diff --git a/home-manager/modules/lib/default.nix b/home-manager/modules/lib/default.nix new file mode 100644 index 00000000000..754713cab5d --- /dev/null +++ b/home-manager/modules/lib/default.nix @@ -0,0 +1,23 @@ +{ lib }: + +{ + dag = + let + d = import ./dag.nix { inherit lib; }; + in + { + empty = d.emptyDag; + isDag = d.isDag; + topoSort = d.dagTopoSort; + map = d.dagMap; + entryAnywhere = d.dagEntryAnywhere; + entryBetween = d.dagEntryBetween; + entryAfter = d.dagEntryAfter; + entryBefore = d.dagEntryBefore; + }; + + strings = import ./strings.nix { inherit lib; }; + + shell = import ./shell.nix { inherit lib; }; + zsh = import ./zsh.nix { inherit lib; }; +} diff --git a/home-manager/modules/lib/file-type.nix b/home-manager/modules/lib/file-type.nix new file mode 100644 index 00000000000..efbb33b231d --- /dev/null +++ b/home-manager/modules/lib/file-type.nix @@ -0,0 +1,102 @@ +{ homeDirectory, lib, pkgs }: + +with lib; + +let + + stringsExtra = import ./strings.nix { inherit lib; }; + +in + +{ + # Constructs a type suitable for a `home.file` like option. The + # target path may be either absolute or relative, in which case it + # is relative the `basePath` argument (which itself must be an + # absolute path). + # + # Arguments: + # - basePathDesc docbook compatible description of the base path + # - basePath the file base path + fileType = basePathDesc: basePath: types.loaOf (types.submodule ( + { name, config, ... }: { + options = { + target = mkOption { + type = types.str; + apply = p: + let + absPath = if hasPrefix "/" p then p else "${basePath}/${p}"; + in + removePrefix (homeDirectory + "/") absPath; + description = '' + Path to target file relative to ${basePathDesc}. + ''; + }; + + text = mkOption { + default = null; + type = types.nullOr types.lines; + description = "Text of the file."; + }; + + source = mkOption { + type = types.path; + description = '' + Path of the source file. The file name must not start + with a period since Nix will not allow such names in + the Nix store. + </para><para> + This may refer to a directory. + ''; + }; + + executable = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Set the execute bit. If <literal>null</literal>, defaults to the mode + of the <varname>source</varname> file or to <literal>false</literal> + for files created through the <varname>text</varname> option. + ''; + }; + + recursive = mkOption { + type = types.bool; + default = false; + description = '' + If the file source is a directory, then this option + determines whether the directory should be recursively + linked to the target location. This option has no effect + if the source is a file. + </para><para> + If <literal>false</literal> (the default) then the target + will be a symbolic link to the source directory. If + <literal>true</literal> then the target will be a + directory structure matching the source's but whose leafs + are symbolic links to the files of the source directory. + ''; + }; + + onChange = mkOption { + type = types.lines; + default = ""; + description = '' + Shell commands to run when file has changed between + generations. The script will be run + <emphasis>after</emphasis> the new files have been linked + into place. + ''; + }; + }; + + config = { + target = mkDefault name; + source = mkIf (config.text != null) ( + mkDefault (pkgs.writeTextFile { + inherit (config) executable text; + name = stringsExtra.storeFileName name; + }) + ); + }; + } + )); +} diff --git a/home-manager/modules/lib/shell.nix b/home-manager/modules/lib/shell.nix new file mode 100644 index 00000000000..f1443c5466a --- /dev/null +++ b/home-manager/modules/lib/shell.nix @@ -0,0 +1,11 @@ +{ lib }: + +rec { + # Produces a Bourne shell like variable export statement. + export = n: v: "export ${n}=\"${toString v}\""; + + # Given an attribute set containing shell variable names and their + # assignment, this function produces a string containing an export + # statement for each set entry. + exportAll = vars: lib.concatStringsSep "\n" (lib.mapAttrsToList export vars); +} diff --git a/home-manager/modules/lib/strings.nix b/home-manager/modules/lib/strings.nix new file mode 100644 index 00000000000..13d6bb03be6 --- /dev/null +++ b/home-manager/modules/lib/strings.nix @@ -0,0 +1,27 @@ +{ lib }: + +with lib; + +{ + # Figures out a valid Nix store name for the given path. + storeFileName = path: + let + # All characters that are considered safe. Note "-" is not + # included to avoid "-" followed by digit being interpreted as a + # version. + safeChars = + [ "+" "." "_" "?" "=" ] + ++ lowerChars + ++ upperChars + ++ stringToCharacters "0123456789"; + + empties = l: genList (x: "") (length l); + + unsafeInName = stringToCharacters ( + replaceStrings safeChars (empties safeChars) path + ); + + safeName = replaceStrings unsafeInName (empties unsafeInName) path; + in + "hm_" + safeName; +} diff --git a/home-manager/modules/lib/types.nix b/home-manager/modules/lib/types.nix new file mode 100644 index 00000000000..1b514d20a82 --- /dev/null +++ b/home-manager/modules/lib/types.nix @@ -0,0 +1,28 @@ +{ lib }: + +with lib; + +{ + + selectorFunction = mkOptionType { + name = "selectorFunction"; + description = + "Function that takes an attribute set and returns a list" + + " containing a selection of the values of the input set"; + check = isFunction; + merge = _loc: defs: + as: concatMap (select: select as) (getValues defs); + }; + + overlayFunction = mkOptionType { + name = "overlayFunction"; + description = + "An overlay function, takes self and super and returns" + + " an attribute set overriding the desired attributes."; + check = isFunction; + merge = _loc: defs: + self: super: + foldl' (res: def: mergeAttrs res (def.value self super)) {} defs; + }; + +} diff --git a/home-manager/modules/lib/zsh.nix b/home-manager/modules/lib/zsh.nix new file mode 100644 index 00000000000..1d3e96b54bb --- /dev/null +++ b/home-manager/modules/lib/zsh.nix @@ -0,0 +1,28 @@ +{ lib }: + +rec { + # Produces a Zsh shell like value + toZshValue = v: if builtins.isBool v then + if v then "true" else "false" + else if builtins.isString v then + "\"${v}\"" + else if builtins.isList v then + "(${lib.concatStringsSep " " (map toZshValue v)})" + else "\"${toString v}\""; + + # Produces a Zsh shell like definition statement + define = n: v: "${n}=${toZshValue v}"; + + # Given an attribute set containing shell variable names and their + # assignments, this function produces a string containing a definition + # statement for each set entry. + defineAll = vars: lib.concatStringsSep "\n" (lib.mapAttrsToList define vars); + + # Produces a Zsh shell like export statement + export = n: v: "export ${define n v}"; + + # Given an attribute set containing shell variable names and their + # assignments, this function produces a string containing an export + # statement for each set entry. + exportAll = vars: lib.concatStringsSep "\n" (lib.mapAttrsToList export vars); +} |