forked from lix-project/lix
Merge "docs: generalize manpage generation script as json-to-tree.py" into main
This commit is contained in:
commit
784a46654c
|
@ -1,63 +0,0 @@
|
||||||
#!/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())
|
|
61
doc/manual/json-to-tree.py
Executable file
61
doc/manual/json-to-tree.py
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
This script is a helper for this project's Meson buildsystem, to replace its
|
||||||
|
usage of `nix eval --write-to`. Writing a JSON object as a nested directory
|
||||||
|
tree is more generic, easier to maintain, and far, far less cursed. Nix
|
||||||
|
has 'good' support for JSON output. Let's just use it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
name = 'json-to-tree.py'
|
||||||
|
|
||||||
|
def log(*args, **kwargs):
|
||||||
|
kwargs['file'] = sys.stderr
|
||||||
|
return print(f'{name}:', *args, **kwargs)
|
||||||
|
|
||||||
|
def write_dict_to_directory(current_directory: Path, data: dict, files_written=0):
|
||||||
|
current_directory.mkdir(parents=True, exist_ok=True)
|
||||||
|
for key, value in data.items():
|
||||||
|
nested_path = current_directory / key
|
||||||
|
match value:
|
||||||
|
case dict(nested_data):
|
||||||
|
files_written += write_dict_to_directory(nested_path, nested_data)
|
||||||
|
|
||||||
|
case str(content):
|
||||||
|
nested_path.write_text(content)
|
||||||
|
files_written += 1
|
||||||
|
|
||||||
|
case rest:
|
||||||
|
assert False, \
|
||||||
|
f'should have been called on a dict or string, not {type(rest)=}\n\t{rest=}'
|
||||||
|
|
||||||
|
return files_written
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(name)
|
||||||
|
parser.add_argument('-i', '--input', type=argparse.FileType('r'), default='-',
|
||||||
|
help='The JSON input to operate on and output as a directory tree',
|
||||||
|
)
|
||||||
|
parser.add_argument('-o', '--output', type=Path, required=True,
|
||||||
|
help='The place to put the directory tree',
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
json_string = args.input.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = json.loads(json_string)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
log(f'could not decode JSON from input: {json_string}')
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
files_written = write_dict_to_directory(args.output, data)
|
||||||
|
log(f'wrote {files_written} files')
|
||||||
|
|
||||||
|
sys.exit(main())
|
|
@ -7,13 +7,13 @@ nix_env_for_docs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
nix_for_docs = [ nix, '--experimental-features', 'nix-command' ]
|
nix_for_docs = [ nix, '--experimental-features', 'nix-command' ]
|
||||||
nix_eval_for_docs = nix_for_docs + [
|
nix_eval_for_docs_common = nix_for_docs + [
|
||||||
'eval',
|
'eval',
|
||||||
'-I', 'nix/corepkgs=corepkgs',
|
'-I', 'nix/corepkgs=corepkgs',
|
||||||
'--store', 'dummy://',
|
'--store', 'dummy://',
|
||||||
'--impure',
|
'--impure',
|
||||||
'--raw',
|
|
||||||
]
|
]
|
||||||
|
nix_eval_for_docs = nix_eval_for_docs_common + '--raw'
|
||||||
|
|
||||||
nix_conf_file_json = custom_target(
|
nix_conf_file_json = custom_target(
|
||||||
command : nix_for_docs + [ 'show-config', '--json' ],
|
command : nix_for_docs + [ 'show-config', '--json' ],
|
||||||
|
@ -132,27 +132,34 @@ nix3_cli_json = custom_target(
|
||||||
capture : true,
|
capture : true,
|
||||||
output : 'nix.json',
|
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,
|
# Intermediate step for manpage generation.
|
||||||
# but during development if nix.json changes, then using `nix eval --write-to` will error,
|
# This splorks the output of generate-manpage.nix as JSON,
|
||||||
# since that part of the build directory already exists.
|
# which gets written as a directory tree below.
|
||||||
# Thus, another Python script. It runs the relevant `nix eval --write-to` command in a temporary
|
nix3_cli_files_json = custom_target(
|
||||||
# directory, and then copies that tree to our build output directory.
|
command : nix_eval_for_docs_common + [
|
||||||
|
'--json',
|
||||||
|
'--expr',
|
||||||
|
'import @INPUT0@ true (builtins.readFile @INPUT1@)',
|
||||||
|
],
|
||||||
|
input : [
|
||||||
|
'generate-manpage.nix',
|
||||||
|
nix3_cli_json,
|
||||||
|
],
|
||||||
|
capture : true,
|
||||||
|
output : 'new-cli.json',
|
||||||
|
env : nix_env_for_docs,
|
||||||
|
)
|
||||||
nix3_cli_files = custom_target(
|
nix3_cli_files = custom_target(
|
||||||
command : [
|
command : [
|
||||||
python,
|
python,
|
||||||
'@INPUT0@',
|
'@INPUT0@',
|
||||||
'--nix=@INPUT1@',
|
'-i', '@INPUT1@',
|
||||||
'--generator=@INPUT2@',
|
'-o', '@OUTPUT@',
|
||||||
'--cli-json=@INPUT3@',
|
|
||||||
'--output=@OUTPUT@',
|
|
||||||
],
|
],
|
||||||
input : [
|
input : [
|
||||||
'generate-manpage.py', # INPUT0
|
'json-to-tree.py',
|
||||||
nix, # INPUT1
|
nix3_cli_files_json,
|
||||||
'generate-manpage.nix', # INPUT2
|
|
||||||
nix3_cli_json, # INPUT3
|
|
||||||
'utils.nix',
|
|
||||||
],
|
],
|
||||||
output : 'new-cli',
|
output : 'new-cli',
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue