summary refs log tree commit diff
path: root/nixos/modules/programs
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2023-09-21 00:05:35 +0200
committerMaximilian Bosch <maximilian@mbosch.me>2023-09-21 13:17:13 +0200
commit11376df6d40c8fdbbd3c9a048b742dc032a88d15 (patch)
tree721577cc368dc8fc2f80910f7d0556ff4c11315c /nixos/modules/programs
parent0a71cf07a82eacd0a618fe7ba7016f7de5f5c2f5 (diff)
downloadnixpkgs-11376df6d40c8fdbbd3c9a048b742dc032a88d15.tar
nixpkgs-11376df6d40c8fdbbd3c9a048b742dc032a88d15.tar.gz
nixpkgs-11376df6d40c8fdbbd3c9a048b742dc032a88d15.tar.bz2
nixpkgs-11376df6d40c8fdbbd3c9a048b742dc032a88d15.tar.lz
nixpkgs-11376df6d40c8fdbbd3c9a048b742dc032a88d15.tar.xz
nixpkgs-11376df6d40c8fdbbd3c9a048b742dc032a88d15.tar.zst
nixpkgs-11376df6d40c8fdbbd3c9a048b742dc032a88d15.zip
nixos/rust-motd: allow ordering sections by `priority`
Closes #234802

The problem here is that with e.g.

    {
      uptime.prefix = "Up";
      banner.command = "hostname | figlet -f slant";
    }

`banner` still appears before `uptime` in the final motd text because
Nix sorts attribute names alphabetically internally.

To work around this without breaking compatibility or losing the
property to override individual sections in other modules - e.g.

    {
      banner.color = mkForce "blue";
    }

I decided to introduce an option `priority` here, similar to the
priority field for `nginx`[1] and with the same semantics (i.e. higher
value means lower priority).

Internally a bunch of env vars are generated, i.e. `env0` to `envN` for
`N` sections with each of them containing a declaration for the TOML,
i.e. `env0` contains `{ uptime.prefix = "Up"; }` and `env1` contains
`{ banner.command = "hostname | figlet -f slant"; }` if `uptime.priority`
is set to a value below 1000.

In this order, the declarations are concatenated together by `jq(1)`
which doesn't sort keys alphabetically which results in a JSON
representation with `uptime` before `banner`. This is finally piped to
`json2toml` which converts this into TOML for rust-motd.

[1] https://nixos.org/manual/nixos/unstable/options#opt-services.nginx.virtualHosts._name_.locations._name_.priority
Diffstat (limited to 'nixos/modules/programs')
-rw-r--r--nixos/modules/programs/rust-motd.nix59
1 files changed, 56 insertions, 3 deletions
diff --git a/nixos/modules/programs/rust-motd.nix b/nixos/modules/programs/rust-motd.nix
index 7fd89e1658e..3e3ce63ab21 100644
--- a/nixos/modules/programs/rust-motd.nix
+++ b/nixos/modules/programs/rust-motd.nix
@@ -5,6 +5,33 @@ with lib;
 let
   cfg = config.programs.rust-motd;
   format = pkgs.formats.toml { };
+
+  orderedSections = listToAttrs
+    (imap0
+      (i: items@{ sectionHeader, ... }: nameValuePair "env${toString i}" {
+        ${sectionHeader} = removeAttrs items [ "priority" "sectionHeader" ];
+      })
+      (sortProperties (mapAttrsToList (k: v: v // { sectionHeader = k; }) cfg.settings)));
+
+  # Order the sections in the TOML according to the `priority` field.
+  # This is done by
+  # * creating an attribute set with keys `env0`/`env1`/.../`envN`
+  #   where `env0` contains the first section and `envN` the last
+  #   (in the form of `{ sectionName = { /* ... */ }}`)
+  # * the declarations of `env0` to `envN` in ascending order are
+  #   concatenated with `jq`. Now we have a JSON representation of
+  #   the config in the correct order.
+  # * this is piped to `json2toml` to get the correct format for rust-motd.
+  motdConf = pkgs.runCommand "motd.conf"
+    (orderedSections // {
+      __structuredAttrs = true;
+      nativeBuildInputs = [ pkgs.remarshal pkgs.jq ];
+    })
+    ''
+      cat "$NIX_BUILD_TOP"/.attrs.json \
+        | jq '${concatMapStringsSep " + " (key: ''."${key}"'') (attrNames orderedSections)}' \
+        | json2toml /dev/stdin "$out"
+    '';
 in {
   options.programs.rust-motd = {
     enable = mkEnableOption (lib.mdDoc "rust-motd");
@@ -28,9 +55,35 @@ in {
       '';
     };
     settings = mkOption {
-      type = types.submodule {
+      type = types.attrsOf (types.submodule {
         freeformType = format.type;
-      };
+        options.priority = mkOption {
+          type = types.int;
+          default = modules.defaultOrderPriority;
+          description = mdDoc ''
+            In `rust-motd`, the order of the sections in TOML correlates to the order
+            of the items displayed in the resulting `motd`. Attributes in Nix are
+            ordered alphabetically, e.g. `banner` would always be before `uptime`.
+
+            To change that, this option can be used. The lower this number is, the higher
+            is the priority and the more a section is at the top of the message.
+
+            For instance
+
+            ```nix
+            {
+              banner.command = "hostname | figlet -f slant";
+              uptime = {
+                prefix = "Up";
+                priority = 0;
+              };
+            }
+            ```
+
+            would make the `uptime` appear before the banner.
+          '';
+        };
+      });
       description = mdDoc ''
         Settings on what to generate. Please read the
         [upstream documentation](https://github.com/rust-motd/rust-motd/blob/main/README.md#configuration)
@@ -53,7 +106,7 @@ in {
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
         ExecStart = "${pkgs.writeShellScript "update-motd" ''
-          ${pkgs.rust-motd}/bin/rust-motd ${format.generate "motd.conf" cfg.settings} > motd
+          ${pkgs.rust-motd}/bin/rust-motd ${motdConf} > motd
         ''}";
         CapabilityBoundingSet = [ "" ];
         LockPersonality = true;