2024-12-21 11:21:34 +01:00
|
|
|
# SPDX-FileCopyrightText: 2024 Lubin Bailly <lubin.bailly@dgnum.eu>
|
|
|
|
#
|
|
|
|
# SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
{
|
|
|
|
lib,
|
|
|
|
config,
|
|
|
|
pkgs,
|
|
|
|
...
|
|
|
|
}:
|
|
|
|
let
|
|
|
|
inherit (lib)
|
|
|
|
attrNames
|
|
|
|
concatMapStringsSep
|
2025-01-04 13:08:26 +01:00
|
|
|
concatStringsSep
|
|
|
|
escapeXML
|
2024-12-21 11:21:34 +01:00
|
|
|
filter
|
|
|
|
getExe
|
|
|
|
hasPrefix
|
|
|
|
hasSuffix
|
|
|
|
head
|
|
|
|
importJSON
|
|
|
|
mapAttrs'
|
|
|
|
mapAttrsToList
|
2025-01-04 13:08:26 +01:00
|
|
|
mkDefault
|
2024-12-21 11:21:34 +01:00
|
|
|
mkEnableOption
|
|
|
|
mkIf
|
|
|
|
mkOption
|
|
|
|
optionalString
|
|
|
|
pathIsDirectory
|
|
|
|
removePrefix
|
|
|
|
;
|
|
|
|
inherit (lib.strings)
|
|
|
|
sanitizeDerivationName
|
|
|
|
;
|
|
|
|
inherit (lib.types)
|
|
|
|
attrs
|
|
|
|
attrsOf
|
|
|
|
deferredModule
|
|
|
|
listOf
|
|
|
|
path
|
|
|
|
submodule
|
|
|
|
str
|
|
|
|
;
|
|
|
|
yaml = pkgs.formats.yaml { };
|
|
|
|
json = pkgs.formats.json { };
|
|
|
|
cfg = config.services.extranix;
|
|
|
|
|
|
|
|
module-eval =
|
|
|
|
module-name: module:
|
|
|
|
let
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
opts-doc = pkgs.nixosOptionsDoc { inherit (eval) options; };
|
|
|
|
opts = importJSON "${opts-doc.optionsJSON}/share/doc/nixos/options.json";
|
|
|
|
filtered-opts = removeAttrs opts (attrNames ignored-opts);
|
|
|
|
path-translation =
|
|
|
|
let
|
|
|
|
translations = map (
|
|
|
|
{ base, url }:
|
|
|
|
{
|
|
|
|
url = "${url}${optionalString (!hasSuffix "/" url) "/"}";
|
|
|
|
base =
|
|
|
|
let
|
|
|
|
base1 = toString base;
|
|
|
|
in
|
|
|
|
base1 + (optionalString (!hasSuffix "/" base1) "/");
|
|
|
|
}
|
|
|
|
) module.path-translations;
|
|
|
|
in
|
|
|
|
path:
|
|
|
|
let
|
|
|
|
fullPath = path + (optionalString (pathIsDirectory path) "/default.nix");
|
|
|
|
fitting = filter ({ base, ... }: hasPrefix base fullPath) translations;
|
|
|
|
translate-info = head (
|
|
|
|
fitting
|
|
|
|
++ [
|
|
|
|
(throw (
|
|
|
|
"${fullPath} is not in any base path of ${module-name}. Base paths are "
|
|
|
|
+ concatMapStringsSep "\n" ({ base, ... }: base) translations
|
|
|
|
))
|
|
|
|
]
|
|
|
|
);
|
|
|
|
innerPath = removePrefix translate-info.base fullPath;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
name = "<${innerPath}>";
|
|
|
|
url = "${translate-info.url}${innerPath}";
|
|
|
|
};
|
|
|
|
result' = json.generate "options-extranix-fileDesc.json" {
|
|
|
|
last_update = "-/-";
|
|
|
|
options = mapAttrsToList (title: val: {
|
|
|
|
inherit title;
|
|
|
|
inherit (val)
|
|
|
|
type
|
|
|
|
readOnly
|
|
|
|
loc
|
|
|
|
;
|
|
|
|
descriptionHTML = pkgs.runCommand "option-${title}.html" { } ''
|
2025-01-04 13:08:26 +01:00
|
|
|
${getExe pkgs.pandoc} -f markdown-raw_html ${pkgs.writeText "option-${title}.md" val.description} > $out
|
2024-12-21 11:21:34 +01:00
|
|
|
'';
|
2025-01-04 13:08:26 +01:00
|
|
|
description = escapeXML val.description;
|
|
|
|
example = escapeXML (val.example.text or "");
|
|
|
|
default = escapeXML (val.default.text or "");
|
2024-12-21 11:21:34 +01:00
|
|
|
declarations = map path-translation val.declarations;
|
|
|
|
}) filtered-opts;
|
|
|
|
};
|
|
|
|
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
|
|
|
|
'';
|
|
|
|
in
|
|
|
|
result;
|
|
|
|
|
|
|
|
options-files = mapAttrs' (name: value: {
|
|
|
|
name = sanitizeDerivationName name;
|
|
|
|
value = module-eval name value;
|
|
|
|
}) 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 =
|
|
|
|
|
|
|
|
attrsOf (submodule {
|
|
|
|
options = {
|
|
|
|
specialArgs = mkOption {
|
|
|
|
type = attrs;
|
|
|
|
default = { };
|
|
|
|
description = ''
|
|
|
|
Special arguments to give to evalModules.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
paths = mkOption {
|
|
|
|
type = listOf deferredModule;
|
|
|
|
description = ''
|
|
|
|
Modules to from which to document options.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
ignored-modules = mkOption {
|
|
|
|
type = listOf deferredModule;
|
|
|
|
default = [ ];
|
|
|
|
description = ''
|
|
|
|
Modules required to make modules of `paths` valid.
|
|
|
|
'';
|
|
|
|
example = ''
|
|
|
|
import "''${infra-modulesPath}/module-list.nix"
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
path-translations = mkOption {
|
|
|
|
type = listOf (submodule {
|
|
|
|
options = {
|
|
|
|
base = mkOption {
|
|
|
|
type = path;
|
|
|
|
description = ''
|
|
|
|
Base path of some module files to be documented.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
url = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = ''
|
|
|
|
Url root to use for files on this path.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
description = ''
|
|
|
|
Rules to convert file paths to urls in the documentation to indicate where
|
|
|
|
the option is declared.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
description = ''
|
|
|
|
Sets of modules to be documented separately. The identifier to give for
|
|
|
|
`settings.params.release_current_stable` (which is the default module shown) is the key after
|
|
|
|
passing through `sanitizeDerivationName`.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
settings = mkOption {
|
|
|
|
inherit (yaml) type;
|
|
|
|
description = ''
|
|
|
|
Settings for the `config.yaml` for the hugo instantiation.
|
|
|
|
'';
|
|
|
|
example = {
|
|
|
|
baseUrl = "https://example.org/";
|
|
|
|
title = "Module documentation";
|
|
|
|
languageCode = "en-us";
|
|
|
|
params = {
|
|
|
|
release_current_stable = "Some-Module";
|
|
|
|
logo = "logo.png";
|
|
|
|
footer_credits_line = ''
|
|
|
|
Based on <a href="https://github.com/mipmip/home-manager-option-search">Home Manager Option Search</a>
|
|
|
|
'';
|
|
|
|
footer_copyright_line = ''
|
|
|
|
Made by catvayor for the <a href="https://dgnum.eu">DGNum</a>.
|
|
|
|
'';
|
|
|
|
main_menu = [
|
|
|
|
{
|
|
|
|
name = ''Sources'';
|
|
|
|
url = "https://git.example.org/";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
static-data = mkOption {
|
|
|
|
type = path;
|
|
|
|
description = ''
|
|
|
|
Static files for the website. Should have `images/favicon.png` for favicon.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
host = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = ''
|
|
|
|
Hostname of the service.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
services = {
|
2025-01-04 13:08:26 +01:00
|
|
|
extranix.settings = {
|
|
|
|
theme = "extranix-options-search";
|
|
|
|
params = {
|
|
|
|
releases = mapAttrsToList (name: _: {
|
2024-12-21 11:21:34 +01:00
|
|
|
inherit name;
|
|
|
|
value = sanitizeDerivationName name;
|
|
|
|
}) cfg.modules;
|
2025-01-04 13:08:26 +01:00
|
|
|
release_current_stable = mkDefault (head (attrNames options-files));
|
2024-12-21 11:21:34 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
nginx = {
|
|
|
|
enable = true;
|
|
|
|
virtualHosts.${cfg.host}.locations."/".alias = "${webroot}/";
|
|
|
|
};
|
|
|
|
};
|
2025-01-04 13:08:26 +01:00
|
|
|
assertions = [
|
|
|
|
{
|
|
|
|
assertion = cfg.modules != { };
|
|
|
|
message = ''
|
|
|
|
`services.extranix` can't be enabled without any modules to document.
|
|
|
|
'';
|
|
|
|
}
|
|
|
|
{
|
|
|
|
assertion = options-files ? ${cfg.settings.params.release_current_stable};
|
|
|
|
message = ''
|
|
|
|
`services.extranix.settings.params.release_current_stable` should be the
|
|
|
|
`sanitizeDerivationName` of a key of `services.extranix.modules`, here one of:
|
|
|
|
+ ${concatStringsSep "\n + " (attrNames options-files)}
|
|
|
|
'';
|
|
|
|
}
|
|
|
|
];
|
2024-12-21 11:21:34 +01:00
|
|
|
};
|
|
|
|
}
|