From f3e32115ee099764e03efbedb6252b01fae2a6ae Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Sun, 6 Aug 2023 22:25:37 +0100 Subject: [PATCH] extremely hacky first pass at autogenerated module docs --- ci.nix | 3 +- doc/extract-options.nix | 55 ++++++++++++++++++++++++++++ doc/parse-options.fnl | 80 +++++++++++++++++++++++++++++++++++++++++ doc/user.rst | 8 ++--- 4 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 doc/extract-options.nix create mode 100644 doc/parse-options.fnl diff --git a/ci.nix b/ci.nix index 657f481..dbc9fb7 100644 --- a/ci.nix +++ b/ci.nix @@ -26,9 +26,10 @@ let }).buildEnv; doc = pkgs.stdenv.mkDerivation { name = "liminix-doc"; - nativeBuildInputs = with pkgs; [ gnumake sphinx ]; + nativeBuildInputs = with pkgs; [ gnumake sphinx fennel luaPackages.dkjson ]; src = ./doc; buildPhase = '' + cat ${(import ./doc/extract-options.nix).doc} | fennel --correlate parse-options.fnl > modules.rst make html ''; installPhase = '' diff --git a/doc/extract-options.nix b/doc/extract-options.nix new file mode 100644 index 0000000..5ac00bf --- /dev/null +++ b/doc/extract-options.nix @@ -0,0 +1,55 @@ +let + overlay = import ../overlay.nix; + pkgs = import ( { + overlays = [overlay]; + config = { + allowUnsupportedSystem = true; # mipsel + permittedInsecurePackages = [ + "python-2.7.18.6" # kernel backports needs python <3 + ]; + }; + }); + inherit (pkgs) lib; + inherit (lib) types; + modulenames = + builtins.attrNames + (lib.filterAttrsRecursive + (n: t: + (t=="directory") || + ((t=="regular") && ((builtins.match ".*\\.nix$" n) != null))) + (builtins.readDir ../modules)); + modulefiles = builtins.map (n: builtins.toPath "${../modules}/${n}") modulenames; + eval = (lib.evalModules { + modules = [ + { _module.args = { inherit pkgs; lib = pkgs.lib; }; } + ] ++ modulefiles; + }); + conf = eval.config; + optToDoc = name: opt : { + inherit name; + description = opt.description or null; + default = opt.default or null; + visible = + if (opt ? visible && opt.visible == "shallow") + then true + else opt.visible or true; + readOnly = opt.readOnly or false; + type = opt.type.description or "unspecified"; + }; + spliceServiceDefn = item : + if item.type == "parametrisable s6-rc service definition" + then + let sd = lib.attrByPath item.loc ["not found"] conf; + in item // { + parameters = + let x = lib.mapAttrsToList optToDoc sd.parameters; in x; + } + else + item; + o = builtins.map spliceServiceDefn + (pkgs.lib.optionAttrSetToDocList eval.options); +in { + doc = pkgs.writeText "options.json" + (builtins.unsafeDiscardStringContext (builtins.toJSON o)) + ; +} diff --git a/doc/parse-options.fnl b/doc/parse-options.fnl new file mode 100644 index 0000000..d8f0913 --- /dev/null +++ b/doc/parse-options.fnl @@ -0,0 +1,80 @@ +(local json (require :dkjson)) + +(local { : view } (require :fennel)) + +(fn headline [name] + (let [(_ _ basename) (string.find name ".*/([^/].*)") + len (basename:len)] + (print basename) + (print (string.rep "=" len)))) + +(fn strip-newlines [text] + (and text + (-> text + (string.gsub "\n([^\n])" " %1") + (string.gsub "\n\n+" "\n")))) + +(fn indent [n text] + (let [margin (string.rep " " n)] + (.. margin (string.gsub text "\n +" (.. "\n" margin ))))) + +(fn extract-text [description] + (and description +; (do (print (view description)) true) + (-> (match description + { :type "literalExpression" : text } text + {} nil + nil nil + t description) + strip-newlines))) + +(fn print-option [o offset] + (let [i (or offset 0)] + (print (indent i (.. " * option ``" o.name "``"))) + (print (indent (+ 4 i) + (or (extract-text o.description) "(no description)"))) + (print) + (print (indent (+ 4 i) (.. "**type** " o.type "\n"))) + (print (indent (+ 4 i) + (.. "**default** " + (or (extract-text (?. o :default)) "(none)") + "\n" + ))) + (print ))) + +(fn print-service [o] + (print (.. " * service ``" o.name "``")) + (print (indent 4 (or (extract-text o.description) "(no description)"))) + (print) + (print (indent 4 "**Service parameters**\n")) + (each [_ param (ipairs o.parameters)] + (print-option param 4))) + +(fn sort-options [module] + (table.sort module (fn [a b] (< a.name b.name))) + module) + +(let [raw (json.decode (io.read "*a")) + modules {}] + (each [_ option (ipairs raw)] + (let [[path] option.declarations + e (or (. modules path) [])] + (table.insert e option) + (tset modules path e))) + (each [name module (pairs modules)] + (print (headline name)) + (let [options (sort-options module)] + (each [_ o (ipairs options)] + (if (= o.type "parametrisable s6-rc service definition") + (print-service o) + (print-option o)))))) + +;; for each element el, add to table modules keyed on +;; el.declarations + +;; for each value in modules +;; print title +;; elements = (sort elements on el.name) +;; for each el in elements +;; is option or service? print whichever +;; diff --git a/doc/user.rst b/doc/user.rst index 667dd03..99722f3 100644 --- a/doc/user.rst +++ b/doc/user.rst @@ -316,11 +316,7 @@ Caveats * it cannot upgrade the kernel, only userland - - -Configuration Options +Configuration options ********************* - - -Module docs will go here. This part of the doc should be autogenerated. +.. include:: modules.rst