docs: use MarkDown for option docs
This commit is contained in:
parent
bc667fb6af
commit
4fcab839d7
|
@ -5,9 +5,9 @@
|
||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
build:
|
build:
|
||||||
os: ubuntu-20.04
|
os: ubuntu-22.04
|
||||||
tools:
|
tools:
|
||||||
python: "3.9"
|
python: "3"
|
||||||
|
|
||||||
sphinx:
|
sphinx:
|
||||||
configuration: docs/conf.py
|
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!
|
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 = ''
|
description = ''
|
||||||
Specifies if the account should be a send-only account.
|
Specifies if the account should be a send-only account.
|
||||||
Emails sent to send-only accounts will be rejected from
|
Emails sent to send-only accounts will be rejected from
|
||||||
unauthorized senders with the sendOnlyRejectMessage
|
unauthorized senders with the `sendOnlyRejectMessage`
|
||||||
stating the reason.
|
stating the reason.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
@ -200,7 +200,7 @@ in
|
||||||
description = ''
|
description = ''
|
||||||
Folder to store search indices. If null, indices are stored
|
Folder to store search indices. If null, indices are stored
|
||||||
along with email, which could not necessarily be desirable,
|
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
|
indices it creates are voluminous and do not need to be backed
|
||||||
up.
|
up.
|
||||||
|
|
||||||
|
@ -242,8 +242,8 @@ in
|
||||||
default = "no";
|
default = "no";
|
||||||
description = ''
|
description = ''
|
||||||
Fail searches when no index is available. If set to
|
Fail searches when no index is available. If set to
|
||||||
<literal>body</literal>, then only body searches (as opposed to
|
`body`, then only body searches (as opposed to
|
||||||
header) are affected. If set to <literal>no</literal>, searches may
|
header) are affected. If set to `no`, searches may
|
||||||
fall back to a very slow brute force search.
|
fall back to a very slow brute force search.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
@ -281,7 +281,7 @@ in
|
||||||
randomizedDelaySec = mkOption {
|
randomizedDelaySec = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
default = 1000;
|
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";}`
|
the value {`"user@example.com" = "user@elsewhere.com";}`
|
||||||
means that mails to `user@example.com` are forwarded to
|
means that mails to `user@example.com` are forwarded to
|
||||||
`user@elsewhere.com`. The difference with the
|
`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
|
can't send mail as `user@example.com`. Also, this option
|
||||||
allows to forward mails to external addresses.
|
allows to forward mails to external addresses.
|
||||||
'';
|
'';
|
||||||
|
@ -367,7 +367,7 @@ in
|
||||||
description = ''
|
description = ''
|
||||||
The unix UID of the virtual mail user. Be mindful that if this is
|
The unix UID of the virtual mail user. Be mindful that if this is
|
||||||
changed, you will need to manually adjust the permissions of
|
changed, you will need to manually adjust the permissions of
|
||||||
mailDirectory.
|
`mailDirectory`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -582,7 +582,7 @@ in
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "mail";
|
default = "mail";
|
||||||
description = ''
|
description = ''
|
||||||
|
The DKIM selector.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -590,7 +590,7 @@ in
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "/var/dkim";
|
default = "/var/dkim";
|
||||||
description = ''
|
description = ''
|
||||||
|
The DKIM directory.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -601,7 +601,7 @@ in
|
||||||
How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys.
|
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
|
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
|
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.
|
change the selector or delete the old key file.
|
||||||
'';
|
'';
|
||||||
|
@ -673,7 +673,7 @@ in
|
||||||
type = types.str;
|
type = types.str;
|
||||||
example = "ACME Corp.";
|
example = "ACME Corp.";
|
||||||
description = ''
|
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.
|
DMARC reports.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
@ -681,7 +681,7 @@ in
|
||||||
fromName = mkOption {
|
fromName = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = cfg.dmarcReporting.organizationName;
|
default = cfg.dmarcReporting.organizationName;
|
||||||
defaultText = literalExpression "organizationName";
|
defaultText = literalMD "{option}`mailserver.dmarcReporting.organizationName`";
|
||||||
description = ''
|
description = ''
|
||||||
The sender name for DMARC reports. Defaults to the organization name.
|
The sender name for DMARC reports. Defaults to the organization name.
|
||||||
'';
|
'';
|
||||||
|
@ -738,7 +738,7 @@ in
|
||||||
if (ip == "0.0.0.0" || ip == "::")
|
if (ip == "0.0.0.0" || ip == "::")
|
||||||
then "127.0.0.1"
|
then "127.0.0.1"
|
||||||
else if isIpv6 ip then "[${ip}]" else ip;
|
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 = ''
|
description = ''
|
||||||
Address that rspamd should use to contact redis.
|
Address that rspamd should use to contact redis.
|
||||||
'';
|
'';
|
||||||
|
@ -776,7 +776,7 @@ in
|
||||||
sendingFqdn = mkOption {
|
sendingFqdn = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = cfg.fqdn;
|
default = cfg.fqdn;
|
||||||
defaultText = "config.mailserver.fqdn";
|
defaultText = lib.literalMD "{option}`mailserver.fqdn`";
|
||||||
example = "myserver.example.com";
|
example = "myserver.example.com";
|
||||||
description = ''
|
description = ''
|
||||||
The fully qualified domain name of the mail server used to
|
The fully qualified domain name of the mail server used to
|
||||||
|
@ -792,7 +792,7 @@ in
|
||||||
|
|
||||||
This setting allows the server to identify as
|
This setting allows the server to identify as
|
||||||
myserver.example.com when forwarding mail, independently of
|
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).
|
to which the user connects).
|
||||||
|
|
||||||
Set this to the name to which the sending IP's reverse DNS
|
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"
|
start program = "${pkgs.systemd}/bin/systemctl start rspamd"
|
||||||
stop program = "${pkgs.systemd}/bin/systemctl stop 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 = ''
|
description = ''
|
||||||
The configuration used for monitoring via monit.
|
The configuration used for monitoring via monit.
|
||||||
Use a mail address that you actively check and set it via 'set alert ...'.
|
Use a mail address that you actively check and set it via 'set alert ...'.
|
||||||
|
@ -881,7 +881,8 @@ in
|
||||||
description = ''
|
description = ''
|
||||||
The location where borg saves the backups.
|
The location where borg saves the backups.
|
||||||
This can be a local path or a remote location such as user@host:/path/to/repo.
|
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";
|
default = "none";
|
||||||
description = ''
|
description = ''
|
||||||
The backup can be encrypted by choosing any other value than 'none'.
|
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 {
|
locations = mkOption {
|
||||||
type = types.listOf types.path;
|
type = types.listOf types.path;
|
||||||
default = [cfg.mailDirectory];
|
default = [cfg.mailDirectory];
|
||||||
|
defaultText = lib.literalExpression "[ config.mailserver.mailDirectory ]";
|
||||||
description = "The locations that are to be backed up by borg.";
|
description = "The locations that are to be backed up by borg.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -984,9 +986,10 @@ in
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The command to be executed before each backup operation.
|
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.
|
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"
|
example = ''
|
||||||
|
export BORG_RSH="ssh -i /path/to/private/key"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -996,7 +999,7 @@ in
|
||||||
description = ''
|
description = ''
|
||||||
The command to be executed after each backup operation.
|
The command to be executed after each backup operation.
|
||||||
This is called after borg create completed successfully and in the same script that runs
|
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;
|
example = true;
|
||||||
description = ''
|
description = ''
|
||||||
Whether to enable automatic reboot after kernel upgrades.
|
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 {
|
method = mkOption {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Add Roundcube, a webmail
|
Add Roundcube, a webmail
|
||||||
=======================
|
========================
|
||||||
|
|
||||||
The NixOS module for roundcube nearly works out of the box with SNM. By
|
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
|
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 information -----------------------------------------------------
|
||||||
|
|
||||||
project = 'NixOS Mailserver'
|
project = 'NixOS Mailserver'
|
||||||
copyright = '2020, NixOS Mailserver Contributors'
|
copyright = '2022, NixOS Mailserver Contributors'
|
||||||
author = '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
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
|
'myst_parser'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
myst_enable_extensions = [
|
||||||
|
'colon_fence',
|
||||||
|
'linkify',
|
||||||
|
]
|
||||||
|
|
||||||
|
smartquotes = False
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
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,
|
# 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,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# 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
|
Contributing to the documentation
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
The documentation is written in RST, build with Sphinx and published
|
The documentation is written in RST (except option documentation which is in MarkDown),
|
||||||
by `Read the Docs <https://readthedocs.org/>`_.
|
built with Sphinx and published by `Read the Docs <https://readthedocs.org/>`_.
|
||||||
|
|
||||||
For the syntax, see `RST/Sphinx Cheatsheet
|
For the syntax, see `RST/Sphinx Cheatsheet
|
||||||
<https://sphinx-tutorial.readthedocs.io/cheatsheet/>`_.
|
<https://sphinx-tutorial.readthedocs.io/cheatsheet/>`_.
|
||||||
|
@ -47,11 +47,11 @@ documentation:
|
||||||
$ firefox ./_build/html/index.html
|
$ firefox ./_build/html/index.html
|
||||||
|
|
||||||
Note if you modify some NixOS mailserver options, you would also need
|
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
|
Nixops
|
||||||
------
|
------
|
||||||
|
|
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 ~= 5.3
|
||||||
sphinx_rtd_theme==0.5.2
|
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"
|
"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": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1669542132,
|
"lastModified": 1669542132,
|
||||||
|
@ -49,6 +65,7 @@
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"blobs": "blobs",
|
"blobs": "blobs",
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"nixpkgs-22_11": "nixpkgs-22_11",
|
"nixpkgs-22_11": "nixpkgs-22_11",
|
||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
|
|
90
flake.nix
90
flake.nix
|
@ -2,6 +2,10 @@
|
||||||
description = "A complete and Simple Nixos Mailserver";
|
description = "A complete and Simple Nixos Mailserver";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
|
flake-compat = {
|
||||||
|
url = "github:edolstra/flake-compat";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
utils.url = "github:numtide/flake-utils";
|
utils.url = "github:numtide/flake-utils";
|
||||||
nixpkgs.url = "flake:nixpkgs/nixos-unstable";
|
nixpkgs.url = "flake:nixpkgs/nixos-unstable";
|
||||||
nixpkgs-22_11.url = "flake:nixpkgs/nixos-22.11";
|
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";
|
system = "x86_64-linux";
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
releases = [
|
releases = [
|
||||||
|
@ -43,22 +48,18 @@
|
||||||
# external-21_05 = <derivation>;
|
# external-21_05 = <derivation>;
|
||||||
# ...
|
# ...
|
||||||
# }
|
# }
|
||||||
allTests = pkgs.lib.listToAttrs (
|
allTests = lib.listToAttrs (
|
||||||
pkgs.lib.flatten (map (t: map (r: genTest t r) releases) testNames));
|
lib.flatten (map (t: map (r: genTest t r) releases) testNames));
|
||||||
|
|
||||||
mailserverModule = import ./.;
|
mailserverModule = import ./.;
|
||||||
|
|
||||||
# Generate a rst file describing options of the NixOS mailserver module
|
# Generate a MarkDown file describing the options of the NixOS mailserver module
|
||||||
generateRstOptions = let
|
optionsDoc = let
|
||||||
eval = import (pkgs.path + "/nixos/lib/eval-config.nix") {
|
eval = lib.evalModules {
|
||||||
inherit system;
|
|
||||||
modules = [
|
modules = [
|
||||||
mailserverModule
|
mailserverModule
|
||||||
{
|
{
|
||||||
# Because the blockbook package is currently broken (we
|
_module.check = false;
|
||||||
# don't care about this package but it is part of the
|
|
||||||
# NixOS module evaluation)
|
|
||||||
nixpkgs.config.allowBroken = true;
|
|
||||||
mailserver = {
|
mailserver = {
|
||||||
fqdn = "mx.example.com";
|
fqdn = "mx.example.com";
|
||||||
domains = [
|
domains = [
|
||||||
|
@ -71,27 +72,26 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
};
|
};
|
||||||
options = pkgs.nixosOptionsDoc {
|
options = builtins.toFile "options.json" (builtins.toJSON
|
||||||
options = eval.options;
|
(lib.filter (opt: opt.visible && !opt.internal && lib.head opt.loc == "mailserver")
|
||||||
};
|
(lib.optionAttrSetToDocList eval.options)));
|
||||||
in pkgs.runCommand "options.rst" { buildInputs = [pkgs.python3]; } ''
|
in pkgs.runCommand "options.md" { buildInputs = [pkgs.python3Minimal]; } ''
|
||||||
echo Generating options.rst from ${options.optionsJSON}/share/doc/nixos/options.json
|
echo "Generating options.md from ${options}"
|
||||||
python ${./scripts/generate-rst-options.py} ${options.optionsJSON}/share/doc/nixos/options.json > $out
|
python ${./scripts/generate-options.py} ${options} > $out
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# This is a script helping users to generate this file in the docs directory
|
# This is a script helping users to generate this file in the docs directory
|
||||||
generateRstOptionsScript = pkgs.writeScriptBin "generate-rst-options" ''
|
generateOptions = pkgs.writeShellScriptBin "generate-options" ''
|
||||||
cp -v ${generateRstOptions} ./docs/options.rst
|
install -vm644 ${optionsDoc} ./docs/options.md
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# This is to ensure we don't forget to update the options.rst file
|
# This is to ensure we don't forget to update the options.md file
|
||||||
testRstOptions = pkgs.runCommand "test-rst-options" {} ''
|
testOptions = pkgs.runCommand "test-options" {} ''
|
||||||
if ! diff -q ${./docs/options.rst} ${generateRstOptions}
|
if ! diff -q ${./docs/options.md} ${optionsDoc}
|
||||||
then
|
then
|
||||||
echo "The file ./docs/options.rst is not up-to-date and needs to be regenerated!"
|
echo "The file ./docs/options.md is not up-to-date and needs to be regenerated!"
|
||||||
echo " hint: run 'nix-shell --run generate-rst-options' to generate this file"
|
echo " hint: run 'nix-shell --run generate-options' to generate this file"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "test: ok" > $out
|
echo "test: ok" > $out
|
||||||
|
@ -99,43 +99,43 @@
|
||||||
|
|
||||||
documentation = pkgs.stdenv.mkDerivation {
|
documentation = pkgs.stdenv.mkDerivation {
|
||||||
name = "documentation";
|
name = "documentation";
|
||||||
src = pkgs.lib.sourceByRegex ./docs ["logo.png" "conf.py" "Makefile" ".*rst$"];
|
src = lib.sourceByRegex ./docs ["logo\\.png" "conf\\.py" "Makefile" ".*\\.rst"];
|
||||||
buildInputs = [(
|
buildInputs = [(
|
||||||
pkgs.python3.withPackages(p: [
|
pkgs.python3.withPackages (p: with p; [
|
||||||
p.sphinx
|
sphinx
|
||||||
p.sphinx_rtd_theme
|
sphinx_rtd_theme
|
||||||
|
myst-parser
|
||||||
])
|
])
|
||||||
)];
|
)];
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
cp ${generateRstOptions} options.rst
|
cp ${optionsDoc} options.md
|
||||||
mkdir -p _static
|
|
||||||
# Workaround for https://github.com/sphinx-doc/sphinx/issues/3451
|
# 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
|
make html
|
||||||
'';
|
'';
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
cp -r _build/html $out
|
cp -Tr _build/html $out
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
in rec {
|
in {
|
||||||
nixosModules.mailserver = mailserverModule ;
|
nixosModules = rec {
|
||||||
nixosModule = self.nixosModules.mailserver;
|
mailserver = mailserverModule;
|
||||||
|
default = mailserver;
|
||||||
|
};
|
||||||
|
nixosModule = self.nixosModules.default; # compatibility
|
||||||
hydraJobs.${system} = allTests // {
|
hydraJobs.${system} = allTests // {
|
||||||
test-rst-options = testRstOptions;
|
test-options = testOptions;
|
||||||
inherit documentation;
|
inherit documentation;
|
||||||
};
|
};
|
||||||
checks.${system} = allTests;
|
checks.${system} = allTests;
|
||||||
devShell.${system} = pkgs.mkShell {
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
buildInputs = with pkgs; [
|
inputsFrom = [ documentation ];
|
||||||
generateRstOptionsScript
|
packages = with pkgs; [
|
||||||
(python3.withPackages (p: with p; [
|
generateOptions
|
||||||
sphinx
|
|
||||||
sphinx_rtd_theme
|
|
||||||
]))
|
|
||||||
jq
|
|
||||||
clamav
|
clamav
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
devShell.${system} = self.devShells.${system}.default; # compatibility
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 New Issue