Merge pull request #215973 from pennae/nrd-manual-structure
nixos/manual: specify manual structure in markdown
This commit is contained in:
commit
b72592ee04
43 changed files with 539 additions and 706 deletions
|
@ -75,7 +75,7 @@ in pkgs.runCommand "doc-support" {}
|
|||
ln -s ${epub-xsl} ./epub.xsl
|
||||
ln -s ${xhtml-xsl} ./xhtml.xsl
|
||||
|
||||
ln -s ${../../nixos/doc/xmlformat.conf} ./xmlformat.conf
|
||||
ln -s ${./xmlformat.conf} ./xmlformat.conf
|
||||
ln -s ${pkgs.documentation-highlighter} ./highlightjs
|
||||
|
||||
echo -n "${version}" > ./version
|
||||
|
|
2
nixos/doc/manual/.gitignore
vendored
2
nixos/doc/manual/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
generated
|
||||
manual-combined.xml
|
|
@ -1,30 +0,0 @@
|
|||
.PHONY: all
|
||||
all: manual-combined.xml
|
||||
|
||||
.PHONY: debug
|
||||
debug: generated manual-combined.xml
|
||||
|
||||
manual-combined.xml: generated *.xml **/*.xml
|
||||
rm -f ./manual-combined.xml
|
||||
nix-shell --pure -Q --packages xmloscopy \
|
||||
--run "xmloscopy --docbook5 ./manual.xml ./manual-combined.xml"
|
||||
|
||||
.PHONY: format
|
||||
format:
|
||||
nix-shell --pure -Q --packages xmlformat \
|
||||
--run "find ../../ -iname '*.xml' -type f -print0 | xargs -0 -I{} -n1 \
|
||||
xmlformat --config-file '../xmlformat.conf' -i {}"
|
||||
|
||||
.PHONY: fix-misc-xml
|
||||
fix-misc-xml:
|
||||
find . -iname '*.xml' -type f \
|
||||
-exec ../varlistentry-fixer.rb {} ';'
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f manual-combined.xml generated
|
||||
|
||||
generated:
|
||||
nix-build ../../release.nix \
|
||||
--attr manualGeneratedSources.x86_64-linux \
|
||||
--out-link ./generated
|
|
@ -21,8 +21,8 @@ which is often not what you want. By contrast, in the imperative
|
|||
approach, containers are configured and updated independently from the
|
||||
host system.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="imperative-containers.section.xml" />
|
||||
<xi:include href="declarative-containers.section.xml" />
|
||||
<xi:include href="container-networking.section.xml" />
|
||||
```{=include=} sections
|
||||
imperative-containers.section.md
|
||||
declarative-containers.section.md
|
||||
container-networking.section.md
|
||||
```
|
||||
|
|
14
nixos/doc/manual/administration/running.md
Normal file
14
nixos/doc/manual/administration/running.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Administration {#ch-running}
|
||||
|
||||
This chapter describes various aspects of managing a running NixOS system, such as how to use the {command}`systemd` service manager.
|
||||
|
||||
```{=include=} chapters
|
||||
service-mgmt.chapter.md
|
||||
rebooting.chapter.md
|
||||
user-sessions.chapter.md
|
||||
control-groups.chapter.md
|
||||
logging.chapter.md
|
||||
cleaning-store.chapter.md
|
||||
containers.chapter.md
|
||||
troubleshooting.chapter.md
|
||||
```
|
|
@ -1,21 +0,0 @@
|
|||
<part xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="ch-running">
|
||||
<title>Administration</title>
|
||||
<partintro xml:id="ch-running-intro">
|
||||
<para>
|
||||
This chapter describes various aspects of managing a running NixOS system,
|
||||
such as how to use the <command>systemd</command> service manager.
|
||||
</para>
|
||||
</partintro>
|
||||
<xi:include href="../from_md/administration/service-mgmt.chapter.xml" />
|
||||
<xi:include href="../from_md/administration/rebooting.chapter.xml" />
|
||||
<xi:include href="../from_md/administration/user-sessions.chapter.xml" />
|
||||
<xi:include href="../from_md/administration/control-groups.chapter.xml" />
|
||||
<xi:include href="../from_md/administration/logging.chapter.xml" />
|
||||
<xi:include href="../from_md/administration/cleaning-store.chapter.xml" />
|
||||
<xi:include href="../from_md/administration/containers.chapter.xml" />
|
||||
<xi:include href="../from_md/administration/troubleshooting.chapter.xml" />
|
||||
</part>
|
|
@ -3,10 +3,10 @@
|
|||
This chapter describes solutions to common problems you might encounter
|
||||
when you manage your NixOS system.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="boot-problems.section.xml" />
|
||||
<xi:include href="maintenance-mode.section.xml" />
|
||||
<xi:include href="rollback.section.xml" />
|
||||
<xi:include href="store-corruption.section.xml" />
|
||||
<xi:include href="network-problems.section.xml" />
|
||||
```{=include=} sections
|
||||
boot-problems.section.md
|
||||
maintenance-mode.section.md
|
||||
rollback.section.md
|
||||
store-corruption.section.md
|
||||
network-problems.section.md
|
||||
```
|
||||
|
|
|
@ -11,8 +11,8 @@ manual](https://nixos.org/nix/manual/#chap-writing-nix-expressions), but
|
|||
here we give a short overview of the most important constructs useful in
|
||||
NixOS configuration files.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="config-file.section.xml" />
|
||||
<xi:include href="abstractions.section.xml" />
|
||||
<xi:include href="modularity.section.xml" />
|
||||
```{=include=} sections
|
||||
config-file.section.md
|
||||
abstractions.section.md
|
||||
modularity.section.md
|
||||
```
|
||||
|
|
27
nixos/doc/manual/configuration/configuration.md
Normal file
27
nixos/doc/manual/configuration/configuration.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Configuration {#ch-configuration}
|
||||
|
||||
This chapter describes how to configure various aspects of a NixOS machine through the configuration file {file}`/etc/nixos/configuration.nix`. As described in [](#sec-changing-config), changes to this file only take effect after you run {command}`nixos-rebuild`.
|
||||
|
||||
```{=include=} chapters
|
||||
config-syntax.chapter.md
|
||||
package-mgmt.chapter.md
|
||||
user-mgmt.chapter.md
|
||||
file-systems.chapter.md
|
||||
x-windows.chapter.md
|
||||
wayland.chapter.md
|
||||
gpu-accel.chapter.md
|
||||
xfce.chapter.md
|
||||
networking.chapter.md
|
||||
linux-kernel.chapter.md
|
||||
subversion.chapter.md
|
||||
```
|
||||
|
||||
```{=include=} chapters
|
||||
@MODULE_CHAPTERS@
|
||||
```
|
||||
|
||||
```{=include=} chapters
|
||||
profiles.chapter.md
|
||||
kubernetes.chapter.md
|
||||
```
|
||||
<!-- Apache; libvirtd virtualisation -->
|
|
@ -1,31 +0,0 @@
|
|||
<part xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="ch-configuration">
|
||||
<title>Configuration</title>
|
||||
<partintro xml:id="ch-configuration-intro">
|
||||
<para>
|
||||
This chapter describes how to configure various aspects of a NixOS machine
|
||||
through the configuration file
|
||||
<filename>/etc/nixos/configuration.nix</filename>. As described in
|
||||
<xref linkend="sec-changing-config" />, changes to this file only take
|
||||
effect after you run <command>nixos-rebuild</command>.
|
||||
</para>
|
||||
</partintro>
|
||||
<xi:include href="../from_md/configuration/config-syntax.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/package-mgmt.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/user-mgmt.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/file-systems.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/x-windows.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/wayland.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/gpu-accel.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/xfce.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/networking.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/linux-kernel.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/subversion.chapter.xml" />
|
||||
<xi:include href="../generated/modules.xml" xpointer="xpointer(//section[@id='modules']/*)" />
|
||||
<xi:include href="../from_md/configuration/profiles.chapter.xml" />
|
||||
<xi:include href="../from_md/configuration/kubernetes.chapter.xml" />
|
||||
<!-- Apache; libvirtd virtualisation -->
|
||||
</part>
|
|
@ -40,7 +40,7 @@ configuration use `pkgs` prefix (variable).
|
|||
To "uninstall" a package, simply remove it from
|
||||
[](#opt-environment.systemPackages) and run `nixos-rebuild switch`.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="customizing-packages.section.xml" />
|
||||
<xi:include href="adding-custom-packages.section.xml" />
|
||||
```{=include=} sections
|
||||
customizing-packages.section.md
|
||||
adding-custom-packages.section.md
|
||||
```
|
||||
|
|
|
@ -36,7 +36,7 @@ dropping you to the emergency shell. You can make a mount asynchronous
|
|||
and non-critical by adding `options = [ "nofail" ];`.
|
||||
:::
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="luks-file-systems.section.xml" />
|
||||
<xi:include href="sshfs-file-systems.section.xml" />
|
||||
```{=include=} sections
|
||||
luks-file-systems.section.md
|
||||
sshfs-file-systems.section.md
|
||||
```
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
This section describes how to configure networking components
|
||||
on your NixOS machine.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="network-manager.section.xml" />
|
||||
<xi:include href="ssh.section.xml" />
|
||||
<xi:include href="ipv4-config.section.xml" />
|
||||
<xi:include href="ipv6-config.section.xml" />
|
||||
<xi:include href="firewall.section.xml" />
|
||||
<xi:include href="wireless.section.xml" />
|
||||
<xi:include href="ad-hoc-network-config.section.xml" />
|
||||
<xi:include href="renaming-interfaces.section.xml" />
|
||||
```{=include=} sections
|
||||
network-manager.section.md
|
||||
ssh.section.md
|
||||
ipv4-config.section.md
|
||||
ipv6-config.section.md
|
||||
firewall.section.md
|
||||
wireless.section.md
|
||||
ad-hoc-network-config.section.md
|
||||
renaming-interfaces.section.md
|
||||
```
|
||||
<!-- TODO: OpenVPN, NAT -->
|
||||
|
|
|
@ -12,7 +12,7 @@ NixOS has two distinct styles of package management:
|
|||
`nix-env` command. This style allows mixing packages from different
|
||||
Nixpkgs versions. It's the only choice for non-root users.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="declarative-packages.section.xml" />
|
||||
<xi:include href="ad-hoc-packages.section.xml" />
|
||||
```{=include=} sections
|
||||
declarative-packages.section.md
|
||||
ad-hoc-packages.section.md
|
||||
```
|
||||
|
|
|
@ -19,16 +19,16 @@ install media, many are actually intended to be used in real installs.
|
|||
What follows is a brief explanation on the purpose and use-case for each
|
||||
profile. Detailing each option configured by each one is out of scope.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="profiles/all-hardware.section.xml" />
|
||||
<xi:include href="profiles/base.section.xml" />
|
||||
<xi:include href="profiles/clone-config.section.xml" />
|
||||
<xi:include href="profiles/demo.section.xml" />
|
||||
<xi:include href="profiles/docker-container.section.xml" />
|
||||
<xi:include href="profiles/graphical.section.xml" />
|
||||
<xi:include href="profiles/hardened.section.xml" />
|
||||
<xi:include href="profiles/headless.section.xml" />
|
||||
<xi:include href="profiles/installation-device.section.xml" />
|
||||
<xi:include href="profiles/minimal.section.xml" />
|
||||
<xi:include href="profiles/qemu-guest.section.xml" />
|
||||
```{=include=} sections
|
||||
profiles/all-hardware.section.md
|
||||
profiles/base.section.md
|
||||
profiles/clone-config.section.md
|
||||
profiles/demo.section.md
|
||||
profiles/docker-container.section.md
|
||||
profiles/graphical.section.md
|
||||
profiles/hardened.section.md
|
||||
profiles/headless.section.md
|
||||
profiles/installation-device.section.md
|
||||
profiles/minimal.section.md
|
||||
profiles/qemu-guest.section.md
|
||||
```
|
||||
|
|
|
@ -68,56 +68,6 @@ let
|
|||
optionIdPrefix = "test-opt-";
|
||||
};
|
||||
|
||||
sources = runCommand "manual-sources" {
|
||||
inputs = lib.sourceFilesBySuffices ./. [ ".xml" ".md" ];
|
||||
nativeBuildInputs = [ pkgs.nixos-render-docs ];
|
||||
} ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
cp -r --no-preserve=all $inputs/* .
|
||||
|
||||
declare -a convert_args
|
||||
while read -r mf; do
|
||||
if [[ "$mf" = *.chapter.md ]]; then
|
||||
convert_args+=("--chapter")
|
||||
else
|
||||
convert_args+=("--section")
|
||||
fi
|
||||
|
||||
convert_args+=("from_md/''${mf%.md}.xml" "$mf")
|
||||
done < <(find . -type f -name '*.md')
|
||||
|
||||
nixos-render-docs manual docbook-fragment \
|
||||
--manpage-urls ${manpageUrls} \
|
||||
"''${convert_args[@]}"
|
||||
'';
|
||||
|
||||
modulesDoc = runCommand "modules.xml" {
|
||||
nativeBuildInputs = [ pkgs.nixos-render-docs ];
|
||||
} ''
|
||||
nixos-render-docs manual docbook-section \
|
||||
--manpage-urls ${manpageUrls} \
|
||||
"$out" \
|
||||
--section \
|
||||
--section-id modules \
|
||||
--chapters ${lib.concatMapStrings (p: "${p.value} ") config.meta.doc}
|
||||
'';
|
||||
|
||||
generatedSources = runCommand "generated-docbook" {} ''
|
||||
mkdir $out
|
||||
ln -s ${modulesDoc} $out/modules.xml
|
||||
ln -s ${optionsDoc.optionsDocBook} $out/options-db.xml
|
||||
ln -s ${testOptionsDoc.optionsDocBook} $out/test-options-db.xml
|
||||
printf "%s" "${version}" > $out/version
|
||||
'';
|
||||
|
||||
copySources =
|
||||
''
|
||||
cp -prd $sources/* . # */
|
||||
ln -s ${generatedSources} ./generated
|
||||
chmod -R u+w .
|
||||
'';
|
||||
|
||||
toc = builtins.toFile "toc.xml"
|
||||
''
|
||||
<toc role="chunk-toc">
|
||||
|
@ -148,70 +98,102 @@ let
|
|||
"--stringparam chunk.toc ${toc}"
|
||||
];
|
||||
|
||||
linterFunctions = ''
|
||||
# outputs the context of an xmllint error output
|
||||
# LEN lines around the failing line are printed
|
||||
function context {
|
||||
# length of context
|
||||
local LEN=6
|
||||
# lines to print before error line
|
||||
local BEFORE=4
|
||||
|
||||
# xmllint output lines are:
|
||||
# file.xml:1234: there was an error on line 1234
|
||||
while IFS=':' read -r file line rest; do
|
||||
echo
|
||||
if [[ -n "$rest" ]]; then
|
||||
echo "$file:$line:$rest"
|
||||
local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1))
|
||||
# number lines & filter context
|
||||
nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p"
|
||||
else
|
||||
if [[ -n "$line" ]]; then
|
||||
echo "$file:$line"
|
||||
else
|
||||
echo "$file"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function lintrng {
|
||||
xmllint --debug --noout --nonet \
|
||||
--relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
|
||||
"$1" \
|
||||
2>&1 | context 1>&2
|
||||
# ^ redirect assumes xmllint doesn’t print to stdout
|
||||
}
|
||||
'';
|
||||
|
||||
manual-combined = runCommand "nixos-manual-combined"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
{ inputs = lib.sourceFilesBySuffices ./. [ ".xml" ".md" ];
|
||||
nativeBuildInputs = [ pkgs.nixos-render-docs pkgs.libxml2.bin pkgs.libxslt.bin ];
|
||||
meta.description = "The NixOS manual as plain docbook XML";
|
||||
}
|
||||
''
|
||||
${copySources}
|
||||
cp -r --no-preserve=all $inputs/* .
|
||||
|
||||
xmllint --xinclude --output ./manual-combined.xml ./manual.xml
|
||||
xmllint --xinclude --noxincludenode \
|
||||
--output ./man-pages-combined.xml ./man-pages.xml
|
||||
substituteInPlace ./manual.md \
|
||||
--replace '@NIXOS_VERSION@' "${version}"
|
||||
substituteInPlace ./configuration/configuration.md \
|
||||
--replace \
|
||||
'@MODULE_CHAPTERS@' \
|
||||
${lib.escapeShellArg (lib.concatMapStringsSep "\n" (p: "${p.value}") config.meta.doc)}
|
||||
substituteInPlace ./nixos-options.md \
|
||||
--replace \
|
||||
'@NIXOS_OPTIONS_JSON@' \
|
||||
${optionsDoc.optionsJSON}/share/doc/nixos/options.json
|
||||
substituteInPlace ./development/writing-nixos-tests.section.md \
|
||||
--replace \
|
||||
'@NIXOS_TEST_OPTIONS_JSON@' \
|
||||
${testOptionsDoc.optionsJSON}/share/doc/nixos/options.json
|
||||
|
||||
# outputs the context of an xmllint error output
|
||||
# LEN lines around the failing line are printed
|
||||
function context {
|
||||
# length of context
|
||||
local LEN=6
|
||||
# lines to print before error line
|
||||
local BEFORE=4
|
||||
nixos-render-docs manual docbook \
|
||||
--manpage-urls ${manpageUrls} \
|
||||
--revision ${lib.escapeShellArg revision} \
|
||||
./manual.md \
|
||||
./manual-combined.xml
|
||||
|
||||
# xmllint output lines are:
|
||||
# file.xml:1234: there was an error on line 1234
|
||||
while IFS=':' read -r file line rest; do
|
||||
echo
|
||||
if [[ -n "$rest" ]]; then
|
||||
echo "$file:$line:$rest"
|
||||
local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1))
|
||||
# number lines & filter context
|
||||
nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p"
|
||||
else
|
||||
if [[ -n "$line" ]]; then
|
||||
echo "$file:$line"
|
||||
else
|
||||
echo "$file"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function lintrng {
|
||||
xmllint --debug --noout --nonet \
|
||||
--relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
|
||||
"$1" \
|
||||
2>&1 | context 1>&2
|
||||
# ^ redirect assumes xmllint doesn’t print to stdout
|
||||
}
|
||||
${linterFunctions}
|
||||
|
||||
mkdir $out
|
||||
cp manual-combined.xml $out/
|
||||
cp man-pages-combined.xml $out/
|
||||
|
||||
lintrng $out/manual-combined.xml
|
||||
lintrng $out/man-pages-combined.xml
|
||||
'';
|
||||
|
||||
manpages-combined = runCommand "nixos-manpages-combined.xml"
|
||||
{ nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
meta.description = "The NixOS manpages as plain docbook XML";
|
||||
}
|
||||
''
|
||||
mkdir generated
|
||||
cp -prd ${./man-pages.xml} man-pages.xml
|
||||
ln -s ${optionsDoc.optionsDocBook} generated/options-db.xml
|
||||
|
||||
xmllint --xinclude --noxincludenode --output $out ./man-pages.xml
|
||||
|
||||
${linterFunctions}
|
||||
|
||||
lintrng $out
|
||||
'';
|
||||
|
||||
in rec {
|
||||
inherit generatedSources;
|
||||
|
||||
inherit (optionsDoc) optionsJSON optionsNix optionsDocBook optionsUsedDocbook;
|
||||
|
||||
# Generate the NixOS manual.
|
||||
manualHTML = runCommand "nixos-manual-html"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
{ nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
meta.description = "The NixOS manual in HTML format";
|
||||
allowedReferences = ["out"];
|
||||
}
|
||||
|
@ -248,8 +230,7 @@ in rec {
|
|||
manualHTMLIndex = "${manualHTML}/share/doc/nixos/index.html";
|
||||
|
||||
manualEpub = runCommand "nixos-manual-epub"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin buildPackages.zip ];
|
||||
{ nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin buildPackages.zip ];
|
||||
}
|
||||
''
|
||||
# Generate the epub manual.
|
||||
|
@ -300,7 +281,7 @@ in rec {
|
|||
--param man.endnotes.are.numbered 0 \
|
||||
--param man.break.after.slash 1 \
|
||||
${docbook_xsl_ns}/xml/xsl/docbook/manpages/docbook.xsl \
|
||||
${manual-combined}/man-pages-combined.xml
|
||||
${manpages-combined}
|
||||
''
|
||||
else ''
|
||||
mkdir -p $out/share/man/man5
|
||||
|
|
14
nixos/doc/manual/development/development.md
Normal file
14
nixos/doc/manual/development/development.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Development {#ch-development}
|
||||
|
||||
This chapter describes how you can modify and extend NixOS.
|
||||
|
||||
```{=include=} chapters
|
||||
sources.chapter.md
|
||||
writing-modules.chapter.md
|
||||
building-parts.chapter.md
|
||||
bootspec.chapter.md
|
||||
what-happens-during-a-system-switch.chapter.md
|
||||
writing-documentation.chapter.md
|
||||
nixos-tests.chapter.md
|
||||
testing-installer.chapter.md
|
||||
```
|
|
@ -1,20 +0,0 @@
|
|||
<part xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="ch-development">
|
||||
<title>Development</title>
|
||||
<partintro xml:id="ch-development-intro">
|
||||
<para>
|
||||
This chapter describes how you can modify and extend NixOS.
|
||||
</para>
|
||||
</partintro>
|
||||
<xi:include href="../from_md/development/sources.chapter.xml" />
|
||||
<xi:include href="../from_md/development/writing-modules.chapter.xml" />
|
||||
<xi:include href="../from_md/development/building-parts.chapter.xml" />
|
||||
<xi:include href="../from_md/development/bootspec.chapter.xml" />
|
||||
<xi:include href="../from_md/development/what-happens-during-a-system-switch.chapter.xml" />
|
||||
<xi:include href="../from_md/development/writing-documentation.chapter.xml" />
|
||||
<xi:include href="../from_md/development/nixos-tests.chapter.xml" />
|
||||
<xi:include href="../from_md/development/testing-installer.chapter.xml" />
|
||||
</part>
|
|
@ -5,9 +5,9 @@ NixOS tests are kept in the directory `nixos/tests`, and are executed
|
|||
(using Nix) by a testing framework that automatically starts one or more
|
||||
virtual machines containing the NixOS system(s) required for the test.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="writing-nixos-tests.section.xml" />
|
||||
<xi:include href="running-nixos-tests.section.xml" />
|
||||
<xi:include href="running-nixos-tests-interactively.section.xml" />
|
||||
<xi:include href="linking-nixos-tests-to-packages.section.xml" />
|
||||
```{=include=} sections
|
||||
writing-nixos-tests.section.md
|
||||
running-nixos-tests.section.md
|
||||
running-nixos-tests-interactively.section.md
|
||||
linking-nixos-tests-to-packages.section.md
|
||||
```
|
||||
|
|
|
@ -47,7 +47,7 @@ Most of these actions are either self-explaining but some of them have to do
|
|||
with our units or the activation script. For this reason, these topics are
|
||||
explained in the next sections.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="unit-handling.section.xml" />
|
||||
<xi:include href="activation-script.section.xml" />
|
||||
```{=include=} sections
|
||||
unit-handling.section.md
|
||||
activation-script.section.md
|
||||
```
|
||||
|
|
|
@ -83,7 +83,7 @@ Keep the following guidelines in mind when you create and add a topic:
|
|||
|
||||
## Adding a Topic to the Book {#sec-writing-docs-adding-a-topic}
|
||||
|
||||
Open the parent XML file and add an `xi:include` element to the list of
|
||||
Open the parent CommonMark file and add a line to the list of
|
||||
chapters with the file name of the topic that you created. If you
|
||||
created a `section`, you add the file to the `chapter` file. If you created
|
||||
a `chapter`, you add the file to the `part` file.
|
||||
|
|
|
@ -189,14 +189,14 @@ in {
|
|||
```
|
||||
:::
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="option-declarations.section.xml" />
|
||||
<xi:include href="option-types.section.xml" />
|
||||
<xi:include href="option-def.section.xml" />
|
||||
<xi:include href="assertions.section.xml" />
|
||||
<xi:include href="meta-attributes.section.xml" />
|
||||
<xi:include href="importing-modules.section.xml" />
|
||||
<xi:include href="replace-modules.section.xml" />
|
||||
<xi:include href="freeform-modules.section.xml" />
|
||||
<xi:include href="settings-options.section.xml" />
|
||||
```{=include=} sections
|
||||
option-declarations.section.md
|
||||
option-types.section.md
|
||||
option-def.section.md
|
||||
assertions.section.md
|
||||
meta-attributes.section.md
|
||||
importing-modules.section.md
|
||||
replace-modules.section.md
|
||||
freeform-modules.section.md
|
||||
settings-options.section.md
|
||||
```
|
||||
|
|
|
@ -470,6 +470,8 @@ In that case, `numpy` is chosen from the generic `python3Packages`.
|
|||
|
||||
The following options can be used when writing tests.
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="../../generated/test-options-db.xml" xpointer="test-options-list"/>
|
||||
```{=include=} options
|
||||
id-prefix: test-opt-
|
||||
list-id: test-options-list
|
||||
source: @NIXOS_TEST_OPTIONS_JSON@
|
||||
```
|
||||
|
|
11
nixos/doc/manual/installation/installation.md
Normal file
11
nixos/doc/manual/installation/installation.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Installation {#ch-installation}
|
||||
|
||||
This section describes how to obtain, install, and configure NixOS for first-time use.
|
||||
|
||||
```{=include=} chapters
|
||||
obtaining.chapter.md
|
||||
installing.chapter.md
|
||||
changing-config.chapter.md
|
||||
upgrading.chapter.md
|
||||
building-nixos.chapter.md
|
||||
```
|
|
@ -1,18 +0,0 @@
|
|||
<part xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="ch-installation">
|
||||
<title>Installation</title>
|
||||
<partintro xml:id="ch-installation-intro">
|
||||
<para>
|
||||
This section describes how to obtain, install, and configure NixOS for
|
||||
first-time use.
|
||||
</para>
|
||||
</partintro>
|
||||
<xi:include href="../from_md/installation/obtaining.chapter.xml" />
|
||||
<xi:include href="../from_md/installation/installing.chapter.xml" />
|
||||
<xi:include href="../from_md/installation/changing-config.chapter.xml" />
|
||||
<xi:include href="../from_md/installation/upgrading.chapter.xml" />
|
||||
<xi:include href="../from_md/installation/building-nixos.chapter.xml" />
|
||||
</part>
|
|
@ -602,11 +602,11 @@ With a partitioned disk.
|
|||
|
||||
## Additional installation notes {#sec-installation-additional-notes}
|
||||
|
||||
```{=docbook}
|
||||
<xi:include href="installing-usb.section.xml" />
|
||||
<xi:include href="installing-pxe.section.xml" />
|
||||
<xi:include href="installing-kexec.section.xml" />
|
||||
<xi:include href="installing-virtualbox-guest.section.xml" />
|
||||
<xi:include href="installing-from-other-distro.section.xml" />
|
||||
<xi:include href="installing-behind-a-proxy.section.xml" />
|
||||
```{=include=} sections
|
||||
installing-usb.section.md
|
||||
installing-pxe.section.md
|
||||
installing-kexec.section.md
|
||||
installing-virtualbox-guest.section.md
|
||||
installing-from-other-distro.section.md
|
||||
installing-behind-a-proxy.section.md
|
||||
```
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<refmeta>
|
||||
<refentrytitle><filename>configuration.nix</filename>
|
||||
</refentrytitle><manvolnum>5</manvolnum>
|
||||
<refmiscinfo class="source">NixOS</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname><filename>configuration.nix</filename></refname>
|
||||
<refpurpose>NixOS system configuration specification</refpurpose>
|
||||
</refnamediv>
|
||||
<refsection>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
The file <filename>/etc/nixos/configuration.nix</filename> contains the
|
||||
declarative specification of your NixOS system configuration. The command
|
||||
<command>nixos-rebuild</command> takes this file and realises the system
|
||||
configuration specified therein.
|
||||
</para>
|
||||
</refsection>
|
||||
<refsection>
|
||||
<title>Options</title>
|
||||
<para>
|
||||
You can use the following options in <filename>configuration.nix</filename>.
|
||||
</para>
|
||||
<xi:include href="./generated/options-db.xml"
|
||||
xpointer="configuration-variable-list" />
|
||||
</refsection>
|
||||
</refentry>
|
|
@ -14,5 +14,33 @@
|
|||
<copyright><year>2007-2022</year><holder>Eelco Dolstra and the Nixpkgs/NixOS contributors</holder>
|
||||
</copyright>
|
||||
</info>
|
||||
<xi:include href="man-configuration.xml" />
|
||||
<refentry>
|
||||
<refmeta>
|
||||
<refentrytitle><filename>configuration.nix</filename>
|
||||
</refentrytitle><manvolnum>5</manvolnum>
|
||||
<refmiscinfo class="source">NixOS</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname><filename>configuration.nix</filename></refname>
|
||||
<refpurpose>NixOS system configuration specification</refpurpose>
|
||||
</refnamediv>
|
||||
<refsection>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
The file <filename>/etc/nixos/configuration.nix</filename> contains the
|
||||
declarative specification of your NixOS system configuration. The command
|
||||
<command>nixos-rebuild</command> takes this file and realises the system
|
||||
configuration specified therein.
|
||||
</para>
|
||||
</refsection>
|
||||
<refsection>
|
||||
<title>Options</title>
|
||||
<para>
|
||||
You can use the following options in <filename>configuration.nix</filename>.
|
||||
</para>
|
||||
<xi:include href="./generated/options-db.xml"
|
||||
xpointer="configuration-variable-list" />
|
||||
</refsection>
|
||||
</refentry>
|
||||
</reference>
|
||||
|
|
53
nixos/doc/manual/manual.md
Normal file
53
nixos/doc/manual/manual.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# NixOS Manual {#book-nixos-manual}
|
||||
## Version @NIXOS_VERSION@
|
||||
|
||||
<!--
|
||||
this is the top-level structure file for the nixos manual.
|
||||
|
||||
the manual structure extends the nixpkgs commonmark further with include
|
||||
blocks to allow better organization of input text. there are six types of
|
||||
include blocks: preface, parts, chapters, sections, appendix, and options.
|
||||
each type except `options`` corresponds to the docbook elements of (roughly)
|
||||
the same name, and can itself can further include blocks to denote its
|
||||
substructure.
|
||||
|
||||
non-`options`` include blocks are fenced code blocks that list a number of
|
||||
files to include, in the form
|
||||
|
||||
```{=include=} <type>
|
||||
<file-name-1>
|
||||
<file-name-2>
|
||||
<...>
|
||||
```
|
||||
|
||||
`options` include blocks do not list file names but contain a list of key-value
|
||||
pairs that describe the options to be included and how to convert them into
|
||||
elements of the manual output type:
|
||||
|
||||
```{=include=} options
|
||||
id-prefix: <options id prefix>
|
||||
list-id: <variable list element id>
|
||||
source: <path to options.json>
|
||||
```
|
||||
|
||||
-->
|
||||
|
||||
```{=include=} preface
|
||||
preface.md
|
||||
```
|
||||
|
||||
```{=include=} parts
|
||||
installation/installation.md
|
||||
configuration/configuration.md
|
||||
administration/running.md
|
||||
development/development.md
|
||||
```
|
||||
|
||||
```{=include=} chapters
|
||||
contributing-to-this-manual.chapter.md
|
||||
```
|
||||
|
||||
```{=include=} appendix
|
||||
nixos-options.md
|
||||
release-notes/release-notes.md
|
||||
```
|
|
@ -1,23 +0,0 @@
|
|||
<book xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="book-nixos-manual">
|
||||
<info>
|
||||
<title>NixOS Manual</title>
|
||||
<subtitle>Version <xi:include href="./generated/version" parse="text" />
|
||||
</subtitle>
|
||||
</info>
|
||||
<xi:include href="preface.xml" />
|
||||
<xi:include href="installation/installation.xml" />
|
||||
<xi:include href="configuration/configuration.xml" />
|
||||
<xi:include href="administration/running.xml" />
|
||||
<xi:include href="development/development.xml" />
|
||||
<xi:include href="./from_md/contributing-to-this-manual.chapter.xml" />
|
||||
<appendix xml:id="ch-options">
|
||||
<title>Configuration Options</title>
|
||||
<xi:include href="./generated/options-db.xml"
|
||||
xpointer="configuration-variable-list" />
|
||||
</appendix>
|
||||
<xi:include href="release-notes/release-notes.xml" />
|
||||
</book>
|
7
nixos/doc/manual/nixos-options.md
Normal file
7
nixos/doc/manual/nixos-options.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Configuration Options {#ch-options}
|
||||
|
||||
```{=include=} options
|
||||
id-prefix: opt-
|
||||
list-id: configuration-variable-list
|
||||
source: @NIXOS_OPTIONS_JSON@
|
||||
```
|
11
nixos/doc/manual/preface.md
Normal file
11
nixos/doc/manual/preface.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Preface {#preface}
|
||||
|
||||
This manual describes how to install, use and extend NixOS, a Linux distribution based on the purely functional package management system [Nix](https://nixos.org/nix), that is composed using modules and packages defined in the [Nixpkgs](https://nixos.org/nixpkgs) project.
|
||||
|
||||
Additional information regarding the Nix package manager and the Nixpkgs project can be found in respectively the [Nix manual](https://nixos.org/nix/manual) and the [Nixpkgs manual](https://nixos.org/nixpkgs/manual).
|
||||
|
||||
If you encounter problems, please report them on the [`Discourse`](https://discourse.nixos.org), the [Matrix room](https://matrix.to/#nix:nixos.org), or on the [`#nixos` channel on Libera.Chat](irc://irc.libera.chat/#nixos). Alternatively, consider [contributing to this manual](#chap-contributing). Bugs should be reported in [NixOS’ GitHub issue tracker](https://github.com/NixOS/nixpkgs/issues).
|
||||
|
||||
::: {.note}
|
||||
Commands prefixed with `#` have to be run as root, either requiring to login as root user or temporarily switching to it using `sudo` for example.
|
||||
:::
|
|
@ -1,42 +0,0 @@
|
|||
<preface xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id="preface">
|
||||
<title>Preface</title>
|
||||
<para>
|
||||
This manual describes how to install, use and extend NixOS, a Linux
|
||||
distribution based on the purely functional package management system
|
||||
<link xlink:href="https://nixos.org/nix">Nix</link>, that is composed
|
||||
using modules and packages defined in the
|
||||
<link xlink:href="https://nixos.org/nixpkgs">Nixpkgs</link> project.
|
||||
</para>
|
||||
<para>
|
||||
Additional information regarding the Nix package manager and the Nixpkgs
|
||||
project can be found in respectively the
|
||||
<link xlink:href="https://nixos.org/nix/manual">Nix manual</link> and the
|
||||
<link xlink:href="https://nixos.org/nixpkgs/manual">Nixpkgs manual</link>.
|
||||
</para>
|
||||
<para>
|
||||
If you encounter problems, please report them on the
|
||||
<literal
|
||||
xlink:href="https://discourse.nixos.org">Discourse</literal>,
|
||||
the <link
|
||||
xlink:href="https://matrix.to/#nix:nixos.org">Matrix room</link>,
|
||||
or on the <link
|
||||
xlink:href="irc://irc.libera.chat/#nixos">
|
||||
<literal>#nixos</literal> channel on Libera.Chat</link>.
|
||||
Alternatively, consider <link
|
||||
xlink:href="#chap-contributing">
|
||||
contributing to this manual</link>. Bugs should be
|
||||
reported in
|
||||
<link
|
||||
xlink:href="https://github.com/NixOS/nixpkgs/issues">NixOS’
|
||||
GitHub issue tracker</link>.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Commands prefixed with <literal>#</literal> have to be run as root, either
|
||||
requiring to login as root user or temporarily switching to it using
|
||||
<literal>sudo</literal> for example.
|
||||
</para>
|
||||
</note>
|
||||
</preface>
|
25
nixos/doc/manual/release-notes/release-notes.md
Normal file
25
nixos/doc/manual/release-notes/release-notes.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Release Notes {#ch-release-notes}
|
||||
|
||||
This section lists the release notes for each stable version of NixOS and current unstable revision.
|
||||
|
||||
```{=include=} sections
|
||||
rl-2305.section.md
|
||||
rl-2211.section.md
|
||||
rl-2205.section.md
|
||||
rl-2111.section.md
|
||||
rl-2105.section.md
|
||||
rl-2009.section.md
|
||||
rl-2003.section.md
|
||||
rl-1909.section.md
|
||||
rl-1903.section.md
|
||||
rl-1809.section.md
|
||||
rl-1803.section.md
|
||||
rl-1709.section.md
|
||||
rl-1703.section.md
|
||||
rl-1609.section.md
|
||||
rl-1603.section.md
|
||||
rl-1509.section.md
|
||||
rl-1412.section.md
|
||||
rl-1404.section.md
|
||||
rl-1310.section.md
|
||||
```
|
|
@ -1,30 +0,0 @@
|
|||
<appendix xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="ch-release-notes">
|
||||
<title>Release Notes</title>
|
||||
<para>
|
||||
This section lists the release notes for each stable version of NixOS and
|
||||
current unstable revision.
|
||||
</para>
|
||||
<xi:include href="../from_md/release-notes/rl-2305.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-2211.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-2205.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-2111.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-2105.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-2009.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-2003.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1909.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1903.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1809.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1803.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1709.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1703.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1609.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1603.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1509.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1412.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1404.section.xml" />
|
||||
<xi:include href="../from_md/release-notes/rl-1310.section.xml" />
|
||||
</appendix>
|
|
@ -1,8 +0,0 @@
|
|||
let
|
||||
pkgs = import ../../.. { };
|
||||
in
|
||||
pkgs.mkShell {
|
||||
name = "nixos-manual";
|
||||
|
||||
packages = with pkgs; [ xmlformat jing xmloscopy ruby ];
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# This script is written intended as a living, evolving tooling
|
||||
# to fix oopsies within the docbook documentation.
|
||||
#
|
||||
# This is *not* a formatter. It, instead, handles some known cases
|
||||
# where something bad happened, and fixing it manually is tedious.
|
||||
#
|
||||
# Read the code to see the different cases it handles.
|
||||
#
|
||||
# ALWAYS `make format` after fixing with this!
|
||||
# ALWAYS read the changes, this tool isn't yet proven to be always right.
|
||||
|
||||
require "rexml/document"
|
||||
include REXML
|
||||
|
||||
if ARGV.length < 1 then
|
||||
$stderr.puts "Needs a filename."
|
||||
exit 1
|
||||
end
|
||||
|
||||
filename = ARGV.shift
|
||||
doc = Document.new(File.open(filename))
|
||||
|
||||
$touched = false
|
||||
|
||||
# Fixing varnames having a sibling element without spacing.
|
||||
# This is to fix an initial `xmlformat` issue where `term`
|
||||
# would mangle as spaces.
|
||||
#
|
||||
# <varlistentry>
|
||||
# <term><varname>types.separatedString</varname><replaceable>sep</replaceable> <----
|
||||
# </term>
|
||||
# ...
|
||||
#
|
||||
# Generates: types.separatedStringsep
|
||||
# ^^^^
|
||||
#
|
||||
# <varlistentry xml:id='fun-makeWrapper'>
|
||||
# <term>
|
||||
# <function>makeWrapper</function><replaceable>executable</replaceable><replaceable>wrapperfile</replaceable><replaceable>args</replaceable> <----
|
||||
# </term>
|
||||
#
|
||||
# Generates: makeWrapperexecutablewrapperfileargs
|
||||
# ^^^^ ^^^^ ^^ ^^
|
||||
#
|
||||
# <term>
|
||||
# <option>--option</option><replaceable>name</replaceable><replaceable>value</replaceable> <-----
|
||||
# </term>
|
||||
#
|
||||
# Generates: --optionnamevalue
|
||||
# ^^ ^^
|
||||
doc.elements.each("//varlistentry/term") do |term|
|
||||
["varname", "function", "option", "replaceable"].each do |prev_name|
|
||||
term.elements.each(prev_name) do |el|
|
||||
if el.next_element and
|
||||
el.next_element.name == "replaceable" and
|
||||
el.next_sibling_node.class == Element
|
||||
then
|
||||
$touched = true
|
||||
term.insert_after(el, Text.new(" "))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# <cmdsynopsis>
|
||||
# <command>nixos-option</command>
|
||||
# <arg>
|
||||
# <option>-I</option><replaceable>path</replaceable> <------
|
||||
# </arg>
|
||||
#
|
||||
# Generates: -Ipath
|
||||
# ^^
|
||||
doc.elements.each("//cmdsynopsis/arg") do |term|
|
||||
["option", "replaceable"].each do |prev_name|
|
||||
term.elements.each(prev_name) do |el|
|
||||
if el.next_element and
|
||||
el.next_element.name == "replaceable" and
|
||||
el.next_sibling_node.class == Element
|
||||
then
|
||||
$touched = true
|
||||
term.insert_after(el, Text.new(" "))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# <cmdsynopsis>
|
||||
# <arg>
|
||||
# <group choice='req'>
|
||||
# <arg choice='plain'>
|
||||
# <option>--profile-name</option>
|
||||
# </arg>
|
||||
#
|
||||
# <arg choice='plain'>
|
||||
# <option>-p</option>
|
||||
# </arg>
|
||||
# </group><replaceable>name</replaceable> <----
|
||||
# </arg>
|
||||
#
|
||||
# Generates: [{--profile-name | -p }name]
|
||||
# ^^^^
|
||||
doc.elements.each("//cmdsynopsis/arg") do |term|
|
||||
["group"].each do |prev_name|
|
||||
term.elements.each(prev_name) do |el|
|
||||
if el.next_element and
|
||||
el.next_element.name == "replaceable" and
|
||||
el.next_sibling_node.class == Element
|
||||
then
|
||||
$touched = true
|
||||
term.insert_after(el, Text.new(" "))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if $touched then
|
||||
doc.context[:attribute_quote] = :quote
|
||||
doc.write(output: File.open(filename, "w"))
|
||||
end
|
|
@ -144,7 +144,6 @@ in rec {
|
|||
manual = manualHTML; # TODO(@oxij): remove eventually
|
||||
manualEpub = (buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manualEpub));
|
||||
manpages = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manpages);
|
||||
manualGeneratedSources = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.generatedSources);
|
||||
options = (buildFromConfig ({ ... }: { }) (config: config.system.build.manual.optionsJSON)).x86_64-linux;
|
||||
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ def pretty_print_exc(e: BaseException, *, _desc_text: str = "error") -> None:
|
|||
print(textwrap.indent(extra_info, "\t"), file=sys.stderr, end="")
|
||||
else:
|
||||
print(e)
|
||||
if e.__context__ is not None:
|
||||
if e.__cause__ is not None:
|
||||
print("", file=sys.stderr)
|
||||
pretty_print_exc(e.__context__, _desc_text="caused by")
|
||||
pretty_print_exc(e.__cause__, _desc_text="caused by")
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description='render nixos manual bits')
|
||||
|
|
|
@ -28,6 +28,9 @@ class Deflist:
|
|||
class Heading(NamedTuple):
|
||||
container_tag: str
|
||||
level: int
|
||||
# special handling for <part> titles: whether partinfo was already closed from elsewhere
|
||||
# or still needs closing.
|
||||
partintro_closed: bool = False
|
||||
|
||||
class DocBookRenderer(Renderer):
|
||||
__output__ = "docbook"
|
||||
|
@ -251,7 +254,17 @@ class DocBookRenderer(Renderer):
|
|||
return result + f'<{tag}{attrs_str}>\n<title>'
|
||||
def heading_close(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict,
|
||||
env: MutableMapping[str, Any]) -> str:
|
||||
return '</title>'
|
||||
heading = self._headings[-1]
|
||||
result = '</title>'
|
||||
if heading.container_tag == 'part':
|
||||
# generate the same ids as were previously assigned manually. if this collides we
|
||||
# rely on outside schema validation to catch it!
|
||||
maybe_id = ""
|
||||
assert tokens[i - 2].type == 'heading_open'
|
||||
if id := cast(str, tokens[i - 2].attrs.get('id', "")):
|
||||
maybe_id = " xml:id=" + quoteattr(id + "-intro")
|
||||
result += f"<partintro{maybe_id}>"
|
||||
return result
|
||||
def example_open(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict,
|
||||
env: MutableMapping[str, Any]) -> str:
|
||||
if id := token.attrs.get('id'):
|
||||
|
@ -266,8 +279,10 @@ class DocBookRenderer(Renderer):
|
|||
result = []
|
||||
while len(self._headings):
|
||||
if level is None or self._headings[-1].level >= level:
|
||||
result.append(f"</{self._headings[-1].container_tag}>")
|
||||
self._headings.pop()
|
||||
heading = self._headings.pop()
|
||||
if heading.container_tag == 'part' and not heading.partintro_closed:
|
||||
result.append("</partintro>")
|
||||
result.append(f"</{heading.container_tag}>")
|
||||
else:
|
||||
break
|
||||
return "\n".join(result)
|
||||
|
|
|
@ -2,68 +2,107 @@ import argparse
|
|||
import json
|
||||
|
||||
from abc import abstractmethod
|
||||
from collections.abc import MutableMapping, Sequence
|
||||
from collections.abc import Mapping, MutableMapping, Sequence
|
||||
from pathlib import Path
|
||||
from typing import Any, cast, NamedTuple, Optional, Union
|
||||
from xml.sax.saxutils import escape, quoteattr
|
||||
|
||||
import markdown_it
|
||||
from markdown_it.token import Token
|
||||
from markdown_it.utils import OptionsDict
|
||||
|
||||
from .docbook import DocBookRenderer
|
||||
from . import options
|
||||
from .docbook import DocBookRenderer, Heading
|
||||
from .md import Converter
|
||||
|
||||
class RenderedSection:
|
||||
id: Optional[str]
|
||||
chapters: list[str]
|
||||
|
||||
def __init__(self, id: Optional[str]) -> None:
|
||||
self.id = id
|
||||
self.chapters = []
|
||||
|
||||
class BaseConverter(Converter):
|
||||
_sections: list[RenderedSection]
|
||||
|
||||
def __init__(self, manpage_urls: dict[str, str]):
|
||||
super().__init__(manpage_urls)
|
||||
self._sections = []
|
||||
|
||||
def add_section(self, id: Optional[str], chapters: list[Path]) -> None:
|
||||
self._sections.append(RenderedSection(id))
|
||||
for chpath in chapters:
|
||||
try:
|
||||
with open(chpath, 'r') as f:
|
||||
self._md.renderer._title_seen = False # type: ignore[attr-defined]
|
||||
self._sections[-1].chapters.append(self._render(f.read()))
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"failed to render manual chapter {chpath}") from e
|
||||
|
||||
@abstractmethod
|
||||
def finalize(self) -> str: raise NotImplementedError()
|
||||
|
||||
class ManualDocBookRenderer(DocBookRenderer):
|
||||
# needed to check correctness of chapters.
|
||||
# we may want to use front matter instead of this kind of heuristic.
|
||||
_title_seen = False
|
||||
_toplevel_tag: str
|
||||
|
||||
def __init__(self, toplevel_tag: str, manpage_urls: Mapping[str, str],
|
||||
parser: Optional[markdown_it.MarkdownIt] = None):
|
||||
super().__init__(manpage_urls, parser)
|
||||
self._toplevel_tag = toplevel_tag
|
||||
self.rules |= {
|
||||
'included_sections': lambda *args: self._included_thing("section", *args),
|
||||
'included_chapters': lambda *args: self._included_thing("chapter", *args),
|
||||
'included_preface': lambda *args: self._included_thing("preface", *args),
|
||||
'included_parts': lambda *args: self._included_thing("part", *args),
|
||||
'included_appendix': lambda *args: self._included_thing("appendix", *args),
|
||||
'included_options': self.included_options,
|
||||
}
|
||||
|
||||
def render(self, tokens: Sequence[Token], options: OptionsDict,
|
||||
env: MutableMapping[str, Any]) -> str:
|
||||
wanted = { 'h1': 'title' }
|
||||
wanted |= { 'h2': 'subtitle' } if self._toplevel_tag == 'book' else {}
|
||||
for (i, (tag, kind)) in enumerate(wanted.items()):
|
||||
if len(tokens) < 3 * (i + 1):
|
||||
raise RuntimeError(f"missing {kind} ({tag}) heading")
|
||||
token = tokens[3 * i]
|
||||
if token.type != 'heading_open' or token.tag != tag:
|
||||
assert token.map
|
||||
raise RuntimeError(f"expected {kind} ({tag}) heading in line {token.map[0] + 1}", token)
|
||||
for t in tokens[3 * len(wanted):]:
|
||||
if t.type != 'heading_open' or (info := wanted.get(t.tag)) is None:
|
||||
continue
|
||||
assert t.map
|
||||
raise RuntimeError(
|
||||
f"only one {info[0]} heading ({t.markup} [text...]) allowed per "
|
||||
f"{self._toplevel_tag}, but found a second in lines [{t.map[0] + 1}..{t.map[1]}]. "
|
||||
"please remove all such headings except the first or demote the subsequent headings.",
|
||||
t)
|
||||
|
||||
# books get special handling because they have *two* title tags. doing this with
|
||||
# generic code is more complicated than it's worth. the checks above have verified
|
||||
# that both titles actually exist.
|
||||
if self._toplevel_tag == 'book':
|
||||
assert tokens[1].children
|
||||
assert tokens[4].children
|
||||
if (maybe_id := cast(str, tokens[0].attrs.get('id', ""))):
|
||||
maybe_id = "xml:id=" + quoteattr(maybe_id)
|
||||
return (f'<book xmlns="http://docbook.org/ns/docbook"'
|
||||
f' xmlns:xlink="http://www.w3.org/1999/xlink"'
|
||||
f' {maybe_id} version="5.0">'
|
||||
f' <title>{self.renderInline(tokens[1].children, options, env)}</title>'
|
||||
f' <subtitle>{self.renderInline(tokens[4].children, options, env)}</subtitle>'
|
||||
f' {super().render(tokens[6:], options, env)}'
|
||||
f'</book>')
|
||||
|
||||
return super().render(tokens, options, env)
|
||||
|
||||
def _heading_tag(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict,
|
||||
env: MutableMapping[str, Any]) -> tuple[str, dict[str, str]]:
|
||||
(tag, attrs) = super()._heading_tag(token, tokens, i, options, env)
|
||||
if self._title_seen:
|
||||
if token.tag == 'h1':
|
||||
assert token.map is not None
|
||||
raise RuntimeError(
|
||||
"only one title heading (# [text...]) allowed per manual chapter "
|
||||
f"but found a second in lines [{token.map[0]}..{token.map[1]}]. "
|
||||
"please remove all such headings except the first, split your "
|
||||
"chapters, or demote the subsequent headings to (##) or lower.",
|
||||
token)
|
||||
# render() has already verified that we don't have supernumerary headings and since the
|
||||
# book tag is handled specially we can leave the check this simple
|
||||
if token.tag != 'h1':
|
||||
return (tag, attrs)
|
||||
self._title_seen = True
|
||||
return ("chapter", attrs | {
|
||||
return (self._toplevel_tag, attrs | {
|
||||
'xmlns': "http://docbook.org/ns/docbook",
|
||||
'xmlns:xlink': "http://www.w3.org/1999/xlink",
|
||||
})
|
||||
|
||||
def _included_thing(self, tag: str, token: Token, tokens: Sequence[Token], i: int,
|
||||
options: OptionsDict, env: MutableMapping[str, Any]) -> str:
|
||||
result = []
|
||||
# close existing partintro. the generic render doesn't really need this because
|
||||
# it doesn't have a concept of structure in the way the manual does.
|
||||
if self._headings and self._headings[-1] == Heading('part', 1):
|
||||
result.append("</partintro>")
|
||||
self._headings[-1] = self._headings[-1]._replace(partintro_closed=True)
|
||||
# must nest properly for structural includes. this requires saving at least
|
||||
# the headings stack, but creating new renderers is cheap and much easier.
|
||||
r = ManualDocBookRenderer(tag, self._manpage_urls, None)
|
||||
for (included, path) in token.meta['included']:
|
||||
try:
|
||||
result.append(r.render(included, options, env))
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"rendering {path}") from e
|
||||
return "".join(result)
|
||||
def included_options(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict,
|
||||
env: MutableMapping[str, Any]) -> str:
|
||||
return cast(str, token.meta['rendered-options'])
|
||||
|
||||
# TODO minimize docbook diffs with existing conversions. remove soon.
|
||||
def paragraph_open(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict,
|
||||
env: MutableMapping[str, Any]) -> str:
|
||||
|
@ -76,127 +115,113 @@ class ManualDocBookRenderer(DocBookRenderer):
|
|||
return f"<programlisting>\n{escape(token.content)}</programlisting>"
|
||||
def fence(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict,
|
||||
env: MutableMapping[str, Any]) -> str:
|
||||
# HACK for temporarily being able to replace md-to-db.sh. pandoc used this syntax to
|
||||
# allow md files to inject arbitrary docbook, and manual chapters use it.
|
||||
if token.info == '{=docbook}':
|
||||
return token.content
|
||||
info = f" language={quoteattr(token.info)}" if token.info != "" else ""
|
||||
return f"<programlisting{info}>\n{escape(token.content)}</programlisting>"
|
||||
|
||||
class DocBookSectionConverter(BaseConverter):
|
||||
__renderer__ = ManualDocBookRenderer
|
||||
class DocBookConverter(Converter):
|
||||
def __renderer__(self, manpage_urls: Mapping[str, str],
|
||||
parser: Optional[markdown_it.MarkdownIt]) -> ManualDocBookRenderer:
|
||||
return ManualDocBookRenderer('book', manpage_urls, parser)
|
||||
|
||||
def finalize(self) -> str:
|
||||
result = []
|
||||
_base_paths: list[Path]
|
||||
_revision: str
|
||||
|
||||
for section in self._sections:
|
||||
id = "id=" + quoteattr(section.id) if section.id is not None else ""
|
||||
result.append(f'<section {id}>')
|
||||
result += section.chapters
|
||||
result.append(f'</section>')
|
||||
def __init__(self, manpage_urls: Mapping[str, str], revision: str):
|
||||
super().__init__(manpage_urls)
|
||||
self._revision = revision
|
||||
|
||||
return "\n".join(result)
|
||||
|
||||
class ManualFragmentDocBookRenderer(ManualDocBookRenderer):
|
||||
_tag: str = "chapter"
|
||||
|
||||
def _heading_tag(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict,
|
||||
env: MutableMapping[str, Any]) -> tuple[str, dict[str, str]]:
|
||||
(tag, attrs) = super()._heading_tag(token, tokens, i, options, env)
|
||||
if token.tag == 'h1':
|
||||
return (self._tag, attrs | { 'xmlns:xi': "http://www.w3.org/2001/XInclude" })
|
||||
return (tag, attrs)
|
||||
|
||||
class DocBookFragmentConverter(Converter):
|
||||
__renderer__ = ManualFragmentDocBookRenderer
|
||||
|
||||
def convert(self, file: Path, tag: str) -> str:
|
||||
assert isinstance(self._md.renderer, ManualFragmentDocBookRenderer)
|
||||
def convert(self, file: Path) -> str:
|
||||
self._base_paths = [ file ]
|
||||
try:
|
||||
with open(file, 'r') as f:
|
||||
self._md.renderer._title_seen = False
|
||||
self._md.renderer._tag = tag
|
||||
return self._render(f.read())
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"failed to render manual {tag} {file}") from e
|
||||
raise RuntimeError(f"failed to render manual {file}") from e
|
||||
|
||||
def _parse(self, src: str, env: Optional[MutableMapping[str, Any]] = None) -> list[Token]:
|
||||
tokens = super()._parse(src, env)
|
||||
for token in tokens:
|
||||
if token.type != "fence" or not token.info.startswith("{=include=} "):
|
||||
continue
|
||||
typ = token.info[12:].strip()
|
||||
if typ == 'options':
|
||||
token.type = 'included_options'
|
||||
self._parse_options(token)
|
||||
elif typ in [ 'sections', 'chapters', 'preface', 'parts', 'appendix' ]:
|
||||
token.type = 'included_' + typ
|
||||
self._parse_included_blocks(token, env)
|
||||
else:
|
||||
raise RuntimeError(f"unsupported structural include type '{typ}'")
|
||||
return tokens
|
||||
|
||||
def _parse_included_blocks(self, token: Token, env: Optional[MutableMapping[str, Any]]) -> None:
|
||||
assert token.map
|
||||
included = token.meta['included'] = []
|
||||
for (lnum, line) in enumerate(token.content.splitlines(), token.map[0] + 2):
|
||||
line = line.strip()
|
||||
path = self._base_paths[-1].parent / line
|
||||
if path in self._base_paths:
|
||||
raise RuntimeError(f"circular include found in line {lnum}")
|
||||
try:
|
||||
self._base_paths.append(path)
|
||||
with open(path, 'r') as f:
|
||||
tokens = self._parse(f.read(), env)
|
||||
included.append((tokens, path))
|
||||
self._base_paths.pop()
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"processing included file {path} from line {lnum}") from e
|
||||
|
||||
def _parse_options(self, token: Token) -> None:
|
||||
assert token.map
|
||||
|
||||
items = {}
|
||||
for (lnum, line) in enumerate(token.content.splitlines(), token.map[0] + 2):
|
||||
if len(args := line.split(":", 1)) != 2:
|
||||
raise RuntimeError(f"options directive with no argument in line {lnum}")
|
||||
(k, v) = (args[0].strip(), args[1].strip())
|
||||
if k in items:
|
||||
raise RuntimeError(f"duplicate options directive {k} in line {lnum}")
|
||||
items[k] = v
|
||||
try:
|
||||
id_prefix = items.pop('id-prefix')
|
||||
varlist_id = items.pop('list-id')
|
||||
source = items.pop('source')
|
||||
except KeyError as e:
|
||||
raise RuntimeError(f"options directive {e} missing in block at line {token.map[0] + 1}")
|
||||
if items.keys():
|
||||
raise RuntimeError(
|
||||
f"unsupported options directives in block at line {token.map[0] + 1}",
|
||||
" ".join(items.keys()))
|
||||
|
||||
try:
|
||||
conv = options.DocBookConverter(
|
||||
self._manpage_urls, self._revision, False, 'fragment', varlist_id, id_prefix)
|
||||
with open(self._base_paths[-1].parent / source, 'r') as f:
|
||||
conv.add_options(json.load(f))
|
||||
token.meta['rendered-options'] = conv.finalize(fragment=True)
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"processing options block in line {token.map[0] + 1}") from e
|
||||
|
||||
|
||||
|
||||
class Section:
|
||||
id: Optional[str] = None
|
||||
chapters: list[str]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.chapters = []
|
||||
|
||||
class SectionAction(argparse.Action):
|
||||
def __call__(self, parser: argparse.ArgumentParser, ns: argparse.Namespace,
|
||||
values: Union[str, Sequence[Any], None], opt_str: Optional[str] = None) -> None:
|
||||
sections = getattr(ns, self.dest)
|
||||
if sections is None: sections = []
|
||||
sections.append(Section())
|
||||
setattr(ns, self.dest, sections)
|
||||
|
||||
class SectionIDAction(argparse.Action):
|
||||
def __call__(self, parser: argparse.ArgumentParser, ns: argparse.Namespace,
|
||||
values: Union[str, Sequence[Any], None], opt_str: Optional[str] = None) -> None:
|
||||
sections = getattr(ns, self.dest)
|
||||
if sections is None: raise argparse.ArgumentError(self, "no active section")
|
||||
sections[-1].id = cast(str, values)
|
||||
|
||||
class ChaptersAction(argparse.Action):
|
||||
def __call__(self, parser: argparse.ArgumentParser, ns: argparse.Namespace,
|
||||
values: Union[str, Sequence[Any], None], opt_str: Optional[str] = None) -> None:
|
||||
sections = getattr(ns, self.dest)
|
||||
if sections is None: raise argparse.ArgumentError(self, "no active section")
|
||||
sections[-1].chapters.extend(map(Path, cast(Sequence[str], values)))
|
||||
|
||||
class SingleFileAction(argparse.Action):
|
||||
def __call__(self, parser: argparse.ArgumentParser, ns: argparse.Namespace,
|
||||
values: Union[str, Sequence[Any], None], opt_str: Optional[str] = None) -> None:
|
||||
assert isinstance(values, Sequence)
|
||||
chapters = getattr(ns, self.dest) or []
|
||||
chapters.append((Path(values[0]), Path(values[1])))
|
||||
setattr(ns, self.dest, chapters)
|
||||
|
||||
def _build_cli_db_section(p: argparse.ArgumentParser) -> None:
|
||||
def _build_cli_db(p: argparse.ArgumentParser) -> None:
|
||||
p.add_argument('--manpage-urls', required=True)
|
||||
p.add_argument("outfile")
|
||||
p.add_argument("--section", dest="contents", action=SectionAction, nargs=0)
|
||||
p.add_argument("--section-id", dest="contents", action=SectionIDAction)
|
||||
p.add_argument("--chapters", dest="contents", action=ChaptersAction, nargs='+')
|
||||
p.add_argument('--revision', required=True)
|
||||
p.add_argument('infile', type=Path)
|
||||
p.add_argument('outfile', type=Path)
|
||||
|
||||
def _build_cli_db_fragment(p: argparse.ArgumentParser) -> None:
|
||||
p.add_argument('--manpage-urls', required=True)
|
||||
p.add_argument("--chapter", action=SingleFileAction, required=True, nargs=2)
|
||||
p.add_argument("--section", action=SingleFileAction, required=True, nargs=2)
|
||||
|
||||
def _run_cli_db_section(args: argparse.Namespace) -> None:
|
||||
def _run_cli_db(args: argparse.Namespace) -> None:
|
||||
with open(args.manpage_urls, 'r') as manpage_urls:
|
||||
md = DocBookSectionConverter(json.load(manpage_urls))
|
||||
for section in args.contents:
|
||||
md.add_section(section.id, section.chapters)
|
||||
with open(args.outfile, 'w') as f:
|
||||
f.write(md.finalize())
|
||||
|
||||
def _run_cli_db_fragment(args: argparse.Namespace) -> None:
|
||||
with open(args.manpage_urls, 'r') as manpage_urls:
|
||||
md = DocBookFragmentConverter(json.load(manpage_urls))
|
||||
for kind in [ 'chapter', 'section' ]:
|
||||
for (target, file) in getattr(args, kind):
|
||||
converted = md.convert(file, kind)
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_text(converted)
|
||||
md = DocBookConverter(json.load(manpage_urls), args.revision)
|
||||
converted = md.convert(args.infile)
|
||||
args.outfile.write_text(converted)
|
||||
|
||||
def build_cli(p: argparse.ArgumentParser) -> None:
|
||||
formats = p.add_subparsers(dest='format', required=True)
|
||||
_build_cli_db_section(formats.add_parser('docbook-section'))
|
||||
_build_cli_db_fragment(formats.add_parser('docbook-fragment'))
|
||||
_build_cli_db(formats.add_parser('docbook'))
|
||||
|
||||
def run_cli(args: argparse.Namespace) -> None:
|
||||
if args.format == 'docbook-section':
|
||||
_run_cli_db_section(args)
|
||||
elif args.format == 'docbook-fragment':
|
||||
_run_cli_db_fragment(args)
|
||||
if args.format == 'docbook':
|
||||
_run_cli_db(args)
|
||||
else:
|
||||
raise RuntimeError('format not hooked up', args)
|
||||
|
|
|
@ -29,7 +29,7 @@ class BaseConverter(Converter):
|
|||
|
||||
_options: dict[str, RenderedOption]
|
||||
|
||||
def __init__(self, manpage_urls: dict[str, str],
|
||||
def __init__(self, manpage_urls: Mapping[str, str],
|
||||
revision: str,
|
||||
markdown_by_default: bool):
|
||||
super().__init__(manpage_urls)
|
||||
|
@ -231,10 +231,11 @@ class DocBookConverter(BaseConverter):
|
|||
def _decl_def_footer(self) -> list[str]:
|
||||
return [ "</simplelist>" ]
|
||||
|
||||
def finalize(self) -> str:
|
||||
def finalize(self, *, fragment: bool = False) -> str:
|
||||
result = []
|
||||
|
||||
result.append('<?xml version="1.0" encoding="UTF-8"?>')
|
||||
if not fragment:
|
||||
result.append('<?xml version="1.0" encoding="UTF-8"?>')
|
||||
if self._document_type == 'appendix':
|
||||
result += [
|
||||
'<appendix xmlns="http://docbook.org/ns/docbook"',
|
||||
|
|
Loading…
Reference in a new issue