1
0
Fork 0
mirror of https://github.com/nix-community/home-manager.git synced 2025-11-08 19:46:05 +01:00

generators: rewrite toSCFG

The former toSCFG implementation had several shortcomings which
did not consider a few possibilities SCFG provides. Details were lined
out in #7465.
The new interface needs more verbosity, but reflects better the
properties of the SCFG format. I also chose to use the names used in the
[Specification].

[Specification]: https://git.sr.ht/~emersion/scfg#specification-draft
This commit is contained in:
Anton Mosich 2025-09-01 23:40:41 +02:00 committed by Matthieu Coudron
parent c9d758b500
commit 89a9fa0f3f
4 changed files with 80 additions and 90 deletions

View file

@ -211,9 +211,15 @@
toSCFG = toSCFG =
{ }: { }:
let let
inherit (lib) concatStringsSep mapAttrsToList any; inherit (lib) concatStringsSep any;
inherit (builtins) typeOf replaceStrings elem; inherit (builtins) typeOf replaceStrings elem;
filterNullDirectives = lib.filter (
directive:
!(directive ? "params" || directive ? "children")
|| !(directive.params or [ null ] == [ null ] && directive.children or [ ] == [ ])
);
# ListOf String -> String # ListOf String -> String
indentStrings = indentStrings =
let let
@ -221,8 +227,8 @@
# the strings themselves *will* contain newlines, so you need # the strings themselves *will* contain newlines, so you need
# to normalize the list by joining and resplitting them. # to normalize the list by joining and resplitting them.
unlines = lib.splitString "\n"; unlines = lib.splitString "\n";
lines = lib.concatStringsSep "\n"; lines = concatStringsSep "\n";
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines); indentAll = lines: concatStringsSep "\n" (map (x: "\t" + x) lines);
in in
stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines)); stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));
@ -256,7 +262,7 @@
"\\" "\\"
"\r" "\r"
"\n" "\n"
" " "\t"
]; ];
# OneOf [Int Float String Bool] -> String # OneOf [Int Float String Bool] -> String
@ -284,7 +290,7 @@
# Bool -> ListOf (OneOf [Int Float String Bool]) -> String # Bool -> ListOf (OneOf [Int Float String Bool]) -> String
toOptParamsString = toOptParamsString =
cond: list: cond: list:
lib.optionalString (cond) ( lib.optionalString cond (
lib.pipe list [ lib.pipe list [
(map literalValueToString) (map literalValueToString)
(concatStringsSep " ") (concatStringsSep " ")
@ -292,65 +298,25 @@
] ]
); );
# Attrset Conversion # Directive Conversion
# String -> AttrsOf Anything -> String # ListOf NameParamChildrenTriplet -> ListOf String
convertAttrsToSCFG = convertDirectivesToSCFG =
name: attrs: directives:
let map (
optParamsString = toOptParamsString (attrs ? "_params") attrs._params; directive:
in (literalValueToString directive.name)
'' + toOptParamsString (directive ? "params" && directive.params != null) directive.params
${name}${optParamsString} { + lib.optionalString (directive ? "children" && directive.children != null) (
${indentStrings (convertToAttrsSCFG' attrs)} " "
}''; + ''
{
# Attrset Conversion ${indentStrings (convertDirectivesToSCFG directive.children)}
# AttrsOf Anything -> ListOf String }''
convertToAttrsSCFG' = )
attrs: ) (filterNullDirectives directives);
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 in
attrs: directives:
lib.optionalString (attrs != { }) '' lib.optionalString (directives != [ ]) ''
${concatStringsSep "\n" (convertToAttrsSCFG' attrs)} ${lib.concatStringsSep "\n" (convertDirectivesToSCFG directives)}
''; '';
} }

View file

@ -1,7 +1,7 @@
{ lib, ... }: { lib, ... }:
{ {
home.file."toscfg-empty-result.txt".text = lib.hm.generators.toSCFG { } { }; home.file."toscfg-empty-result.txt".text = lib.hm.generators.toSCFG { } [ ];
nmt.script = '' nmt.script = ''
assertFileContent \ assertFileContent \

View file

@ -2,8 +2,9 @@ dir {
blk1 p1 "\"p2\"" { blk1 p1 "\"p2\"" {
sub1 arg11 arg12 sub1 arg11 arg12
sub2 arg21 arg22 sub2 arg21 arg22
sub2 arg1 arg2
sub3 arg31 arg32 { sub3 arg31 arg32 {
sub-sub1 "sub sub1"
sub-sub2 arg321 arg322 sub-sub2 arg321 arg322
} }
} }

View file

@ -1,35 +1,58 @@
{ lib, ... }: { lib, ... }:
{ {
home.file."toscfg-example-result.txt".text = lib.hm.generators.toSCFG { } { home.file."toscfg-example-result.txt".text = lib.hm.generators.toSCFG { } (
dir = { lib.singleton {
blk1 = { name = "dir";
_params = [ children = lib.singleton {
name = "blk1";
params = [
"p1" "p1"
''"p2"'' ''"p2"''
]; ];
sub1 = [ children = [
"arg11" {
"arg12" name = "sub1";
params = [
"arg11"
"arg12"
];
}
{
name = "sub2";
params = [
"arg21"
"arg22"
];
}
{
name = "sub2";
params = [
"arg1"
"arg2"
];
}
{
name = "sub3";
params = [
"arg31"
"arg32"
];
children = [
{ name = "sub sub1"; }
{
name = "sub-sub2";
params = [
"arg321"
"arg322"
];
}
];
}
]; ];
sub2 = [
"arg21"
"arg22"
];
sub3 = {
_params = [
"arg31"
"arg32"
];
sub-sub1 = [ ];
sub-sub2 = [
"arg321"
"arg322"
];
};
}; };
}; }
}; );
nmt.script = '' nmt.script = ''
assertFileContent \ assertFileContent \