Skip to content

Commit

Permalink
formats.xenLight: init
Browse files Browse the repository at this point in the history
Signed-off-by: Fernando Rodrigues <[email protected]>
  • Loading branch information
SigmaSquadron committed Dec 11, 2024
1 parent c629271 commit 74bbd20
Showing 1 changed file with 167 additions and 0 deletions.
167 changes: 167 additions & 0 deletions pkgs/pkgs-lib/formats.nix
Original file line number Diff line number Diff line change
Expand Up @@ -544,4 +544,171 @@ rec {
'') {};
};

# The Xen Project Hypervisor's `xl` configuration syntax.
# Useful for the entire Xen module and declarative VM configurations.
# https://xenbits.xen.org/docs/unstable/man/xl.cfg.5.html
# https://xenbits.xen.org/docs/unstable/man/xl.conf.5.html
xenLight =
{
type ? "cfg",
}:
assert lib.assertOneOf "pkgs.formats.xenLight's 'type' attribute" type [
"cfg"
"conf"
];
{
type =
let
valueType =
oneOf [
bool
float
int
path
str
(listOf valueType)
(listOf (attrsOf valueType))
]
// {
description = "xl.${type} value";
};
in
attrsOf valueType;
generate =
let
# Modified version of lib.generators.toKeyValue that does not use
# newlines and parses Xen's `SPEC` and `SPEC_STRING` value types.
generator =
let
inherit (lib)
all
concatLists
concatStrings
concatStringsSep
flatten
hasPrefix
hasSuffix
isAttrs
isList
isString
mapAttrs
mapAttrsToList
optionalString
removePrefix
removeSuffix
;

# This prevents standardisedString from adding extra quotes to SPECs and SPEC_STRINGs
escapedString = val: mapAttrs (name: value: if (isString value) then ''{${value}}'' else value) val;

# This function:
# - Converts our native `true` and `false` types to numeric booleans,
# - Adds quotes to strings that aren't lists or escaped with '{}'.
standardisedString =
v:
if isString v then
if ((hasPrefix "[" v) && (hasSuffix "]" v)) then
v
else if ((hasPrefix "{" v) && (hasSuffix "}" v)) then
removePrefix "{" (removeSuffix "}" v)
else
''"${v}"''
else if v == true then
1
else if v == false then
0
else
v;

mkKeyValue = lib.generators.mkKeyValueDefault { } "=";

mkConfig =
{
semicolon,
quotes,
}:
k: v:
optionalString quotes ''"''
+ (mkKeyValue k (standardisedString v))
+ optionalString quotes ''"''
+ optionalString semicolon ";";

mkConfigFile =
{
semicolon ? true,
quotes ? false,
}:
k: v: [
(mkConfig { inherit semicolon quotes; } k (
let
specString = concatStringsSep "," (
flatten (
map (
val:
(concatStringsSep "" (
[ ''"'' ]
++ [
(concatStringsSep "," (
flatten (
mapAttrsToList (mkConfigFile {
semicolon = false;
}) (escapedString val)
)
))
]
++ [ ''"'' ]
))
) v
)
);

spec = concatStringsSep "," (
map (
val:
(concatStringsSep "" (
flatten (
map (
val2:
[ "[" ]
++ [
(concatStringsSep "," (
flatten (
mapAttrsToList (mkConfigFile {
semicolon = false;
quotes = true;
}) (escapedString val2)
)
))
]
++ [ "]" ]
) val
)
))
) v
);

standard = concatStringsSep "," (map (val: standardisedString val) v);

keyValuePairs =
if (all (x: isAttrs x) v) then
specString
else if (all (x: isList x) v) then
spec
else if (all (x: !isAttrs x) v) then
standard
else
throw "pkgs.formats.xenLight: lists must include only attribute sets (SPEC_STRING), only lists (SPEC), or only simple types.";
in
if isList v then ''[${keyValuePairs}]'' else v
))
];
in
attrs:
(removeSuffix ";" (
concatStrings (concatLists (mapAttrsToList (name: value: mkConfigFile { } name value) attrs))
))
+ "\n";
in
name: value: pkgs.writeText name (generator value);
};
}

0 comments on commit 74bbd20

Please sign in to comment.