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/default.nix4
-rw-r--r--home-manager/modules/lib/file-type.nix30
-rw-r--r--home-manager/modules/lib/gvariant.nix156
-rw-r--r--home-manager/modules/lib/maintainers.nix44
-rw-r--r--home-manager/modules/lib/types-dag.nix63
-rw-r--r--home-manager/modules/lib/types.nix78
6 files changed, 331 insertions, 44 deletions
diff --git a/home-manager/modules/lib/default.nix b/home-manager/modules/lib/default.nix
index 6b2bbacc249..7c2c72f709c 100644
--- a/home-manager/modules/lib/default.nix
+++ b/home-manager/modules/lib/default.nix
@@ -16,8 +16,10 @@ rec {
entryBefore = d.dagEntryBefore;
};
+ gvariant = import ./gvariant.nix { inherit lib; };
+ maintainers = import ./maintainers.nix;
strings = import ./strings.nix { inherit lib; };
- types = import ./types.nix { inherit dag lib; };
+ types = import ./types.nix { inherit dag gvariant 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
index 3096a6d37bb..56a3a1286a0 100644
--- a/home-manager/modules/lib/file-type.nix
+++ b/home-manager/modules/lib/file-type.nix
@@ -11,7 +11,7 @@ with lib;
# Arguments:
# - basePathDesc docbook compatible description of the base path
# - basePath the file base path
- fileType = basePathDesc: basePath: types.loaOf (types.submodule (
+ fileType = basePathDesc: basePath: types.attrsOf (types.submodule (
{ name, config, ... }: {
options = {
target = mkOption {
@@ -21,6 +21,7 @@ with lib;
absPath = if hasPrefix "/" p then p else "${basePath}/${p}";
in
removePrefix (homeDirectory + "/") absPath;
+ defaultText = literalExample "<name>";
description = ''
Path to target file relative to ${basePathDesc}.
'';
@@ -29,17 +30,20 @@ with lib;
text = mkOption {
default = null;
type = types.nullOr types.lines;
- description = "Text of the file.";
+ description = ''
+ Text of the file. If this option is null then
+ <link linkend="opt-home.file._name_.source">home.file.&lt;name?&gt;.source</link>
+ must be set.
+ '';
};
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.
+ Path of the source file or directory. If
+ <link linkend="opt-home.file._name_.text">home.file.&lt;name?&gt;.text</link>
+ is non-null then this option will automatically point to a file
+ containing that text.
'';
};
@@ -80,6 +84,18 @@ with lib;
into place.
'';
};
+
+ force = mkOption {
+ type = types.bool;
+ default = false;
+ visible = false;
+ description = ''
+ Whether the target path should be unconditionally replaced
+ by the managed file source. Warning, this will silently
+ delete the target regardless of whether it is a file or
+ link.
+ '';
+ };
};
config = {
diff --git a/home-manager/modules/lib/gvariant.nix b/home-manager/modules/lib/gvariant.nix
new file mode 100644
index 00000000000..92aa7d98371
--- /dev/null
+++ b/home-manager/modules/lib/gvariant.nix
@@ -0,0 +1,156 @@
+# A partial and basic implementation of GVariant formatted strings.
+#
+# Note, this API is not considered fully stable and it might therefore
+# change in backwards incompatible ways without prior notice.
+
+{ lib }:
+
+with lib;
+
+let
+
+ mkPrimitive = t: v: {
+ _type = "gvariant";
+ type = t;
+ value = v;
+ __toString = self: "@${self.type} ${toString self.value}";
+ };
+
+ type = {
+ arrayOf = t: "a${t}";
+ maybeOf = t: "m${t}";
+ tupleOf = ts: "(${concatStrings ts})";
+ string = "s";
+ boolean = "b";
+ uchar = "y";
+ int16 = "n";
+ uint16 = "q";
+ int32 = "i";
+ uint32 = "u";
+ int64 = "x";
+ uint64 = "t";
+ double = "d";
+ };
+
+ # Returns the GVariant type of a given Nix value. If no type can be
+ # found for the value then the empty string is returned.
+ typeOf = v:
+ with type;
+ if builtins.isBool v then
+ boolean
+ else if builtins.isInt v then
+ int32
+ else if builtins.isFloat v then
+ double
+ else if builtins.isString v then
+ string
+ else if builtins.isList v then
+ let elemType = elemTypeOf v;
+ in if elemType == "" then "" else arrayOf elemType
+ else if builtins.isAttrs v && v ? type then
+ v.type
+ else
+ "";
+
+ elemTypeOf = vs:
+ if builtins.isList vs then
+ if vs == [ ] then "" else typeOf (head vs)
+ else
+ "";
+
+ mkMaybe = elemType: elem:
+ mkPrimitive (type.maybeOf elemType) elem // {
+ __toString = self:
+ if self.value == null then
+ "@${self.type} nothing"
+ else
+ "just ${toString self.value}";
+ };
+
+in rec {
+
+ inherit type typeOf;
+
+ isArray = hasPrefix "a";
+ isMaybe = hasPrefix "m";
+ isTuple = hasPrefix "(";
+
+ # Returns the GVariant value that most closely matches the given Nix
+ # value. If no GVariant value can be found then `null` is returned.
+ #
+ # No support for dictionaries, maybe types, or variants.
+ mkValue = v:
+ if builtins.isBool v then
+ mkBoolean v
+ else if builtins.isInt v then
+ mkInt32 v
+ else if builtins.isFloat v then
+ mkDouble v
+ else if builtins.isString v then
+ mkString v
+ else if builtins.isList v then
+ if v == [ ] then mkArray type.string [ ] else mkArray (elemTypeOf v) v
+ else if builtins.isAttrs v && (v._type or "") == "gvariant" then
+ v
+ else
+ null;
+
+ mkArray = elemType: elems:
+ mkPrimitive (type.arrayOf elemType) (map mkValue elems) // {
+ __toString = self:
+ "@${self.type} [${concatMapStringsSep "," toString self.value}]";
+ };
+
+ mkEmptyArray = elemType: mkArray elemType [ ];
+
+ mkNothing = elemType: mkMaybe elemType null;
+
+ mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem;
+
+ mkTuple = elems:
+ let
+ gvarElems = map mkValue elems;
+ tupleType = type.tupleOf (map (e: e.type) gvarElems);
+ in mkPrimitive tupleType gvarElems // {
+ __toString = self:
+ "@${self.type} (${concatMapStringsSep "," toString self.value})";
+ };
+
+ mkBoolean = v:
+ mkPrimitive type.boolean v // {
+ __toString = self: if self.value then "true" else "false";
+ };
+
+ mkString = v:
+ mkPrimitive type.string v // {
+ __toString = self: "'${escape [ "'" "\\" ] self.value}'";
+ };
+
+ mkObjectpath = v:
+ mkPrimitive type.string v // {
+ __toString = self: "objectpath '${escape [ "'" ] self.value}'";
+ };
+
+ mkUchar = mkPrimitive type.uchar;
+
+ mkInt16 = mkPrimitive type.int16;
+
+ mkUint16 = mkPrimitive type.uint16;
+
+ mkInt32 = v:
+ mkPrimitive type.int32 v // {
+ __toString = self: toString self.value;
+ };
+
+ mkUint32 = mkPrimitive type.uint32;
+
+ mkInt64 = mkPrimitive type.int64;
+
+ mkUint64 = mkPrimitive type.uint64;
+
+ mkDouble = v:
+ mkPrimitive type.double v // {
+ __toString = self: toString self.value;
+ };
+
+}
diff --git a/home-manager/modules/lib/maintainers.nix b/home-manager/modules/lib/maintainers.nix
new file mode 100644
index 00000000000..8cb8781228b
--- /dev/null
+++ b/home-manager/modules/lib/maintainers.nix
@@ -0,0 +1,44 @@
+# Home Manager maintainers.
+#
+# This attribute set contains Home Manager module maintainers that do
+# not have an entry in the Nixpkgs maintainer list [1]. Entries here
+# are expected to be follow the same format as described in [1].
+#
+# [1] https://github.com/NixOS/nixpkgs/blob/fca0d6e093c82b31103dc0dacc48da2a9b06e24b/maintainers/maintainer-list.nix#LC1
+
+{
+ justinlovinger = {
+ name = "Justin Lovinger";
+ email = "git@justinlovinger.com";
+ github = "JustinLovinger";
+ githubId = 7183441;
+ };
+ owm111 = {
+ email = "7798336+owm111@users.noreply.github.com";
+ name = "Owen McGrath";
+ github = "owm111";
+ githubId = 7798336;
+ };
+ cwyc = {
+ email = "cwyc@users.noreply.github.com";
+ name = "cwyc";
+ github = "cwyc";
+ githubId = 16950437;
+ };
+ berbiche = {
+ name = "Nicolas Berbiche";
+ email = "berbiche@users.noreply.github.com";
+ github = "berbiche";
+ githubId = 20448408;
+ keys = [{
+ longkeyid = "rsa4096/0xB461292445C6E696";
+ fingerprint = "D446 E58D 87A0 31C7 EC15 88D7 B461 2924 45C6 E696";
+ }];
+ };
+ olmokramer = {
+ name = "Olmo Kramer";
+ email = "olmokramer@users.noreply.github.com";
+ github = "olmokramer";
+ githubId = 3612514;
+ };
+}
diff --git a/home-manager/modules/lib/types-dag.nix b/home-manager/modules/lib/types-dag.nix
index 4dbdb907b0e..2efb12645d4 100644
--- a/home-manager/modules/lib/types-dag.nix
+++ b/home-manager/modules/lib/types-dag.nix
@@ -7,16 +7,25 @@ let
isDagEntry = e: isAttrs e && (e ? data) && (e ? after) && (e ? before);
dagContentType = elemType:
- types.submodule {
+ types.submodule ({ name, ... }: {
options = {
data = mkOption { type = elemType; };
after = mkOption { type = with types; uniq (listOf str); };
before = mkOption { type = with types; uniq (listOf str); };
};
- };
+ config = mkIf (elemType.name == "submodule") {
+ data._module.args.dagName = name;
+ };
+ });
-in {
+in rec {
# A directed acyclic graph of some inner type.
+ #
+ # Note, if the element type is a submodule then the `name` argument
+ # will always be set to the string "data" since it picks up the
+ # internal structure of the DAG values. To give access to the
+ # "actual" attribute name a new submodule argument is provided with
+ # the name `dagName`.
dagOf = elemType:
let
convertAllToDags = let
@@ -51,34 +60,40 @@ in {
let padWidth = stringLength (toString (length list));
in fixedWidthNumber padWidth i;
- convertAllToDags = defs:
+ convertAll = loc: defs:
let
- convertAttrValue = n: v:
- if isDagEntry v then v else dag.entryAnywhere v;
-
- convertListValue = namePrefix: vs:
+ convertListValue = namePrefix: def:
let
+ vs = def.value;
pad = paddedIndexStr vs;
- makeEntry = i: v:
- nameValuePair "${namePrefix}.${pad i}" (dag.entryAnywhere v);
- in listToAttrs (imap1 makeEntry vs);
+ makeEntry = i: v: nameValuePair "${namePrefix}.${pad i}" v;
+ warning = ''
+ In file ${def.file}
+ a list is being assigned to the option '${
+ concatStringsSep "." loc
+ }'.
+ This will soon be an error due to the list form being deprecated.
+ Please use the attribute set form instead with DAG functions to
+ express the desired order of entries.
+ '';
+ in warn warning (listToAttrs (imap1 makeEntry vs));
- convertValue = i: value:
- if isList value then
- convertListValue "unnamed-${paddedIndexStr defs i}" value
+ convertValue = i: def:
+ if isList def.value then
+ convertListValue "unnamed-${paddedIndexStr defs i}" def
else
- mapAttrs convertAttrValue value;
- in imap1 (i: def: def // { value = convertValue i def.value; }) defs;
+ def.value;
+ in imap1 (i: def: def // { value = convertValue i def; }) defs;
- attrEquivalent = types.attrsOf (dagContentType elemType);
+ dagType = dagOf elemType;
in mkOptionType rec {
- name = "dagOf";
- description = "DAG of ${elemType.description}s";
- check = x: isAttrs x || isList x;
- merge = loc: defs: attrEquivalent.merge loc (convertAllToDags defs);
- getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "<name>" ]);
- getSubModules = elemType.getSubModules;
- substSubModules = m: dagOf (elemType.substSubModules m);
+ name = "listOrDagOf";
+ description = "list or DAG of ${elemType.description}s";
+ check = x: isList x || dagType.check x;
+ merge = loc: defs: dagType.merge loc (convertAll loc defs);
+ getSubOptions = dagType.getSubOptions;
+ getSubModules = dagType.getSubModules;
+ substSubModules = m: listOrDagOf (elemType.substSubModules m);
functor = (defaultFunctor name) // { wrapped = elemType; };
};
}
diff --git a/home-manager/modules/lib/types.nix b/home-manager/modules/lib/types.nix
index 78a875f519e..64a6b4a34fa 100644
--- a/home-manager/modules/lib/types.nix
+++ b/home-manager/modules/lib/types.nix
@@ -1,4 +1,5 @@
-{ lib, dag ? import ./dag.nix { inherit lib; } }:
+{ lib, dag ? import ./dag.nix { inherit lib; }
+, gvariant ? import ./gvariant.nix { inherit lib; } }:
with lib;
@@ -6,31 +7,84 @@ let
typesDag = import ./types-dag.nix { inherit dag lib; };
-in
+ # Needed since the type is called gvariant and its merge attribute
+ # must refer back to the type.
+ gvar = gvariant;
-{
+in rec {
inherit (typesDag) dagOf listOrDagOf;
selectorFunction = mkOptionType {
name = "selectorFunction";
- description =
- "Function that takes an attribute set and returns a list"
+ 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);
+ merge = _loc: defs: as: concatMap (select: select as) (getValues defs);
};
overlayFunction = mkOptionType {
name = "overlayFunction";
- description =
- "An overlay function, takes self and super and returns"
+ 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;
+ merge = _loc: defs: self: super:
+ foldl' (res: def: mergeAttrs res (def.value self super)) { } defs;
+ };
+
+ fontType = types.submodule {
+ options = {
+ package = mkOption {
+ type = types.nullOr types.package;
+ default = null;
+ example = literalExample "pkgs.dejavu_fonts";
+ description = ''
+ Package providing the font. This package will be installed
+ to your profile. If <literal>null</literal> then the font
+ is assumed to already be available in your profile.
+ '';
+ };
+
+ name = mkOption {
+ type = types.str;
+ example = "DejaVu Sans 8";
+ description = ''
+ The family name and size of the font within the package.
+ '';
+ };
+ };
+ };
+
+ gvariant = mkOptionType rec {
+ name = "gvariant";
+ description = "GVariant value";
+ check = v: gvar.mkValue v != null;
+ merge = loc: defs:
+ let
+ vdefs = map (d: d // { value = gvar.mkValue d.value; }) defs;
+ vals = map (d: d.value) vdefs;
+ defTypes = map (x: x.type) vals;
+ sameOrNull = x: y: if x == y then y else null;
+ # A bit naive to just check the first entry…
+ sharedDefType = foldl' sameOrNull (head defTypes) defTypes;
+ allChecked = all (x: check x) vals;
+ in if sharedDefType == null then
+ throw ("Cannot merge definitions of `${showOption loc}' with"
+ + " mismatched GVariant types given in"
+ + " ${showFiles (getFiles defs)}.")
+ else if gvar.isArray sharedDefType && allChecked then
+ (types.listOf gvariant).merge loc
+ (map (d: d // { value = d.value.value; }) vdefs)
+ else if gvar.isTuple sharedDefType && allChecked then
+ mergeOneOption loc defs
+ else if gvar.isMaybe sharedDefType && allChecked then
+ mergeOneOption loc defs
+ else if gvar.type.string == sharedDefType && allChecked then
+ types.str.merge loc defs
+ else if gvar.type.double == sharedDefType && allChecked then
+ types.float.merge loc defs
+ else
+ mergeDefaultOption loc defs;
};
}