Commit 1dd7bb2b authored by Domen Kožar's avatar Domen Kožar Committed by GitHub
Browse files

Merge pull request #20507 from Profpatsch/lib-ini-generator

lib: File generators from Nix Expressions
parents 065fa2fe 53fc7b82
Loading
Loading
Loading
Loading
+392 −349
Original line number Diff line number Diff line
@@ -8,6 +8,15 @@
  The nixpkgs repository has several utility functions to manipulate Nix expressions.
</para>

<section xml:id="sec-overrides">
  <title>Overriding</title>

  <para>
    Sometimes one wants to override parts of
    <literal>nixpkgs</literal>, e.g. derivation attributes, the results of
    derivations or even the whole package set.
  </para>

  <section xml:id="sec-pkgs-overridePackages">
    <title>pkgs.overridePackages</title>

@@ -258,6 +267,40 @@ c = lib.makeOverridable f { a = 1; b = 2; }</programlisting>

  </section>

</section>

<section xml:id="sec-generators">
  <title>Generators</title>

  <para>
    Generators are functions that create file formats from nix
    data structures, e. g. for configuration files.
    There are generators available for: <literal>INI</literal>,
    <literal>JSON</literal> and <literal>YAML</literal>
  </para>

  <para>
    All generators follow a similar call interface: <code>generatorName
    configFunctions data</code>, where <literal>configFunctions</literal> is a
    set of user-defined functions that format variable parts of the content.
    They each have common defaults, so often they do not need to be set
    manually. An example is <code>mkSectionName ? (name: libStr.escape [ "[" "]"
    ] name)</code> from the <literal>INI</literal> generator. It gets the name
    of a section and returns a sanitized name. The default
    <literal>mkSectionName</literal> escapes <literal>[</literal> and
    <literal>]</literal> with a backslash. 
  </para>

  <note><para>Nix store paths can be converted to strings by enclosing a
  derivation attribute like so: <code>"${drv}"</code>.</para></note>

  <para>
    Detailed documentation for each generator can be found in
    <literal>lib/generators.nix</literal>.
  </para>

</section>


<section xml:id="sec-fhs-environments">
  <title>buildFHSUserEnv</title>
+2 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ let

  # misc
  debug = import ./debug.nix;
  generators = import ./generators.nix;
  misc = import ./deprecated.nix;

  # domain-specific
@@ -39,7 +40,7 @@ in
            customisation maintainers meta sources
            modules options types
            licenses platforms systems
            debug misc
            debug generators misc
            sandbox fetchers;
  }
  # !!! don't include everything at top-level; perhaps only the most

lib/generators.nix

0 → 100644
+72 −0
Original line number Diff line number Diff line
/* Functions that generate widespread file
 * formats from nix data structures.
 *
 * They all follow a similar interface:
 * generator { config-attrs } data
 *
 * Tests can be found in ./tests.nix
 * Documentation in the manual, #sec-generators
 */
with import ./trivial.nix;
let
  libStr = import ./strings.nix;
  libAttr = import ./attrsets.nix;

  flipMapAttrs = flip libAttr.mapAttrs;
in

rec {

  /* Generates an INI-style config file from an
   * attrset of sections to an attrset of key-value pairs.
   *
   * generators.toINI {} {
   *   foo = { hi = "${pkgs.hello}"; ciao = "bar"; };
   *   baz = { "also, integers" = 42; };
   * }
   *
   *> [baz]
   *> also, integers=42
   *>
   *> [foo]
   *> ciao=bar
   *> hi=/nix/store/y93qql1p5ggfnaqjjqhxcw0vqw95rlz0-hello-2.10
   *
   * The mk* configuration attributes can generically change
   * the way sections and key-value strings are generated.
   *
   * For more examples see the test cases in ./tests.nix.
   */
  toINI = {
    # apply transformations (e.g. escapes) to section names
    mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
    # format a setting line from key and value
    mkKeyValue    ? (k: v: "${libStr.escape ["="] k}=${toString v}")
  }: attrsOfAttrs:
    let
        # map function to string for each key val
        mapAttrsToStringsSep = sep: mapFn: attrs:
          libStr.concatStringsSep sep
            (libAttr.mapAttrsToList mapFn attrs);
        mkLine = k: v: mkKeyValue k v + "\n";
        mkSection = sectName: sectValues: ''
          [${mkSectionName sectName}]
        '' + libStr.concatStrings (libAttr.mapAttrsToList mkLine sectValues);
    in
      # map input to ini sections
      mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;


  /* Generates JSON from an arbitrary (non-function) value.
    * For more information see the documentation of the builtin.
    */
  toJSON = {}: builtins.toJSON;


  /* YAML has been a strict superset of JSON since 1.2, so we
    * use toJSON. Before it only had a few differences referring
    * to implicit typing rules, so it should work with older
    * parsers as well.
    */
  toYAML = {}@args: toJSON args;
}
+74 −0
Original line number Diff line number Diff line
@@ -130,4 +130,78 @@ runTests {
    expected = false;
  };


  /* Generator tests */
  # these tests assume attributes are converted to lists
  # in alphabetical order

  testToINIEmpty = {
    expr = generators.toINI {} {};
    expected = "";
  };

  testToINIEmptySection = {
    expr = generators.toINI {} { foo = {}; bar = {}; };
    expected = ''
      [bar]

      [foo]
    '';
  };

  testToINIDefaultEscapes = {
    expr = generators.toINI {} {
      "no [ and ] allowed unescaped" = {
        "and also no = in keys" = 42;
      };
    };
    expected = ''
      [no \[ and \] allowed unescaped]
      and also no \= in keys=42
    '';
  };

  testToINIDefaultFull = {
    expr = generators.toINI {} {
      "section 1" = {
        attribute1 = 5;
        x = "Me-se JarJar Binx";
      };
      "foo[]" = {
        "he\\h=he" = "this is okay";
      };
    };
    expected = ''
      [foo\[\]]
      he\h\=he=this is okay

      [section 1]
      attribute1=5
      x=Me-se JarJar Binx
    '';
  };

  /* right now only invocation check */
  testToJSONSimple =
    let val = {
      foobar = [ "baz" 1 2 3 ];
    };
    in {
      expr = generators.toJSON {} val;
      # trival implementation
      expected = builtins.toJSON val;
  };

  /* right now only invocation check */
  testToYAMLSimple =
    let val = {
      list = [ { one = 1; } { two = 2; } ];
      all = 42;
    };
    in {
      expr = generators.toYAML {} val;
      # trival implementation
      expected = builtins.toJSON val;
  };

}