Skip to content

senpai: use SCFG format #4086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
92 changes: 66 additions & 26 deletions modules/programs/senpai.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

with lib;

let
cfg = config.programs.senpai;
cfgFmt = pkgs.formats.yaml { };
let cfg = config.programs.senpai;
in {
options.programs.senpai = {
enable = mkEnableOption "senpai";
Expand All @@ -16,17 +14,21 @@ in {
};
config = mkOption {
type = types.submodule {
freeformType = cfgFmt.type;
options = {
addr = mkOption {
address = mkOption {
type = types.str;
description = ''
The address (host[:port]) of the IRC server. senpai uses TLS
connections by default unless you specify no-tls option. TLS
connections default to port 6697, plain-text use port 6667.
The address (_host[:port]_) of the IRC server. senpai uses TLS
connections by default unless you specify tls option to be false.
TLS connections default to port 6697, plain-text use port 6667.

ircs:// & irc:// & irc+insecure:// URLs are supported, in which
case only the hostname and port parts will be used. If the scheme
is ircs/irc+insecure, tls will be overriden and set to true/false
accordingly.
'';
};
nick = mkOption {
nickname = mkOption {
type = types.str;
description = ''
Your nickname, sent with a NICK IRC message. It mustn't contain
Expand All @@ -41,33 +43,71 @@ in {
reside world-readable in the Nix store.
'';
};
no-tls = mkOption {
type = types.bool;
default = false;
description = "Disables TLS encryption.";
password-cmd = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Alternatively to providing your SASL authentication password
directly in plaintext, you can specify a command to be run to
fetch the password at runtime. This is useful if you store your
passwords in a separate (probably encrypted) file using `gpg` or
a command line password manager such as _pass_ or _gopass_. If a
password-cmd is provided, the value of password will be ignored
and the first line of the output of *password-cmd* will be used
for login.
'';
};
};
};
example = literalExpression ''
{
addr = "libera.chat:6697";
nick = "nicholas";
password = "verysecurepassword";
}
'';
};
extraConfig = mkOption {
type = types.attrs;
default = { };
description = ''
Configuration for senpai. For a complete list of options, see
<citerefentry><refentrytitle>senpai</refentrytitle>
<manvolnum>5</manvolnum></citerefentry>.
Options that should be appended to the senpai configuration file.
'';
};
example = literalExpression ''
{
address = "libera.chat:6697";
nickname = "nicholas";
password = "verysecurepassword";
}
'';
description = ''
Configuration for senpai. For a complete list of options, see
<citerefentry><refentrytitle>senpai</refentrytitle>
<manvolnum>5</manvolnum></citerefentry>.
'';
};

config = mkIf cfg.enable {
warnings = with cfg.config;
if (password-cmd != null && password != null) then
[ "senpai: password-command overrides password!" ]
else
[ ];
home.packages = [ cfg.package ];
xdg.configFile."senpai/senpai.yaml".source =
cfgFmt.generate "senpai.yaml" cfg.config;
xdg.configFile."senpai/senpai.scfg".text = let
toSCFG' = v:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an inline generator for the (pretty custom) SCFG format. Would a PR to add this to generators.nix be more appropriate?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in this PR.

if isAttrs v then ''
{
${toSCFG v}
}
'' else if isList v then
concatStringsSep " " v
else if isString v then
v
else if isInt v || isFloat v || isBool v then
builtins.toJSON v
else
abort "toSCFG: type ${builtins.typeOf v} is unsupported";
toSCFG = v:
concatStringsSep "\n"
(mapAttrsToList (key: val: "${key} ${toSCFG' val}")
(filterAttrs (_: val: val != null && val != { }) v));
in toSCFG (cfg.config // cfg.extraConfig);
};

meta.maintainers = [ hm.maintainers.malvo ];
meta.maintainers = [ maintainers.jleightcap ];
}
1 change: 1 addition & 0 deletions tests/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ import nmt {
./modules/programs/sagemath
./modules/programs/sbt
./modules/programs/scmpuff
./modules/programs/senpai
./modules/programs/sioyek
./modules/programs/sm64ex
./modules/programs/ssh
Expand Down
4 changes: 4 additions & 0 deletions tests/modules/programs/senpai/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
senpai-example-settings = ./example-settings.nix;
senpai-empty-settings = ./empty-settings.nix;
}
2 changes: 2 additions & 0 deletions tests/modules/programs/senpai/empty-settings-expected.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
address irc.libera.chat
nickname Guest123456
20 changes: 20 additions & 0 deletions tests/modules/programs/senpai/empty-settings.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{ config, ... }:

{
config = {
programs.senpai = {
enable = true;
package = config.lib.test.mkStubPackage { };
config = {
address = "irc.libera.chat";
nickname = "Guest123456";
};
};

nmt.script = ''
assertFileContent \
home-files/.config/senpai/senpai.scfg \
${./empty-settings-expected.conf}
'';
};
}
15 changes: 15 additions & 0 deletions tests/modules/programs/senpai/example-settings-expected.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
address irc.libera.chat
channel #rahxephon
colors {
prompt 2
}

highlight guest senpai lenon
nickname Guest123456
pane-widths {
nicknames 16
}

password-cmd gopass show irc/guest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be password-cmd "gopass show irc/guest"?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@ncfavier ncfavier Jun 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does, but password-cmd is intentionally parsed as a list of arguments to be fed to an execve-like interface, rather than a single shell command string: https://git.sr.ht/~taiite/senpai/tree/master/item/config.go#L199-214

The option should reflect that by having type nullOr (listOf str). This will avoid giving users the illusion that they can use shell syntax and quoting.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I understand. Thank you for the well reasoned response -- an option wrapping execve as a list of strings is much more correct 🙂

realname Guest von Lenon
username senpai
29 changes: 29 additions & 0 deletions tests/modules/programs/senpai/example-settings.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{ config, ... }:

{
config = {
programs.senpai = {
enable = true;
package = config.lib.test.mkStubPackage { };
config = {
address = "irc.libera.chat";
nickname = "Guest123456";
password-cmd = "gopass show irc/guest";
};
extraConfig = {
username = "senpai";
realname = "Guest von Lenon";
channel = [ "#rahxephon" ];
highlight = [ "guest" "senpai" "lenon" ];
pane-widths = { nicknames = 16; };
colors = { prompt = 2; };
};
};

nmt.script = ''
assertFileContent \
home-files/.config/senpai/senpai.scfg \
${./example-settings-expected.conf}
'';
};
}