feat(users/sterni/htmlman): static site generator for manual pages
htmlman is a very simple nix based static site generator which is intended for rendering HTML representations for man pages plus an index page listing all available pages. For the sake of simplicity (and unlike previous iterations of this piece of code) other documentation artifacts and formats are not supported. Usually web services like GitHub and depot's web interface are pretty good at displaying "normal" documentation artifacts like markdown files, but man pages are usually not rendered — with the additional problem that it's source is virtually unreadable. htmlman should provide a simple static site generator which can be plugged into GitHub actions or the like to automatically generate rendered version of man pages tracked in version control. Change-Id: Ib53292964b3ff84c32d70c5fde257a2edb8c2122 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2596 Tested-by: BuildkiteCI Reviewed-by: tazjin <mail@tazj.in> Reviewed-by: Profpatsch <mail@profpatsch.de> Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
parent
e41bd6a82d
commit
2cd2b58a04
5 changed files with 291 additions and 0 deletions
1
third_party/nixpkgs-exposed/OWNERS
vendored
1
third_party/nixpkgs-exposed/OWNERS
vendored
|
@ -4,3 +4,4 @@
|
|||
inherited: true
|
||||
owners:
|
||||
- Profpatsch
|
||||
- sterni
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
lutris
|
||||
makeFontsConf
|
||||
makeWrapper
|
||||
mandoc
|
||||
mdbook
|
||||
meson
|
||||
mime-types
|
||||
|
|
36
users/sterni/htmlman/README.md
Normal file
36
users/sterni/htmlman/README.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# htmlman
|
||||
|
||||
static site generator for man pages intended for
|
||||
rendering man page documentation viewable using
|
||||
a web browser.
|
||||
|
||||
## usage
|
||||
|
||||
If you have a nix expression, `doc.nix`, like this:
|
||||
|
||||
```nix
|
||||
{ depot, ... }:
|
||||
|
||||
depot.users.sterni.htmlman {
|
||||
title = "foo project";
|
||||
pages = [
|
||||
{
|
||||
name = "foo";
|
||||
section = 1;
|
||||
}
|
||||
{
|
||||
name = "foo";
|
||||
section = 3;
|
||||
path = ../devman/foo.3;
|
||||
}
|
||||
];
|
||||
manDir = ../man;
|
||||
}
|
||||
```
|
||||
|
||||
You can run the following to directly deploy the resulting
|
||||
documentation output to a specific target directory:
|
||||
|
||||
```sh
|
||||
nix-build -A deploy doc.nix && ./result target_directory
|
||||
```
|
204
users/sterni/htmlman/default.nix
Normal file
204
users/sterni/htmlman/default.nix
Normal file
|
@ -0,0 +1,204 @@
|
|||
{ depot, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (depot.nix)
|
||||
getBins
|
||||
runExecline
|
||||
;
|
||||
|
||||
inherit (depot.tools)
|
||||
cheddar
|
||||
;
|
||||
|
||||
inherit (pkgs)
|
||||
mandoc
|
||||
coreutils
|
||||
fetchurl
|
||||
writers
|
||||
;
|
||||
|
||||
bins = getBins cheddar [ "cheddar" ]
|
||||
// getBins mandoc [ "mandoc" ]
|
||||
// getBins coreutils [ "cat" "mv" "mkdir" ]
|
||||
;
|
||||
|
||||
normalizeDrv = fetchurl {
|
||||
url = "https://necolas.github.io/normalize.css/8.0.1/normalize.css";
|
||||
sha256 = "04jmvybwh2ks4dlnfa70sb3a3z3ig4cv0ya9rizjvm140xq1h22q";
|
||||
};
|
||||
|
||||
execlineStdoutInto = target: line: [
|
||||
"redirfd" "-w" "1" target
|
||||
] ++ line;
|
||||
|
||||
# I will not write a pure nix markdown renderer
|
||||
# I will not write a pure nix markdown renderer
|
||||
# I will not write a pure nix markdown renderer
|
||||
# I will not write a pure nix markdown renderer
|
||||
# I will not write a pure nix markdown renderer
|
||||
markdown = md:
|
||||
let
|
||||
html = runExecline.local "rendered-markdown" {
|
||||
stdin = md;
|
||||
} ([
|
||||
"importas" "-iu" "out" "out"
|
||||
] ++ execlineStdoutInto "$out" [
|
||||
bins.cheddar "--about-filter" "description.md"
|
||||
]);
|
||||
in builtins.readFile html;
|
||||
|
||||
indexTemplate = { title, description, pages ? [] }: ''
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>${title}</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="index-text">
|
||||
<h1>${title}</h1>
|
||||
${markdown description}
|
||||
<h2>man pages</h2>
|
||||
<ul>
|
||||
${lib.concatMapStrings ({ name, section, ... }: ''
|
||||
<li><a href="${name}.${toString section}.html">${name}(${toString section})</a></li>
|
||||
'') pages}
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
'';
|
||||
|
||||
defaultStyle = import ./defaultStyle.nix { };
|
||||
|
||||
# This deploy script automatically copies the build result into
|
||||
# a TARGET directory and marks it as writeable optionally.
|
||||
# It is exposed as the deploy attribute of the result of
|
||||
# htmlman, so an htmlman expression can be used like this:
|
||||
# nix-build -A deploy htmlman.nix && ./result target_dir
|
||||
deployScript = title: drv: writers.writeDash "deploy-${title}" ''
|
||||
usage() {
|
||||
printf 'Usage: %s [-w] TARGET\n\n' "$0"
|
||||
printf 'Deploy htmlman documentation to TARGET directory.\n\n'
|
||||
printf ' -h Display this help message\n'
|
||||
printf ' -w Make TARGET directory writeable\n'
|
||||
}
|
||||
|
||||
if test "$#" -lt 1; then
|
||||
usage
|
||||
exit 100
|
||||
fi
|
||||
|
||||
writeable=false
|
||||
|
||||
while test "$#" -gt 0; do
|
||||
case "$1" in
|
||||
-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-w)
|
||||
writeable=true
|
||||
;;
|
||||
-*)
|
||||
usage
|
||||
exit 100
|
||||
;;
|
||||
*)
|
||||
if test -z "$target"; then
|
||||
target="$1"
|
||||
else
|
||||
echo "Too many arguments"
|
||||
exit 100
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$target"; then
|
||||
echo "Missing TARGET"
|
||||
usage
|
||||
exit 100
|
||||
fi
|
||||
|
||||
set -ex
|
||||
|
||||
mkdir -p "$target"
|
||||
cp -RTL --reflink=auto "${drv}" "$target"
|
||||
|
||||
if $writeable; then
|
||||
chmod -R +w "$target"
|
||||
fi
|
||||
'';
|
||||
|
||||
htmlman =
|
||||
{ title
|
||||
# title of the index page
|
||||
, description ? ""
|
||||
# description which is displayed after
|
||||
# the main heading on the index page
|
||||
, pages ? []
|
||||
# man pages of the following structure:
|
||||
# {
|
||||
# name : string;
|
||||
# section : int;
|
||||
# path : either path string;
|
||||
# }
|
||||
# path is optional, if it is not given,
|
||||
# the man page source must be located at
|
||||
# "${manDir}/${name}.${toString section}"
|
||||
, manDir ? null
|
||||
# directory in which man page sources are located
|
||||
, style ? defaultStyle
|
||||
# CSS to use as a string
|
||||
, normalizeCss ? true
|
||||
# whether to include normalize.css before the custom CSS
|
||||
}:
|
||||
|
||||
let
|
||||
index = indexTemplate {
|
||||
inherit title description pages;
|
||||
};
|
||||
resolvePath = { path ? null, name, section }:
|
||||
if path != null
|
||||
then path
|
||||
else "${manDir}/${name}.${toString section}";
|
||||
html =
|
||||
runExecline.local "htmlman-${title}" {
|
||||
derivationArgs = {
|
||||
inherit index style;
|
||||
passAsFile = [ "index" "style" ];
|
||||
};
|
||||
} ([
|
||||
"multisubstitute" [
|
||||
"importas" "-iu" "out" "out"
|
||||
"importas" "-iu" "index" "indexPath"
|
||||
"importas" "-iu" "style" "stylePath"
|
||||
]
|
||||
"if" [ bins.mkdir "-p" "$out" ]
|
||||
"if" [ bins.mv "$index" "\${out}/index.html" ]
|
||||
"if" (execlineStdoutInto "\${out}/style.css" [
|
||||
"if" ([
|
||||
bins.cat
|
||||
] ++ lib.optional normalizeCss normalizeDrv
|
||||
++ [
|
||||
"$style"
|
||||
])
|
||||
])
|
||||
] ++ lib.concatMap ({ name, section, ... }@p:
|
||||
execlineStdoutInto "\${out}/${name}.${toString section}.html" [
|
||||
"if" [
|
||||
bins.mandoc
|
||||
"-T" "html" "-mdoc"
|
||||
"-O" "style=style.css"
|
||||
(resolvePath p)
|
||||
]
|
||||
]) pages);
|
||||
in html // {
|
||||
deploy = deployScript title html;
|
||||
};
|
||||
in
|
||||
htmlman
|
49
users/sterni/htmlman/defaultStyle.nix
Normal file
49
users/sterni/htmlman/defaultStyle.nix
Normal file
|
@ -0,0 +1,49 @@
|
|||
{ ... }:
|
||||
|
||||
''
|
||||
body {
|
||||
font-size: 1em;
|
||||
line-height: 1.5;
|
||||
font-family: serif;
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
color: #3e7eff;
|
||||
}
|
||||
|
||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.manual-text, .index-text {
|
||||
padding: 20px;
|
||||
max-width: 800px;
|
||||
background-color: white;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
table.head, table.foot {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Nd {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* use same as cheddar for man pages */
|
||||
pre {
|
||||
padding: 16px;
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
''
|
Loading…
Reference in a new issue