docs: use MarkDown for option docs
This commit is contained in:
parent
bc667fb6af
commit
4fcab839d7
13 changed files with 1403 additions and 1487 deletions
|
@ -5,9 +5,9 @@
|
|||
version: 2
|
||||
|
||||
build:
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.9"
|
||||
python: "3"
|
||||
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
|
51
default.nix
51
default.nix
|
@ -79,7 +79,7 @@ in
|
|||
```
|
||||
|
||||
Warning: this is stored in plaintext in the Nix store!
|
||||
Use `hashedPasswordFile` instead.
|
||||
Use {option}`mailserver.loginAccounts.<name>.hashedPasswordFile` instead.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -156,7 +156,7 @@ in
|
|||
description = ''
|
||||
Specifies if the account should be a send-only account.
|
||||
Emails sent to send-only accounts will be rejected from
|
||||
unauthorized senders with the sendOnlyRejectMessage
|
||||
unauthorized senders with the `sendOnlyRejectMessage`
|
||||
stating the reason.
|
||||
'';
|
||||
};
|
||||
|
@ -200,7 +200,7 @@ in
|
|||
description = ''
|
||||
Folder to store search indices. If null, indices are stored
|
||||
along with email, which could not necessarily be desirable,
|
||||
especially when the fullTextSearch option is enable since
|
||||
especially when {option}`mailserver.fullTextSearch.enable` is `true` since
|
||||
indices it creates are voluminous and do not need to be backed
|
||||
up.
|
||||
|
||||
|
@ -242,8 +242,8 @@ in
|
|||
default = "no";
|
||||
description = ''
|
||||
Fail searches when no index is available. If set to
|
||||
<literal>body</literal>, then only body searches (as opposed to
|
||||
header) are affected. If set to <literal>no</literal>, searches may
|
||||
`body`, then only body searches (as opposed to
|
||||
header) are affected. If set to `no`, searches may
|
||||
fall back to a very slow brute force search.
|
||||
'';
|
||||
};
|
||||
|
@ -281,7 +281,7 @@ in
|
|||
randomizedDelaySec = mkOption {
|
||||
type = types.int;
|
||||
default = 1000;
|
||||
description = "Run the maintenance job not exactly at the time specified with <literal>onCalendar</literal>, but plus or minus this many seconds.";
|
||||
description = "Run the maintenance job not exactly at the time specified with `onCalendar`, but plus or minus this many seconds.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -333,7 +333,7 @@ in
|
|||
the value {`"user@example.com" = "user@elsewhere.com";}`
|
||||
means that mails to `user@example.com` are forwarded to
|
||||
`user@elsewhere.com`. The difference with the
|
||||
`extraVirtualAliases` option is that `user@elsewhere.com`
|
||||
{option}`mailserver.extraVirtualAliases` option is that `user@elsewhere.com`
|
||||
can't send mail as `user@example.com`. Also, this option
|
||||
allows to forward mails to external addresses.
|
||||
'';
|
||||
|
@ -367,7 +367,7 @@ in
|
|||
description = ''
|
||||
The unix UID of the virtual mail user. Be mindful that if this is
|
||||
changed, you will need to manually adjust the permissions of
|
||||
mailDirectory.
|
||||
`mailDirectory`.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -582,7 +582,7 @@ in
|
|||
type = types.str;
|
||||
default = "mail";
|
||||
description = ''
|
||||
|
||||
The DKIM selector.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -590,7 +590,7 @@ in
|
|||
type = types.path;
|
||||
default = "/var/dkim";
|
||||
description = ''
|
||||
|
||||
The DKIM directory.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -601,7 +601,7 @@ in
|
|||
How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys.
|
||||
|
||||
If you have already deployed a key with a different number of bits than specified
|
||||
here, then you should use a different selector (dkimSelector). In order to get
|
||||
here, then you should use a different selector ({option}`mailserver.dkimSelector`). In order to get
|
||||
this package to generate a key with the new number of bits, you will either have to
|
||||
change the selector or delete the old key file.
|
||||
'';
|
||||
|
@ -673,7 +673,7 @@ in
|
|||
type = types.str;
|
||||
example = "ACME Corp.";
|
||||
description = ''
|
||||
The name of your organization used in the <literal>org_name</literal> attribute in
|
||||
The name of your organization used in the `org_name` attribute in
|
||||
DMARC reports.
|
||||
'';
|
||||
};
|
||||
|
@ -681,7 +681,7 @@ in
|
|||
fromName = mkOption {
|
||||
type = types.str;
|
||||
default = cfg.dmarcReporting.organizationName;
|
||||
defaultText = literalExpression "organizationName";
|
||||
defaultText = literalMD "{option}`mailserver.dmarcReporting.organizationName`";
|
||||
description = ''
|
||||
The sender name for DMARC reports. Defaults to the organization name.
|
||||
'';
|
||||
|
@ -738,7 +738,7 @@ in
|
|||
if (ip == "0.0.0.0" || ip == "::")
|
||||
then "127.0.0.1"
|
||||
else if isIpv6 ip then "[${ip}]" else ip;
|
||||
defaultText = lib.literalDocBook "computed from <option>config.services.redis.servers.rspamd.bind</option>";
|
||||
defaultText = lib.literalMD "computed from `config.services.redis.servers.rspamd.bind`";
|
||||
description = ''
|
||||
Address that rspamd should use to contact redis.
|
||||
'';
|
||||
|
@ -776,7 +776,7 @@ in
|
|||
sendingFqdn = mkOption {
|
||||
type = types.str;
|
||||
default = cfg.fqdn;
|
||||
defaultText = "config.mailserver.fqdn";
|
||||
defaultText = lib.literalMD "{option}`mailserver.fqdn`";
|
||||
example = "myserver.example.com";
|
||||
description = ''
|
||||
The fully qualified domain name of the mail server used to
|
||||
|
@ -792,7 +792,7 @@ in
|
|||
|
||||
This setting allows the server to identify as
|
||||
myserver.example.com when forwarding mail, independently of
|
||||
`fqdn` (which, for SSL reasons, should generally be the name
|
||||
{option}`mailserver.fqdn` (which, for SSL reasons, should generally be the name
|
||||
to which the user connects).
|
||||
|
||||
Set this to the name to which the sending IP's reverse DNS
|
||||
|
@ -864,7 +864,7 @@ in
|
|||
start program = "${pkgs.systemd}/bin/systemctl start rspamd"
|
||||
stop program = "${pkgs.systemd}/bin/systemctl stop rspamd"
|
||||
'';
|
||||
defaultText = lib.literalDocBook "see source";
|
||||
defaultText = lib.literalMD "see [source](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/blob/master/default.nix)";
|
||||
description = ''
|
||||
The configuration used for monitoring via monit.
|
||||
Use a mail address that you actively check and set it via 'set alert ...'.
|
||||
|
@ -881,7 +881,8 @@ in
|
|||
description = ''
|
||||
The location where borg saves the backups.
|
||||
This can be a local path or a remote location such as user@host:/path/to/repo.
|
||||
It is exported and thus available as an environment variable to cmdPreexec and cmdPostexec.
|
||||
It is exported and thus available as an environment variable to
|
||||
{option}`mailserver.borgbackup.cmdPreexec` and {option}`mailserver.borgbackup.cmdPostexec`.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -941,7 +942,7 @@ in
|
|||
default = "none";
|
||||
description = ''
|
||||
The backup can be encrypted by choosing any other value than 'none'.
|
||||
When using encryption the password / passphrase must be provided in passphraseFile.
|
||||
When using encryption the password/passphrase must be provided in `passphraseFile`.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -964,6 +965,7 @@ in
|
|||
locations = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [cfg.mailDirectory];
|
||||
defaultText = lib.literalExpression "[ config.mailserver.mailDirectory ]";
|
||||
description = "The locations that are to be backed up by borg.";
|
||||
};
|
||||
|
||||
|
@ -984,9 +986,10 @@ in
|
|||
default = null;
|
||||
description = ''
|
||||
The command to be executed before each backup operation.
|
||||
This is called prior to borg init in the same script that runs borg init and create and cmdPostexec.
|
||||
Example:
|
||||
export BORG_RSH="ssh -i /path/to/private/key"
|
||||
This is called prior to borg init in the same script that runs borg init and create and `cmdPostexec`.
|
||||
'';
|
||||
example = ''
|
||||
export BORG_RSH="ssh -i /path/to/private/key"
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -996,7 +999,7 @@ in
|
|||
description = ''
|
||||
The command to be executed after each backup operation.
|
||||
This is called after borg create completed successfully and in the same script that runs
|
||||
cmdPreexec, borg init and create.
|
||||
`cmdPreexec`, borg init and create.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -1009,7 +1012,7 @@ in
|
|||
example = true;
|
||||
description = ''
|
||||
Whether to enable automatic reboot after kernel upgrades.
|
||||
This is to be used in conjunction with system.autoUpgrade.enable = true"
|
||||
This is to be used in conjunction with `system.autoUpgrade.enable = true;`
|
||||
'';
|
||||
};
|
||||
method = mkOption {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Add Roundcube, a webmail
|
||||
=======================
|
||||
========================
|
||||
|
||||
The NixOS module for roundcube nearly works out of the box with SNM. By
|
||||
default, it sets up a nginx virtual host to serve the webmail, other web
|
||||
|
|
12
docs/conf.py
12
docs/conf.py
|
@ -18,7 +18,7 @@
|
|||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'NixOS Mailserver'
|
||||
copyright = '2020, NixOS Mailserver Contributors'
|
||||
copyright = '2022, NixOS Mailserver Contributors'
|
||||
author = 'NixOS Mailserver Contributors'
|
||||
|
||||
|
||||
|
@ -28,8 +28,16 @@ author = 'NixOS Mailserver Contributors'
|
|||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'myst_parser'
|
||||
]
|
||||
|
||||
myst_enable_extensions = [
|
||||
'colon_fence',
|
||||
'linkify',
|
||||
]
|
||||
|
||||
smartquotes = False
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
|
@ -50,4 +58,4 @@ html_theme = 'sphinx_rtd_theme'
|
|||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
html_static_path = []
|
||||
|
|
|
@ -30,8 +30,8 @@ run tests manually. For instance:
|
|||
Contributing to the documentation
|
||||
---------------------------------
|
||||
|
||||
The documentation is written in RST, build with Sphinx and published
|
||||
by `Read the Docs <https://readthedocs.org/>`_.
|
||||
The documentation is written in RST (except option documentation which is in MarkDown),
|
||||
built with Sphinx and published by `Read the Docs <https://readthedocs.org/>`_.
|
||||
|
||||
For the syntax, see `RST/Sphinx Cheatsheet
|
||||
<https://sphinx-tutorial.readthedocs.io/cheatsheet/>`_.
|
||||
|
@ -47,11 +47,11 @@ documentation:
|
|||
$ firefox ./_build/html/index.html
|
||||
|
||||
Note if you modify some NixOS mailserver options, you would also need
|
||||
to regenerate the ``options.rst`` file:
|
||||
to regenerate the ``options.md`` file:
|
||||
|
||||
::
|
||||
|
||||
$ nix-shell --run generate-rst-options
|
||||
$ nix-shell --run generate-options
|
||||
|
||||
Nixops
|
||||
------
|
||||
|
|
1202
docs/options.md
Normal file
1202
docs/options.md
Normal file
File diff suppressed because it is too large
Load diff
1319
docs/options.rst
1319
docs/options.rst
File diff suppressed because it is too large
Load diff
|
@ -1,2 +1,4 @@
|
|||
sphinx==4.0.2
|
||||
sphinx_rtd_theme==0.5.2
|
||||
sphinx ~= 5.3
|
||||
sphinx_rtd_theme ~= 1.1
|
||||
myst-parser ~= 0.18
|
||||
linkify-it-py ~= 2.0
|
||||
|
|
17
flake.lock
17
flake.lock
|
@ -16,6 +16,22 @@
|
|||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1668681692,
|
||||
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1669542132,
|
||||
|
@ -49,6 +65,7 @@
|
|||
"root": {
|
||||
"inputs": {
|
||||
"blobs": "blobs",
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-22_11": "nixpkgs-22_11",
|
||||
"utils": "utils"
|
||||
|
|
90
flake.nix
90
flake.nix
|
@ -2,6 +2,10 @@
|
|||
description = "A complete and Simple Nixos Mailserver";
|
||||
|
||||
inputs = {
|
||||
flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
};
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "flake:nixpkgs/nixos-unstable";
|
||||
nixpkgs-22_11.url = "flake:nixpkgs/nixos-22.11";
|
||||
|
@ -11,7 +15,8 @@
|
|||
};
|
||||
};
|
||||
|
||||
outputs = { self, utils, blobs, nixpkgs, nixpkgs-22_11 }: let
|
||||
outputs = { self, utils, blobs, nixpkgs, nixpkgs-22_11, ... }: let
|
||||
lib = nixpkgs.lib;
|
||||
system = "x86_64-linux";
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
releases = [
|
||||
|
@ -43,22 +48,18 @@
|
|||
# external-21_05 = <derivation>;
|
||||
# ...
|
||||
# }
|
||||
allTests = pkgs.lib.listToAttrs (
|
||||
pkgs.lib.flatten (map (t: map (r: genTest t r) releases) testNames));
|
||||
allTests = lib.listToAttrs (
|
||||
lib.flatten (map (t: map (r: genTest t r) releases) testNames));
|
||||
|
||||
mailserverModule = import ./.;
|
||||
|
||||
# Generate a rst file describing options of the NixOS mailserver module
|
||||
generateRstOptions = let
|
||||
eval = import (pkgs.path + "/nixos/lib/eval-config.nix") {
|
||||
inherit system;
|
||||
# Generate a MarkDown file describing the options of the NixOS mailserver module
|
||||
optionsDoc = let
|
||||
eval = lib.evalModules {
|
||||
modules = [
|
||||
mailserverModule
|
||||
{
|
||||
# Because the blockbook package is currently broken (we
|
||||
# don't care about this package but it is part of the
|
||||
# NixOS module evaluation)
|
||||
nixpkgs.config.allowBroken = true;
|
||||
_module.check = false;
|
||||
mailserver = {
|
||||
fqdn = "mx.example.com";
|
||||
domains = [
|
||||
|
@ -71,27 +72,26 @@
|
|||
};
|
||||
}
|
||||
];
|
||||
|
||||
};
|
||||
options = pkgs.nixosOptionsDoc {
|
||||
options = eval.options;
|
||||
};
|
||||
in pkgs.runCommand "options.rst" { buildInputs = [pkgs.python3]; } ''
|
||||
echo Generating options.rst from ${options.optionsJSON}/share/doc/nixos/options.json
|
||||
python ${./scripts/generate-rst-options.py} ${options.optionsJSON}/share/doc/nixos/options.json > $out
|
||||
options = builtins.toFile "options.json" (builtins.toJSON
|
||||
(lib.filter (opt: opt.visible && !opt.internal && lib.head opt.loc == "mailserver")
|
||||
(lib.optionAttrSetToDocList eval.options)));
|
||||
in pkgs.runCommand "options.md" { buildInputs = [pkgs.python3Minimal]; } ''
|
||||
echo "Generating options.md from ${options}"
|
||||
python ${./scripts/generate-options.py} ${options} > $out
|
||||
'';
|
||||
|
||||
# This is a script helping users to generate this file in the docs directory
|
||||
generateRstOptionsScript = pkgs.writeScriptBin "generate-rst-options" ''
|
||||
cp -v ${generateRstOptions} ./docs/options.rst
|
||||
generateOptions = pkgs.writeShellScriptBin "generate-options" ''
|
||||
install -vm644 ${optionsDoc} ./docs/options.md
|
||||
'';
|
||||
|
||||
# This is to ensure we don't forget to update the options.rst file
|
||||
testRstOptions = pkgs.runCommand "test-rst-options" {} ''
|
||||
if ! diff -q ${./docs/options.rst} ${generateRstOptions}
|
||||
# This is to ensure we don't forget to update the options.md file
|
||||
testOptions = pkgs.runCommand "test-options" {} ''
|
||||
if ! diff -q ${./docs/options.md} ${optionsDoc}
|
||||
then
|
||||
echo "The file ./docs/options.rst is not up-to-date and needs to be regenerated!"
|
||||
echo " hint: run 'nix-shell --run generate-rst-options' to generate this file"
|
||||
echo "The file ./docs/options.md is not up-to-date and needs to be regenerated!"
|
||||
echo " hint: run 'nix-shell --run generate-options' to generate this file"
|
||||
exit 1
|
||||
fi
|
||||
echo "test: ok" > $out
|
||||
|
@ -99,43 +99,43 @@
|
|||
|
||||
documentation = pkgs.stdenv.mkDerivation {
|
||||
name = "documentation";
|
||||
src = pkgs.lib.sourceByRegex ./docs ["logo.png" "conf.py" "Makefile" ".*rst$"];
|
||||
src = lib.sourceByRegex ./docs ["logo\\.png" "conf\\.py" "Makefile" ".*\\.rst"];
|
||||
buildInputs = [(
|
||||
pkgs.python3.withPackages(p: [
|
||||
p.sphinx
|
||||
p.sphinx_rtd_theme
|
||||
pkgs.python3.withPackages (p: with p; [
|
||||
sphinx
|
||||
sphinx_rtd_theme
|
||||
myst-parser
|
||||
])
|
||||
)];
|
||||
buildPhase = ''
|
||||
cp ${generateRstOptions} options.rst
|
||||
mkdir -p _static
|
||||
cp ${optionsDoc} options.md
|
||||
# Workaround for https://github.com/sphinx-doc/sphinx/issues/3451
|
||||
export SOURCE_DATE_EPOCH=$(${pkgs.coreutils}/bin/date +%s)
|
||||
unset SOURCE_DATE_EPOCH
|
||||
make html
|
||||
'';
|
||||
installPhase = ''
|
||||
cp -r _build/html $out
|
||||
cp -Tr _build/html $out
|
||||
'';
|
||||
};
|
||||
|
||||
in rec {
|
||||
nixosModules.mailserver = mailserverModule ;
|
||||
nixosModule = self.nixosModules.mailserver;
|
||||
in {
|
||||
nixosModules = rec {
|
||||
mailserver = mailserverModule;
|
||||
default = mailserver;
|
||||
};
|
||||
nixosModule = self.nixosModules.default; # compatibility
|
||||
hydraJobs.${system} = allTests // {
|
||||
test-rst-options = testRstOptions;
|
||||
test-options = testOptions;
|
||||
inherit documentation;
|
||||
};
|
||||
checks.${system} = allTests;
|
||||
devShell.${system} = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
generateRstOptionsScript
|
||||
(python3.withPackages (p: with p; [
|
||||
sphinx
|
||||
sphinx_rtd_theme
|
||||
]))
|
||||
jq
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
inputsFrom = [ documentation ];
|
||||
packages = with pkgs; [
|
||||
generateOptions
|
||||
clamav
|
||||
];
|
||||
};
|
||||
devShell.${system} = self.devShells.${system}.default; # compatibility
|
||||
};
|
||||
}
|
||||
|
|
81
scripts/generate-options.py
Normal file
81
scripts/generate-options.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
import json
|
||||
import sys
|
||||
|
||||
header = """
|
||||
# Mailserver options
|
||||
|
||||
## `mailserver`
|
||||
|
||||
"""
|
||||
|
||||
template = """
|
||||
`````{{option}} {key}
|
||||
{description}
|
||||
|
||||
{type}
|
||||
{default}
|
||||
{example}
|
||||
`````
|
||||
"""
|
||||
|
||||
f = open(sys.argv[1])
|
||||
options = json.load(f)
|
||||
|
||||
groups = ["mailserver.loginAccounts",
|
||||
"mailserver.certificate",
|
||||
"mailserver.dkim",
|
||||
"mailserver.dmarcReporting",
|
||||
"mailserver.fullTextSearch",
|
||||
"mailserver.redis",
|
||||
"mailserver.monitoring",
|
||||
"mailserver.backup",
|
||||
"mailserver.borgbackup"]
|
||||
|
||||
def render_option_value(opt, attr):
|
||||
if attr in opt:
|
||||
if isinstance(opt[attr], dict) and '_type' in opt[attr]:
|
||||
if opt[attr]['_type'] == 'literalExpression':
|
||||
if '\n' in opt[attr]['text']:
|
||||
res = '\n```nix\n' + opt[attr]['text'].rstrip('\n') + '\n```'
|
||||
else:
|
||||
res = '```{}```'.format(opt[attr]['text'])
|
||||
elif opt[attr]['_type'] == 'literalMD':
|
||||
res = opt[attr]['text']
|
||||
else:
|
||||
s = str(opt[attr])
|
||||
if s == "":
|
||||
res = '`""`'
|
||||
elif '\n' in s:
|
||||
res = '\n```\n' + s.rstrip('\n') + '\n```'
|
||||
else:
|
||||
res = '```{}```'.format(s)
|
||||
res = '- ' + attr + ': ' + res
|
||||
else:
|
||||
res = ""
|
||||
return res
|
||||
|
||||
def print_option(opt):
|
||||
if isinstance(opt['description'], dict) and '_type' in opt['description']: # mdDoc
|
||||
description = opt['description']['text']
|
||||
else:
|
||||
description = opt['description']
|
||||
print(template.format(
|
||||
key=opt['name'],
|
||||
description=description or "",
|
||||
type="- type: ```{}```".format(opt['type']),
|
||||
default=render_option_value(opt, 'default'),
|
||||
example=render_option_value(opt, 'example')))
|
||||
|
||||
|
||||
print(header)
|
||||
for opt in options:
|
||||
if any([opt['name'].startswith(c) for c in groups]):
|
||||
continue
|
||||
print_option(opt)
|
||||
|
||||
for c in groups:
|
||||
print('## `{}`'.format(c))
|
||||
print()
|
||||
for opt in options:
|
||||
if opt['name'].startswith(c):
|
||||
print_option(opt)
|
|
@ -1,87 +0,0 @@
|
|||
import json
|
||||
import sys
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
header = """
|
||||
Mailserver Options
|
||||
==================
|
||||
|
||||
mailserver
|
||||
~~~~~~~~~~
|
||||
|
||||
"""
|
||||
|
||||
template = """
|
||||
{key}
|
||||
{line}
|
||||
|
||||
{description}
|
||||
|
||||
{type}
|
||||
{default}
|
||||
{example}
|
||||
"""
|
||||
|
||||
f = open(sys.argv[1])
|
||||
options = json.load(f)
|
||||
|
||||
options = {k: v for k, v in options.items()
|
||||
if k.startswith("mailserver.")}
|
||||
|
||||
groups = ["mailserver.loginAccount",
|
||||
"mailserver.certificate",
|
||||
"mailserver.dkim",
|
||||
"mailserver.dmarcReporting",
|
||||
"mailserver.fullTextSearch",
|
||||
"mailserver.redis",
|
||||
"mailserver.monitoring",
|
||||
"mailserver.backup",
|
||||
"mailserver.borg"]
|
||||
|
||||
def render_option_value(opt, attr):
|
||||
if attr in opt:
|
||||
if isinstance(opt[attr], dict) and '_type' in opt[attr]:
|
||||
if opt[attr]['_type'] == 'literalExpression':
|
||||
if '\n' in opt[attr]['text']:
|
||||
res = '\n.. code:: nix\n\n' + textwrap.indent(opt[attr]['text'], ' ') + '\n'
|
||||
else:
|
||||
res = '``{}``'.format(opt[attr]['text'])
|
||||
elif opt[attr]['_type'] == 'literalDocBook':
|
||||
res = opt[attr]['text']
|
||||
else:
|
||||
s = str(opt[attr])
|
||||
if s == "":
|
||||
res = '``""``'
|
||||
elif '\n' in s:
|
||||
res = '\n.. code::\n\n' + textwrap.indent(s, ' ') + '\n'
|
||||
else:
|
||||
res = '``{}``'.format(s)
|
||||
res = '- ' + attr + ': ' + res
|
||||
else:
|
||||
res = ""
|
||||
return res
|
||||
|
||||
def print_option(name, value):
|
||||
print(template.format(
|
||||
key=name,
|
||||
line="-"*len(name),
|
||||
description=value['description'] or "",
|
||||
type="- type: ``{}``".format(value['type']),
|
||||
default=render_option_value(value, 'default'),
|
||||
example=render_option_value(value, 'example')))
|
||||
|
||||
|
||||
print(header)
|
||||
for k, v in options.items():
|
||||
if any([k.startswith(c) for c in groups]):
|
||||
continue
|
||||
print_option(k, v)
|
||||
|
||||
for c in groups:
|
||||
print(c)
|
||||
print("~"*len(c))
|
||||
print()
|
||||
for k, v in options.items():
|
||||
if k.startswith(c):
|
||||
print_option(k, v)
|
11
shell.nix
11
shell.nix
|
@ -1 +1,10 @@
|
|||
(import (builtins.fetchGit "https://github.com/edolstra/flake-compat") { src = ./.; }).shellNix
|
||||
(import
|
||||
(
|
||||
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
|
||||
fetchTarball {
|
||||
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||
}
|
||||
)
|
||||
{ src = ./.; }
|
||||
).shellNix
|
||||
|
|
Loading…
Reference in a new issue