From 5bac308c7c141857c6ead02ca02b2e832d0e5921 Mon Sep 17 00:00:00 2001 From: Qyriad Date: Fri, 5 Apr 2024 21:11:40 -0600 Subject: [PATCH] meson: fix warm nix3 CLI manual generation `nix eval --write-to` refuses to write to a directory that exists at all, so now we generate in a temporary directory, and copy the generated tree to the build directory. This is equivalent to what the Make buildsystem did, actually, but hopefully more robust. Future work: documenting the doc generation architecture in the top-level meson.build outline comment. Change-Id: Ic3eb6d26e3cc249a1c042fd3ced22d637ac66a69 --- doc/manual/generate-manpage.py | 63 ++++++++++++++++++++++++++++++++++ doc/manual/meson.build | 23 +++++++++---- 2 files changed, 80 insertions(+), 6 deletions(-) create mode 100755 doc/manual/generate-manpage.py diff --git a/doc/manual/generate-manpage.py b/doc/manual/generate-manpage.py new file mode 100755 index 000000000..f082caffa --- /dev/null +++ b/doc/manual/generate-manpage.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 + +""" +This script is a helper for this project's Meson buildsystem, to generate +manpages as mdbook markdown for nix3 CLI commands. It is an analogue to an +inline sequence of bash commands in the autoconf+Make buildsystem, which works +around a limitation in `nix eval --write-to`, in that it refuses to write to any +directory that already exists. + +Basically, this script is a glorified but hopefully-more-robust version of: +$ rm -rf $output +$ nix eval --write-to $output.tmp --expr 'import doc/manual/generate-manpage.nix true + (builtins.readFile ./generate-manpage.nix)' +$ mv $output.tmp $output +""" + +import argparse +import os.path +import shlex +import shutil +import subprocess +import sys +import tempfile + +name = 'generate-manpage.py' + +def log(*args, **kwargs): + kwargs['file'] = sys.stderr + return print(f'{name}:', *args, **kwargs) + +def main(): + parser = argparse.ArgumentParser(name) + parser.add_argument('--nix', required=True, help='Full path to the nix binary to use') + parser.add_argument('-o', '--output', required=True, help='Output directory') + parser.add_argument('--generator', required=True, help='Path to generate-manpage.nix') + parser.add_argument('--cli-json', required=True, help='Path to the nix.json output from Nix') + args = parser.parse_args() + + with tempfile.TemporaryDirectory() as tempdir: + + temp_out = os.path.join(tempdir, 'new-cli') + + nix_args = [ + args.nix, + '--experimental-features', + 'nix-command', + 'eval', + '-I', 'nix/corepkgs=corepkgs', + '--store', 'dummy://', + '--impure', + '--raw', + '--write-to', temp_out, + '--expr', + f'import {args.generator} true (builtins.readFile {args.cli_json})', + ] + + log('generating nix3 man pages with', shlex.join(nix_args)) + + subprocess.check_call(nix_args) + + shutil.copytree(temp_out, args.output, dirs_exist_ok=True) + +sys.exit(main()) diff --git a/doc/manual/meson.build b/doc/manual/meson.build index 02b707ff3..dafec9a4c 100644 --- a/doc/manual/meson.build +++ b/doc/manual/meson.build @@ -132,15 +132,26 @@ nix3_cli_json = custom_target( capture : true, output : 'nix.json', ) +# `nix eval --write-to` is rather picky, and refuses to write to a directory that exists at all. +# This is fine for clean builds because it creates the directory and then is never run again, +# but during development if nix.json changes, then using `nix eval --write-to` will error, +# since that part of the build directory already exists. +# Thus, another Python script. It runs the relevant `nix eval --write-to` command in a temporary +# directory, and then copies that tree to our build output directory. nix3_cli_files = custom_target( - command : nix_eval_for_docs + [ - '--write-to', '@OUTPUT@', - '--expr', - 'import @INPUT1@ true (builtins.readFile @INPUT0@)', + command : [ + python, + '@INPUT0@', + '--nix=@INPUT1@', + '--generator=@INPUT2@', + '--cli-json=@INPUT3@', + '--output=@OUTPUT@', ], input : [ - nix3_cli_json, - 'generate-manpage.nix', + 'generate-manpage.py', # INPUT0 + nix, # INPUT1 + 'generate-manpage.nix', # INPUT2 + nix3_cli_json, # INPUT3 'utils.nix', ], output : 'new-cli',