diff --git a/doc/contributing/contributing-to-documentation.chapter.md b/doc/contributing/contributing-to-documentation.chapter.md index a732eee4b962..0b7b49bf7dda 100644 --- a/doc/contributing/contributing-to-documentation.chapter.md +++ b/doc/contributing/contributing-to-documentation.chapter.md @@ -23,6 +23,14 @@ $ nix-shell If the build succeeds, the manual will be in `./result/share/doc/nixpkgs/manual.html`. +## devmode {#sec-contributing-devmode} + +The shell in the manual source directory makes available a command, `devmode`. +It is a daemon, that: +1. watches the manual's source for changes and when they occur — rebuilds +2. HTTP serves the manual, injecting a script that triggers reload on changes +3. opens the manual in the default browser + ## Syntax {#sec-contributing-markup} As per [RFC 0072](https://github.com/NixOS/rfcs/pull/72), all new documentation content should be written in [CommonMark](https://commonmark.org/) Markdown dialect. diff --git a/doc/shell.nix b/doc/shell.nix new file mode 100644 index 000000000000..d71e3f3a709a --- /dev/null +++ b/doc/shell.nix @@ -0,0 +1,20 @@ +let + pkgs = import ../. { + config = {}; + overlays = []; + }; + + common = import ./common.nix; + inherit (common) outputPath indexPath; + + web-devmode = import ../pkgs/tools/nix/web-devmode.nix { + inherit pkgs; + buildArgs = "./."; + open = "/${outputPath}/${indexPath}"; + }; +in + pkgs.mkShell { + packages = [ + web-devmode + ]; + } diff --git a/nixos/doc/manual/contributing-to-this-manual.chapter.md b/nixos/doc/manual/contributing-to-this-manual.chapter.md index c306cc084cdb..4633c7e1b058 100644 --- a/nixos/doc/manual/contributing-to-this-manual.chapter.md +++ b/nixos/doc/manual/contributing-to-this-manual.chapter.md @@ -11,6 +11,8 @@ $ nix-build nixos/release.nix -A manual.x86_64-linux If the build succeeds, the manual will be in `./result/share/doc/nixos/index.html`. +There's also [a convenient development daemon](https://nixos.org/manual/nixpkgs/unstable/#sec-contributing-devmode). + **Contributing to the man pages** The man pages are written in [DocBook] which is XML. diff --git a/nixos/doc/manual/shell.nix b/nixos/doc/manual/shell.nix new file mode 100644 index 000000000000..70500a12b037 --- /dev/null +++ b/nixos/doc/manual/shell.nix @@ -0,0 +1,20 @@ +let + pkgs = import ../../.. { + config = {}; + overlays = []; + }; + + common = import ./common.nix; + inherit (common) outputPath indexPath; + + web-devmode = import ../../../pkgs/tools/nix/web-devmode.nix { + inherit pkgs; + buildArgs = "../../release.nix -A manualHTML.${builtins.currentSystem}"; + open = "/${outputPath}/${indexPath}"; + }; +in + pkgs.mkShell { + packages = [ + web-devmode + ]; + } diff --git a/pkgs/tools/nix/web-devmode.nix b/pkgs/tools/nix/web-devmode.nix new file mode 100644 index 000000000000..6ebdc31118f0 --- /dev/null +++ b/pkgs/tools/nix/web-devmode.nix @@ -0,0 +1,117 @@ +{ + pkgs, + # arguments to `nix-build`, e.g. `"foo.nix -A bar"` + buildArgs, + # what path to open a browser at + open, +}: let + inherit (pkgs) lib; + + error_page = pkgs.writeShellScriptBin "error_page" '' + echo " + + + + +
$1
+ " + ''; + + # The following would have been simpler: + # 1. serve from `$serve` + # 2. pass each build a `--out-link $serve/result` + # But that way live-server does not seem to detect changes and therefore no + # auto-reloads occur. + # Instead, we copy the contents of each build to the `$serve` directory. + # Using rsync here, instead of `cp`, to get as close to an atomic + # directory copy operation as possible. `--delay-updates` should + # also go towards that. + build_and_copy = pkgs.writeShellScriptBin "build_and_copy" '' + set -euxo pipefail + + set +e + stderr=$(2>&1 nix-build --out-link $out_link ${buildArgs}) + exit_status=$? + set -e + + if [ $exit_status -eq 0 ]; + then + # setting permissions to be able to clean up + ${lib.getBin pkgs.rsync}/bin/rsync \ + --recursive \ + --chmod=u=rwX \ + --delete-before \ + --delay-updates \ + $out_link/ \ + $serve/ + else + set +x + ${lib.getBin error_page}/bin/error_page "$stderr" > $error_page_absolute + set -x + + ${lib.getBin pkgs.findutils}/bin/find $serve \ + -type f \ + ! -name $error_page_relative \ + -delete + fi + ''; + + # https://watchexec.github.io/ + watcher = pkgs.writeShellScriptBin "watcher" '' + set -euxo pipefail + + ${lib.getBin pkgs.watchexec}/bin/watchexec \ + --shell=none \ + --restart \ + --print-events \ + ${lib.getBin build_and_copy}/bin/build_and_copy + ''; + + # A Rust alternative to live-server exists, but it was not in nixpkgs. + # `--no-css-inject`: without this it seems that only CSS is auto-reloaded. + # https://www.npmjs.com/package/live-server + server = pkgs.writeShellScriptBin "server" '' + set -euxo pipefail + + ${lib.getBin pkgs.nodePackages_latest.live-server}/bin/live-server \ + --host=127.0.0.1 \ + --verbose \ + --no-css-inject \ + --entry-file=$error_page_relative \ + --open=${open} \ + $serve + ''; + + devmode = + pkgs.writeShellScriptBin "devmode" + '' + set -euxo pipefail + + function handle_exit { + rm -rf "$tmpdir" + } + + tmpdir=$(mktemp -d) + trap handle_exit EXIT + + export out_link="$tmpdir/result" + export serve="$tmpdir/serve" + mkdir $serve + export error_page_relative=error.html + export error_page_absolute=$serve/$error_page_relative + ${lib.getBin error_page}/bin/error_page "building …" > $error_page_absolute + + ${lib.getBin pkgs.parallel}/bin/parallel \ + --will-cite \ + --line-buffer \ + --tagstr '{/}' \ + ::: \ + "${lib.getBin watcher}/bin/watcher" \ + "${lib.getBin server}/bin/server" + ''; +in + devmode