mirror of
https://gitlab.com/TECHNOFAB/nixlets.git
synced 2026-03-22 10:39:27 +01:00
feat: add support for importing nixlets into each other
This commit is contained in:
parent
c44a5fc995
commit
2c21317f45
6 changed files with 345 additions and 151 deletions
3
docs/options.md
Normal file
3
docs/options.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Options
|
||||||
|
|
||||||
|
{{ include_raw("options.md") }}
|
||||||
126
lib/default.nix
126
lib/default.nix
|
|
@ -2,25 +2,68 @@
|
||||||
lib,
|
lib,
|
||||||
kubenix,
|
kubenix,
|
||||||
...
|
...
|
||||||
} @ attrs:
|
} @ attrs: let
|
||||||
with lib; rec {
|
inherit (lib) mkOption types evalModules concatMapStringsSep assertMsg;
|
||||||
evalValues = file: {rawValues, ...} @ args: (lib.evalModules {
|
nixlet-lib = rec {
|
||||||
specialArgs = {
|
nixletModule = ./nixletModule.nix;
|
||||||
|
|
||||||
|
evalValues = file: {
|
||||||
|
rawValues,
|
||||||
|
dependencies,
|
||||||
|
args,
|
||||||
|
check ? true,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
moduleArgs =
|
||||||
|
args
|
||||||
|
// {
|
||||||
utils = import ./utils.nix attrs;
|
utils = import ./utils.nix attrs;
|
||||||
};
|
};
|
||||||
modules = [
|
# get the values from the dependencies, then import them nested
|
||||||
file
|
# (so you can set postgres.replicaCount in values.nix for example when adding "postgres" as dependency)
|
||||||
(_: {
|
extraModules = map (depName: {
|
||||||
# pass through all args to the values.nix module
|
options.${depName} = mkOption {
|
||||||
config =
|
type = types.submodule {
|
||||||
rawValues
|
imports = ["${dependencies.${depName}.path}/values.nix"];
|
||||||
|
_module.args =
|
||||||
|
moduleArgs
|
||||||
// {
|
// {
|
||||||
_module.args = args;
|
# make sure that dependencies see their own name and version etc.
|
||||||
|
nixlet = {
|
||||||
|
inherit (dependencies.${depName}) name version description;
|
||||||
|
inherit (moduleArgs.nixlet) project;
|
||||||
};
|
};
|
||||||
})
|
};
|
||||||
];
|
};
|
||||||
});
|
default = {};
|
||||||
mkValues = file: args: (evalValues file args).config;
|
description = let
|
||||||
|
n = dependencies.${depName};
|
||||||
|
in ''
|
||||||
|
Imported Nixlet as a dependency:
|
||||||
|
|
||||||
|
|Name|Version|Description|
|
||||||
|
|----|-------|-----------|
|
||||||
|
|${n.name}|${n.version}|${n.description}|
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}) (builtins.attrNames dependencies);
|
||||||
|
in
|
||||||
|
builtins.addErrorContext "[nixlets] while evaluating values" (
|
||||||
|
evalModules {
|
||||||
|
modules =
|
||||||
|
[
|
||||||
|
file
|
||||||
|
{
|
||||||
|
_module = {
|
||||||
|
args = moduleArgs;
|
||||||
|
inherit check;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{config = rawValues;}
|
||||||
|
]
|
||||||
|
++ extraModules;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
# wraps mkNixletInner to allow passing either a path or an attrset
|
# wraps mkNixletInner to allow passing either a path or an attrset
|
||||||
mkNixlet = arg:
|
mkNixlet = arg:
|
||||||
|
|
@ -50,10 +93,24 @@ with lib; rec {
|
||||||
project = defaultProject;
|
project = defaultProject;
|
||||||
};
|
};
|
||||||
nixlet = {
|
nixlet = {
|
||||||
|
_type = "nixlet";
|
||||||
inherit name version description path;
|
inherit name version description path;
|
||||||
|
# just values of the current nixlet (lighweight)
|
||||||
values = evalValues "${path}/values.nix" {
|
values = evalValues "${path}/values.nix" {
|
||||||
rawValues = {};
|
rawValues = {};
|
||||||
nixlet = baseNixletArg;
|
dependencies = {};
|
||||||
|
# no checking since this doesn't include dependencies
|
||||||
|
check = false;
|
||||||
|
args.nixlet = baseNixletArg;
|
||||||
|
};
|
||||||
|
# full values, including dependencies etc. (complex)
|
||||||
|
fullValues = args: let
|
||||||
|
evaled = nixlet.eval args;
|
||||||
|
in
|
||||||
|
evalValues "${path}/values.nix" {
|
||||||
|
rawValues = {};
|
||||||
|
inherit (evaled.config.nixlet) dependencies;
|
||||||
|
args.nixlet = baseNixletArg;
|
||||||
};
|
};
|
||||||
mkDocs = opts: mkDocs (opts // {inherit nixlet;});
|
mkDocs = opts: mkDocs (opts // {inherit nixlet;});
|
||||||
eval = {
|
eval = {
|
||||||
|
|
@ -62,35 +119,47 @@ with lib; rec {
|
||||||
overrides ? (_: {}),
|
overrides ? (_: {}),
|
||||||
values ? {},
|
values ? {},
|
||||||
}:
|
}:
|
||||||
assert lib.assertMsg (project != null) "No default project set, please pass a project to the render method"; let
|
assert assertMsg (project != null) "No default project set, please pass a project to the eval/render method"; let
|
||||||
nixletArg = baseNixletArg // {inherit project;};
|
nixletArg = baseNixletArg // {inherit project;};
|
||||||
in
|
in
|
||||||
|
builtins.addErrorContext "[nixlets] while evaluating nixlet ${name}" (
|
||||||
kubenix.evalModules.${system} {
|
kubenix.evalModules.${system} {
|
||||||
module = {kubenix, ...}: {
|
module = {
|
||||||
|
config,
|
||||||
|
kubenix,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
imports = with kubenix.modules; [
|
imports = with kubenix.modules; [
|
||||||
k8s
|
k8s
|
||||||
helm
|
helm
|
||||||
docker
|
docker
|
||||||
files
|
files
|
||||||
./secretsModule.nix
|
./secretsModule.nix
|
||||||
(_: let
|
./nixletModule.nix
|
||||||
finalValues = mkValues "${path}/values.nix" {
|
(let
|
||||||
|
finalValues =
|
||||||
|
(evalValues "${path}/values.nix" {
|
||||||
rawValues = values;
|
rawValues = values;
|
||||||
nixlet = nixletArg;
|
inherit (config.nixlet) dependencies;
|
||||||
};
|
args.nixlet = nixletArg;
|
||||||
|
}).config;
|
||||||
in {
|
in {
|
||||||
imports = [path];
|
imports = [path];
|
||||||
_module.args.nixlet =
|
_module.args = {
|
||||||
|
nixlet =
|
||||||
{
|
{
|
||||||
values = finalValues;
|
values = finalValues;
|
||||||
}
|
}
|
||||||
// nixletArg;
|
// nixletArg;
|
||||||
|
inherit nixlet-lib system;
|
||||||
|
};
|
||||||
})
|
})
|
||||||
overrides
|
overrides
|
||||||
];
|
];
|
||||||
kubenix.project = project;
|
kubenix.project = project;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
);
|
||||||
render = {
|
render = {
|
||||||
system,
|
system,
|
||||||
project ? defaultProject,
|
project ? defaultProject,
|
||||||
|
|
@ -105,6 +174,7 @@ with lib; rec {
|
||||||
.resultYAML;
|
.resultYAML;
|
||||||
# combines all secrets files in a single directory
|
# combines all secrets files in a single directory
|
||||||
secrets = args: (nixlet.eval args).config.kubernetes.secretsCombined;
|
secrets = args: (nixlet.eval args).config.kubernetes.secretsCombined;
|
||||||
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
nixlet;
|
nixlet;
|
||||||
|
|
@ -133,8 +203,8 @@ with lib; rec {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
''
|
''
|
||||||
+ lib.concatStringsSep "\n" (
|
+ concatMapStringsSep "\n" (
|
||||||
builtins.map (nixlet:
|
(nixlet:
|
||||||
with nixlet; ''
|
with nixlet; ''
|
||||||
URL="https://gitlab.com/api/v4/projects/${projectId}/packages/generic/${name}/${version}/${name}.tar.gz"
|
URL="https://gitlab.com/api/v4/projects/${projectId}/packages/generic/${name}/${version}/${name}.tar.gz"
|
||||||
if ${pkgs.curl}/bin/curl --output /dev/null --silent --head --fail --header "$AUTH_HEADER" $URL; then
|
if ${pkgs.curl}/bin/curl --output /dev/null --silent --head --fail --header "$AUTH_HEADER" $URL; then
|
||||||
|
|
@ -153,4 +223,6 @@ with lib; rec {
|
||||||
|
|
||||||
mkDocs = opts:
|
mkDocs = opts:
|
||||||
import ./valuesDocs.nix (opts // {inherit lib;});
|
import ./valuesDocs.nix (opts // {inherit lib;});
|
||||||
}
|
};
|
||||||
|
in
|
||||||
|
nixlet-lib
|
||||||
|
|
|
||||||
75
lib/nixletModule.nix
Normal file
75
lib/nixletModule.nix
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
nixlet,
|
||||||
|
system,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib) mkOption types mkOptionType isType mkMerge mapAttrs mkIf literalExpression;
|
||||||
|
cfg = config.nixlet;
|
||||||
|
|
||||||
|
nixletType = mkOptionType {
|
||||||
|
name = "nixlet";
|
||||||
|
description = "reference";
|
||||||
|
descriptionClass = "noun";
|
||||||
|
check = isType "nixlet";
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
{
|
||||||
|
# shortcut, allows accessing deps a bit shorter/more easily
|
||||||
|
_module.args.deps = cfg.deps;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
options.nixlet = {
|
||||||
|
dependencies = mkOption {
|
||||||
|
type = types.attrsOf nixletType;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
Import other nixlets as dependencies. Works similar to Helm, specify values for these
|
||||||
|
Nixlets by using their name as a prefix. Like `postgres.replicaCount` in `values.nix` for example.
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
"postgres" = nixlet-lib.mkNixlet <path>;
|
||||||
|
"mongodb" = nixlet-lib.fetchNixlet ...; # etc.
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
deps = mkOption {
|
||||||
|
readOnly = true;
|
||||||
|
type = types.attrsOf types.attrs;
|
||||||
|
default = mapAttrs (name: val:
|
||||||
|
builtins.addErrorContext "[nixlets] while evaluating dependency ${name}"
|
||||||
|
(val.eval {
|
||||||
|
inherit system;
|
||||||
|
inherit (config.kubenix) project;
|
||||||
|
values = nixlet.values.${name};
|
||||||
|
}).config)
|
||||||
|
cfg.dependencies;
|
||||||
|
description = ''
|
||||||
|
Evaluated dependency nixlets. Allows accessing their resources like for example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
config.nixlet.deps."<name>".kubernetes.resources
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
depAutoMerge = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether to automatically merge dependency nixlets' configs
|
||||||
|
with the current nixlet. If disabled, you can access dependency outputs via:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
config.nixlet.deps."<name>".kubernetes.resources
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.depAutoMerge {
|
||||||
|
kubernetes.resources = mkMerge (map (dep: dep.kubernetes.resources) (builtins.attrValues cfg.deps));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
nixlet,
|
nixlet,
|
||||||
|
# whether to generate docs for the full values, including dependencies
|
||||||
|
fullValues ? false,
|
||||||
transformOptions ? opt: opt,
|
transformOptions ? opt: opt,
|
||||||
filter ? _: true,
|
filter ? _: true,
|
||||||
headingDepth ? 3,
|
headingDepth ? 3,
|
||||||
|
|
@ -13,7 +15,12 @@
|
||||||
mapAttrsToList
|
mapAttrsToList
|
||||||
concatStrings
|
concatStrings
|
||||||
replicate
|
replicate
|
||||||
|
optionalString
|
||||||
|
optionAttrSetToDocList
|
||||||
|
attrByPath
|
||||||
|
generators
|
||||||
;
|
;
|
||||||
|
inherit (generators) toPretty;
|
||||||
|
|
||||||
_transformOptions = opt:
|
_transformOptions = opt:
|
||||||
transformOptions (opt
|
transformOptions (opt
|
||||||
|
|
@ -25,7 +32,12 @@
|
||||||
name = lib.removePrefix "config." opt.name;
|
name = lib.removePrefix "config." opt.name;
|
||||||
});
|
});
|
||||||
|
|
||||||
rawOpts = lib.optionAttrSetToDocList nixlet.values.options;
|
valueSource =
|
||||||
|
if fullValues
|
||||||
|
# TODO: get rid of system, just here cuz of kubenix
|
||||||
|
then (nixlet.fullValues {system = "x86_64-linux";})
|
||||||
|
else nixlet.values;
|
||||||
|
rawOpts = optionAttrSetToDocList valueSource.options;
|
||||||
transformedOpts = map _transformOptions rawOpts;
|
transformedOpts = map _transformOptions rawOpts;
|
||||||
filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
|
filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
|
||||||
|
|
||||||
|
|
@ -58,7 +70,20 @@
|
||||||
${opt.type}
|
${opt.type}
|
||||||
```
|
```
|
||||||
''
|
''
|
||||||
+ (lib.optionalString (opt ? default && opt.default != null) ''
|
# used to show what changes a nixlet did to values of dependencies
|
||||||
|
+ (let
|
||||||
|
val = toPretty {} (attrByPath opt.loc "_not found_" valueSource.config);
|
||||||
|
default = removeSuffix "\n" opt.default.text;
|
||||||
|
in
|
||||||
|
optionalString (opt.type != "submodule" && val != default)
|
||||||
|
''
|
||||||
|
**Overridden value**:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
${val}
|
||||||
|
```
|
||||||
|
'')
|
||||||
|
+ (optionalString (opt ? default && opt.default != null) ''
|
||||||
|
|
||||||
**Default value**:
|
**Default value**:
|
||||||
|
|
||||||
|
|
@ -66,7 +91,7 @@
|
||||||
${removeSuffix "\n" opt.default.text}
|
${removeSuffix "\n" opt.default.text}
|
||||||
```
|
```
|
||||||
'')
|
'')
|
||||||
+ (lib.optionalString (opt ? example) ''
|
+ (optionalString (opt ? example) ''
|
||||||
|
|
||||||
**Example value**:
|
**Example value**:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,22 @@
|
||||||
cell,
|
cell,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (inputs) doclib;
|
inherit (inputs) pkgs doclib nixlet-lib;
|
||||||
inherit (cell) nixlets;
|
inherit (cell) nixlets;
|
||||||
|
|
||||||
|
optionsDoc = doclib.mkOptionDocs {
|
||||||
|
module = nixlet-lib.nixletModule;
|
||||||
|
roots = [
|
||||||
|
{
|
||||||
|
url = "https://gitlab.com/TECHNOFAB/nixlets/-/blob/main/lib";
|
||||||
|
path = "${inputs.self}/lib";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
optionsDocs = pkgs.runCommand "options-docs" {} ''
|
||||||
|
mkdir -p $out
|
||||||
|
ln -s ${optionsDoc} $out/options.md
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
(doclib.mkDocs {
|
(doclib.mkDocs {
|
||||||
docs."default" = {
|
docs."default" = {
|
||||||
|
|
@ -23,9 +37,13 @@ in
|
||||||
domains = ["nixlets.projects.tf"];
|
domains = ["nixlets.projects.tf"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
macros = {
|
||||||
|
enable = true;
|
||||||
|
includeDir = toString optionsDocs;
|
||||||
|
};
|
||||||
dynamic-nav = {
|
dynamic-nav = {
|
||||||
enable = true;
|
enable = true;
|
||||||
files."Nixlets Values" = builtins.map (val: {${val.name} = val.mkDocs {};}) (builtins.attrValues nixlets);
|
files."Nixlets Values" = builtins.map (val: {${val.name} = val.mkDocs {fullValues = true;};}) (builtins.attrValues nixlets);
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
site_name = "Nixlets";
|
site_name = "Nixlets";
|
||||||
|
|
@ -45,6 +63,7 @@ in
|
||||||
{"Usage" = "usage.md";}
|
{"Usage" = "usage.md";}
|
||||||
{"Generating Docs" = "generating_docs.md";}
|
{"Generating Docs" = "generating_docs.md";}
|
||||||
{"Secrets" = "secrets.md";}
|
{"Secrets" = "secrets.md";}
|
||||||
|
{"Options" = "options.md";}
|
||||||
];
|
];
|
||||||
markdown_extensions = [
|
markdown_extensions = [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
6
nix/repo/flake.lock
generated
6
nix/repo/flake.lock
generated
|
|
@ -38,11 +38,11 @@
|
||||||
"nixmkdocs-lib": {
|
"nixmkdocs-lib": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "lib",
|
"dir": "lib",
|
||||||
"lastModified": 1766062227,
|
"lastModified": 1767549915,
|
||||||
"narHash": "sha256-jhr5CUi9eDeMIAJn7ayXP8Wr+Y2loV5EhdDIKDkRIdw=",
|
"narHash": "sha256-by3r2qddlyzylup5fzSaDwtoy3eFHNKb65IuIq6bsAs=",
|
||||||
"owner": "TECHNOFAB",
|
"owner": "TECHNOFAB",
|
||||||
"repo": "nixmkdocs",
|
"repo": "nixmkdocs",
|
||||||
"rev": "cb0bb5dc3382e8ba5d81324a2f1fd94ccd5a5df4",
|
"rev": "f3b2f4b19178e97c5580367be0f97e61a085db6d",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue