From 48e8cf48b0940a4559368f42f5428a34e7b0d97b Mon Sep 17 00:00:00 2001 From: technofab Date: Sat, 19 Jul 2025 16:25:46 +0200 Subject: [PATCH] feat: add function to generate docs for nixlet values add docs for nixlets in this repo to the mkdocs site --- flake.nix | 48 +++++++++++++- lib/default.nix | 156 ++++++++++++++++++++++++--------------------- lib/valuesDocs.nix | 84 ++++++++++++++++++++++++ 3 files changed, 214 insertions(+), 74 deletions(-) create mode 100644 lib/valuesDocs.nix diff --git a/flake.nix b/flake.nix index 7906b36..44bf709 100644 --- a/flake.nix +++ b/flake.nix @@ -60,7 +60,23 @@ doc = { path = ./docs; - deps = pp: [pp.mkdocs-material (pp.callPackage inputs.mkdocs-material-umami {})]; + deps = pp: [ + pp.mkdocs-material + (pp.callPackage inputs.mkdocs-material-umami {}) + (pp.buildPythonPackage rec { + pname = "mkdocs-gen-files"; + version = "0.5.0"; + pyproject = true; + build-system = [pp.hatchling]; + src = pkgs.fetchFromGitHub { + owner = "oprypin"; + repo = "mkdocs-gen-files"; + rev = "v${version}"; + hash = "sha256-nRRdY7/en42s4PmHH+9vccRIl4pIp1F/Ka1bYvSHpBw="; + }; + dependencies = [pp.mkdocs]; + }) + ]; config = { site_name = "Nixlets"; repo_name = "TECHNOFAB/nixlets"; @@ -95,13 +111,41 @@ } ]; }; - plugins = ["search" "material-umami"]; + plugins = [ + "search" + "material-umami" + { + # bit hacky, but works :D + "gen-files".scripts = let + docsEntries = builtins.toJSON (builtins.mapAttrs (n: v: v.mkDocs {}) self.nixlets); + in [ + (builtins.toFile "gen.py" + # py + '' + import mkdocs_gen_files, json + data = json.loads('${docsEntries}') + for name, file in data.items(): + with open(file, 'r') as infile: + content = infile.read() + with mkdocs_gen_files.open(f"options/{name}.md", "w") as outfile: + outfile.write(content) + '') + ]; + } + ]; nav = [ {"Introduction" = "index.md";} {"Creating Nixlets" = "creation.md";} {"Packaging" = "packaging.md";} {"Usage" = "usage.md";} {"Secrets" = "secrets.md";} + { + "Nixlets Values" = + lib.mapAttrsToList (n: v: { + ${v.name} = "options/${n}.md"; + }) + self.nixlets; + } ]; markdown_extensions = [ { diff --git a/lib/default.nix b/lib/default.nix index 0243448..8fec02c 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -4,24 +4,23 @@ ... } @ attrs: with lib; rec { - mkValues = file: {rawValues, ...} @ args: - (lib.evalModules { - specialArgs = { - utils = import ./utils.nix attrs; - }; - modules = [ - file - ({...}: { - # pass through all args to the values.nix module - config = - rawValues - // { - _module.args = args; - }; - }) - ]; - }) - .config; + evalValues = file: {rawValues, ...} @ args: (lib.evalModules { + specialArgs = { + utils = import ./utils.nix attrs; + }; + modules = [ + file + ({...}: { + # pass through all args to the values.nix module + config = + rawValues + // { + _module.args = args; + }; + }) + ]; + }); + mkValues = file: args: (evalValues file args).config; # wraps mkNixletInner to allow passing either a path or an attrset mkNixlet = arg: @@ -44,60 +43,70 @@ with lib; rec { description ? "", defaultProject ? null, ... - }: rec { - inherit name version description path; - eval = { - system, - project ? defaultProject, - overrides ? ({...}: {}), - values ? {}, - }: - assert lib.assertMsg (project != null) "No default project set, please pass a project to the render method"; let - # every nixlet gets "nixlet" as arg with some useful data about itself - nixletArg = { - inherit name project version description; - }; - in (kubenix.evalModules.${system} { - module = {kubenix, ...}: { - imports = with kubenix.modules; [ - k8s - helm - docker - files - ./secretsModule.nix - ({...}: let - finalValues = mkValues "${path}/values.nix" { - rawValues = values; - nixlet = nixletArg; - }; - in { - imports = [path]; - _module.args.nixlet = - { - values = finalValues; - } - // nixletArg; - }) - overrides - ]; - kubenix.project = project; - }; - }); - render = { - system, - project ? defaultProject, - overrides ? ({...}: {}), - values ? {}, - }: - (eval { - inherit system project overrides values; - }) - .config - .kubernetes - .resultYAML; - # combines all secrets files in a single directory - secrets = args: (eval args).config.kubernetes.secretsCombined; - }; + }: let + # every nixlet gets "nixlet" as arg with some useful data about itself + baseNixletArg = { + inherit name version description; + project = defaultProject; + }; + nixlet = { + inherit name version description path; + values = evalValues "${path}/values.nix" { + rawValues = {}; + nixlet = baseNixletArg; + }; + mkDocs = opts: mkDocs (opts // {inherit nixlet;}); + eval = { + system, + project ? defaultProject, + overrides ? ({...}: {}), + values ? {}, + }: + assert lib.assertMsg (project != null) "No default project set, please pass a project to the render method"; let + nixletArg = baseNixletArg // {inherit project;}; + in (kubenix.evalModules.${system} { + module = {kubenix, ...}: { + imports = with kubenix.modules; [ + k8s + helm + docker + files + ./secretsModule.nix + ({...}: let + finalValues = mkValues "${path}/values.nix" { + rawValues = values; + nixlet = nixletArg; + }; + in { + imports = [path]; + _module.args.nixlet = + { + values = finalValues; + } + // nixletArg; + }) + overrides + ]; + kubenix.project = project; + }; + }); + render = { + system, + project ? defaultProject, + overrides ? ({...}: {}), + values ? {}, + }: + (nixlet.eval { + inherit system project overrides values; + }) + .config + .kubernetes + .resultYAML; + # combines all secrets files in a single directory + secrets = args: (nixlet.eval args).config.kubernetes.secretsCombined; + }; + in + nixlet; fetchNixlet = url: sha256: mkNixlet (builtins.fetchTarball {inherit url sha256;}); fetchNixletFromGitlab = { @@ -140,4 +149,7 @@ with lib; rec { nixlets ) ); + + mkDocs = {nixlet, ...} @ opts: + import ./valuesDocs.nix (opts // {inherit lib;}); } diff --git a/lib/valuesDocs.nix b/lib/valuesDocs.nix new file mode 100644 index 0000000..e0a14ef --- /dev/null +++ b/lib/valuesDocs.nix @@ -0,0 +1,84 @@ +{ + lib, + nixlet, + transformOptions ? opt: opt, + filter ? _: true, + headingDepth ? 3, + ... +}: let + inherit + (lib) + removeSuffix + concatStringsSep + mapAttrsToList + concatStrings + replicate + ; + + _transformOptions = opt: + transformOptions (opt + // { + visible = let + filtered = !builtins.elem (builtins.head opt.loc) ["_module"]; + in + filtered && opt.visible && (filter opt); + name = lib.removePrefix "config." opt.name; + }); + + rawOpts = lib.optionAttrSetToDocList nixlet.values.options; + transformedOpts = map _transformOptions rawOpts; + filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts; + + optionsNix = builtins.listToAttrs ( + map (o: { + name = o.name; + value = removeAttrs o [ + "visible" + "internal" + ]; + }) + filteredOpts + ); + + optToMd = opt: let + headingDecl = concatStrings (replicate headingDepth "#"); + in + '' + ${headingDecl} `${opt.name}` + + ${ + if opt.description != null + then opt.description + else "(no description)" + } + + **Type**: + + ```console + ${opt.type} + ``` + '' + + (lib.optionalString (opt ? default && opt.default != null) '' + + **Default value**: + + ```nix + ${removeSuffix "\n" opt.default.text} + ``` + '') + + (lib.optionalString (opt ? example) '' + + **Example value**: + + ```nix + ${removeSuffix "\n" opt.example.text} + ``` + '') + + "\n"; + + opts = mapAttrsToList (name: opt: + optToMd opt) + optionsNix; + markdown = concatStringsSep "\n" opts; +in + builtins.toFile "values-doc.md" markdown