Merge branch 'ps/build-meson-html'

The build procedure based on meson learned to generate HTML
documention pages.

* ps/build-meson-html:
  Documentation: wire up sanity checks for Meson
  t/Makefile: make "check-meson" work with Dash
  meson: install static files for HTML documentation
  meson: generate articles
  Documentation: refactor "howto-index.sh" for out-of-tree builds
  Documentation: refactor "api-index.sh" for out-of-tree builds
  meson: generate user manual
  Documentation: inline user-manual.conf
  meson: generate HTML pages for all man page categories
  meson: fix generation of merge tools
  meson: properly wire up dependencies for our docs
  meson: wire up support for AsciiDoctor
This commit is contained in:
Junio C Hamano
2025-01-02 13:37:08 -08:00
12 changed files with 402 additions and 63 deletions

View File

@ -12,6 +12,7 @@ cmds-*.txt
mergetools-*.txt
SubmittingPatches.txt
tmp-doc-diff/
tmp-meson-diff/
GIT-ASCIIDOCFLAGS
/.build/
/GIT-EXCLUDED-PROGRAMS

View File

@ -339,6 +339,7 @@ clean:
$(RM) $(cmds_txt) $(mergetools_txt) *.made
$(RM) GIT-ASCIIDOCFLAGS
$(RM) asciidoc.conf asciidoctor-extensions.rb
$(RM) -rf tmp-meson-diff
docinfo.html: docinfo-html.in
$(QUIET_GEN)$(RM) $@ && cat $< >$@
@ -362,12 +363,12 @@ manpage-cmd = $(QUIET_XMLTO)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
%.xml : %.txt $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_XML) -d manpage -o $@ $<
user-manual.xml: user-manual.txt user-manual.conf $(ASCIIDOC_DEPS)
user-manual.xml: user-manual.txt $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_XML) -d book -o $@ $<
technical/api-index.txt: technical/api-index-skel.txt \
technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
$(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh
$(QUIET_GEN)'$(SHELL_PATH_SQ)' technical/api-index.sh ./technical ./technical/api-index.txt
technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
$(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt \
@ -411,8 +412,8 @@ gitman.info: gitman.texi
$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
$(QUIET_DB2TEXI)$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@
howto-index.txt: howto-index.sh $(HOWTO_TXT)
$(QUIET_GEN)'$(SHELL_PATH_SQ)' ./howto-index.sh $(sort $(HOWTO_TXT)) >$@
howto-index.txt: howto/howto-index.sh $(HOWTO_TXT)
$(QUIET_GEN)'$(SHELL_PATH_SQ)' ./howto/howto-index.sh $(sort $(HOWTO_TXT)) >$@
$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt
@ -494,6 +495,20 @@ lint-docs-fsck-msgids: $(LINT_DOCS_FSCK_MSGIDS)
lint-docs-manpages:
$(QUIET_GEN)./lint-manpages.sh
.PHONY: lint-docs-meson
lint-docs-meson:
@# awk acts up when trying to match single quotes, so we use \047 instead.
@mkdir -p tmp-meson-diff && \
awk "/^manpages = {$$/ {flag=1 ; next } /^}$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047 : [157],\$$/, \"\"); print }" meson.build | \
grep -v -e '#' -e '^$$' | \
sort >tmp-meson-diff/meson.txt && \
ls git*.txt scalar.txt | grep -v -e git-bisect-lk2009.txt -e git-tools.txt >tmp-meson-diff/actual.txt && \
if ! cmp tmp-meson-diff/meson.txt tmp-meson-diff/actual.txt; then \
echo "Meson man pages differ from actual man pages:"; \
diff -u tmp-meson-diff/meson.txt tmp-meson-diff/actual.txt; \
exit 1; \
fi
## Lint: list of targets above
.PHONY: lint-docs
lint-docs: lint-docs-fsck-msgids
@ -501,6 +516,7 @@ lint-docs: lint-docs-gitlink
lint-docs: lint-docs-man-end-blurb
lint-docs: lint-docs-man-section-order
lint-docs: lint-docs-manpages
lint-docs: lint-docs-meson
ifeq ($(wildcard po/Makefile),po/Makefile)
doc-l10n install-l10n::

View File

@ -25,12 +25,22 @@ manmanual=Git Manual
mansource=Git @GIT_VERSION@
revdate=@GIT_DATE@
ifdef::doctype-book[]
[titles]
underlines="__","==","--","~~","^^"
endif::doctype-book[]
ifdef::backend-docbook[]
[linkgit-inlinemacro]
ifndef::doctype-book[]
{0%{target}}
{0#<citerefentry>}
{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
{0#</citerefentry>}
endif::doctype-book[]
ifdef::doctype-book[]
<ulink url="{target}.html">{target}{0?({0})}</ulink>
endif::doctype-book[]
[literal-inlinemacro]
{eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1<literal>\2</literal>', re.sub(r'(\.\.\.?)([^\]$.])', r'<literal>\1</literal>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))}

View File

@ -48,7 +48,7 @@ do
file="$txt"
fi
echo "* link:$file[$title] $from
echo "* link:howto/$(basename "$file")[$title] $from
$abstract
"

View File

@ -0,0 +1,62 @@
howto_sources = [
'coordinate-embargoed-releases.txt',
'keep-canonical-history-correct.txt',
'maintain-git.txt',
'new-command.txt',
'rebase-from-internal-branch.txt',
'rebuild-from-update-hook.txt',
'recover-corrupted-blob-object.txt',
'recover-corrupted-object-harder.txt',
'revert-a-faulty-merge.txt',
'revert-branch-rebase.txt',
'separating-topic-branches.txt',
'setup-git-server-over-http.txt',
'update-hook-example.txt',
'use-git-daemon.txt',
'using-merge-subtree.txt',
'using-signed-tag-in-pull-request.txt',
]
howto_index = custom_target(
command: [
shell,
meson.current_source_dir() / 'howto-index.sh',
'@INPUT@',
],
env: script_environment,
capture: true,
input: howto_sources,
output: 'howto-index.txt',
)
custom_target(
command: asciidoc_html_options,
input: howto_index,
output: 'howto-index.html',
depends: documentation_deps,
install: true,
install_dir: get_option('datadir') / 'doc/git-doc',
)
foreach howto : howto_sources
howto_stripped = custom_target(
command: [
find_program('sed'),
'-e',
'1,/^$/d',
'@INPUT@',
],
input: howto,
output: fs.stem(howto) + '.stripped',
capture: true,
)
custom_target(
command: asciidoc_html_options,
input: howto_stripped,
output: fs.stem(howto_stripped.full_path()) + '.html',
depends: documentation_deps,
install: true,
install_dir: get_option('datadir') / 'doc/git-doc/howto',
)
endforeach

View File

@ -204,30 +204,88 @@ manpages = {
'gitworkflows.txt' : 7,
}
asciidoc = find_program('asciidoc')
docs_backend = get_option('docs_backend')
if docs_backend == 'auto'
if find_program('asciidoc', required: false).found()
docs_backend = 'asciidoc'
elif find_program('asciidoctor', required: false).found()
docs_backend = 'asciidoctor'
else
error('Neither asciidoc nor asciidoctor were found.')
endif
endif
if docs_backend == 'asciidoc'
asciidoc = find_program('asciidoc', required: true)
asciidoc_html = 'xhtml11'
asciidoc_docbook = 'docbook'
xmlto_extra = [ ]
asciidoc_conf = custom_target(
command: [
shell,
meson.project_source_root() / 'GIT-VERSION-GEN',
meson.project_source_root(),
'@INPUT@',
'@OUTPUT@',
],
input: 'asciidoc.conf.in',
output: 'asciidoc.conf',
depends: [git_version_file],
env: version_gen_environment,
)
asciidoc_common_options = [
asciidoc,
'--conf-file=' + asciidoc_conf.full_path(),
'--attribute=build_dir=' + meson.current_build_dir(),
]
documentation_deps = [
asciidoc_conf,
]
elif docs_backend == 'asciidoctor'
asciidoctor = find_program('asciidoctor', required: true)
asciidoc_html = 'xhtml5'
asciidoc_docbook = 'docbook5'
xmlto_extra = [
'--skip-validation',
'-x', meson.current_source_dir() / 'manpage.xsl',
]
asciidoctor_extensions = custom_target(
command: [
shell,
meson.project_source_root() / 'GIT-VERSION-GEN',
meson.project_source_root(),
'@INPUT@',
'@OUTPUT@',
],
input: 'asciidoctor-extensions.rb.in',
output: 'asciidoctor-extensions.rb',
depends: [git_version_file],
env: version_gen_environment,
)
asciidoc_common_options = [
asciidoctor,
'--attribute', 'compat-mode',
'--attribute', 'tabsize=8',
'--attribute', 'litdd=&#x2d;&#x2d;',
'--attribute', 'docinfo=shared',
'--attribute', 'build_dir=' + meson.current_build_dir(),
'--load-path', meson.current_build_dir(),
'--require', 'asciidoctor-extensions',
]
documentation_deps = [
asciidoctor_extensions,
]
endif
git = find_program('git', required: false)
xmlto = find_program('xmlto')
asciidoc_conf = custom_target(
command: [
shell,
meson.project_source_root() / 'GIT-VERSION-GEN',
meson.project_source_root(),
'@INPUT@',
'@OUTPUT@',
],
input: meson.current_source_dir() / 'asciidoc.conf.in',
output: 'asciidoc.conf',
depends: [git_version_file],
env: version_gen_environment,
)
asciidoc_common_options = [
asciidoc,
'--conf-file=' + asciidoc_conf.full_path(),
'--attribute=build_dir=' + meson.current_build_dir(),
]
cmd_lists = [
'cmds-ancillaryinterrogators.txt',
'cmds-ancillarymanipulators.txt',
@ -243,17 +301,14 @@ cmd_lists = [
'cmds-foreignscminterface.txt',
]
documentation_deps = [
asciidoc_conf,
]
documentation_deps += custom_target(
command: [
perl,
meson.current_source_dir() / 'cmd-list.perl',
'@INPUT@',
meson.project_source_root(),
meson.current_build_dir(),
] + cmd_lists,
input: 'cmd-list.perl',
output: cmd_lists
)
@ -261,15 +316,15 @@ foreach mode : [ 'diff', 'merge' ]
documentation_deps += custom_target(
command: [
shell,
meson.current_source_dir() / 'generate-mergetool-list.sh',
'@INPUT@',
'..',
'diff',
mode,
'@OUTPUT@'
],
env: [
'MERGE_TOOLS_DIR=' + meson.project_source_root() / 'mergetools',
'TOOL_MODE=' + mode,
],
input: 'generate-mergetool-list.sh',
output: 'mergetools-' + mode + '.txt',
)
endforeach
@ -278,12 +333,13 @@ foreach manpage, category : manpages
if get_option('docs').contains('man')
manpage_xml_target = custom_target(
command: asciidoc_common_options + [
'--backend=docbook',
'--backend=' + asciidoc_docbook,
'--doctype=manpage',
'--out-file=@OUTPUT@',
meson.current_source_dir() / manpage,
'@INPUT@',
],
depends: documentation_deps,
input: manpage,
output: fs.stem(manpage) + '.xml',
)
@ -291,16 +347,18 @@ foreach manpage, category : manpages
manpage_target = custom_target(
command: [
xmlto,
'-m',
meson.current_source_dir() / 'manpage-normal.xsl',
'-m',
meson.current_source_dir() / 'manpage-bold-literal.xsl',
'-m', '@INPUT0@',
'-m', '@INPUT1@',
'--stringparam',
'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
'man',
manpage_xml_target,
'-o',
meson.current_build_dir(),
] + xmlto_extra,
input: [
'manpage-normal.xsl',
'manpage-bold-literal.xsl',
],
output: manpage_path,
install: true,
@ -308,18 +366,139 @@ foreach manpage, category : manpages
)
endif
if get_option('docs').contains('html') and category == 1
if get_option('docs').contains('html')
custom_target(
command: asciidoc_common_options + [
'--backend=xhtml11',
'--backend=' + asciidoc_html,
'--doctype=manpage',
'--out-file=@OUTPUT@',
meson.current_source_dir() / manpage,
'@INPUT@',
],
depends: documentation_deps,
input: manpage,
output: fs.stem(manpage) + '.html',
install: true,
install_dir: get_option('datadir') / 'doc/git-doc',
)
endif
endforeach
if get_option('docs').contains('html')
configure_file(
input: 'docinfo-html.in',
output: 'docinfo.html',
copy: true,
install: true,
install_dir: get_option('datadir') / 'doc/git-doc',
)
configure_file(
input: 'docbook-xsl.css',
output: 'docbook-xsl.css',
copy: true,
install: true,
install_dir: get_option('datadir') / 'doc/git-doc',
)
install_symlink('index.html',
install_dir: get_option('datadir') / 'doc/git-doc',
pointing_to: 'git.html',
)
xsltproc = find_program('xsltproc')
user_manual_xml = custom_target(
command: asciidoc_common_options + [
'--backend=' + asciidoc_docbook,
'--doctype=book',
'--out-file=@OUTPUT@',
'@INPUT@',
],
input: 'user-manual.txt',
output: 'user-manual.xml',
depends: documentation_deps,
)
custom_target(
command: [
xsltproc,
'--xinclude',
'--stringparam', 'html.stylesheet', 'docbook-xsl.css',
'--param', 'generate.consistent.ids', '1',
'--output', '@OUTPUT@',
'@INPUT@',
user_manual_xml,
],
input: 'docbook.xsl',
output: 'user-manual.html',
install: true,
install_dir: get_option('datadir') / 'doc/git-doc',
)
articles = [
'DecisionMaking.txt',
'MyFirstContribution.txt',
'MyFirstObjectWalk.txt',
'ReviewingGuidelines.txt',
'SubmittingPatches',
'ToolsForGit.txt',
'git-bisect-lk2009.txt',
'git-tools.txt',
]
foreach article : articles
custom_target(
command: asciidoc_common_options + [
'--backend=' + asciidoc_html,
'--out-file=@OUTPUT@',
'@INPUT@',
],
input: article,
output: fs.stem(article) + '.html',
depends: documentation_deps,
install: true,
install_dir: get_option('datadir') / 'doc/git-doc',
)
endforeach
asciidoc_html_options = asciidoc_common_options + [
'--backend=' + asciidoc_html,
'--out-file=@OUTPUT@',
'--attribute', 'git-relative-html-prefix=../',
'@INPUT@',
]
subdir('howto')
subdir('technical')
endif
# Sanity check that we are not missing any tests present in 't/'. This check
# only runs once at configure time and is thus best-effort, only. Furthermore,
# it only verifies man pages for the sake of simplicity.
configured_manpages = manpages.keys() + [ 'git-bisect-lk2009.txt', 'git-tools.txt' ]
actual_manpages = run_command(shell, '-c', 'ls git*.txt scalar.txt',
check: true,
env: script_environment,
).stdout().strip().split('\n')
if configured_manpages != actual_manpages
missing_manpage = [ ]
foreach actual_manpage : actual_manpages
if actual_manpage not in configured_manpages
missing_manpage += actual_manpage
endif
endforeach
if missing_manpage.length() > 0
error('Man page found, but not configured:\n\n - ' + '\n - '.join(missing_manpage))
endif
superfluous_manpage = [ ]
foreach configured_manpage : configured_manpages
if configured_manpage not in actual_manpages
superfluous_manpage += configured_manpage
endif
endforeach
if superfluous_manpage.length() > 0
error('Man page configured, but not found:\n\n - ' + '\n - '.join(superfluous_manpage))
endif
endif

View File

@ -1,6 +1,17 @@
#!/bin/sh
if test $# -ne 2
then
echo >&2 "USAGE: $0 <SOURCE_DIR> <OUTPUT>"
exit 1
fi
SOURCE_DIR="$1"
OUTPUT="$2"
(
cd "$SOURCE_DIR"
c=////////////////////////////////////////////////////////////////
skel=api-index-skel.txt
sed -e '/^\/\/ table of contents begin/q' "$skel"
@ -18,11 +29,11 @@
done
echo "$c"
sed -n -e '/^\/\/ table of contents end/,$p' "$skel"
) >api-index.txt+
) >"$OUTPUT"+
if test -f api-index.txt && cmp api-index.txt api-index.txt+ >/dev/null
if test -f "$OUTPUT" && cmp "$OUTPUT" "$OUTPUT"+ >/dev/null
then
rm -f api-index.txt+
rm -f "$OUTPUT"+
else
mv api-index.txt+ api-index.txt
mv "$OUTPUT"+ "$OUTPUT"
fi

View File

@ -0,0 +1,66 @@
api_docs = [
'api-error-handling.txt',
'api-merge.txt',
'api-parse-options.txt',
'api-simple-ipc.txt',
'api-trace2.txt',
]
articles = [
'bitmap-format.txt',
'build-systems.txt',
'bundle-uri.txt',
'commit-graph.txt',
'directory-rename-detection.txt',
'hash-function-transition.txt',
'long-running-process-protocol.txt',
'multi-pack-index.txt',
'packfile-uri.txt',
'pack-heuristics.txt',
'parallel-checkout.txt',
'partial-clone.txt',
'platform-support.txt',
'racy-git.txt',
'reftable.txt',
'remembering-renames.txt',
'repository-version.txt',
'rerere.txt',
'scalar.txt',
'send-pack-pipeline.txt',
'shallow.txt',
'sparse-checkout.txt',
'sparse-index.txt',
'trivial-merge.txt',
'unit-tests.txt',
]
api_index = custom_target(
command: [
shell,
meson.current_source_dir() / 'api-index.sh',
meson.current_source_dir(),
'@OUTPUT@',
],
env: script_environment,
input: api_docs,
output: 'api-index.txt',
)
custom_target(
command: asciidoc_html_options,
input: api_index,
output: 'api-index.html',
depends: documentation_deps,
install: true,
install_dir: get_option('datadir') / 'doc/git-doc/technical',
)
foreach article : api_docs + articles
custom_target(
command: asciidoc_html_options,
input: article,
output: fs.stem(article) + '.html',
install: true,
install_dir: get_option('datadir') / 'doc/git-doc/technical',
)
endforeach

View File

@ -1,11 +0,0 @@
[titles]
underlines="__","==","--","~~","^^"
[attributes]
caret=^
startsb=&#91;
endsb=&#93;
tilde=&#126;
[linkgit-inlinemacro]
<ulink url="{target}.html">{target}{0?({0})}</ulink>

View File

@ -85,6 +85,8 @@ option('docs', type: 'array', choices: ['man', 'html'], value: [],
description: 'Which documenattion formats to build and install.')
option('default_help_format', type: 'combo', choices: ['man', 'html'], value: 'man',
description: 'Default format used when executing git-help(1).')
option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',
description: 'Which backend to use to generate documentation.')
# Testing.
option('tests', type: 'boolean', value: true,

1
t/.gitignore vendored
View File

@ -2,4 +2,5 @@
/test-results
/.prove
/chainlinttmp
/mesontmp
/out/

View File

@ -103,6 +103,7 @@ clean-except-prove-cache: clean-chainlint
clean: clean-except-prove-cache
$(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
$(RM) -r mesontmp
$(RM) .prove
clean-chainlint:
@ -116,16 +117,17 @@ check-chainlint:
check-meson:
@# awk acts up when trying to match single quotes, so we use \047 instead.
@printf "%s\n" \
@mkdir -p mesontmp && \
printf "%s\n" \
"integration_tests t[0-9][0-9][0-9][0-9]-*.sh" \
"unit_test_programs unit-tests/t-*.c" \
"clar_test_suites unit-tests/u-*.c" | \
while read -r variable pattern; do \
meson_tests=$$(awk "/^$$variable = \[\$$/ {flag=1 ; next } /^]$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047,\$$/, \"\"); print }" meson.build) && \
actual_tests=$$(ls $$pattern) && \
if test "$$meson_tests" != "$$actual_tests"; then \
awk "/^$$variable = \[\$$/ {flag=1 ; next } /^]$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047,\$$/, \"\"); print }" meson.build >mesontmp/meson.txt && \
ls $$pattern >mesontmp/actual.txt && \
if ! cmp mesontmp/meson.txt mesontmp/actual.txt; then \
echo "Meson tests differ from actual tests:"; \
diff -u <(echo "$$meson_tests") <(echo "$$actual_tests"); \
diff -u mesontmp/meson.txt mesontmp/actual.txt; \
exit 1; \
fi; \
done