@@ -20,9 +20,24 @@ module Git
end
end
end
+
+ class DocumentPostProcessor < Asciidoctor::Extensions::Postprocessor
+ def process document, output
+ if document.basebackend? 'docbook'
+ git_version = document.attributes['git_version']
+ new_tags = "" \
+ "<refmiscinfo class=\"source\">Git</refmiscinfo>\n" \
+ "<refmiscinfo class=\"version\">#{git_version}</refmiscinfo>\n" \
+ "<refmiscinfo class=\"manual\">Git Manual</refmiscinfo>\n"
+ output = output.sub(/<\/refmeta>/, new_tags + "</refmeta>")
+ end
+ output
+ end
+ end
end
end
Asciidoctor::Extensions.register do
inline_macro Git::Documentation::LinkGitProcessor, :linkgit
+ postprocessor Git::Documentation::DocumentPostProcessor
end
When we build with AsciiDoc, asciidoc.conf ensures that each xml-file we generate contains some meta-information which `xmlto` can act on, based on the following template: <refmeta> <refentrytitle>{mantitle}</refentrytitle> <manvolnum>{manvolnum}</manvolnum> <refmiscinfo class="source">Git</refmiscinfo> <refmiscinfo class="version">{git_version}</refmiscinfo> <refmiscinfo class="manual">Git Manual</refmiscinfo> </refmeta> When we build with Asciidoctor, it does not honor this configuration file and we end up with only this (for a hypothetical git-foo.xml): <refmeta> <refentrytitle>git-foo</refentrytitle> <manvolnum>1</manvolnum> </refmeta> That is, we miss out on the `<refmiscinfo/>` tags. As a result, the header of each man page doesn't say "Git Manual", but "git-foo(1)" instead. Worse, the footers don't give the Git version number and instead provide the fairly ugly "[FIXME: source]". That Asciidoctor ignores asciidoc.conf is nothing new. This is why we implement the `linkgit:` macro in asciidoc.conf *and* in asciidoctor-extensions.rb. Follow suit and provide these tags in asciidoctor-extensions.rb, using a "postprocessor" extension where we just search and replace in the XML, treated as text. We may consider a few alternatives: * Provide the `mansource` attribute to Asciidoctor. This attribute is only respected (i.e., turned into those <refmiscinfo/> tags) with 1) the "manpage" doctype and/or converter [1], which we currently do not use, or 2) using Asciidoctor 1.5.7 or newer [2]. * We could inject these lines into the xml-files from the *Makefile*, e.g., using `sed`. That would reduce repetition, but it feels wrong to impose another step and another risk on the AsciiDoc-processing only to benefit the Asciidoctor-one. * I tried providing a "docinfo processor" to inject these tags, but could not figure out how to "merge" the two <refmeta/> sections that resulted. To avoid xmlto barfing on the result, I needed need to use `xmlto --skip-validation ...`, which seems unfortunate. Let's instead inject the missing tags using a postprocessor. We'll make it fairly obvious that we aim to inject the exact same three lines of `<refmiscinfo/>` that asciidoc.conf provides. We inject them in *post*-processing so we need to do the variable expansion ourselves. We do introduce the bug that asciidoc.conf already has in that we won't do any escaping, e.g., of funky versions like "some v <2.25, >2.20". The postprocessor we add here works on the XML as raw text and doesn't really use the full potential of XML to do a more structured injection. This is actually precisely what the Asciidoctor User Manual does in its postprocessor example [3]. I looked into two other approaches: 1. The nokogiri library is apparently the "modern" way of doing XML in ruby. I got it working fairly easily: require 'nokogiri' doc = Nokogiri::XML(output) doc.search("refmeta").each { |n| n.add_child(new_tags) } output = doc.to_xml However, this adds another dependency (e.g., the "ruby-nokogiri" package on Ubuntu). Using Asciidoctor is not our default, but it will probably need to become so soon (AsciiDoc relies on Python 2, which is going away). Let's avoid adding a dependency just so that we can say "search...add_child" rather than "sub(regex...)". 2. The older REXML is apparently always(?) bundled with ruby, but I couldn't even parse the original document: require 'rexml/document' doc = REXML::Document.new(output) ... The error was "no implicit conversion of nil into String" and I stopped there. Having never dabbled with ruby outside of this very file, I might be missing something obvious, but I don't think it's unlikely that doing a plain old search-and-replace will work just as fine or better compared to parsing XML and worrying about libraries and library versions. [1] https://asciidoctor.org/docs/user-manual/#builtin-attributes [2] https://public-inbox.org/git/20190319074321.GA2189@sigill.intra.peff.net/ [3] https://asciidoctor.org/docs/user-manual/#postprocessor-example Signed-off-by: Martin Ågren <martin.agren@gmail.com> --- Documentation/asciidoctor-extensions.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+)