Merge pull request 'docs: add clan options search page' (#4077) from davhau/docs: add clan options search page into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4077
This commit is contained in:
1
docs/.gitignore
vendored
1
docs/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/site/reference
|
||||
/site/static
|
||||
/site/options-page
|
||||
!/site/static/extra.css
|
||||
|
||||
@@ -179,6 +179,7 @@ nav:
|
||||
- 04-fetching-nix-from-python: decisions/04-fetching-nix-from-python.md
|
||||
- 05-deployment-parameters: decisions/05-deployment-parameters.md
|
||||
- Template: decisions/_template.md
|
||||
- Options: options.md
|
||||
|
||||
docs_dir: site
|
||||
site_dir: out
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
asciinema-player-css,
|
||||
roboto,
|
||||
fira-code,
|
||||
docs-options,
|
||||
...
|
||||
}:
|
||||
let
|
||||
@@ -35,6 +36,11 @@ pkgs.stdenv.mkDerivation {
|
||||
mkdir -p ./site/reference/cli
|
||||
cp -af ${module-docs}/* ./site/reference/
|
||||
cp -af ${clan-cli-docs}/* ./site/reference/cli/
|
||||
chmod -R +w ./site/reference
|
||||
echo "Generated API documentation in './site/reference/' "
|
||||
|
||||
cp -r ${docs-options} ./site/options-page
|
||||
chmod -R +w ./site/options-page
|
||||
|
||||
mkdir -p ./site/static/asciinema-player
|
||||
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{ inputs, self, ... }:
|
||||
{
|
||||
imports = [
|
||||
./options/flake-module.nix
|
||||
];
|
||||
perSystem =
|
||||
{
|
||||
config,
|
||||
@@ -112,19 +115,20 @@
|
||||
clanModulesViaService
|
||||
;
|
||||
};
|
||||
devShells.docs = pkgs.callPackage ./shell.nix {
|
||||
inherit (self'.packages) docs clan-cli-docs inventory-api-docs;
|
||||
inherit
|
||||
asciinema-player-js
|
||||
asciinema-player-css
|
||||
module-docs
|
||||
self'
|
||||
;
|
||||
};
|
||||
devShells.docs = self'.packages.docs.overrideAttrs (_old: {
|
||||
nativeBuildInputs =
|
||||
self'.devShells.default.nativeBuildInputs ++ self'.packages.docs.nativeBuildInputs;
|
||||
shellHook = ''
|
||||
${self'.devShells.default.shellHook}
|
||||
git_root=$(git rev-parse --show-toplevel)
|
||||
cd "$git_root"
|
||||
runPhase configurePhase
|
||||
'';
|
||||
});
|
||||
packages = {
|
||||
docs = pkgs.python3.pkgs.callPackage ./default.nix {
|
||||
clan-core = self;
|
||||
inherit (self'.packages) clan-cli-docs inventory-api-docs;
|
||||
inherit (self'.packages) clan-cli-docs docs-options inventory-api-docs;
|
||||
inherit (inputs) nixpkgs;
|
||||
inherit module-docs;
|
||||
inherit asciinema-player-js;
|
||||
|
||||
167
docs/nix/options/flake-module.nix
Normal file
167
docs/nix/options/flake-module.nix
Normal file
@@ -0,0 +1,167 @@
|
||||
{ self, config, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
inputs',
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mapAttrsToList
|
||||
flip
|
||||
mapAttrs
|
||||
mkOption
|
||||
types
|
||||
splitString
|
||||
stringLength
|
||||
substring
|
||||
;
|
||||
inherit (self) clanLib;
|
||||
|
||||
serviceModules = self.clan.modules;
|
||||
|
||||
baseHref = "/options-page/";
|
||||
|
||||
evalService =
|
||||
serviceModule:
|
||||
lib.evalModules {
|
||||
modules = [
|
||||
{
|
||||
imports = [
|
||||
serviceModule
|
||||
../../../lib/inventory/distributed-service/service-module.nix
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
getRoles = module: (evalService module).config.roles;
|
||||
|
||||
getManifest = module: (evalService module).config.manifest;
|
||||
|
||||
loadFile = file: if builtins.pathExists file then builtins.readFile file else "";
|
||||
|
||||
settingsModules =
|
||||
module: flip mapAttrs (getRoles module) (_roleName: roleConfig: roleConfig.interface);
|
||||
|
||||
# Map each letter to its capitalized version
|
||||
capitalizeChar =
|
||||
char:
|
||||
{
|
||||
a = "A";
|
||||
b = "B";
|
||||
c = "C";
|
||||
d = "D";
|
||||
e = "E";
|
||||
f = "F";
|
||||
g = "G";
|
||||
h = "H";
|
||||
i = "I";
|
||||
j = "J";
|
||||
k = "K";
|
||||
l = "L";
|
||||
m = "M";
|
||||
n = "N";
|
||||
o = "O";
|
||||
p = "P";
|
||||
q = "Q";
|
||||
r = "R";
|
||||
s = "S";
|
||||
t = "T";
|
||||
u = "U";
|
||||
v = "V";
|
||||
w = "W";
|
||||
x = "X";
|
||||
y = "Y";
|
||||
z = "Z";
|
||||
}
|
||||
.${char};
|
||||
|
||||
title =
|
||||
name:
|
||||
let
|
||||
# split by -
|
||||
parts = splitString "-" name;
|
||||
# capitalize first letter of each part
|
||||
capitalize = part: (capitalizeChar (substring 0 1 part)) + substring 1 (stringLength part) part;
|
||||
capitalizedParts = map capitalize parts;
|
||||
in
|
||||
builtins.concatStringsSep " " capitalizedParts;
|
||||
|
||||
fakeInstanceOptions =
|
||||
name: module:
|
||||
let
|
||||
manifest = getManifest module;
|
||||
description = ''
|
||||
# ${title name} (Clan Service)
|
||||
|
||||
**${manifest.description}**
|
||||
|
||||
${loadFile (module._file + "/../README.md")}
|
||||
|
||||
${
|
||||
if manifest.categories != [ ] then
|
||||
"Categories: " + builtins.concatStringsSep ", " manifest.categories
|
||||
else
|
||||
"No categories defined"
|
||||
}
|
||||
|
||||
'';
|
||||
in
|
||||
{
|
||||
options = {
|
||||
_ = mkOption {
|
||||
type = types.raw;
|
||||
};
|
||||
instances.${name} = lib.mkOption {
|
||||
inherit description;
|
||||
type = types.submodule {
|
||||
options.roles = flip mapAttrs (settingsModules module) (
|
||||
roleName: roleSettingsModule:
|
||||
mkOption {
|
||||
type = types.submodule {
|
||||
imports = [
|
||||
(import ../../../lib/inventory/build-inventory/roles-interface.nix {
|
||||
inherit clanLib;
|
||||
nestedSettingsOption = mkOption {
|
||||
type = types.raw;
|
||||
description = ''
|
||||
See [instances.${name}.roles.${roleName}.settings](${baseHref}?option_scope=0&option=instances.${name}.roles.${roleName}.settings)
|
||||
'';
|
||||
};
|
||||
settingsOption = mkOption {
|
||||
type = types.submoduleWith {
|
||||
modules = [ roleSettingsModule ];
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mkScope = name: modules: {
|
||||
inherit name;
|
||||
modules = [
|
||||
(import ../../../lib/inventory/build-inventory/interface.nix {
|
||||
inherit clanLib;
|
||||
noInstanceOptions = true;
|
||||
})
|
||||
] ++ mapAttrsToList fakeInstanceOptions modules;
|
||||
urlPrefix = "https://github.com/nix-community/dream2nix/blob/main/";
|
||||
};
|
||||
in
|
||||
{
|
||||
packages.docs-options = inputs'.nuschtos.packages.mkMultiSearch {
|
||||
inherit baseHref;
|
||||
title = "Clan Options";
|
||||
# scopes = mapAttrsToList mkScope serviceModules;
|
||||
scopes = [ (mkScope "Clan Inventory" serviceModules) ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
docs,
|
||||
pkgs,
|
||||
module-docs,
|
||||
clan-cli-docs,
|
||||
asciinema-player-js,
|
||||
asciinema-player-css,
|
||||
roboto,
|
||||
fira-code,
|
||||
self',
|
||||
...
|
||||
}:
|
||||
pkgs.mkShell {
|
||||
name = "clan-docs";
|
||||
inputsFrom = [
|
||||
docs
|
||||
self'.devShells.default
|
||||
];
|
||||
shellHook = ''
|
||||
git_root=$(git rev-parse --show-toplevel)
|
||||
cd ''${git_root}/docs
|
||||
|
||||
mkdir -p ./site/reference/cli
|
||||
cp -af ${module-docs}/* ./site/reference/
|
||||
cp -af ${clan-cli-docs}/* ./site/reference/cli/
|
||||
|
||||
chmod -R +w ./site/reference/*
|
||||
|
||||
echo "Generated API documentation in './site/reference/' "
|
||||
|
||||
mkdir -p ./site/static/asciinema-player
|
||||
|
||||
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js
|
||||
ln -snf ${asciinema-player-css} ./site/static/asciinema-player/asciinema-player.css
|
||||
|
||||
# Link to fonts
|
||||
ln -snf ${roboto}/share/fonts/truetype/Roboto-Regular.ttf ./site/static/
|
||||
ln -snf ${fira-code}/share/fonts/truetype/FiraCode-VF.ttf ./site/static/
|
||||
'';
|
||||
}
|
||||
14
docs/overrides/options.html
Normal file
14
docs/overrides/options.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{% extends "base.html" %} {% block extrahead %}
|
||||
<style>
|
||||
.md-main__inner {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
.md-content {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
.md-main__inner {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %} {% block site_nav %}{% endblock %} {% block content %} {{
|
||||
page.content }} {% endblock %}
|
||||
6
docs/site/options.md
Normal file
6
docs/site/options.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
template: options.html
|
||||
---
|
||||
|
||||
|
||||
<iframe src="/options-page/" height="1000" width="100%"></iframe>
|
||||
72
flake.lock
generated
72
flake.lock
generated
@@ -67,6 +67,52 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"ixx": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"nuschtos",
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nuschtos",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748294338,
|
||||
"narHash": "sha256-FVO01jdmUNArzBS7NmaktLdGA5qA3lUMJ4B7a05Iynw=",
|
||||
"owner": "NuschtOS",
|
||||
"repo": "ixx",
|
||||
"rev": "cc5f390f7caf265461d4aab37e98d2292ebbdb85",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NuschtOS",
|
||||
"ref": "v0.0.8",
|
||||
"repo": "ixx",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-darwin": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -128,15 +174,41 @@
|
||||
"url": "https://nixos.org/channels/nixpkgs-unstable/nixexprs.tar.xz"
|
||||
}
|
||||
},
|
||||
"nuschtos": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"ixx": "ixx",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749730855,
|
||||
"narHash": "sha256-L3x2nSlFkXkM6tQPLJP3oCBMIsRifhIDPMQQdHO5xWo=",
|
||||
"owner": "NuschtOS",
|
||||
"repo": "search",
|
||||
"rev": "8dfe5879dd009ff4742b668d9c699bc4b9761742",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NuschtOS",
|
||||
"repo": "search",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"data-mesher": "data-mesher",
|
||||
"disko": "disko",
|
||||
"flake-parts": "flake-parts",
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-darwin": "nix-darwin",
|
||||
"nix-select": "nix-select",
|
||||
"nixos-facter-modules": "nixos-facter-modules",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nuschtos": "nuschtos",
|
||||
"sops-nix": "sops-nix",
|
||||
"systems": "systems",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
|
||||
@@ -34,6 +34,13 @@
|
||||
treefmt-nix.follows = "treefmt-nix";
|
||||
};
|
||||
};
|
||||
|
||||
# dependencies needed for nuschtos
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
flake-utils.inputs.systems.follows = "systems";
|
||||
nuschtos.url = "github:NuschtOS/search";
|
||||
nuschtos.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nuschtos.inputs.flake-utils.follows = "flake-utils";
|
||||
};
|
||||
|
||||
outputs =
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{ clanLib }:
|
||||
{
|
||||
clanLib,
|
||||
# workaround for docs rendering to include fake instance options
|
||||
noInstanceOptions ? false,
|
||||
}:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
@@ -370,121 +374,63 @@ in
|
||||
);
|
||||
};
|
||||
|
||||
instances = lib.mkOption {
|
||||
description = "Multi host service module instances";
|
||||
type = types.attrsOf (
|
||||
types.submoduleWith {
|
||||
modules = [
|
||||
(
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
# ModuleSpec
|
||||
module = lib.mkOption {
|
||||
type = types.submodule {
|
||||
options.input = lib.mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
defaultText = "Name of the input. Default to 'null' which means the module is local";
|
||||
description = ''
|
||||
Name of the input. Default to 'null' which means the module is local
|
||||
'';
|
||||
};
|
||||
options.name = lib.mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
defaultText = "<Name of the Instance>";
|
||||
description = ''
|
||||
Attribute of the clan service module imported from the chosen input.
|
||||
|
||||
Defaults to the name of the instance.
|
||||
'';
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
roles = lib.mkOption {
|
||||
default = { };
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
# TODO: deduplicate
|
||||
machines = lib.mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options.settings = lib.mkOption {
|
||||
default = { };
|
||||
type = clanLib.types.uniqueDeferredSerializableModule;
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
};
|
||||
tags = lib.mkOption {
|
||||
type = types.attrsOf (types.submodule { });
|
||||
default = { };
|
||||
};
|
||||
settings = lib.mkOption {
|
||||
default = { };
|
||||
type = clanLib.types.uniqueDeferredSerializableModule;
|
||||
};
|
||||
extraModules = lib.mkOption {
|
||||
instances =
|
||||
if noInstanceOptions then
|
||||
{ }
|
||||
else
|
||||
lib.mkOption {
|
||||
description = "Multi host service module instances";
|
||||
type = types.attrsOf (
|
||||
types.submoduleWith {
|
||||
modules = [
|
||||
(
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
# ModuleSpec
|
||||
module = lib.mkOption {
|
||||
type = types.submodule {
|
||||
options.input = lib.mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
defaultText = "Name of the input. Default to 'null' which means the module is local";
|
||||
description = ''
|
||||
List of additionally imported `.nix` expressions.
|
||||
|
||||
Supported types:
|
||||
|
||||
- **Strings**: Interpreted relative to the 'directory' passed to buildClan.
|
||||
- **Paths**: should be relative to the current file.
|
||||
- **Any**: Nix expression must be serializable to JSON.
|
||||
|
||||
!!! Note
|
||||
**The import only happens if the machine is part of the service or role.**
|
||||
|
||||
Other types are passed through to the nixos configuration.
|
||||
|
||||
???+ Example
|
||||
To import the `special.nix` file
|
||||
|
||||
```
|
||||
. Clan Directory
|
||||
├── flake.nix
|
||||
...
|
||||
└── modules
|
||||
├── special.nix
|
||||
└── ...
|
||||
```
|
||||
|
||||
```nix
|
||||
{
|
||||
extraModules = [ "modules/special.nix" ];
|
||||
}
|
||||
```
|
||||
Name of the input. Default to 'null' which means the module is local
|
||||
'';
|
||||
};
|
||||
options.name = lib.mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
defaultText = "<Name of the Instance>";
|
||||
description = ''
|
||||
Attribute of the clan service module imported from the chosen input.
|
||||
|
||||
Defaults to the name of the instance.
|
||||
'';
|
||||
apply = value: if lib.isString value then value else builtins.seq (builtins.toJSON value) value;
|
||||
default = [ ];
|
||||
type = types.listOf (
|
||||
types.oneOf [
|
||||
types.str
|
||||
types.path
|
||||
(types.attrsOf types.anything)
|
||||
]
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
roles = lib.mkOption {
|
||||
default = { };
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
imports = [ (import ./roles-interface.nix { inherit clanLib; }) ];
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
};
|
||||
|
||||
services = lib.mkOption {
|
||||
# TODO: deprecate these options
|
||||
# services are deprecated in favor of `instances`
|
||||
# visible = false;
|
||||
description = ''
|
||||
Services of the inventory.
|
||||
|
||||
|
||||
86
lib/inventory/build-inventory/roles-interface.nix
Normal file
86
lib/inventory/build-inventory/roles-interface.nix
Normal file
@@ -0,0 +1,86 @@
|
||||
{
|
||||
clanLib,
|
||||
settingsOption ? null,
|
||||
nestedSettingsOption ? null,
|
||||
}:
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
types
|
||||
;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
# TODO: deduplicate
|
||||
machines = lib.mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options.settings =
|
||||
if nestedSettingsOption != null then
|
||||
nestedSettingsOption
|
||||
else
|
||||
lib.mkOption {
|
||||
default = { };
|
||||
type = clanLib.types.uniqueDeferredSerializableModule;
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
};
|
||||
tags = lib.mkOption {
|
||||
type = types.attrsOf (types.submodule { });
|
||||
default = { };
|
||||
};
|
||||
settings =
|
||||
if settingsOption != null then
|
||||
settingsOption
|
||||
else
|
||||
lib.mkOption {
|
||||
default = { };
|
||||
type = clanLib.types.uniqueDeferredSerializableModule;
|
||||
};
|
||||
extraModules = lib.mkOption {
|
||||
description = ''
|
||||
List of additionally imported `.nix` expressions.
|
||||
|
||||
Supported types:
|
||||
|
||||
- **Strings**: Interpreted relative to the 'directory' passed to buildClan.
|
||||
- **Paths**: should be relative to the current file.
|
||||
- **Any**: Nix expression must be serializable to JSON.
|
||||
|
||||
!!! Note
|
||||
**The import only happens if the machine is part of the service or role.**
|
||||
|
||||
Other types are passed through to the nixos configuration.
|
||||
|
||||
???+ Example
|
||||
To import the `special.nix` file
|
||||
|
||||
```
|
||||
. Clan Directory
|
||||
├── flake.nix
|
||||
...
|
||||
└── modules
|
||||
├── special.nix
|
||||
└── ...
|
||||
```
|
||||
|
||||
```nix
|
||||
{
|
||||
extraModules = [ "modules/special.nix" ];
|
||||
}
|
||||
```
|
||||
'';
|
||||
apply = value: if lib.isString value then value else builtins.seq (builtins.toJSON value) value;
|
||||
default = [ ];
|
||||
type = types.listOf (
|
||||
types.oneOf [
|
||||
types.str
|
||||
types.path
|
||||
(types.attrsOf types.anything)
|
||||
]
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user