mirror of
https://github.com/nix-community/dream2nix.git
synced 2024-11-22 15:04:46 +03:00
init flake parts docs modules
This commit is contained in:
parent
5e938ebb20
commit
87d65e704e
399
modules/flake-parts/render/default.nix
Normal file
399
modules/flake-parts/render/default.nix
Normal file
@ -0,0 +1,399 @@
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
flake-parts-lib,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
types
|
||||
concatMap
|
||||
concatLists
|
||||
mapAttrsToList
|
||||
attrValues
|
||||
hasPrefix
|
||||
removePrefix
|
||||
;
|
||||
|
||||
failPkgAttr = name: _v:
|
||||
throw ''
|
||||
Most nixpkgs attributes are not supported when generating documentation.
|
||||
Please check with `--show-trace` to see which option leads to this `pkgs.${lib.strings.escapeNixIdentifier name}` reference. Often it can be cut short with a `defaultText` argument to `lib.mkOption`, or by escaping an option `example` using `lib.literalExpression`.
|
||||
'';
|
||||
in {
|
||||
options.perSystem = flake-parts-lib.mkPerSystemOption ({
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
cfg = config.render;
|
||||
|
||||
pkgsStub = lib.mapAttrs failPkgAttr pkgs;
|
||||
|
||||
fixups = {
|
||||
lib,
|
||||
flake-parts-lib,
|
||||
...
|
||||
}: {
|
||||
options.perSystem = flake-parts-lib.mkPerSystemOption {
|
||||
config = {
|
||||
_module.args.pkgs =
|
||||
pkgsStub
|
||||
// {
|
||||
_type = "pkgs";
|
||||
inherit lib;
|
||||
formats =
|
||||
lib.mapAttrs
|
||||
(
|
||||
formatName: formatFn: formatArgs: let
|
||||
result = formatFn formatArgs;
|
||||
stubs =
|
||||
lib.mapAttrs
|
||||
(
|
||||
name: _:
|
||||
throw "The attribute `(pkgs.formats.${lib.strings.escapeNixIdentifier formatName} x).${lib.strings.escapeNixIdentifier name}` is not supported during documentation generation. Please check with `--show-trace` to see which option leads to this `${lib.strings.escapeNixIdentifier name}` reference. Often it can be cut short with a `defaultText` argument to `lib.mkOption`, or by escaping an option `example` using `lib.literalExpression`."
|
||||
)
|
||||
result;
|
||||
in
|
||||
stubs
|
||||
// {
|
||||
inherit (result) type;
|
||||
}
|
||||
)
|
||||
pkgs.formats;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
eval = evalWith {
|
||||
modules = concatLists (mapAttrsToList (name: inputCfg: inputCfg.getModules inputCfg.flake) cfg.inputs);
|
||||
};
|
||||
evalWith = {modules}:
|
||||
inputs.flake-parts.lib.evalFlakeModule
|
||||
{
|
||||
inputs = {
|
||||
inherit (inputs) nixpkgs;
|
||||
self =
|
||||
eval.config.flake
|
||||
// {
|
||||
outPath =
|
||||
throw "The `self.outPath` attribute is not available when generating documentation, because the documentation should not depend on the specifics of the flake files where it is loaded. This error is generally caused by a missing `defaultText` on one or more options in the trace. Please run this evaluation with `--show-trace`, and look for `while evaluating the default value of option` and add a `defaultText` to one or more of the options involved.";
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
imports =
|
||||
modules
|
||||
++ [
|
||||
fixups
|
||||
];
|
||||
systems = [(throw "The `systems` option value is not available when generating documentation. This is generally caused by a missing `defaultText` on one or more options in the trace. Please run this evaluation with `--show-trace`, look for `while evaluating the default value of option` and add a `defaultText` to the one or more of the options involved.")];
|
||||
};
|
||||
|
||||
opts = eval.options;
|
||||
|
||||
coreOptDecls = config.render.inputs.flake-parts._nixosOptionsDoc.optionsNix;
|
||||
|
||||
filterTransformOptions = {
|
||||
sourceName,
|
||||
sourcePath,
|
||||
baseUrl,
|
||||
coreOptDecls,
|
||||
}: let
|
||||
sourcePathStr = toString sourcePath;
|
||||
in
|
||||
opt: let
|
||||
declarations =
|
||||
concatMap
|
||||
(
|
||||
decl:
|
||||
if hasPrefix sourcePathStr (toString decl)
|
||||
then let
|
||||
subpath = removePrefix sourcePathStr (toString decl);
|
||||
in [
|
||||
{
|
||||
url = baseUrl + subpath;
|
||||
name = sourceName + subpath;
|
||||
}
|
||||
]
|
||||
else []
|
||||
)
|
||||
opt.declarations;
|
||||
in
|
||||
if
|
||||
declarations
|
||||
== []
|
||||
|| (
|
||||
sourceName != "flake-parts" && coreOptDecls ? ${lib.showOption opt.loc}
|
||||
)
|
||||
then opt // {visible = false;}
|
||||
else opt // {inherit declarations;};
|
||||
|
||||
inputModule = {
|
||||
config,
|
||||
name,
|
||||
...
|
||||
}: {
|
||||
options = {
|
||||
flake = mkOption {
|
||||
type = types.raw;
|
||||
description = ''
|
||||
A flake.
|
||||
'';
|
||||
default = inputs.${name};
|
||||
};
|
||||
|
||||
sourcePath = mkOption {
|
||||
type = types.path;
|
||||
description = ''
|
||||
Source path in which the modules are contained.
|
||||
'';
|
||||
default = config.flake.outPath;
|
||||
};
|
||||
|
||||
title = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Title of the markdown page.
|
||||
'';
|
||||
default = name;
|
||||
};
|
||||
|
||||
flakeRef = mkOption {
|
||||
type = types.str;
|
||||
default =
|
||||
# This only works for github for now, but we can set a non-default
|
||||
# value in the list just fine.
|
||||
let
|
||||
match = builtins.match "https://github.com/([^/]*)/([^/]*)/blob/([^/]*)" config.baseUrl;
|
||||
owner = lib.elemAt match 0;
|
||||
repo = lib.elemAt match 1;
|
||||
branch = lib.elemAt match 2; # ignored for now because they're all default branches
|
||||
in
|
||||
if match != null
|
||||
then "github:${owner}/${repo}"
|
||||
else throw "Couldn't figure out flakeref for ${name}: ${config.baseUrl}";
|
||||
};
|
||||
|
||||
preface = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Stuff between the title and the options.
|
||||
'';
|
||||
default = ''
|
||||
|
||||
${config.intro}
|
||||
|
||||
${config.installation}
|
||||
|
||||
'';
|
||||
};
|
||||
|
||||
intro = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Introductory paragraph between title and installation.
|
||||
'';
|
||||
};
|
||||
|
||||
installationDeclareInput = mkOption {
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to show how to declare the input.
|
||||
'';
|
||||
default = true;
|
||||
};
|
||||
|
||||
installation = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Installation paragraph between installation and options.
|
||||
'';
|
||||
default = ''
|
||||
## Installation
|
||||
|
||||
${
|
||||
if config.installationDeclareInput
|
||||
then ''
|
||||
To use these options, add to your flake inputs:
|
||||
|
||||
```nix
|
||||
${config.sourceName}.url = "${config.flakeRef}";
|
||||
```
|
||||
|
||||
and inside the `mkFlake`:
|
||||
''
|
||||
else ''
|
||||
To use these options, add inside the `mkFlake`:
|
||||
''
|
||||
}
|
||||
|
||||
```nix
|
||||
imports = [
|
||||
inputs.${config.sourceName}.${lib.concatMapStringsSep "." lib.strings.escapeNixIdentifier config.attributePath}
|
||||
];
|
||||
```
|
||||
|
||||
Run `nix flake lock` and you're set.
|
||||
'';
|
||||
};
|
||||
|
||||
sourceName = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Name by which the source is shown in the list of declarations.
|
||||
'';
|
||||
default = name;
|
||||
};
|
||||
|
||||
baseUrl = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
URL prefix for source location links.
|
||||
'';
|
||||
};
|
||||
|
||||
getModules = mkOption {
|
||||
type = types.functionTo (types.listOf types.raw);
|
||||
description = ''
|
||||
Get the modules to render.
|
||||
'';
|
||||
default = flake: [
|
||||
(
|
||||
builtins.addErrorContext "while getting modules for input '${name}'"
|
||||
(lib.getAttrFromPath config.attributePath flake)
|
||||
)
|
||||
];
|
||||
};
|
||||
|
||||
attributePath = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = ''
|
||||
Flake output attribute path to import.
|
||||
'';
|
||||
default = ["flakeModule"];
|
||||
};
|
||||
|
||||
rendered = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
Built Markdown docs.
|
||||
'';
|
||||
readOnly = true;
|
||||
};
|
||||
|
||||
_nixosOptionsDoc = mkOption {};
|
||||
|
||||
separateEval = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to include this in the main evaluation.
|
||||
'';
|
||||
};
|
||||
|
||||
filterTransformOptions = mkOption {
|
||||
default = filterTransformOptions;
|
||||
description = ''
|
||||
Function to customize the set of options to render for this input.
|
||||
'';
|
||||
};
|
||||
|
||||
killLinks = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Remove local anchor links, a workaround for proper {option}`` support in the doc tooling.
|
||||
'';
|
||||
};
|
||||
};
|
||||
config = {
|
||||
_nixosOptionsDoc = pkgs.nixosOptionsDoc {
|
||||
options =
|
||||
if config.separateEval
|
||||
then
|
||||
(evalWith {
|
||||
modules = config.getModules config.flake;
|
||||
})
|
||||
.options
|
||||
else opts;
|
||||
documentType = "none";
|
||||
transformOptions = config.filterTransformOptions {
|
||||
inherit (config) sourceName baseUrl sourcePath;
|
||||
inherit coreOptDecls;
|
||||
};
|
||||
warningsAreErrors = true; # not sure if feasible long term
|
||||
markdownByDefault = true;
|
||||
};
|
||||
rendered =
|
||||
pkgs.runCommand "option-doc-${config.sourceName}"
|
||||
{
|
||||
nativeBuildInputs = [pkgs.libxslt.bin pkgs.pandoc];
|
||||
inputDoc = config._nixosOptionsDoc.optionsDocBook;
|
||||
inherit (config) title preface;
|
||||
} ''
|
||||
xsltproc --stringparam title "$title" \
|
||||
--stringparam killLinks '${lib.boolToString config.killLinks}' \
|
||||
-o options.db.xml ${./options.xsl} \
|
||||
"$inputDoc"
|
||||
mkdir $out
|
||||
pandoc --verbose --from docbook --to html options.db.xml >options.html
|
||||
substitute options.html $out/options.html --replace '<p>@intro@</p>' "$preface"
|
||||
grep -v '@intro@' <$out/options.html >/dev/null || {
|
||||
grep '@intro@' <$out/options.html
|
||||
echo intro replacement failed; exit 1;
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = {
|
||||
render = {
|
||||
inputs = mkOption {
|
||||
description = "Which modules to render.";
|
||||
type = types.attrsOf (types.submodule inputModule);
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
packages =
|
||||
lib.mapAttrs' (name: inputCfg: {
|
||||
name = "generated-docs-${name}";
|
||||
value = inputCfg.rendered;
|
||||
})
|
||||
cfg.inputs
|
||||
// {
|
||||
generated-docs =
|
||||
pkgs.runCommand "generated-docs"
|
||||
{
|
||||
passthru = {
|
||||
inherit config;
|
||||
inherit eval;
|
||||
# This won't be in sync with the actual nixosOptionsDoc
|
||||
# invocations, but it's useful for troubleshooting.
|
||||
allOptionsPerhaps =
|
||||
(pkgs.nixosOptionsDoc {
|
||||
options = opts;
|
||||
})
|
||||
.optionsNix;
|
||||
};
|
||||
}
|
||||
''
|
||||
mkdir $out
|
||||
${
|
||||
lib.concatStringsSep "\n"
|
||||
(lib.mapAttrsToList
|
||||
(name: inputCfg: ''
|
||||
cp ${inputCfg.rendered}/options.html $out/${name}.html
|
||||
'')
|
||||
cfg.inputs)
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
66
modules/flake-parts/render/options.xsl
Normal file
66
modules/flake-parts/render/options.xsl
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet
|
||||
version="1.0"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:db="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
>
|
||||
<xsl:template match="/">
|
||||
<xsl:apply-templates/>
|
||||
</xsl:template>
|
||||
<xsl:template match="db:link">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$killLinks = 'true'">
|
||||
<xsl:copy-of select="./node()"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:copy-of select="."/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
<xsl:template match="db:variablelist">
|
||||
<chapter>
|
||||
<title>
|
||||
<xsl:value-of select="$title"/>
|
||||
</title>
|
||||
<para>@intro@</para>
|
||||
<section><title>Options</title>
|
||||
<xsl:for-each select="db:varlistentry">
|
||||
<para><link xlink:href="#{db:term/@xml:id}"><xsl:copy-of select="db:term/db:option"/></link></para>
|
||||
</xsl:for-each>
|
||||
</section>
|
||||
<xsl:apply-templates />
|
||||
</chapter>
|
||||
</xsl:template>
|
||||
<xsl:template match="db:varlistentry">
|
||||
<section>
|
||||
<title>
|
||||
<link xlink:href="#{db:term/@xml:id}" xml:id="{db:term/@xml:id}"><xsl:copy-of select="db:term/db:option"/></link>
|
||||
</title>
|
||||
<xsl:apply-templates select="db:listitem/*"/>
|
||||
</section>
|
||||
</xsl:template>
|
||||
<!-- Pandoc doesn't like block-level simplelist -->
|
||||
<!-- https://github.com/jgm/pandoc/issues/8086 -->
|
||||
<xsl:template match="db:simplelist">
|
||||
<para>
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</para>
|
||||
</xsl:template>
|
||||
<!-- Turn filename tags with href attrs into explicit links -->
|
||||
<xsl:template match="db:filename">
|
||||
<link xlink:href="{@xlink:href}">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</link>
|
||||
</xsl:template>
|
||||
<xsl:template match="@*|node()">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
1
modules/flake-parts/site/.gitignore
vendored
Normal file
1
modules/flake-parts/site/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
book
|
1
modules/flake-parts/site/_redirects
Normal file
1
modules/flake-parts/site/_redirects
Normal file
@ -0,0 +1 @@
|
||||
/getting-things.html /cheat-sheet.html
|
19
modules/flake-parts/site/book.toml
Normal file
19
modules/flake-parts/site/book.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[book]
|
||||
authors = ["Robert Hensing", "Various module authors"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "flake-parts"
|
||||
|
||||
[output.html]
|
||||
git-repository-url = "https://github.com/hercules-ci/flake-parts"
|
||||
edit-url-template = "https://github.com/hercules-ci/flake.parts-website/edit/main/site/{path}"
|
||||
additional-js = [ "no-edit-options.js" ]
|
||||
additional-css = [ "flake-parts.css" ]
|
||||
no-section-label = true
|
||||
|
||||
[output.html.print]
|
||||
enable = false # big single page; don't need that
|
||||
|
||||
[output.linkcheck]
|
||||
follow-web-links = false # no Internet during the build
|
81
modules/flake-parts/site/default.nix
Normal file
81
modules/flake-parts/site/default.nix
Normal file
@ -0,0 +1,81 @@
|
||||
{inputs, ...}: {
|
||||
perSystem = {
|
||||
config,
|
||||
self',
|
||||
inputs',
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
/*
|
||||
Check the links, including anchors (not currently supported by mdbook)
|
||||
|
||||
Putting this in a separate check has the benefits that
|
||||
- output can always be inspect with browser
|
||||
- this slow check (1 minute) is not part of the iteration cycle
|
||||
|
||||
Ideally https://github.com/linkchecker/linkchecker/pull/661 is merged
|
||||
upstream, so that it's quick and can run often without blocking the
|
||||
iteration cycle unnecessarily.
|
||||
*/
|
||||
checks.linkcheck =
|
||||
pkgs.runCommand "linkcheck"
|
||||
{
|
||||
nativeBuildInputs = [pkgs.linkchecker pkgs.python3];
|
||||
site = config.packages.default;
|
||||
} ''
|
||||
# https://linkchecker.github.io/linkchecker/man/linkcheckerrc.html
|
||||
cat >>$TMPDIR/linkcheckrc <<EOF
|
||||
[checking]
|
||||
threads=''${NIX_BUILD_CORES:-4}
|
||||
|
||||
[AnchorCheck]
|
||||
|
||||
EOF
|
||||
|
||||
echo Checking $site
|
||||
linkchecker -f $TMPDIR/linkcheckrc $site/
|
||||
|
||||
touch $out
|
||||
'';
|
||||
|
||||
packages = {
|
||||
default = pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "site";
|
||||
nativeBuildInputs = [pkgs.mdbook pkgs.mdbook-linkcheck];
|
||||
src = ./.;
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
{
|
||||
while read ln; do
|
||||
case "$ln" in
|
||||
*end_of_intro*)
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "$ln"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
cat src/intro-continued.md
|
||||
} <${inputs.flake-parts + "/README.md"} >src/README.md
|
||||
|
||||
mkdir -p src/options
|
||||
for f in ${config.packages.generated-docs}/*.html; do
|
||||
cp "$f" "src/options/$(basename "$f" .html).md"
|
||||
done
|
||||
mdbook build --dest-dir $TMPDIR/out
|
||||
cp -r $TMPDIR/out/html $out
|
||||
cp _redirects $out
|
||||
|
||||
echo '<html><head><script>window.location.pathname = window.location.pathname.replace(/options.html$/, "") + "options/flake-parts.html"</script></head><body><a href="options/flake-parts.html">to the options</a></body></html>' \
|
||||
>$out/options.html
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
dontInstall = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
19
modules/flake-parts/site/flake-parts.css
Normal file
19
modules/flake-parts/site/flake-parts.css
Normal file
@ -0,0 +1,19 @@
|
||||
h1.menu-title::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
background-image: url(./favicon.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
width: 1.8ex;
|
||||
height: 1.8ex;
|
||||
margin-right: 0.9ex;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.light {
|
||||
--links: #058;
|
||||
--sidebar-active: #0af;
|
||||
}
|
||||
.sidebar .sidebar-scrollbox {
|
||||
/* We don't use numbers, so we can take a consistent amount of space */
|
||||
padding: var(--page-padding) !important;
|
||||
}
|
7
modules/flake-parts/site/no-edit-options.js
Normal file
7
modules/flake-parts/site/no-edit-options.js
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
if (window.location.pathname.match(/options/)) {
|
||||
var buttons = document.querySelector("#menu-bar > div.right-buttons")
|
||||
if (buttons != null) {
|
||||
buttons.style.display = "none"
|
||||
}
|
||||
}
|
3
modules/flake-parts/site/src/SUMMARY.md
Normal file
3
modules/flake-parts/site/src/SUMMARY.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Summary
|
||||
|
||||
- [Reference Documentation]()
|
Loading…
Reference in New Issue
Block a user