2024-12-11 17:03:41 +01:00
|
|
|
{
|
|
|
|
lib,
|
|
|
|
config,
|
|
|
|
pkgs,
|
|
|
|
...
|
|
|
|
}:
|
|
|
|
let
|
|
|
|
inherit (lib)
|
|
|
|
mkOption
|
|
|
|
mkEnableOption
|
|
|
|
mkIf
|
|
|
|
types
|
|
|
|
importJSON
|
|
|
|
mapAttrs'
|
|
|
|
mapAttrsToList
|
|
|
|
removePrefix
|
|
|
|
pathIsDirectory
|
|
|
|
hasSuffix
|
2024-12-12 14:11:49 +01:00
|
|
|
hasPrefix
|
2024-12-11 23:27:47 +01:00
|
|
|
attrNames
|
2024-12-12 14:11:49 +01:00
|
|
|
filter
|
|
|
|
head
|
2024-12-16 13:01:09 +01:00
|
|
|
getExe
|
2024-12-11 17:03:41 +01:00
|
|
|
;
|
|
|
|
inherit (lib.strings)
|
|
|
|
sanitizeDerivationName
|
|
|
|
;
|
|
|
|
yaml = pkgs.formats.yaml { };
|
|
|
|
json = pkgs.formats.json { };
|
|
|
|
cfg = config.services.extranix;
|
|
|
|
|
|
|
|
module-eval =
|
2024-12-12 14:11:49 +01:00
|
|
|
module-name: module:
|
2024-12-11 17:03:41 +01:00
|
|
|
let
|
2024-12-11 23:27:47 +01:00
|
|
|
ignored-eval = lib.evalModules {
|
|
|
|
modules = module.ignored-modules;
|
|
|
|
inherit (module) specialArgs;
|
|
|
|
};
|
|
|
|
ignored-opts-doc = pkgs.nixosOptionsDoc { inherit (ignored-eval) options; };
|
|
|
|
ignored-opts = importJSON "${ignored-opts-doc.optionsJSON}/share/doc/nixos/options.json";
|
|
|
|
eval = lib.evalModules {
|
|
|
|
modules = module.paths ++ module.ignored-modules;
|
|
|
|
inherit (module) specialArgs;
|
|
|
|
};
|
2024-12-11 17:03:41 +01:00
|
|
|
opts-doc = pkgs.nixosOptionsDoc { inherit (eval) options; };
|
2024-12-11 23:27:47 +01:00
|
|
|
opts = importJSON "${opts-doc.optionsJSON}/share/doc/nixos/options.json";
|
|
|
|
filtered-opts = removeAttrs opts (attrNames ignored-opts);
|
2024-12-12 14:11:49 +01:00
|
|
|
path-translation =
|
|
|
|
let
|
|
|
|
translations = map (
|
|
|
|
{ base, url }:
|
|
|
|
{
|
|
|
|
url = "${url}${if hasSuffix "/" url then "" else "/"}";
|
|
|
|
base =
|
|
|
|
let
|
|
|
|
base1 = toString base;
|
|
|
|
in
|
|
|
|
base1 + (if hasSuffix "/" base1 then "" else "/");
|
|
|
|
}
|
|
|
|
) module.path-translations;
|
|
|
|
in
|
|
|
|
path:
|
|
|
|
let
|
|
|
|
fullPath = path + (if pathIsDirectory path then "/default.nix" else "");
|
|
|
|
fitting = filter ({ base, ... }: hasPrefix base fullPath) translations;
|
|
|
|
translate-info = head (
|
|
|
|
fitting ++ [ (throw "${fullPath} is not in any base path of ${module-name}") ]
|
|
|
|
);
|
|
|
|
innerPath = removePrefix translate-info.base fullPath;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
name = "<${innerPath}>";
|
|
|
|
url = "${translate-info.url}${innerPath}";
|
|
|
|
};
|
2024-12-16 13:01:09 +01:00
|
|
|
result' = json.generate "options-extranix-fileDesc.json" {
|
2024-12-11 17:03:41 +01:00
|
|
|
last_update = "-/-";
|
|
|
|
options = mapAttrsToList (title: val: {
|
|
|
|
inherit title;
|
|
|
|
inherit (val)
|
|
|
|
type
|
|
|
|
readOnly
|
|
|
|
loc
|
2024-12-16 13:01:09 +01:00
|
|
|
description
|
2024-12-11 17:03:41 +01:00
|
|
|
;
|
2024-12-16 13:01:09 +01:00
|
|
|
descriptionHTML = pkgs.runCommand "option-${title}.html" { } ''
|
|
|
|
${getExe pkgs.pandoc} -f markdown ${pkgs.writeText "option-${title}.md" val.description} > $out
|
|
|
|
'';
|
2024-12-11 17:03:41 +01:00
|
|
|
example = val.example.text or "";
|
|
|
|
default = val.default.text or "";
|
2024-12-12 14:11:49 +01:00
|
|
|
declarations = map path-translation val.declarations;
|
2024-12-11 17:03:41 +01:00
|
|
|
}) filtered-opts;
|
|
|
|
};
|
2024-12-16 13:01:09 +01:00
|
|
|
result =
|
|
|
|
pkgs.runCommand "options-extranix.json"
|
|
|
|
{
|
|
|
|
nativeBuildInputs = [ pkgs.jq ];
|
|
|
|
}
|
|
|
|
''
|
|
|
|
jq -r '.options[].descriptionHTML | "--rawfile\n" + . + "\n" + .' ${result'} | xargs \
|
|
|
|
jq -c '.options |= map(.descriptionHTML as $desc | .descriptionHTML |= $ARGS.named.[$desc])' ${result'} \
|
|
|
|
> $out
|
|
|
|
'';
|
2024-12-11 17:03:41 +01:00
|
|
|
in
|
|
|
|
result;
|
|
|
|
|
|
|
|
options-files = mapAttrs' (name: value: {
|
|
|
|
name = sanitizeDerivationName name;
|
2024-12-12 14:11:49 +01:00
|
|
|
value = module-eval name value;
|
2024-12-11 17:03:41 +01:00
|
|
|
}) cfg.modules;
|
|
|
|
|
|
|
|
webroot = pkgs.callPackage ./webroot.nix {
|
|
|
|
inherit options-files;
|
|
|
|
inherit (cfg) static-data;
|
|
|
|
settings = yaml.generate "config.yaml" cfg.settings;
|
|
|
|
hugo-theme-extranix-options-search = pkgs.callPackage ./hugo-theme-extranix-options-search.nix { };
|
|
|
|
};
|
|
|
|
in
|
|
|
|
{
|
|
|
|
options.services.extranix = {
|
|
|
|
enable = mkEnableOption "extranix documentation";
|
|
|
|
modules = mkOption {
|
|
|
|
type =
|
|
|
|
let
|
|
|
|
module-mod.options = {
|
2024-12-11 23:27:47 +01:00
|
|
|
specialArgs = mkOption {
|
|
|
|
type = types.attrs;
|
|
|
|
default = { };
|
|
|
|
};
|
2024-12-11 17:03:41 +01:00
|
|
|
paths = mkOption {
|
2024-12-15 18:12:44 +01:00
|
|
|
type = types.listOf types.deferredModule;
|
2024-12-11 17:03:41 +01:00
|
|
|
};
|
2024-12-11 23:27:47 +01:00
|
|
|
ignored-modules = mkOption {
|
|
|
|
type = types.listOf types.deferredModule;
|
|
|
|
default = [ ];
|
|
|
|
};
|
2024-12-12 14:11:49 +01:00
|
|
|
path-translations = mkOption {
|
|
|
|
type =
|
|
|
|
let
|
|
|
|
path-mod.options = {
|
|
|
|
base = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
};
|
|
|
|
url = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
in
|
|
|
|
types.listOf (types.submodule path-mod);
|
2024-12-11 17:03:41 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
in
|
|
|
|
types.attrsOf (types.submodule module-mod);
|
|
|
|
};
|
|
|
|
settings = mkOption {
|
|
|
|
type = yaml.type;
|
|
|
|
};
|
|
|
|
static-data = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
};
|
|
|
|
host = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
services = {
|
|
|
|
extranix = {
|
|
|
|
settings = {
|
|
|
|
markup.goldmark.renderer.unsafe = true;
|
|
|
|
theme = "extranix-options-search";
|
|
|
|
params.releases = mapAttrsToList (name: _: {
|
|
|
|
inherit name;
|
|
|
|
value = sanitizeDerivationName name;
|
|
|
|
}) cfg.modules;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
nginx = {
|
|
|
|
enable = true;
|
|
|
|
virtualHosts.${cfg.host}.locations."/".alias = "${webroot}/";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|