Add Git blob include processor and preprocessor

This commit is contained in:
Gabriel Arazas 2023-04-07 06:20:00 +08:00
parent 9a2ba74191
commit 509fdcdfce
No known key found for this signature in database
GPG Key ID: ADE0C41DAB221FCC
3 changed files with 124 additions and 0 deletions

View File

@ -13,6 +13,7 @@ require_relative 'github-raw-content-include-processor/extension'
require_relative 'gitlab-link-inline-macro/extension' require_relative 'gitlab-link-inline-macro/extension'
require_relative 'gitlab-raw-content-include-processor/extension' require_relative 'gitlab-raw-content-include-processor/extension'
require_relative 'chat-block-processor/extension' require_relative 'chat-block-processor/extension'
require_relative 'git-blob-include-processor/extension'
require_relative 'wikipedia-inline-macro/extension' require_relative 'wikipedia-inline-macro/extension'
Asciidoctor::Extensions.register do Asciidoctor::Extensions.register do
@ -28,5 +29,8 @@ Asciidoctor::Extensions.register do
inline_macro GitLabLinkInlineMacro inline_macro GitLabLinkInlineMacro
include_processor GitLabRawIncludeProcessor include_processor GitLabRawIncludeProcessor
include_processor GitBlobIncludeProcessor
preprocessor GitContentBranchAttributePreprocessor
inline_macro WikipediaInlineMacro inline_macro WikipediaInlineMacro
end end

View File

@ -0,0 +1,58 @@
= Git blob include processor
:toc:
An include processor that includes content from the current Git repo.
The use case for this is specifically for creating dedicated branches for certain content.
== Synopsis
[source, asciidoc]
----
include::git:$REVSPEC[]
----
Where `$REVSPEC` is a revision as specified in link:https://manpages.debian.org/gitrevisions.7[gitrevisions.7].
Take note this include processor only accepts a blob object's content to be extracted.
This is meant to be used with other attributes.
See <<Attributes>> for more details.
If the resulting operation ends in an error (i.e., non-existing revision, file, something went wrong), it should log a warning and transclude an error.
== Attributes
- `path` is the filepath to be retrieved from the revision.
- `context-lines` is the number of surrounding lines for the diff.
This is only effective if `diff` option is given.
There's also a couple of link:https://docs.asciidoctor.org/asciidoc/latest/attributes/options/[options] for this component.
You can give the following options through `opts` attribute (i.e., `opts="diff,reverse"`).
- `diff` will show the difference in link:https://en.wikipedia.org/wiki/Diff[diff] format.
- `reverse` reverses the sides to be compared.
== Extra notes
The extension is composed of two parts: an include processor and a preprocessor.
The preprocessor add a document attribute, `doccontentref`, which it gives the Git reference for that content.
`doccontentref` is the difference between the process working directory (`Dir.pwd`) and the base directory of the content to be converted.
In case the process working directory is not entirely consistent for several reasons, you could give the attribute `rootdir` as the basis for the comparison.
The include processor also accepts an empty target with the prefix (i.e., `include::git:[]`) as a shorthand for `include::git:{doccontentref}`.
== Example usage
The following examples assume that `doccontentref` points to `content/posts/sample`.
- `include::git:HEAD[path=shell.nix]` should transclude the current iteration of `shell.nix`.
- `include::git:{doccontentref}[opts="diff", path=Gemfile]` should include a diff of the Gemfile from `content/posts/sample` branch (assuming that Gemfile has changed).
- `include::git:non-existing-rev[opts="diff"]` should result in a warning with the non-existing revision.

View File

@ -0,0 +1,62 @@
# frozen_string_literal: true
require 'rugged'
class GitBlobIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'git:'
end
def process(doc, reader, target, attrs)
repo = Rugged::Repository.discover(__dir__)
git_object_ref = target.delete_prefix 'git:'
git_object_ref = doc.attributes['doccontentref'] if git_object_ref.empty?
begin
git_object = repo.rev_parse git_object_ref
if attrs.key? 'diff-option'
options = {}
options[:paths] = [attrs['path']] if attrs.key? 'path'
options[:context_lines] = attrs['context-lines'] if attrs.key? 'context-lines'
options[:reverse] = true if attrs.key? 'reverse-option'
reader.push_include git_object.diff(**options).patch
else
inner_entry = case git_object.type
when :blob
git_object
when :commit
git_object.tree.path attrs['path']
when :tree
git_object.path attrs['path']
when :tag
git_object.target.tree.path attrs['path']
end
reader.push_include repo.lookup(inner_entry[:oid]).content
end
rescue StandardError => e
reader.push_include "Unresolved directive for '#{target}' with the following error:\n#{e}"
warn e
end
reader
end
end
class GitContentBranchAttributePreprocessor < Asciidoctor::Extensions::Preprocessor
def process(document, reader)
base_dir = Pathname.new(document.base_dir)
rootdir = if document.attributes['rootdir'].nil?
Dir.pwd
else
document.attributes['rootdir']
end
document.attributes['doccontentref'] = base_dir.relative_path_from(rootdir).to_s
reader
end
end