mirror of
https://github.com/nix-community/home-manager
synced 2024-12-19 08:19:48 +01:00
senpai: switch to scfg format
This commit is contained in:
parent
029545350c
commit
ca922258e1
15 changed files with 275 additions and 20 deletions
|
@ -99,4 +99,97 @@
|
||||||
in attrs: ''
|
in attrs: ''
|
||||||
${concatStringsSep "\n" (mapAttrsToList convertAttributeToKDL 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 (reserved ++ [ " " "'" "{" "}" ]))
|
||||||
|
(lib.stringToCharacters s);
|
||||||
|
|
||||||
|
# String -> String
|
||||||
|
sanitizeString =
|
||||||
|
replaceStrings reserved [ ''\"'' "\\\\" "\\r" "\\n" "\\t" ];
|
||||||
|
|
||||||
|
reserved = [ ''"'' "\\" "\r" "\n" " " ];
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
|
||||||
|
# Bool -> ListOf (OneOf [Int Float String Bool]) -> String
|
||||||
|
toOptParamsString = cond: list:
|
||||||
|
lib.optionalString (cond) (lib.pipe list [
|
||||||
|
(map literalValueToString)
|
||||||
|
(concatStringsSep " ")
|
||||||
|
(s: " " + s)
|
||||||
|
]);
|
||||||
|
|
||||||
|
# Attrset Conversion
|
||||||
|
# String -> AttrsOf Anything -> String
|
||||||
|
convertAttrsToSCFG = name: attrs:
|
||||||
|
let
|
||||||
|
optParamsString = toOptParamsString (attrs ? "_params") attrs._params;
|
||||||
|
in ''
|
||||||
|
${name}${optParamsString} {
|
||||||
|
${indentStrings (convertToAttrsSCFG' attrs)}
|
||||||
|
}'';
|
||||||
|
|
||||||
|
# Attrset Conversion
|
||||||
|
# AttrsOf Anything -> ListOf String
|
||||||
|
convertToAttrsSCFG' = attrs:
|
||||||
|
mapAttrsToList convertAttributeToSCFG
|
||||||
|
(lib.filterAttrs (name: val: !isNull val && name != "_params") attrs);
|
||||||
|
|
||||||
|
# List Conversion
|
||||||
|
# String -> ListOf (OneOf [Int Float String Bool]) -> String
|
||||||
|
convertListOfFlatAttrsToSCFG = name: list:
|
||||||
|
let optParamsString = toOptParamsString (list != [ ]) list;
|
||||||
|
in "${name}${optParamsString}";
|
||||||
|
|
||||||
|
# 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}
|
||||||
|
'');
|
||||||
|
in attrs:
|
||||||
|
lib.optionalString (attrs != { }) ''
|
||||||
|
${concatStringsSep "\n" (convertToAttrsSCFG' attrs)}
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let cfg = config.programs.senpai;
|
||||||
cfg = config.programs.senpai;
|
|
||||||
cfgFmt = pkgs.formats.yaml { };
|
|
||||||
in {
|
in {
|
||||||
options.programs.senpai = {
|
options.programs.senpai = {
|
||||||
enable = mkEnableOption "senpai";
|
enable = mkEnableOption "senpai";
|
||||||
|
@ -16,23 +14,30 @@ in {
|
||||||
};
|
};
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
type = types.submodule {
|
type = types.submodule {
|
||||||
freeformType = cfgFmt.type;
|
freeformType = types.attrsOf types.anything;
|
||||||
options = {
|
options = {
|
||||||
addr = mkOption {
|
address = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = ''
|
description = ''
|
||||||
The address (host[:port]) of the IRC server. senpai uses TLS
|
The address (`host[:port]`) of the IRC server. senpai uses TLS
|
||||||
connections by default unless you specify no-tls option. TLS
|
connections by default unless you specify tls option to be false.
|
||||||
connections default to port 6697, plain-text use port 6667.
|
TLS connections default to port 6697, plain-text use port 6667.
|
||||||
|
|
||||||
|
UR`ircs://`, `irc://`, and `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;
|
type = types.str;
|
||||||
description = ''
|
description = ''
|
||||||
Your nickname, sent with a NICK IRC message. It mustn't contain
|
Your nickname, sent with a NICK IRC message. It mustn't contain
|
||||||
spaces or colons (:).
|
spaces or colons (:).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
password = mkOption {
|
password = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
@ -41,17 +46,28 @@ in {
|
||||||
reside world-readable in the Nix store.
|
reside world-readable in the Nix store.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
no-tls = mkOption {
|
|
||||||
type = types.bool;
|
password-cmd = mkOption {
|
||||||
default = false;
|
type = types.nullOr (types.listOf types.str);
|
||||||
description = "Disables TLS encryption.";
|
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 `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 ''
|
example = literalExpression ''
|
||||||
{
|
{
|
||||||
addr = "libera.chat:6697";
|
address = "libera.chat:6697";
|
||||||
nick = "nicholas";
|
nickname = "nicholas";
|
||||||
password = "verysecurepassword";
|
password = "verysecurepassword";
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
@ -63,9 +79,27 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
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 ];
|
home.packages = [ cfg.package ];
|
||||||
xdg.configFile."senpai/senpai.yaml".source =
|
xdg.configFile."senpai/senpai.scfg".text =
|
||||||
cfgFmt.generate "senpai.yaml" cfg.config;
|
lib.hm.generators.toSCFG { } cfg.config;
|
||||||
};
|
};
|
||||||
|
|
||||||
meta.maintainers = [ hm.maintainers.malvo ];
|
meta.maintainers = [ hm.maintainers.malvo ];
|
||||||
|
|
|
@ -136,6 +136,7 @@ in import nmtSrc {
|
||||||
./modules/programs/sapling
|
./modules/programs/sapling
|
||||||
./modules/programs/sbt
|
./modules/programs/sbt
|
||||||
./modules/programs/scmpuff
|
./modules/programs/scmpuff
|
||||||
|
./modules/programs/senpai
|
||||||
./modules/programs/sftpman
|
./modules/programs/sftpman
|
||||||
./modules/programs/sioyek
|
./modules/programs/sioyek
|
||||||
./modules/programs/sm64ex
|
./modules/programs/sm64ex
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
{ generators-tokdl = ./tokdl.nix; }
|
{
|
||||||
|
generators-tokdl = ./tokdl.nix;
|
||||||
|
generators-toscfg-empty = ./toscfg-empty.nix;
|
||||||
|
generators-toscfg-example = ./toscfg-example.nix;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
home.file."result.txt".text = lib.hm.generators.toKDL { } {
|
home.file."tokdl-result.txt".text = lib.hm.generators.toKDL { } {
|
||||||
a = 1;
|
a = 1;
|
||||||
b = "string";
|
b = "string";
|
||||||
c = ''
|
c = ''
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
nmt.script = ''
|
nmt.script = ''
|
||||||
assertFileContent \
|
assertFileContent \
|
||||||
home-files/result.txt \
|
home-files/tokdl-result.txt \
|
||||||
${./tokdl-result.txt}
|
${./tokdl-result.txt}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
0
tests/lib/generators/toscfg-empty-result.txt
Normal file
0
tests/lib/generators/toscfg-empty-result.txt
Normal file
11
tests/lib/generators/toscfg-empty.nix
Normal file
11
tests/lib/generators/toscfg-empty.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
home.file."toscfg-empty-result.txt".text = lib.hm.generators.toSCFG { } { };
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileContent \
|
||||||
|
home-files/toscfg-empty-result.txt \
|
||||||
|
${./toscfg-empty-result.txt}
|
||||||
|
'';
|
||||||
|
}
|
12
tests/lib/generators/toscfg-err-dir-empty-name.nix
Normal file
12
tests/lib/generators/toscfg-err-dir-empty-name.nix
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
home.file."toscfg-err-dir-empty-name-result.txt".text =
|
||||||
|
lib.hm.generators.toSCFG { } { "" = [ ]; };
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileContent \
|
||||||
|
home-files/toscfg-err-dir-empty-name-result.txt \
|
||||||
|
${./toscfg-err-dir-empty-name-result.txt}
|
||||||
|
'';
|
||||||
|
}
|
10
tests/lib/generators/toscfg-example-result.txt
Normal file
10
tests/lib/generators/toscfg-example-result.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
dir {
|
||||||
|
blk1 p1 "\"p2\"" {
|
||||||
|
sub1 arg11 arg12
|
||||||
|
sub2 arg21 arg22
|
||||||
|
sub3 arg31 arg32 {
|
||||||
|
sub-sub1
|
||||||
|
sub-sub2 arg321 arg322
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
tests/lib/generators/toscfg-example.nix
Normal file
24
tests/lib/generators/toscfg-example.nix
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
home.file."toscfg-example-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-example-result.txt \
|
||||||
|
${./toscfg-example-result.txt}
|
||||||
|
'';
|
||||||
|
}
|
4
tests/modules/programs/senpai/default.nix
Normal file
4
tests/modules/programs/senpai/default.nix
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
senpai-example-settings = ./example-settings.nix;
|
||||||
|
senpai-empty-settings = ./empty-settings.nix;
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
address irc.libera.chat
|
||||||
|
nickname Guest123456
|
20
tests/modules/programs/senpai/empty-settings.nix
Normal file
20
tests/modules/programs/senpai/empty-settings.nix
Normal file
|
@ -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
tests/modules/programs/senpai/example-settings-expected.conf
Normal file
13
tests/modules/programs/senpai/example-settings-expected.conf
Normal file
|
@ -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
tests/modules/programs/senpai/example-settings.nix
Normal file
27
tests/modules/programs/senpai/example-settings.nix
Normal file
|
@ -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}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue