aboutsummaryrefslogtreecommitdiff
path: root/home-manager/modules/lib
diff options
context:
space:
mode:
Diffstat (limited to 'home-manager/modules/lib')
-rw-r--r--home-manager/modules/lib/dag.nix124
-rw-r--r--home-manager/modules/lib/default.nix23
-rw-r--r--home-manager/modules/lib/file-type.nix102
-rw-r--r--home-manager/modules/lib/shell.nix11
-rw-r--r--home-manager/modules/lib/strings.nix27
-rw-r--r--home-manager/modules/lib/types.nix28
-rw-r--r--home-manager/modules/lib/zsh.nix28
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);
+}