about summary refs log tree commit diff
path: root/nixpkgs/lib
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2023-09-01 11:51:02 +0000
committerAlyssa Ross <hi@alyssa.is>2023-09-01 11:51:02 +0000
commitaa4353b499e6950b7333578f936455a628145c31 (patch)
treec6332cedece2327a18d08794755b3fc0f9f1905b /nixpkgs/lib
parentac456d475f4e50818499b804359355c0f3b4bbf7 (diff)
parent52185f4d76c18d8348f963795dfed1de018e8dfe (diff)
downloadnixlib-aa4353b499e6950b7333578f936455a628145c31.tar
nixlib-aa4353b499e6950b7333578f936455a628145c31.tar.gz
nixlib-aa4353b499e6950b7333578f936455a628145c31.tar.bz2
nixlib-aa4353b499e6950b7333578f936455a628145c31.tar.lz
nixlib-aa4353b499e6950b7333578f936455a628145c31.tar.xz
nixlib-aa4353b499e6950b7333578f936455a628145c31.tar.zst
nixlib-aa4353b499e6950b7333578f936455a628145c31.zip
Merge https://github.com/NixOS/nixpkgs
Diffstat (limited to 'nixpkgs/lib')
-rw-r--r--nixpkgs/lib/default.nix1
-rw-r--r--nixpkgs/lib/generators.nix8
-rw-r--r--nixpkgs/lib/gvariant.nix290
-rw-r--r--nixpkgs/lib/tests/modules/gvariant.nix93
4 files changed, 392 insertions, 0 deletions
diff --git a/nixpkgs/lib/default.nix b/nixpkgs/lib/default.nix
index 136f4a4a4637..509636452b2b 100644
--- a/nixpkgs/lib/default.nix
+++ b/nixpkgs/lib/default.nix
@@ -41,6 +41,7 @@ let
 
     # serialization
     cli = callLibs ./cli.nix;
+    gvariant = callLibs ./gvariant.nix;
     generators = callLibs ./generators.nix;
 
     # misc
diff --git a/nixpkgs/lib/generators.nix b/nixpkgs/lib/generators.nix
index c37be1942d82..0368577d5a51 100644
--- a/nixpkgs/lib/generators.nix
+++ b/nixpkgs/lib/generators.nix
@@ -230,6 +230,14 @@ rec {
     in
       toINI_ (gitFlattenAttrs attrs);
 
+  # mkKeyValueDefault wrapper that handles dconf INI quirks.
+  # The main differences of the format is that it requires strings to be quoted.
+  mkDconfKeyValue = mkKeyValueDefault { mkValueString = v: toString (lib.gvariant.mkValue v); } "=";
+
+  # Generates INI in dconf keyfile style. See https://help.gnome.org/admin/system-admin-guide/stable/dconf-keyfiles.html.en
+  # for details.
+  toDconfINI = toINI { mkKeyValue = mkDconfKeyValue; };
+
   /* Generates JSON from an arbitrary (non-function) value.
     * For more information see the documentation of the builtin.
     */
diff --git a/nixpkgs/lib/gvariant.nix b/nixpkgs/lib/gvariant.nix
new file mode 100644
index 000000000000..3142ffc5f149
--- /dev/null
+++ b/nixpkgs/lib/gvariant.nix
@@ -0,0 +1,290 @@
+# This file is based on https://github.com/nix-community/home-manager
+# Copyright (c) 2017-2022 Home Manager contributors
+#
+
+
+{ lib }:
+
+/* A partial and basic implementation of GVariant formatted strings.
+   See https://docs.gtk.org/glib/gvariant-format-strings.html for detauls.
+
+   Note, this API is not considered fully stable and it might therefore
+   change in backwards incompatible ways without prior notice.
+*/
+let
+  inherit (lib)
+    concatMapStringsSep concatStrings escape head replaceStrings;
+
+  mkPrimitive = t: v: {
+    _type = "gvariant";
+    type = t;
+    value = v;
+    __toString = self: "@${self.type} ${toString self.value}"; # https://docs.gtk.org/glib/gvariant-text.html
+  };
+
+  type = {
+    arrayOf = t: "a${t}";
+    maybeOf = t: "m${t}";
+    tupleOf = ts: "(${concatStrings ts})";
+    dictionaryEntryOf = nameType: valueType: "{${nameType}${valueType}}";
+    string = "s";
+    boolean = "b";
+    uchar = "y";
+    int16 = "n";
+    uint16 = "q";
+    int32 = "i";
+    uint32 = "u";
+    int64 = "x";
+    uint64 = "t";
+    double = "d";
+    variant = "v";
+  };
+
+  /* Check if a value is a GVariant value
+
+     Type:
+       isGVariant :: Any -> Bool
+  */
+  isGVariant = v: v._type or "" == "gvariant";
+
+in
+rec {
+
+  inherit type isGVariant;
+
+  /* Returns the GVariant value that most closely matches the given Nix value.
+     If no GVariant value can be found unambiguously then error is thrown.
+
+     Type:
+       mkValue :: Any -> gvariant
+  */
+  mkValue = v:
+    if builtins.isBool v then
+      mkBoolean v
+    else if builtins.isFloat v then
+      mkDouble v
+    else if builtins.isString v then
+      mkString v
+    else if builtins.isList v then
+      mkArray v
+    else if isGVariant v then
+      v
+    else
+      throw "The GVariant type of ${v} can't be inferred.";
+
+  /* Returns the GVariant array from the given type of the elements and a Nix list.
+
+     Type:
+       mkArray :: [Any] -> gvariant
+
+     Example:
+       # Creating a string array
+       lib.gvariant.mkArray [ "a" "b" "c" ]
+  */
+  mkArray = elems:
+    let
+      vs = map mkValue (lib.throwIf (elems == [ ]) "Please create empty array with mkEmptyArray." elems);
+      elemType = lib.throwIfNot (lib.all (t: (head vs).type == t) (map (v: v.type) vs))
+        "Elements in a list should have same type."
+        (head vs).type;
+    in
+    mkPrimitive (type.arrayOf elemType) vs // {
+      __toString = self:
+        "@${self.type} [${concatMapStringsSep "," toString self.value}]";
+    };
+
+  /* Returns the GVariant array from the given empty Nix list.
+
+     Type:
+       mkEmptyArray :: gvariant.type -> gvariant
+
+     Example:
+       # Creating an empty string array
+       lib.gvariant.mkEmptyArray (lib.gvariant.type.string)
+  */
+  mkEmptyArray = elemType: mkPrimitive (type.arrayOf elemType) [ ] // {
+    __toString = self: "@${self.type} []";
+  };
+
+
+  /* Returns the GVariant variant from the given Nix value. Variants are containers
+     of different GVariant type.
+
+     Type:
+       mkVariant :: Any -> gvariant
+
+     Example:
+       lib.gvariant.mkArray [
+         (lib.gvariant.mkVariant "a string")
+         (lib.gvariant.mkVariant (lib.gvariant.mkInt32 1))
+       ]
+  */
+  mkVariant = elem:
+    let gvarElem = mkValue elem;
+    in mkPrimitive type.variant gvarElem // {
+      __toString = self: "<${toString self.value}>";
+    };
+
+  /* Returns the GVariant dictionary entry from the given key and value.
+
+     Type:
+       mkDictionaryEntry :: String -> Any -> gvariant
+
+     Example:
+       # A dictionary describing an Epiphany’s search provider
+       [
+         (lib.gvariant.mkDictionaryEntry "url" (lib.gvariant.mkVariant "https://duckduckgo.com/?q=%s&t=epiphany"))
+         (lib.gvariant.mkDictionaryEntry "bang" (lib.gvariant.mkVariant "!d"))
+         (lib.gvariant.mkDictionaryEntry "name" (lib.gvariant.mkVariant "DuckDuckGo"))
+       ]
+  */
+  mkDictionaryEntry =
+    # The key of the entry
+    name:
+    # The value of the entry
+    value:
+    let
+      name' = mkValue name;
+      value' = mkValue value;
+      dictionaryType = type.dictionaryEntryOf name'.type value'.type;
+    in
+    mkPrimitive dictionaryType { inherit name value; } // {
+      __toString = self: "@${self.type} {${name'},${value'}}";
+    };
+
+  /* Returns the GVariant maybe from the given element type.
+
+     Type:
+       mkMaybe :: gvariant.type -> Any -> gvariant
+  */
+  mkMaybe = elemType: elem:
+    mkPrimitive (type.maybeOf elemType) elem // {
+      __toString = self:
+        if self.value == null then
+          "@${self.type} nothing"
+        else
+          "just ${toString self.value}";
+    };
+
+  /* Returns the GVariant nothing from the given element type.
+
+     Type:
+       mkNothing :: gvariant.type -> gvariant
+  */
+  mkNothing = elemType: mkMaybe elemType null;
+
+  /* Returns the GVariant just from the given Nix value.
+
+     Type:
+       mkJust :: Any -> gvariant
+  */
+  mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem;
+
+  /* Returns the GVariant tuple from the given Nix list.
+
+     Type:
+       mkTuple :: [Any] -> gvariant
+  */
+  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})";
+    };
+
+  /* Returns the GVariant boolean from the given Nix bool value.
+
+     Type:
+       mkBoolean :: Bool -> gvariant
+  */
+  mkBoolean = v:
+    mkPrimitive type.boolean v // {
+      __toString = self: if self.value then "true" else "false";
+    };
+
+  /* Returns the GVariant string from the given Nix string value.
+
+     Type:
+       mkString :: String -> gvariant
+  */
+  mkString = v:
+    let sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s);
+    in mkPrimitive type.string v // {
+      __toString = self: "'${sanitize self.value}'";
+    };
+
+  /* Returns the GVariant object path from the given Nix string value.
+
+     Type:
+       mkObjectpath :: String -> gvariant
+  */
+  mkObjectpath = v:
+    mkPrimitive type.string v // {
+      __toString = self: "objectpath '${escape [ "'" ] self.value}'";
+    };
+
+  /* Returns the GVariant uchar from the given Nix int value.
+
+     Type:
+       mkUchar :: Int -> gvariant
+  */
+  mkUchar = mkPrimitive type.uchar;
+
+  /* Returns the GVariant int16 from the given Nix int value.
+
+     Type:
+       mkInt16 :: Int -> gvariant
+  */
+  mkInt16 = mkPrimitive type.int16;
+
+  /* Returns the GVariant uint16 from the given Nix int value.
+
+     Type:
+       mkUint16 :: Int -> gvariant
+  */
+  mkUint16 = mkPrimitive type.uint16;
+
+  /* Returns the GVariant int32 from the given Nix int value.
+
+     Type:
+       mkInt32 :: Int -> gvariant
+  */
+  mkInt32 = v:
+    mkPrimitive type.int32 v // {
+      __toString = self: toString self.value;
+    };
+
+  /* Returns the GVariant uint32 from the given Nix int value.
+
+     Type:
+       mkUint32 :: Int -> gvariant
+  */
+  mkUint32 = mkPrimitive type.uint32;
+
+  /* Returns the GVariant int64 from the given Nix int value.
+
+     Type:
+       mkInt64 :: Int -> gvariant
+  */
+  mkInt64 = mkPrimitive type.int64;
+
+  /* Returns the GVariant uint64 from the given Nix int value.
+
+     Type:
+       mkUint64 :: Int -> gvariant
+  */
+  mkUint64 = mkPrimitive type.uint64;
+
+  /* Returns the GVariant double from the given Nix float value.
+
+     Type:
+       mkDouble :: Float -> gvariant
+  */
+  mkDouble = v:
+    mkPrimitive type.double v // {
+      __toString = self: toString self.value;
+    };
+}
diff --git a/nixpkgs/lib/tests/modules/gvariant.nix b/nixpkgs/lib/tests/modules/gvariant.nix
new file mode 100644
index 000000000000..a792ebf85b74
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/gvariant.nix
@@ -0,0 +1,93 @@
+{ config, lib, ... }:
+
+let inherit (lib) concatStringsSep mapAttrsToList mkMerge mkOption types gvariant;
+in {
+  options.examples = mkOption { type = types.attrsOf gvariant; };
+
+  config = {
+    examples = with gvariant;
+      mkMerge [
+        { bool = true; }
+        { bool = true; }
+
+        { float = 3.14; }
+
+        { int32 = mkInt32 (- 42); }
+        { int32 = mkInt32 (- 42); }
+
+        { uint32 = mkUint32 42; }
+        { uint32 = mkUint32 42; }
+
+        { int16 = mkInt16 (-42); }
+        { int16 = mkInt16 (-42); }
+
+        { uint16 = mkUint16 42; }
+        { uint16 = mkUint16 42; }
+
+        { int64 = mkInt64 (-42); }
+        { int64 = mkInt64 (-42); }
+
+        { uint64 = mkUint64 42; }
+        { uint64 = mkUint64 42; }
+
+        { array1 = [ "one" ]; }
+        { array1 = mkArray [ "two" ]; }
+        { array2 = mkArray [ (mkInt32 1) ]; }
+        { array2 = mkArray [ (nkUint32 2) ]; }
+
+        { emptyArray1 = [ ]; }
+        { emptyArray2 = mkEmptyArray type.uint32; }
+
+        { string = "foo"; }
+        { string = "foo"; }
+        {
+          escapedString = ''
+            '\
+          '';
+        }
+
+        { tuple = mkTuple [ (mkInt32 1) [ "foo" ] ]; }
+
+        { maybe1 = mkNothing type.string; }
+        { maybe2 = mkJust (mkUint32 4); }
+
+        { variant1 = mkVariant "foo"; }
+        { variant2 = mkVariant 42; }
+
+        { dictionaryEntry = mkDictionaryEntry (mkInt32 1) [ "foo" ]; }
+      ];
+
+    assertions = [
+      {
+        assertion = (
+          let
+            mkLine = n: v: "${n} = ${toString (gvariant.mkValue v)}";
+            result = concatStringsSep "\n" (mapAttrsToList mkLine config.examples);
+          in
+          result + "\n"
+        ) == ''
+          array1 = @as ['one','two']
+          array2 = @au [1,2]
+          bool = true
+          dictionaryEntry = @{ias} {1,@as ['foo']}
+          emptyArray1 = @as []
+          emptyArray2 = @au []
+          escapedString = '\'\\\n'
+          float = 3.140000
+          int = -42
+          int16 = @n -42
+          int64 = @x -42
+          maybe1 = @ms nothing
+          maybe2 = just @u 4
+          string = 'foo'
+          tuple = @(ias) (1,@as ['foo'])
+          uint16 = @q 42
+          uint32 = @u 42
+          uint64 = @t 42
+          variant1 = @v <'foo'>
+          variant2 = @v <42>
+        '';
+      }
+    ];
+  };
+}