giblish 0.8.2 → 2.0.0.pre.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/unit_tests.yml +30 -0
- data/.gitignore +7 -3
- data/.ruby-version +1 -1
- data/Changelog.adoc +59 -0
- data/README.adoc +261 -0
- data/docs/concepts/text_search.adoc +213 -0
- data/docs/concepts/text_search_im/cgi-search_request.puml +35 -0
- data/docs/concepts/text_search_im/cgi-search_request.svg +397 -0
- data/docs/concepts/text_search_im/search_request.puml +40 -0
- data/docs/concepts/text_search_im/search_request.svg +408 -0
- data/docs/howtos/trigger_generation.adoc +180 -0
- data/docs/{setup_server_assets → howtos/trigger_generation_im}/Render Documents.png +0 -0
- data/docs/{setup_server_assets → howtos/trigger_generation_im}/View Documents.png +0 -0
- data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_hooks.graphml +0 -0
- data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_hooks.svg +0 -0
- data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_jenkins.graphml +0 -0
- data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_jenkins.svg +0 -0
- data/docs/howtos/trigger_generation_im/docgen_github.puml +51 -0
- data/docs/{setup_server_assets → howtos/trigger_generation_im}/giblish_deployment.graphml +0 -0
- data/docs/howtos/trigger_generation_im/post-receive-example.sh +50 -0
- data/docs/reference/box_flow_spec.adoc +22 -0
- data/docs/reference/search_spec.adoc +185 -0
- data/giblish.gemspec +54 -32
- data/lib/giblish/adocsrc_providers.rb +23 -0
- data/lib/giblish/application.rb +214 -41
- data/lib/giblish/cmdline.rb +273 -259
- data/lib/giblish/config_utils.rb +41 -0
- data/lib/giblish/configurator.rb +163 -0
- data/lib/giblish/conversion_info.rb +120 -0
- data/lib/giblish/docattr_providers.rb +125 -0
- data/lib/giblish/docid/docid.rb +181 -0
- data/lib/giblish/github_trigger/webhook_manager.rb +64 -0
- data/lib/giblish/gitrepos/checkoutmanager.rb +124 -0
- data/lib/giblish/{gititf.rb → gitrepos/gititf.rb} +30 -4
- data/lib/giblish/gitrepos/gitsummary.erb +61 -0
- data/lib/giblish/gitrepos/gitsummaryprovider.rb +78 -0
- data/lib/giblish/gitrepos/history_pb.rb +41 -0
- data/lib/giblish/indexbuilders/d3treegraph.rb +88 -0
- data/lib/giblish/indexbuilders/depgraphbuilder.rb +109 -0
- data/lib/giblish/indexbuilders/dotdigraphadoc.rb +174 -0
- data/lib/giblish/indexbuilders/standard_index.erb +10 -0
- data/lib/giblish/indexbuilders/subtree_indices.rb +132 -0
- data/lib/giblish/indexbuilders/templates/circles.html.erb +111 -0
- data/lib/giblish/indexbuilders/templates/flame.html.erb +61 -0
- data/lib/giblish/indexbuilders/templates/tree.html.erb +366 -0
- data/lib/giblish/indexbuilders/templates/treemap.html.erb +127 -0
- data/lib/giblish/indexbuilders/verbatimtree.rb +94 -0
- data/lib/giblish/pathtree.rb +473 -74
- data/lib/giblish/resourcepaths.rb +150 -0
- data/lib/giblish/search/expand_adoc.rb +55 -0
- data/lib/giblish/search/headingindexer.rb +312 -0
- data/lib/giblish/search/request_manager.rb +110 -0
- data/lib/giblish/search/searchquery.rb +68 -0
- data/lib/giblish/search/textsearcher.rb +349 -0
- data/lib/giblish/subtreeinfobuilder.rb +77 -0
- data/lib/giblish/treeconverter.rb +272 -0
- data/lib/giblish/utils.rb +142 -294
- data/lib/giblish/version.rb +1 -1
- data/lib/giblish.rb +10 -7
- data/scripts/hooks/post-receive.example +66 -0
- data/{docgen/scripts/githook_examples → scripts/hooks}/post-update.example +0 -0
- data/{docgen → scripts}/resources/css/adoc-colony.css +0 -0
- data/scripts/resources/css/giblish-serif.css +419 -0
- data/scripts/resources/css/giblish.css +1979 -419
- data/{docgen → scripts}/resources/fonts/Ubuntu-B.ttf +0 -0
- data/{docgen → scripts}/resources/fonts/Ubuntu-BI.ttf +0 -0
- data/{docgen → scripts}/resources/fonts/Ubuntu-R.ttf +0 -0
- data/{docgen → scripts}/resources/fonts/Ubuntu-RI.ttf +0 -0
- data/{docgen → scripts}/resources/fonts/mplus1p-regular-fallback.ttf +0 -0
- data/{docgen → scripts}/resources/images/giblish_logo.png +0 -0
- data/{docgen → scripts}/resources/images/giblish_logo.svg +0 -0
- data/{docgen → scripts}/resources/themes/giblish.yml +0 -0
- data/scripts/wserv_development.rb +32 -0
- data/web_apps/cgi_search/gibsearch.rb +43 -0
- data/web_apps/gh_webhook_trigger/config.ru +2 -0
- data/web_apps/gh_webhook_trigger/gh_webhook_trigger.rb +73 -0
- data/web_apps/gh_webhook_trigger/public/dummy.txt +3 -0
- data/web_apps/sinatra_search/config.ru +2 -0
- data/web_apps/sinatra_search/public/dummy.txt +3 -0
- data/web_apps/sinatra_search/sinatra_search.rb +34 -0
- data/web_apps/sinatra_search/tmp/restart.txt +0 -0
- metadata +188 -85
- data/.rubocop.yml +0 -7
- data/.travis.yml +0 -3
- data/Changelog +0 -16
- data/Gemfile +0 -4
- data/README.adoc +0 -1
- data/Rakefile +0 -41
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/data/testdocs/malformed/no_header.adoc +0 -5
- data/data/testdocs/toplevel.adoc +0 -19
- data/data/testdocs/wellformed/adorned_purpose.adoc +0 -17
- data/data/testdocs/wellformed/docidtest/docid_1.adoc +0 -24
- data/data/testdocs/wellformed/docidtest/docid_2.adoc +0 -8
- data/data/testdocs/wellformed/simple.adoc +0 -14
- data/data/testdocs/wellformed/source_highlighting/highlight_source.adoc +0 -38
- data/docgen/resources/css/giblish.css +0 -1979
- data/docgen/scripts/Jenkinsfile +0 -18
- data/docgen/scripts/gen_adoc_org.sh +0 -58
- data/docs/README.adoc +0 -387
- data/docs/setup_server.adoc +0 -202
- data/lib/giblish/buildgraph.rb +0 -216
- data/lib/giblish/buildindex.rb +0 -459
- data/lib/giblish/core.rb +0 -451
- data/lib/giblish/docconverter.rb +0 -308
- data/lib/giblish/docid.rb +0 -180
- data/lib/giblish/docinfo.rb +0 -75
- data/lib/giblish/indexheadings.rb +0 -251
- data/lib/giblish-search.cgi +0 -459
- data/scripts/hooks/post-receive +0 -57
- data/scripts/publish_html.sh +0 -99
@@ -0,0 +1,124 @@
|
|
1
|
+
require "git"
|
2
|
+
require "date"
|
3
|
+
require_relative "../utils"
|
4
|
+
require_relative "../version"
|
5
|
+
require_relative "gititf"
|
6
|
+
require_relative "gitsummaryprovider"
|
7
|
+
|
8
|
+
module Giblish
|
9
|
+
# acquires a handle to an existing git repo and provide the user
|
10
|
+
# with a iteration method 'each_checkout' where each matching branch and/or tag is
|
11
|
+
# checked out and presented to the user code.
|
12
|
+
class GitCheckoutManager
|
13
|
+
attr_reader :branches, :tags, :summary_provider, :git_repo, :repo_root
|
14
|
+
|
15
|
+
# cmd_opts:: a CmdLine::Options instance
|
16
|
+
#
|
17
|
+
# Required options:
|
18
|
+
# srcdir:: Pathname to the top dir of the local git repo to work with
|
19
|
+
# local_only:: if true, do not try to access any remote branches or merge with any
|
20
|
+
# upstream changes
|
21
|
+
# Optional options:
|
22
|
+
# abort_on_error:: bail out at an error or continue. Default 'true'
|
23
|
+
# branch_regex:: the regex for the branches to include during iteration (default: none)
|
24
|
+
# tag_regex:: the regex for the tags to include during iteration (default: none)
|
25
|
+
def initialize(cmd_opts)
|
26
|
+
@repo_root = GitItf.find_gitrepo_root(cmd_opts.srcdir)
|
27
|
+
raise ArgumentError, "The path: #{cmd_opts.srcdir} is not within a git repo!" if @repo_root.nil?
|
28
|
+
|
29
|
+
@local_only = cmd_opts.local_only
|
30
|
+
@abort_on_error = cmd_opts.abort_on_error.nil? ? true : cmd_opts.abort_on_error
|
31
|
+
|
32
|
+
@git_repo = init_git_repo(@repo_root, @local_only)
|
33
|
+
@branches = select_user_branches(cmd_opts.branch_regex, @local_only)
|
34
|
+
@tags = select_user_tags(cmd_opts.tag_regex)
|
35
|
+
@summary_provider = GitSummaryDataProvider.new(@repo_root.basename)
|
36
|
+
end
|
37
|
+
|
38
|
+
# present each git checkout matching the init criteria to the user's code.
|
39
|
+
#
|
40
|
+
# === Example
|
41
|
+
#
|
42
|
+
# gcm = GitCheckoutManager.new(opts)
|
43
|
+
# gcm.each_checkout do |name|
|
44
|
+
# ... do things with the currently checked out working tree ...
|
45
|
+
# end
|
46
|
+
def each_checkout
|
47
|
+
current_branch = @git_repo.current_branch
|
48
|
+
checkouts = (@branches + @tags)
|
49
|
+
if checkouts.empty?
|
50
|
+
Giblog.logger.info { "No matching branches or tags found." }
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
checkouts.each do |treeish|
|
55
|
+
sync_treeish(treeish)
|
56
|
+
# cache branch/tag info for downstream content generation
|
57
|
+
@summary_provider.cache_info(@git_repo, treeish)
|
58
|
+
|
59
|
+
yield(treeish.name)
|
60
|
+
rescue => e
|
61
|
+
Giblog.logger.error { e.message }
|
62
|
+
raise e if @abort_on_error
|
63
|
+
end
|
64
|
+
|
65
|
+
if @git_repo.current_branch != current_branch
|
66
|
+
Giblog.logger.info { "Checking out '#{current_branch}'" }
|
67
|
+
@git_repo.checkout current_branch
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def sync_treeish(treeish)
|
74
|
+
Giblog.logger.info { "Checking out '#{treeish.name}'" }
|
75
|
+
@git_repo.checkout treeish.name
|
76
|
+
|
77
|
+
# merge branches with their upstream at origin unless
|
78
|
+
# 'only local'
|
79
|
+
unless (treeish.respond_to?(:tag?) && treeish.tag?) || @local_only
|
80
|
+
# this is a branch, make sure it is up-to-date
|
81
|
+
Giblog.logger.info { "Merging with origin/#{treeish.name}" }
|
82
|
+
@git_repo.merge "origin/#{treeish.name}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def init_git_repo(git_repo_root, local_only)
|
87
|
+
# Sanity check git repo root
|
88
|
+
raise ArgumentError, "No git repo root dir given" unless git_repo_root
|
89
|
+
|
90
|
+
msg = "Could not find a git repo at #{git_repo_root} !"
|
91
|
+
begin
|
92
|
+
# Connect to the git repo
|
93
|
+
git_repo = Git.open(git_repo_root)
|
94
|
+
# fetch all remote refs if ok with user
|
95
|
+
msg = "Could not fetch from origin (do you need '--local-only'?)!"
|
96
|
+
git_repo.fetch unless local_only
|
97
|
+
rescue => e
|
98
|
+
raise "#{msg}\n\n#{e.message}"
|
99
|
+
end
|
100
|
+
git_repo
|
101
|
+
end
|
102
|
+
|
103
|
+
# Get the branches/tags the user wants to parse
|
104
|
+
def select_user_branches(regexp, local_only)
|
105
|
+
return [] unless regexp
|
106
|
+
|
107
|
+
user_checkouts = local_only ? @git_repo.branches.local : @git_repo.branches.remote
|
108
|
+
user_checkouts.select! do |b|
|
109
|
+
# match branches but remove eventual HEAD -> ... entry
|
110
|
+
regexp.match b.name unless /^HEAD/.match?(b.name)
|
111
|
+
end
|
112
|
+
Giblog.logger.debug { "selected git branches: #{user_checkouts.collect { |b| b.name }.join(", ")}" }
|
113
|
+
user_checkouts
|
114
|
+
end
|
115
|
+
|
116
|
+
def select_user_tags(regexp)
|
117
|
+
return [] unless regexp
|
118
|
+
|
119
|
+
@git_repo.tags.select do |t|
|
120
|
+
regexp.match t.name
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require "open3"
|
2
|
-
|
2
|
+
require "git"
|
3
3
|
|
4
4
|
module Giblish
|
5
5
|
# A home-grown interface class to git. Used for situations when the
|
@@ -8,14 +8,32 @@ module Giblish
|
|
8
8
|
attr_reader :repo_root, :git_dir
|
9
9
|
|
10
10
|
def initialize(path)
|
11
|
-
@repo_root =
|
11
|
+
@repo_root = GitItf.find_gitrepo_root(path)
|
12
12
|
raise ArgumentError("The path: @{path} is not within a git repo!") if @repo_root.nil?
|
13
13
|
|
14
14
|
@git_dir = @repo_root / ".git"
|
15
15
|
end
|
16
16
|
|
17
|
+
# Find the root directory of the git repo in which the
|
18
|
+
# given dirpath resides.
|
19
|
+
#
|
20
|
+
# dirpath:: an absolute path to a directory that resides
|
21
|
+
# within a git repo.
|
22
|
+
#
|
23
|
+
# returns:: the root direcotry of the git repo or nil if the input path
|
24
|
+
# does not reside within a git repo.
|
25
|
+
def self.find_gitrepo_root(dirpath)
|
26
|
+
Pathname.new(dirpath).ascend do |p|
|
27
|
+
next unless p.exist?
|
28
|
+
|
29
|
+
git_dir = p.realpath.join(".git")
|
30
|
+
return p if git_dir.directory?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
17
34
|
# Get the log history of the supplied file as an array of
|
18
35
|
# hashes, each entry has keys:
|
36
|
+
#
|
19
37
|
# sha
|
20
38
|
# date
|
21
39
|
# author
|
@@ -29,6 +47,14 @@ module Giblish
|
|
29
47
|
process_log_output(o)
|
30
48
|
end
|
31
49
|
|
50
|
+
def current_branch
|
51
|
+
# git rev-parse --abbrev-ref HEAD
|
52
|
+
o, e, s = exec_cmd("rev-parse", %w[--abbrev-ref HEAD], "")
|
53
|
+
raise "Failed to get git log for #{filename}!!\n#{e}" if s.exitstatus != 0
|
54
|
+
|
55
|
+
o.strip
|
56
|
+
end
|
57
|
+
|
32
58
|
private
|
33
59
|
|
34
60
|
# Process the log output from git
|
@@ -47,7 +73,7 @@ module Giblish
|
|
47
73
|
end
|
48
74
|
|
49
75
|
if in_message
|
50
|
-
hsh["message"] << "#{line[4
|
76
|
+
hsh["message"] << "#{line[4..]}\n"
|
51
77
|
next
|
52
78
|
end
|
53
79
|
|
@@ -58,7 +84,7 @@ module Giblish
|
|
58
84
|
case key
|
59
85
|
when "commit"
|
60
86
|
hsh_array << hsh if hsh
|
61
|
-
hsh = {
|
87
|
+
hsh = {"sha" => value, "message" => +"", "parent" => []}
|
62
88
|
when "parent"
|
63
89
|
hsh["parent"] << value
|
64
90
|
when "author"
|
@@ -0,0 +1,61 @@
|
|
1
|
+
= Document repo '<%= @repo_name %>'
|
2
|
+
Generated at <%= DateTime.now.strftime("%Y-%m-%d %H:%M:%S") %> by giblish - v<%= Giblish::VERSION %>
|
3
|
+
|
4
|
+
// Display one table for each branch
|
5
|
+
<% unless @branch_info.empty? %>
|
6
|
+
Branches::
|
7
|
+
|
8
|
+
<% @branch_info.each do |b|
|
9
|
+
c = b.latest_commit
|
10
|
+
%>
|
11
|
+
|
12
|
+
xref:<%= index_path(b.name) %>[*<%= b.name %>*]
|
13
|
+
[cols="1a,5a"]
|
14
|
+
|===
|
15
|
+
|
16
|
+
2+^|_last committed to <%= c.datetime.strftime("%Y-%m-%d") %> by <%= c.committer %>._
|
17
|
+
|
18
|
+
|*Sha*
|
19
|
+
|<%= c.sha[0..7] %> ...
|
20
|
+
|
21
|
+
|*Message*
|
22
|
+
|<%= c.message %>
|
23
|
+
|
24
|
+
|===
|
25
|
+
|
26
|
+
|
27
|
+
<% end %>
|
28
|
+
<% end %>
|
29
|
+
|
30
|
+
// Display one table for each tag
|
31
|
+
<% unless @tag_infos.empty? %>
|
32
|
+
Tags::
|
33
|
+
|
34
|
+
<% @tag_infos.each do |t|
|
35
|
+
c = t.commit
|
36
|
+
%>
|
37
|
+
|
38
|
+
xref:<%= index_path(t.name) %>[*<%= t.name %>*]
|
39
|
+
[cols="1a,5a"]
|
40
|
+
|===
|
41
|
+
|
42
|
+
2+^| _was created <%= t.date.strftime("%Y-%m-%d") %> by <%= t.author %>._
|
43
|
+
|
44
|
+
|*Message*
|
45
|
+
|<%= t.message %>
|
46
|
+
|
47
|
+
2+^|_The tag points to the commit made <%= c.datetime.strftime("%Y-%m-%d") %> by <%= c.committer %>._
|
48
|
+
|
49
|
+
|*Sha*
|
50
|
+
|<%= c.sha[0..8] %> ...
|
51
|
+
|
52
|
+
|*Message*
|
53
|
+
|<%= t.commit.message %>
|
54
|
+
|
55
|
+
|===
|
56
|
+
|
57
|
+
|
58
|
+
<% end %>
|
59
|
+
<% end %>
|
60
|
+
|
61
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "erb"
|
2
|
+
|
3
|
+
module Giblish
|
4
|
+
class GitSummaryDataProvider
|
5
|
+
attr_reader :tags, :branches
|
6
|
+
attr_accessor :index_basename
|
7
|
+
|
8
|
+
CommitInfo = Struct.new(:sha, :datetime, :committer, :message)
|
9
|
+
TagInfo = Struct.new(:sha, :name, :date, :message, :author, :commit) do
|
10
|
+
def id
|
11
|
+
Giblish.to_valid_id(name)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
BranchInfo = Struct.new(:name, :latest_commit)
|
15
|
+
|
16
|
+
DEFAULT_GIT_SUMMARY_TEMPLATE = "/gitsummary.erb"
|
17
|
+
|
18
|
+
def initialize(repo_name)
|
19
|
+
@index_basename = "index"
|
20
|
+
|
21
|
+
# all these are used by erb
|
22
|
+
@repo_name = repo_name
|
23
|
+
@branch_info = []
|
24
|
+
@tag_infos = []
|
25
|
+
end
|
26
|
+
|
27
|
+
# Cache info on one tag or branch
|
28
|
+
#
|
29
|
+
# repo:: a handle to a Git repo object
|
30
|
+
# treeish:: either a Git::Tag or a Git::Branch object
|
31
|
+
def cache_info(repo, treeish)
|
32
|
+
if treeish.respond_to?(:tag?) && treeish.tag?
|
33
|
+
@tag_infos.push(
|
34
|
+
cache_tag_info(repo, treeish)
|
35
|
+
).sort_by!(&:date).reverse!
|
36
|
+
else
|
37
|
+
@branch_info.push(cache_branch_info(repo, treeish))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# returns:: a string with the relative path to the index file
|
42
|
+
# in the given branch/tag subtree
|
43
|
+
def index_path(treeish_name)
|
44
|
+
Giblish.to_fs_str(treeish_name) + "/" + @index_basename + ".adoc"
|
45
|
+
end
|
46
|
+
|
47
|
+
def source
|
48
|
+
erb_template = File.read(__dir__ + DEFAULT_GIT_SUMMARY_TEMPLATE)
|
49
|
+
ERB.new(erb_template, trim_mode: "<>").result(binding)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def cache_tag_info(repo, tag)
|
55
|
+
unless tag.annotated?
|
56
|
+
c = repo.gcommit(tag)
|
57
|
+
commit = CommitInfo.new(c.sha, c.date, c.author.name, c.message)
|
58
|
+
return TagInfo.new(tag.sha, tag.name, c.date, "<No message - this is not an annotated tag>", c.committer.name, commit)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Handle annotated tags
|
62
|
+
# get sha of the associated commit. (a bit convoluted...)
|
63
|
+
c = repo.gcommit(tag.contents_array[0].split(" ")[1])
|
64
|
+
commit = CommitInfo.new(c.sha, c.date, c.author.name, c.message)
|
65
|
+
TagInfo.new(tag.sha, tag.name, tag.tagger.date, tag.message, tag.tagger.name, commit)
|
66
|
+
end
|
67
|
+
|
68
|
+
def cache_branch_info(repo, branch)
|
69
|
+
# get sha of the associated commit. (a bit convoluted...)
|
70
|
+
c = repo.gcommit(branch)
|
71
|
+
commit = CommitInfo.new(c.sha, c.date, c.author.name, c.message)
|
72
|
+
|
73
|
+
# puts c.instance_variables
|
74
|
+
|
75
|
+
BranchInfo.new(branch.name, commit)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "../subtreeinfobuilder"
|
2
|
+
|
3
|
+
module Giblish
|
4
|
+
# Adds a 'FileHistory' instance to each file node's data delegator.
|
5
|
+
# Users down-the-line can then call node.data.history to receive
|
6
|
+
# an Array of HistoryEntry objects.
|
7
|
+
class AddHistoryPostBuilder
|
8
|
+
def initialize(repo_root)
|
9
|
+
@git_itf = GitItf.new(repo_root)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Called from TreeConverter during post build phase
|
13
|
+
def on_postbuild(src_tree, dst_tree, converter)
|
14
|
+
current_branch = @git_itf.current_branch
|
15
|
+
|
16
|
+
dst_tree.traverse_preorder do |level, dst_node|
|
17
|
+
unless dst_node.leaf?
|
18
|
+
dst_node.data = DataDelegator.new if dst_node.data.nil?
|
19
|
+
dst_node.data.add(FileHistory.new(current_branch))
|
20
|
+
next
|
21
|
+
end
|
22
|
+
# next unless dst_node.leaf?
|
23
|
+
|
24
|
+
src_node = dst_node.data.src_node
|
25
|
+
next unless src_node.pathname.exist?
|
26
|
+
|
27
|
+
# Get the commit history of the doc as an Array of entries
|
28
|
+
file_log = FileHistory.new(current_branch)
|
29
|
+
@git_itf.file_log(src_node.pathname.to_s).each do |log_entry|
|
30
|
+
file_log.history << FileHistory::LogEntry.new(
|
31
|
+
log_entry["date"],
|
32
|
+
log_entry["author"],
|
33
|
+
log_entry["message"],
|
34
|
+
log_entry["sha"]
|
35
|
+
)
|
36
|
+
end
|
37
|
+
dst_node.data.add(file_log)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Generate asciidoc that represents a given pathtree as a
|
2
|
+
# verbatim block with indented, clickable entries.
|
3
|
+
class D3TreeGraph
|
4
|
+
attr_reader :tree
|
5
|
+
|
6
|
+
# tree: PathTree
|
7
|
+
# === Required node data methods
|
8
|
+
# title
|
9
|
+
# docid
|
10
|
+
#
|
11
|
+
# options:
|
12
|
+
# dir_index_base_name: String - the basename of the index file
|
13
|
+
# residing in each directory
|
14
|
+
def initialize(tree:, options: {dir_index_base_name: "index"})
|
15
|
+
@tree = transform_data(tree)
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def source
|
20
|
+
erb_template = File.read("#{__dir__}/templates/tree.html.erb")
|
21
|
+
ERB.new(erb_template, trim_mode: "<>").result(binding)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# 1 1
|
27
|
+
# / | \ |-2
|
28
|
+
# 2 5 6 -> | |-3
|
29
|
+
# /\ / \ | |-4
|
30
|
+
# 3 4 7 8 |-5
|
31
|
+
# |-6
|
32
|
+
# |-7
|
33
|
+
# |-8
|
34
|
+
def transform_data(tree)
|
35
|
+
data = {}
|
36
|
+
last_level = 0
|
37
|
+
path = []
|
38
|
+
# root -> left -> right
|
39
|
+
tree.traverse_preorder do |level, node|
|
40
|
+
d = node.leaf? ? leaf_info(node) : directory_info(node)
|
41
|
+
|
42
|
+
if level == 0
|
43
|
+
data = d
|
44
|
+
path << d
|
45
|
+
elsif level > last_level
|
46
|
+
path[-1][:children] << d
|
47
|
+
path << d
|
48
|
+
elsif level == last_level
|
49
|
+
path[-2][:children] << d
|
50
|
+
path[-1] = d
|
51
|
+
else
|
52
|
+
path[level - 1][:children] << d
|
53
|
+
path[level] = d
|
54
|
+
path = path[0..level]
|
55
|
+
end
|
56
|
+
last_level = level
|
57
|
+
end
|
58
|
+
data
|
59
|
+
end
|
60
|
+
|
61
|
+
def leaf_info(node)
|
62
|
+
conv_info = node.data
|
63
|
+
if conv_info.converted
|
64
|
+
name = (conv_info.docid.nil? ? "" : "#{conv_info.docid} - ") + conv_info.title
|
65
|
+
dst_ref = conv_info.src_rel_path.sub_ext(".html")
|
66
|
+
{
|
67
|
+
name: name,
|
68
|
+
dst_ref: dst_ref,
|
69
|
+
children: []
|
70
|
+
}
|
71
|
+
else
|
72
|
+
Giblog.logger.warn { "Could not get node data for #{conv_info.src_basename}" }
|
73
|
+
{
|
74
|
+
name: "ERR: Failed Conversion",
|
75
|
+
dst_ref: "",
|
76
|
+
children: []
|
77
|
+
}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def directory_info(node)
|
82
|
+
{
|
83
|
+
name: node.segment,
|
84
|
+
dst_ref: "",
|
85
|
+
children: []
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require_relative "dotdigraphadoc"
|
2
|
+
|
3
|
+
module Giblish
|
4
|
+
# Provide the source for a graphviz-based index page.
|
5
|
+
#
|
6
|
+
# Note: The asciidoctor-diagram API seems a bit strange when it comes to storing
|
7
|
+
# temporary files:
|
8
|
+
# * it uses a document attribute {imagesoutdir} and stores the
|
9
|
+
# generated svg image under that regardless of svg-type.
|
10
|
+
# * it uses an option in the diagram macro "cachedir" under which a cached image
|
11
|
+
# is stored.
|
12
|
+
class GraphPageBase
|
13
|
+
attr_reader :adoc_source
|
14
|
+
|
15
|
+
def initialize(info_2_ids, dst_node, basename, opts = {})
|
16
|
+
# use a tmp dir since asciidoctor-diagram generates cache files
|
17
|
+
# that it doesn't remove afterwards
|
18
|
+
Dir.mktmpdir do |dir|
|
19
|
+
# build the graph source
|
20
|
+
graph = DotDigraphAdoc.new(
|
21
|
+
info_2_ids: info_2_ids,
|
22
|
+
opts: {"svg-type" => "inline", "cachedir" => dir}
|
23
|
+
)
|
24
|
+
|
25
|
+
@adoc_source = <<~DEPGRAPH_PAGE
|
26
|
+
= Dependency graph
|
27
|
+
:imagesoutdir: #{dir}
|
28
|
+
|
29
|
+
#{graph.source}
|
30
|
+
|
31
|
+
DEPGRAPH_PAGE
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Generates a summary page with a docid-based dependency graph for an entire destination
|
37
|
+
# tree.
|
38
|
+
class DependencyGraphPostBuilder
|
39
|
+
# the dependency graph relies on graphwiz (dot), check if we can access that
|
40
|
+
def self.dot_supported
|
41
|
+
!Giblish.which("dot").nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
DEFAULT_BASENAME = "gibgraph"
|
45
|
+
|
46
|
+
# node_2_ids:: a { src_node => [doc id refs]} hash. It will be queried during
|
47
|
+
# the post-build phase => it must be populated before the end of the
|
48
|
+
# build phase
|
49
|
+
def initialize(node_2_ids, docattr_provider = nil, api_opt_provider = nil, adoc_src_provider = nil, basename = DEFAULT_BASENAME)
|
50
|
+
# this class relies on graphwiz (dot), make sure we can access it
|
51
|
+
raise "Could not find the 'dot' tool needed to generate a dependency graph!" unless DependencyGraphPostBuilder.dot_supported
|
52
|
+
|
53
|
+
# require asciidoctor module needed for generating diagrams
|
54
|
+
require "asciidoctor-diagram/graphviz"
|
55
|
+
|
56
|
+
@node_2_ids = node_2_ids
|
57
|
+
@docattr_provider = docattr_provider
|
58
|
+
@api_opt_provider = api_opt_provider
|
59
|
+
@adoc_src_provider = adoc_src_provider || GraphPageBase
|
60
|
+
@basename = basename
|
61
|
+
|
62
|
+
@adoc_source = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def document_attributes(src_node, dst_node, dst_top)
|
66
|
+
@docattr_provider.nil? ? {} : @docattr_provider.document_attributes(src_node, dst_node, dst_top)
|
67
|
+
end
|
68
|
+
|
69
|
+
def api_options(src_node, dst_node, dst_top)
|
70
|
+
@api_opt_provider.nil? ? {} : @api_opt_provider.api_options(dst_top)
|
71
|
+
end
|
72
|
+
|
73
|
+
def adoc_source(src_node, dst_node, dst_top)
|
74
|
+
@adoc_source
|
75
|
+
end
|
76
|
+
|
77
|
+
# Called from TreeConverter during post build phase
|
78
|
+
def on_postbuild(src_tree, dst_tree, converter)
|
79
|
+
return unless DependencyGraphPostBuilder.dot_supported
|
80
|
+
|
81
|
+
# convert {src_node => [doc ids]} to {conv_info => [doc ids]}
|
82
|
+
info_2_ids = {}
|
83
|
+
dst_tree.traverse_preorder do |_level, dst_node|
|
84
|
+
next unless dst_node.leaf?
|
85
|
+
|
86
|
+
sn = dst_node.data.src_node
|
87
|
+
info_2_ids[dst_node] = @node_2_ids[sn] if @node_2_ids.key?(sn)
|
88
|
+
end
|
89
|
+
|
90
|
+
# add a virtual 'gibgraph.adoc' node as the only node in a source tree
|
91
|
+
# with this object as provider of both adoc source and conversion options
|
92
|
+
v_srcpath = Pathname.new("/virtual") / "#{@basename}.adoc"
|
93
|
+
src_node = PathTree.new(v_srcpath, self).node(v_srcpath, from_root: true)
|
94
|
+
|
95
|
+
# add the destination node where the converted file will be stored
|
96
|
+
i_node = dst_tree.add_descendants(@basename)
|
97
|
+
|
98
|
+
# get the adoc source from the provider (Class or instance)
|
99
|
+
@adoc_source = if @adoc_src_provider.is_a?(Class)
|
100
|
+
@adoc_src_provider.new(info_2_ids, dst_tree, @basename).adoc_source
|
101
|
+
else
|
102
|
+
@adoc_src_provider.adoc_source
|
103
|
+
end
|
104
|
+
|
105
|
+
# do the conversion
|
106
|
+
converter.convert(src_node, i_node, dst_tree)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|