All checks were successful
Build all the nodes / geo02 (push) Successful in 59s
Build all the nodes / geo01 (push) Successful in 1m0s
Build all the nodes / hypervisor02 (push) Successful in 1m0s
Build all the nodes / hypervisor01 (push) Successful in 1m0s
Build all the nodes / netaccess01 (push) Successful in 19s
Build all the nodes / netcore00 (push) Successful in 19s
Build all the nodes / netcore02 (push) Successful in 20s
Build all the nodes / netcore01 (push) Successful in 20s
Build all the nodes / ap01 (push) Successful in 1m24s
Build all the nodes / bridge01 (push) Successful in 2m5s
Build all the nodes / build01 (push) Successful in 2m5s
Build all the nodes / hypervisor03 (push) Successful in 2m5s
Build all the nodes / cof02 (push) Successful in 2m12s
Build all the nodes / storage01 (push) Successful in 58s
Build all the nodes / tower01 (push) Successful in 56s
Build all the nodes / rescue01 (push) Successful in 1m0s
Build the shell / build-shell (push) Successful in 44s
Run pre-commit on all files / pre-commit (push) Successful in 46s
Build all the nodes / compute01 (push) Successful in 3m10s
Build all the nodes / web01 (push) Successful in 2m3s
Build all the nodes / web02 (push) Successful in 1m29s
Build all the nodes / web03 (push) Successful in 1m35s
Build all the nodes / vault01 (push) Successful in 1m0s
359 lines
9.1 KiB
Nix
359 lines
9.1 KiB
Nix
# SPDX-FileCopyrightText: 2024 Lubin Bailly <lubin.bailly@dgnum.eu>
|
|
# SPDX-FileCopyrightText: 2025 Tom Hubrecht <tom.hubrecht@dgnum.eu>
|
|
#
|
|
# SPDX-License-Identifier: EUPL-1.2
|
|
|
|
{
|
|
lib,
|
|
config,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
inherit (lib)
|
|
attrNames
|
|
concatStringsSep
|
|
escapeXML
|
|
evalModules
|
|
filter
|
|
flip
|
|
getAttr
|
|
hasPrefix
|
|
head
|
|
listToAttrs
|
|
mapAttrsToList
|
|
literalExpression
|
|
mkEnableOption
|
|
mkIf
|
|
mkOption
|
|
nameValuePair
|
|
optionAttrSetToDocList
|
|
optionalString
|
|
pathIsDirectory
|
|
pipe
|
|
removeAttrs
|
|
removePrefix
|
|
removeSuffix
|
|
;
|
|
|
|
inherit (lib.strings)
|
|
sanitizeDerivationName
|
|
;
|
|
|
|
inherit (lib.types)
|
|
attrs
|
|
attrsOf
|
|
deferredModule
|
|
listOf
|
|
nullOr
|
|
path
|
|
submodule
|
|
str
|
|
;
|
|
|
|
mkDocJSON =
|
|
module:
|
|
{
|
|
ignored-modules,
|
|
path-translations,
|
|
paths,
|
|
specialArgs,
|
|
...
|
|
}:
|
|
let
|
|
# NOTE: A big simplification of nixpkgs' make-options-doc
|
|
# It turns out that we only need the json output, and have
|
|
# no `baseOptionsJSON`, so the transformation done is `id`
|
|
mkOpts = (flip pipe) [
|
|
# Evaluate the modules
|
|
(modules: evalModules { inherit modules specialArgs; })
|
|
# Extract the options
|
|
(getAttr "options")
|
|
# Transform into a list of options
|
|
optionAttrSetToDocList
|
|
# Remove invisible and internal options
|
|
(filter (o: o.visible && !o.internal))
|
|
# Remove extraneous attributes
|
|
(builtins.map (
|
|
o:
|
|
nameValuePair o.name (
|
|
removeAttrs o [
|
|
"name"
|
|
"visible"
|
|
"internal"
|
|
]
|
|
)
|
|
))
|
|
# Transform back to an attribute set
|
|
listToAttrs
|
|
];
|
|
|
|
# INFO: Subtract options of the ignored modules from
|
|
# the complete set of options
|
|
ignored = attrNames (mkOpts ignored-modules);
|
|
options = removeAttrs (mkOpts (paths ++ ignored-modules)) ignored;
|
|
|
|
directories = builtins.map (getAttr "base") path-translations;
|
|
|
|
mkTranslation =
|
|
path:
|
|
let
|
|
# Get the file associated to the module
|
|
file = if pathIsDirectory path then path + "/default.nix" else path;
|
|
|
|
# Get the parent module set
|
|
matching = filter (m: hasPrefix m.base path) path-translations;
|
|
parent = head matching;
|
|
filePath = removePrefix parent.base file;
|
|
in
|
|
if matching == [ ] then
|
|
(throw "${file} is not a descendant of ${module}. Declared parents are: \n ${concatStringsSep "\n " directories}")
|
|
else
|
|
{
|
|
name = "<${filePath}>";
|
|
url = "${parent.url}/${filePath}";
|
|
};
|
|
in
|
|
pkgs.runCommand "options-extranix"
|
|
{
|
|
fileName = sanitizeDerivationName "options-${module}.json";
|
|
nativeBuildInputs = [ pkgs.jq ];
|
|
|
|
passAsFile = [ "result" ];
|
|
result = builtins.toJSON {
|
|
last_update = "-/-";
|
|
options = mapAttrsToList (
|
|
title:
|
|
{
|
|
default ? {
|
|
text = "";
|
|
},
|
|
description,
|
|
example ? {
|
|
text = "";
|
|
},
|
|
loc,
|
|
readOnly,
|
|
type,
|
|
declarations,
|
|
...
|
|
}:
|
|
{
|
|
inherit
|
|
loc
|
|
readOnly
|
|
title
|
|
type
|
|
;
|
|
|
|
descriptionHTML = pkgs.runCommandLocal "option-${title}.html" {
|
|
inherit description;
|
|
passAsFile = [ "description" ];
|
|
|
|
nativeBuildInputs = [ pkgs.pandoc ];
|
|
} "pandoc -f markdown-raw_html $descriptionPath > $out";
|
|
|
|
description = escapeXML description;
|
|
example = escapeXML example.text;
|
|
default = escapeXML default.text;
|
|
declarations = builtins.map mkTranslation declarations;
|
|
}
|
|
) options;
|
|
};
|
|
}
|
|
''
|
|
mkdir -p $out
|
|
jq -r '.options[].descriptionHTML | "--rawfile\n" + . + "\n" + .' $resultPath | xargs \
|
|
jq -c '.options |= map(.descriptionHTML as $desc | .descriptionHTML |= $ARGS.named.[$desc])' $resultPath \
|
|
> $out/$fileName
|
|
'';
|
|
|
|
website =
|
|
pkgs.runCommand "search-infra"
|
|
{
|
|
inherit (cfg) theme;
|
|
|
|
nativeBuildInputs = [ pkgs.hugo ];
|
|
|
|
config = builtins.toJSON cfg.settings;
|
|
passAsFile = [ "config" ];
|
|
|
|
data = pkgs.symlinkJoin {
|
|
name = "options-data";
|
|
paths = mapAttrsToList mkDocJSON cfg.modules;
|
|
};
|
|
}
|
|
''
|
|
# Setup the directory structure
|
|
mkdir themes && ln -s $theme themes/options-search
|
|
ln -s $configPath hugo.json
|
|
mkdir static
|
|
${optionalString (cfg.static != null) "cp -R ${cfg.static} static"}
|
|
ln -s $data static/data
|
|
|
|
# Build the website
|
|
hugo -d $out
|
|
'';
|
|
|
|
cfg = config.services.extranix;
|
|
in
|
|
|
|
{
|
|
options.services.extranix = {
|
|
enable = mkEnableOption "extranix documentation";
|
|
|
|
theme = mkOption {
|
|
type = path;
|
|
description = ''
|
|
Path to a hugo theme for the search website.
|
|
'';
|
|
};
|
|
|
|
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.
|
|
'';
|
|
apply = v: "${removeSuffix "/" (builtins.toString v)}/";
|
|
};
|
|
url = mkOption {
|
|
type = str;
|
|
description = ''
|
|
Url root to use for files on this path.
|
|
'';
|
|
apply = removeSuffix "/";
|
|
};
|
|
};
|
|
});
|
|
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`.
|
|
'';
|
|
};
|
|
|
|
host = mkOption {
|
|
type = str;
|
|
description = ''
|
|
Hostname of the service.
|
|
'';
|
|
};
|
|
|
|
index = mkOption {
|
|
type = str;
|
|
default = head (attrNames cfg.modules);
|
|
defaultText = literalExpression "head (attrNames config.services.extranix.modules)";
|
|
description = ''
|
|
The main module to show when loading the website.
|
|
'';
|
|
apply = sanitizeDerivationName;
|
|
};
|
|
|
|
static = mkOption {
|
|
type = nullOr path;
|
|
default = null;
|
|
description = ''
|
|
Path to extra static files.
|
|
'';
|
|
};
|
|
|
|
settings = mkOption {
|
|
inherit (pkgs.formats.json { }) type;
|
|
|
|
description = ''
|
|
Settings of the hugo website.
|
|
'';
|
|
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/";
|
|
}
|
|
];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
services = {
|
|
extranix.settings = {
|
|
theme = "options-search";
|
|
params = {
|
|
releases = mapAttrsToList (name: _: {
|
|
inherit name;
|
|
value = sanitizeDerivationName name;
|
|
}) cfg.modules;
|
|
|
|
release_current_stable = cfg.index;
|
|
};
|
|
};
|
|
|
|
nginx = {
|
|
enable = true;
|
|
virtualHosts.${cfg.host}.locations."/".root = website;
|
|
};
|
|
};
|
|
|
|
assertions = [
|
|
{
|
|
assertion = cfg.modules != { };
|
|
message = ''
|
|
`services.extranix` can't be enabled without any modules to document.
|
|
'';
|
|
}
|
|
];
|
|
};
|
|
}
|