Skip to content

Commit

Permalink
senpai: switch to scfg format
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick Widmer committed Nov 12, 2023
1 parent 691cbcc commit 2366926
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 20 deletions.
98 changes: 98 additions & 0 deletions modules/lib/generators.nix
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,102 @@
in attrs: ''
${concatStringsSep "\n" (mapAttrsToList convertAttributeToKDL attrs)}
'';

toSCFG = { }:
let
inherit (lib) concatStringsSep mapAttrsToList any;
inherit (builtins) typeOf replaceStrings elem;

# ListOf String -> String
indentStrings = let
# Although the input of this function is a list of strings,
# the strings themselves *will* contain newlines, so you need
# to normalize the list by joining and resplitting them.
unlines = lib.splitString "\n";
lines = lib.concatStringsSep "\n";
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines);
in stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));

# String -> Bool
specialChars = s:
any (char: elem char [ ''"'' "\\" "\r" "\n" "'" "{" "}" " " " " ])
(lib.stringToCharacters s);

# String -> String
sanitizeString = replaceStrings [ ''"'' "\\" "\r" "\n" " " ] [
''\"''
"\\\\"
"\\r"
"\\n"
"\\t"
];

# OneOf [Int Float String Bool] -> String
literalValueToString = element:
lib.throwIfNot (elem (typeOf element) [ "int" "float" "string" "bool" ])
"Cannot convert value of type ${typeOf element} to SCFG literal."
(if element == false then
"false"
else if element == true then
"true"
else if typeOf element == "string" then
if element == "" || specialChars element then
''"${sanitizeString element}"''
else
element
else
toString element);

# Attrset Conversion
# String -> AttrsOf Anything -> String
convertAttrsToSCFG = name: attrs:
let
optParamsString = lib.optionalString (attrs ? "_params")
(lib.pipe attrs._params [
(map literalValueToString)
(lib.concatStringsSep " ")
(s: s + " ")
]);
in ''
${name} ${optParamsString}{
${indentStrings
(mapAttrsToList convertAttributeToSCFG (filterAttrsSCFG attrs))}
}'';

# List Conversion
# String -> ListOf (OneOf [Int Float String Bool]) -> String
convertListOfFlatAttrsToSCFG = name: list:
if list == [ ] then
name
else
let flatElements = map literalValueToString list;
in "${name} ${concatStringsSep " " flatElements}";

# Combined Conversion
# String -> Anything -> String
convertAttributeToSCFG = name: value:
lib.throwIf (name == "") "Directive must not be empty"
(let vType = typeOf value;
in if elem vType [ "int" "float" "bool" "string" ] then
"${name} ${literalValueToString value}"
else if vType == "set" then
convertAttrsToSCFG name value
else if vType == "list" then
convertListOfFlatAttrsToSCFG name value
else
throw ''
Cannot convert type `(${typeOf value})` to SCFG:
${name} = ${toString value}
'');

# AttrsOf Anything -> AttrsOf Anything
filterAttrsSCFG =
lib.filterAttrs (name: val: !isNull val && name != "_params");
in attrs:
if attrs == { } then
''""''
else ''
${concatStringsSep "\n"
(mapAttrsToList convertAttributeToSCFG (filterAttrsSCFG attrs))}
'';
}
67 changes: 50 additions & 17 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,23 @@ in {
};
config = mkOption {
type = types.submodule {
freeformType = cfgFmt.type;
freeformType = types.attrsOf types.anything;
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 (<literal>host[:port]</literal>) 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.
<literal>ircs://</literal>, <literal>irc://</literal>, and
<literal>irc+insecure://</literal> 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,17 +45,28 @@ 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.listOf types.str);
default = null;
example = [ "gopass" "show" "irc/guest" ];
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 <literal>pass</literal>
or <literal>gopass</literal>. If a password-cmd is provided, the
value of password will be ignored and the first line of the output
of <literal>password-cmd</literal> will be used
for login.
'';
};
};
};
example = literalExpression ''
{
addr = "libera.chat:6697";
nick = "nicholas";
address = "libera.chat:6697";
nickname = "nicholas";
password = "verysecurepassword";
}
'';
Expand All @@ -63,9 +78,27 @@ in {
};

config = mkIf cfg.enable {
assertions = with cfg.config; [
{
assertion = !isNull password-cmd -> isNull password;
message = "senpai: password-cmd overrides password!";
}
{
assertion = !cfg.config ? addr;
message = "senpai: addr is deprecated, use address instead";
}
{
assertion = !cfg.config ? nick;
message = "senpai: nick is deprecated, use nickname instead";
}
{
assertion = !cfg.config ? no-tls;
message = "senpai: no-tls is deprecated, use tls instead";
}
];
home.packages = [ cfg.package ];
xdg.configFile."senpai/senpai.yaml".source =
cfgFmt.generate "senpai.yaml" cfg.config;
xdg.configFile."senpai/senpai.scfg".text =
lib.hm.generators.toSCFG { } cfg.config;
};

meta.maintainers = [ hm.maintainers.malvo ];
Expand Down
1 change: 1 addition & 0 deletions tests/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,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
5 changes: 4 additions & 1 deletion tests/lib/generators/default.nix
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
{ generators-tokdl = ./tokdl.nix; }
{
generators-tokdl = ./tokdl.nix;
generators-toscfg = ./toscfg.nix;
}
4 changes: 2 additions & 2 deletions tests/lib/generators/tokdl.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{ config, lib, ... }:

{
home.file."result.txt".text = lib.hm.generators.toKDL { } {
home.file."tokdl/result.txt".text = lib.hm.generators.toKDL { } {
a = 1;
b = "string";
c = ''
Expand Down Expand Up @@ -47,7 +47,7 @@

nmt.script = ''
assertFileContent \
home-files/result.txt \
home-files/tokdl/result.txt \
${./tokdl-result.txt}
'';
}
10 changes: 10 additions & 0 deletions tests/lib/generators/toscfg-result.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
dir {
blk1 p1 "\"p2\"" {
sub1 arg11 arg12
sub2 arg21 arg22
sub3 arg31 arg32 {
sub-sub1
sub-sub2 arg321 arg322
}
}
}
24 changes: 24 additions & 0 deletions tests/lib/generators/toscfg.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{ config, lib, ... }:

{
home.file."toscfg/result.txt".text = lib.hm.generators.toSCFG { } {
dir = {
blk1 = {
_params = [ "p1" ''"p2"'' ];
sub1 = [ "arg11" "arg12" ];
sub2 = [ "arg21" "arg22" ];
sub3 = {
_params = [ "arg31" "arg32" ];
sub-sub1 = [ ];
sub-sub2 = [ "arg321" "arg322" ];
};
};
};
};

nmt.script = ''
assertFileContent \
home-files/toscfg/result.txt \
${./toscfg-result.txt}
'';
}
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}
'';
};
}
13 changes: 13 additions & 0 deletions tests/modules/programs/senpai/example-settings-expected.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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
realname "Guest von Lenon"
username senpai
27 changes: 27 additions & 0 deletions tests/modules/programs/senpai/example-settings.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{ config, ... }:

{
config = {
programs.senpai = {
enable = true;
package = config.lib.test.mkStubPackage { };
config = {
address = "irc.libera.chat";
nickname = "Guest123456";
password-cmd = [ "gopass" "show" "irc/guest" ];
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}
'';
};
}

0 comments on commit 2366926

Please sign in to comment.