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

446 lines
17 KiB
Nix
Raw 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.

{ core, nixpkgs, secrets, vault, web, ... } @ libs:
let
inherit(core) context debug derivation lambda library list path set string type;
inherit(secrets.secret) Secret;
inherit(secrets.vault) Vault;
inherit(web.html) HTML;
Configuration
= let
debug' = debug "Configuration";
defaultCall
= { environment, host, ... }:
{ arguments, configuration, wrap, ... } @ this:
debug'.error "defaultCall"
{
text
= ''
${type.format this} should not be a function, that depends on `config`.
'';
data = this;
when = list.find "config" arguments;
}
wrap
(
this
// {
configuration = configuration (environment // { inherit host; });
}
);
defaultWrap
= { configuration, ... }:
configuration;
toLegacy
= theVault:
let
fix
= source:
value:
let
result
= fixDictionary
source
(set.expect value);
in
debug.debug "fix"
{
text = "Config of ${context.formatRelative source}";
data = value;
showType = false;
}
debug.debug "fix"
{
text = "Secrets of ${context.formatRelative source}";
data = result.secrets;
nice = true;
when = result.secrets != {};
}
result.value
// (
set.ifOrEmpty (result.secrets != {})
{
vault
= (result.value.vault or {})
// {
secrets
= if result.value ? vault.secrets
then
Vault.update
result.value.vault.secrets
result.secrets
else
result.secrets;
};
}
);
fixInner
= source:
value:
debug.debug "fixInner"
{
text = "Option ${context.formatRelative source}";
data = value;
when = !set.isInstanceOf value;
}
type.matchPrimitiveOrDefault value
{
list = fixList source value;
set = fixSet source value;
}
{
secrets = {};
inherit value;
};
fixList
= source:
value:
debug.debug "fixList"
{
text = "Option ${context.formatRelative source}";
data = value;
}
list.fold
(
{ index, secrets, value }:
entry:
let
result = fixInner (source index) entry;
in
{
secrets = Vault.update secrets result.secrets;
index = index + 1;
value = value ++ [ result.value ];
}
)
{
secrets = {};
index = 0;
value = [];
}
value;
fixDictionary
= source:
value:
debug.debug "fixDictionary"
{
text = "Option ${context.formatRelative source}";
data = value;
}
set.fold
(
{ secrets, value }:
attribute:
entry:
let
result = fixInner (source attribute) entry;
in
if debug.Debug.isInstanceOf result
then
"${result}"
else
{
secrets = Vault.update secrets result.secrets;
value = value // { ${attribute} = result.value; };
}
)
{
secrets = {};
value = {};
}
value;
fixSet
= source:
{ ... } @ value:
debug.debug "fixSet"
{
text = "Option ${context.formatRelative source}";
data = value;
when = value._type or null == null;
}
(
if derivation.isInstanceOf' value
|| value._type or null != null
|| HTML.isInstanceOf value
then
{
inherit value;
secrets = {};
}
else if type.getType value == null
then
fixDictionary source value
else if debug.Debug.isInstanceOf value
then
abort "${value}"
else if Secret.isInstanceOf value
then
theVault source value
else
debug'.panic [ "toLegacy" "fixSet" ]
{
text = "Got Object in ${context.formatRelative source}:";
data = value;
}
null
);
in
args:
{ call, configuration, source, wrap, ... } @ this:
let
this'
= this
// {
arguments = set.names (lambda.arguments configuration);
wrap = wrap';
};
wrap' = x: fix source (wrap x);
imports
= type.matchPrimitiveOrPanic configuration
{
lambda = [ (call args this') ];
set = [ (wrap' this') ];
};
in
{
#inherit source;
_file = context.formatFileName source;
imports = imports;
};
in
type "Configuration"
{
from
= variant:
{
call ? defaultCall,
wrap ? defaultWrap,
}:
{ configuration, source, ... } @ config:
Configuration.instanciateAs variant
(
config
// {
inherit call toLegacy wrap;
}
);
};
Configuration' = variant: Configuration variant {};
LegacyConfiguration
= Configuration "Legacy"
{
call
= { ... }:
{ configuration, ... }:
configuration;
};
collect
= let
collectPath
= { source, ... } @ this:
fileName:
collect
(
this
// {
configuration = path.import fileName;
source = source { inherit fileName; };
}
);
in
{ configuration, ... } @ this:
type.matchPrimitiveOrPanic configuration
{
lambda = [ this ];
list
= list.concatMap
(configuration: collect (this // { inherit configuration; }) )
configuration;
null = []; # Just Ignore
path = collectPath this configuration;
set = [ this ];
string = collectPath this configuration;
};
load = library.import ./load.nix libs;
mapToArguments
= list.map
(
config:
let
config' = Configuration.expect config;
arguments = set.names (lambda.arguments config'.configuration);
in
debug.warn "mapToArguments"
{
text = "Unknown Source";
data = config';
when = config'.source == null;
}
type.matchPrimitiveOrPanic config'.configuration
{
lambda = "${type.getVariant config'}: { ${string.concatWith ", " arguments} } from ${context.formatRelative config'.source}";
set = "${type.getVariant config'}: from ${context.formatRelative config'.source}";
}
);
mapToLegacy
= { configurations, environment, host, modules, ... }:
let
theVault = Vault {};
configurations'
= list.map
(
{ toLegacy, ... } @ cfg:
toLegacy theVault
{
inherit host modules;
environment
= environment
// {
inherit(host) users;
inherit(config) config;
inherit(config.config) websites;
};
}
cfg
)
configurations;
modules'
= (set.values modules)
++ [ web.module vault ]
++ configurations';
config
= debug.info "mapToLegacy"
{
text = "modules'";
data = modules';
nice = true;
}
debug.debug "mapToLegacy"
{
text = "environment";
data = set.names environment;
nice = true;
when = false;
}
debug.debug "mapToLegacy"
{
text = "nixosSystem";
show = true;
nice = true;
when = false;
}
(
nixpkgs.lib.nixosSystem
{
baseModules = [];
extraModules = [];
inherit(nixpkgs) lib;
modules = modules';
modulesLocation = null;
pkgs = null;
prefix = [];
specialArgs = {};
system = null;
}
);
in
config;
sortUniqueChecked
= configurations:
let
configurations'
= list.fold
(
result:
config:
let
config' = Configuration.expect config;
result' = insert result config';
in
debug.panic "sortUniqueChecked"
{
text = "Configuration expected";
data = config;
when = !(Configuration.isInstanceOf config);
}
debug.panic "sortUniqueChecked"
{
text = "Could not insert";
show = true;
when = debug.Debug.isInstanceOf result';
}
result'
)
{}
configurations;
insert
= { ... } @ result:
{ configuration, source, ... } @ config:
let
stringContext = string.getContext key;
key = "${context.formatRelative source}";
# Should be safe, as long the keys of resulting attribute set are discarded?
key' = "${type.getVariant config} ${string.discardContext key}";
value = result.${key'} or null;
in
debug.debug "sortUniqueChecked"
{
text = "Remove String-Context of ${key}";
data = stringContext;
when = stringContext != {};
}
(
if configuration == {}
|| configuration == null
then
result
else if value == null
then
result
// {
${key'} = config;
}
else
# Brackets are necessary to compare functions.
# See: https://cs.tvl.fyi/depot/-/blob/tvix/docs/value-pointer-equality.md
if [ value ] == [ config ]
then
result
else
debug.panic "sortUniqueChecked"
{
text = "Confliciting configurations from the same source ${key'} o.O";
data
= {
prev = value;
next = config;
};
nice = true;
}
result
);
in
set.values configurations';
in
{
inherit Configuration Configuration' LegacyConfiguration;
inherit collect load mapToArguments mapToLegacy sortUniqueChecked;
}