Sebastian Walz 860d31cee1
Tohu vaBohu
2023-04-21 00:22:52 +02:00

507 lines
22 KiB
Nix
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ extendPath, ... } @ lib:
let
inherit(builtins) all attrNames attrValues concatMap concatStringsSep dirOf elem elemAt filter foldl'
fromJSON functionArgs genList getFlake head listToAttrs isAttrs isBool isFloat
isFunction isInt isList isPath isString map match removeAttrs replaceStrings
split storeDir stringLength substring toString tryEval trace typeOf
unsafeGetAttrPos;
checks = import ./checks.nix lib;
merge = import ./merge.nix lib;
coerceToString
= {
bool
= { value, ... }:
if value
then
"true"
else
"false";
default
= { value, ... }:
toString value;
dictionary
= { value, ... }:
let
keyValuePairs
= attrValues
(
mapAttrs
(
name:
value:
"${extendPath null name} = ${toObject value};"
)
value
);
in
"{ ${concatStringsSep " " keyValuePairs} }";
string
= { value, ... }:
"\"${value}\"";
};
convertLegacy
= {
"abi"
= context:
{ ... } @ value:
{
__type__ = "ApplicationBinaryInterface";
abi = value.abi or null;
assertions = value.assertions or [];
family = value.family;
float = value.float or null;
name = value.name;
};
"cpuType"
= context:
{ ... } @ value:
{
__type__ = "CPUType";
arch = value.arch or null;
bits = value.bits;
endianess = toObject (extendPath context "significantByte") value.significantByte;
name = value.name;
version = value.version or null;
};
"exec-format"
= context:
{ ... } @ value:
{
__type__ = "ExecutableFormat";
__toString = { name, ... }: name;
name = value.name;
};
"if"
= context:
{ ... } @ value:
{
__type__ = "ConfigureIf";
condition = value.condition;
content = value.content;
};
"kernel"
= context:
{ ... } @ value:
{
__type__ = "Kernel";
executables = toObject (extendPath context "execFormat") value.execFormat;
families
= let
context' = extendPath context "families";
in
mapAttr
(name: toObject (extendPath context' name))
value.families;
name = value.name;
version = value.version or null;
};
"literalDocBook"
= context:
{ ... } @ value:
{
__type__ = "LiteralDocBook";
__toString = { text, ... }: text;
text = value.text;
};
"literalExpression"
= context:
{ ... } @ value:
{
__type__ = "LiteralExpression";
__toString = { text, ... }: text;
text = value.text;
};
"literalMD"
= context:
{ ... } @ value:
{
__type__ = "LiteralMarkdown";
__toString = { text, ... }: text;
text = value.text;
};
"mdDoc"
= context:
{ ... } @ value:
{
__type__ = "Markdown";
__toString = { text, ... }: text;
text = value.text;
};
"merge"
= context:
{ ... } @ value:
{
__type__ = "MergeConfigurations";
contents = values.contents;
};
"option"
= context:
{
default ? null,
defaultText ? null,
example ? null,
description ? null,
relatedPackages ? null,
type ? null,
apply ? (x: x),
internal ? false,
value ? null,
visible ? true,
readOnly ? false,
...
} @ option:
{
__type__ = "Option";
documentation
= if visible
then
{
default
= if defaultText != null
then
defaultText
else
toString default;
inherit description example relatedPackages;
type = { inherit(type) description descriptionClass name; };
}
else
null;
inherit apply default internal readOnly;
path = context;
optionType = toObject context type;
source
= if option ? description
then
unsafeGetAttrPos "description" option
else if option ? example
then
unsafeGetAttrPos "example" option
else
unsafeGetAttrPos (head (attrNames option)) option;
};
"option-type"
= path:
{
check, # T -> bool
deprecationMessage, # string?
description, # string
descriptionClass, # string?
emptyValue, # {} | { value: T; }
functor, # { name: string, type: OptionType?, wrappend: any, payload: any, binOp: T -> T -> T },
# getSubOptions, # T -> { string -> U }
# getSubModules, # [ LegacyModule ]?
# merge, # [ string ] -> [ { file: path; value: T; } ] -> { string -> T }
name, # string
nestedTypes, # { elemType: OptionType } | { freeformType: OptionType } | { left: OptionType, right: OptionType } | { coercedType: OptionType, finalType: OptionType }
# substSubModules, # T -> U
# typeMerge, # T -> T -> T
...
}:
let
inherit(functor) payload;
applyFn
= { check, name, ... }:
self:
(
args:
let
result = self args;
in
if check result
then
result
else
throw "Function application did not result in return-value of type `${name}`."
);
documentation
= {
inherit name description descriptionClass;
};
empty = emptyValue != {};
inner
= mapAttrs
(name: toObject (extendPath path name))
nestedTypes;
name'
= let
variant = match "([^ ]*) (.*)" name;
in
if variant != null
then
{
name = elemAt 0 variant;
variant = elemAt 1 variant;
}
else
{
inherit name variant;
};
new
= {
check,
documentation ? documentation,
merge,
...
}:
{
inherit check documentation;
};
pattern
= let
len = stringLength description - 28;
in
substring 28 len description;
range
= let
parts = split "(.+between | and | [(].+)" description;
from = elemAt parts 2;
till = elemAt parts 4;
in
{
from = fromJSON from;
till = fromJSON till;
};
variants
= {
anything = new { check = checks.isAny; merge = merge.anything; };
attrs = new { check = checks.isSet; merge = merge.sets; };
attrsOf = new { check = checks.isSetOf inner; merge = merge.sets; };
bool = new { check = checks.isBool; merge = merge.equal; };
deferredModule = new { check = checks.isNever; merge = merge.never; };
either = new { check = checks.isEitherOr either; merge = merge.eitherOr inner; };
enum = new { check = checks.isInList payload; merge = merge.equal; };
float = new { check = checks.isFloat; merge = merge.equal; };
functionTo = new { apply = applyFn inner; check = checks.isFunction; merge = merge.functions inner; };
int = new { check = checks.isInteger; merge = merge.equal; };
intBetween = new { check = checks.isIntegerBetween range; inherit(variants.int) merge; };
lazyAttrsOf = new { check = checks.isSetOf inner; merge = merge.sets; };
listOf = new { check = checks.isListOf empty inner; merge = merge.lists; };
nonEmptyStr = new { check = checks.isNonEmptyString; inherit(variants.str) merge; };
nullOr = new { check = checks.isNullOr inner; merge = merge.nullOr inner; };
numberBetween = new { check = checks.isNumberBetween range; merge = merge.equal; };
numberNonnegative = new { check = checks.isNonNegativeNumber; merge = merge.equal; };
numberPositive = new { check = checks.isPositiveNumber; merge = merge.equal; };
optionType = new { check = checks.isOptionType; merge = merge.null; };
package = new { check = checks.isPackage; merge = merge.never; };
passwdEntry = new { inherit check; merge = merge.never; };
path = new { check = checks.isPath; merge = merge.equal; };
positiveInt = new { check = checks.isPositiveInteger; inherit(variants.int) merge; };
raw = new { check = checks.isAny; merge = merge.never; };
separatedString = new { check = checks.isString; merge = merge.stringsWith payload; };
signedInt8 = new { check = checks.isSignedByte; inherit(variants.int) merge; };
signedInt16 = new { check = checks.isSignedWord; inherit(variants.int) merge; };
signedInt32 = new { check = checks.isSignedLong; inherit(variants.int) merge; };
singleLineStr = new { check = checks.isStringMatching "[^\n\r]*\n?"; merge = merge.line; };
str = new { check = checks.isString; merge = merge.equal; };
string = new { check = checks.isString; merge = merge.stringsWith ""; };
strMatching = new { check = checks.isStringMatching pattern; inherit(variants.str) merge; };
submodule = new { check = checks.isNever; merge = merge.never; };
uniq = new { inherit(inner) check; merge = merge.never; };
unique = new { inherit(inner) check; merge = merge.never; };
unsignedInt = new { check = checks.isUnsignedInteger; inherit(variants.int) merge; };
unsignedInt8 = new { check = checks.isSignedByte; inherit(variants.int) merge; };
unsignedInt16 = new { check = checks.isSignedWord; inherit(variants.int) merge; };
unsignedInt32 = new { check = checks.isSignedLong; inherit(variants.int) merge; };
unspecified = new { check = checks.isAny; merge = merge.default; };
};
in
{
__type__ = "OptionType";
}
// (
variants.${name'.name}
or (
throw
"Type-Conversion of legacy option-type `${name}` not implemented yet!."
);
);
"order"
= context:
{ ... } @ value:
{
__type__ = "ConfigurationOrder";
content = value.content;
priority = value.priority;
};
"override"
= context:
{ ... } @ value:
{
__type__ = "ConfigurationOverride";
content = value.content;
priority = value.priority;
};
"param"
= context:
{ ... } @ value:
{
__type__ = "ConfigurationParameter";
option = toObject (extendPath context "option") values.option;
render = value.render;
};
"significant-byte"
= context:
{ ... } @ value:
{
__type__ = "Endianess";
__toString = { name, ... }: name;
name = value.name;
};
"system"
= context:
{ ... } @ value:
{
__type__ = "System";
abi = toObject (extendPath context "abi") values.abi;
cpu = toObject (extendPath context "cpu") values.cpu;
kernel = toObject (extendPath context "kernel") values.kernel;
vendor = toObject (extendPath context "vendor") values.vendor;
};
"vendor"
= context:
{ ... } @ value:
{
__type__ = "Vendor";
__toString = { name, ... }: name;
name = value.name;
};
};
functionToObject
= context:
value:
{
__type__ = "Function";
__functor
= { value, ... }:
argument:
toObject context (value argument);
inherit value;
};
listToObject
= context:
value:
{
__type__ = "List";
__functor
= { value, ... }:
index:
let
type = typeOf index;
max = length value;
in
if type == "int"
then
if index >= 0 && index < max
then
elemAt index value
else
throw "Index ${toString index} out of bounds (0${toString max})!"
else
throw "Integer as index expected, got `${type}`!";
__toString
= { value, ... }:
let
value'
= map
(
{ __type__, ... } @ value:
if value ? __toString
then
"${value}"
else
throw "Cannot coerce object of type `${__type__}` to string!"
)
value;
in
"[ ${concatStringsSep ", " value'} ]";
value
= genList
(
index:
toObject
"${context}[${toString index}]"
(elemAt index value)
)
(length value);
};
setToObject
= context:
{
__type__ ? null,
_type ? null,
type ? null,
...
} @ value:
if __type__
then
value
else if _type != null
then
let
convert
= convertLegacy.${_type}
or (throw "No wrapper for type `${type}` implemented.");
in
convert context value
else if type == "derivation"
then
value
// {
__type__ = "Derivation";
__toString = { outPath, ... }: "<Derivation ${outPath}>";
}
else
{
__type__ = "Dictionary";
__functor
= { value, ... }:
name:
let
name' = toObject null name;
key = "${name'}";
in
if name' ? __toString
then
value.${key} or (throw "Missing field `${key}` in dictionary.")
else
throw "Cannot coerce key to string.";
__toString = dictionaryToString;
value
= mapAttrs
(name: toObject "${context}[\"${name}\"]")
value;
};
toObject
= context:
value:
{
bool = { __type__ = "Bool"; inherit value; __toString = coerceToString.bool; };
float = { __type__ = "Float"; inherit value; __toString = coerceToString.default; };
int = { __type__ = "Integer"; inherit value; __toString = coerceToString.default; };
lambda = functionToObject context value;
list = listToObject context value;
null = { __type__ = "Null"; __toString = _: "null"; };
path = { __type__ = "Path"; inherit value; __toString = coerceToString.default; };
set = setToObject context value;
string = { __type__ = "String"; inherit value; __toString = coerceToString.string; };
}.${typeOf value};
in
toObject