giblish 0.8.2 → 1.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/unit_tests.yml +30 -0
- data/.gitignore +7 -3
- data/.ruby-version +1 -1
- data/Changelog.adoc +61 -0
- data/README.adoc +267 -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 +47 -29
- 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 +168 -73
- 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,50 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
#
|
3
|
+
# this hook runs a script which, in turn, generates html documentation
|
4
|
+
# and publishes them to the given destination.
|
5
|
+
#
|
6
|
+
|
7
|
+
# the git refs that should trigger a doc generation at update
|
8
|
+
TRIGGERING_REFS_REGEX=$'main'
|
9
|
+
|
10
|
+
# the staging repo root (where the working tree exists)
|
11
|
+
STAGING_REPO="/usr/local/git_staging/myrepo_staging"
|
12
|
+
|
13
|
+
# The web-server top dir for the published documents
|
14
|
+
DST_DIR="/var/www/mysite/html/public/docs"
|
15
|
+
|
16
|
+
# "true" runs an 'rm -rf' of the destination dir before generating new htmls
|
17
|
+
CLEAR_DST="false"
|
18
|
+
|
19
|
+
echo "post-receive hook running..."
|
20
|
+
|
21
|
+
# read the input that git sends to this hook
|
22
|
+
read oldrev newrev ref
|
23
|
+
|
24
|
+
# remove the 'refs/heads/' prefix from the git ref
|
25
|
+
ref="${ref/refs\/heads\//}"
|
26
|
+
|
27
|
+
# filter out refs that are irrelevant for doc generation
|
28
|
+
if [[ ! "${ref}" =~ "${TRIGGERING_REFS_REGEX}" ]]; then
|
29
|
+
echo "Ref '${ref}' received. Doing nothing: only refs matching the regex: /${TRIGGERING_REFS_REGEX}/ will trigger a doc generation."
|
30
|
+
exit 0
|
31
|
+
fi
|
32
|
+
|
33
|
+
echo "Document generation triggered by an update to ${ref}."
|
34
|
+
echo ""
|
35
|
+
|
36
|
+
# use a subshell with the correct working dir for the actual doc generation
|
37
|
+
(
|
38
|
+
cd "${STAGING_REPO}"
|
39
|
+
|
40
|
+
# need to unset the GIT_DIR env set by the invoking hook for giblish to work correctly
|
41
|
+
unset GIT_DIR
|
42
|
+
|
43
|
+
if [[ "${CLEAR_DST}" -eq "true" ]]; then
|
44
|
+
echo "Remove everything under ${DST_DIR}/"
|
45
|
+
rm -rf ${DST_DIR}/*
|
46
|
+
fi
|
47
|
+
|
48
|
+
# Generate html docs
|
49
|
+
giblish --copy-asset-folders "_assets$" -g "${TRIGGERING_REFS_REGEX}" -r scripts/resources -s mystyle . "${DST_DIR}"
|
50
|
+
)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
= Tree flow
|
2
|
+
|
3
|
+
== Algorithm
|
4
|
+
|
5
|
+
Preconditions::
|
6
|
+
* No padding
|
7
|
+
* Left-to-right filling
|
8
|
+
* 1 sublevel
|
9
|
+
* Width for outer box is fixed, height is variable
|
10
|
+
|
11
|
+
Outer box = B [bx, by, bw, bh]
|
12
|
+
Inner boxes = In [In_x, In_y, In_w, In_h]
|
13
|
+
|
14
|
+
Horizontal strips = Sn
|
15
|
+
|
16
|
+
foreach In in I
|
17
|
+
if In_w > S_free_width
|
18
|
+
S = S(n+1)
|
19
|
+
end
|
20
|
+
In_coord = S_free_coord
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,185 @@
|
|
1
|
+
= Text search spec for giblish
|
2
|
+
:docid: G-002
|
3
|
+
|
4
|
+
== Information expected to be included in a search request
|
5
|
+
|
6
|
+
URL endpoint for the search service::
|
7
|
+
When a search is triggered, the correct URL for triggering the search service must be POSTed to.
|
8
|
+
|
9
|
+
URI parameters::
|
10
|
+
The search service expects a number of parameters as part of the search query, see <<uri_params>>.
|
11
|
+
|
12
|
+
.URI parameters
|
13
|
+
[[uri_params]]
|
14
|
+
[cols="2,2,5,3"]
|
15
|
+
|===
|
16
|
+
|name |status |comment |example
|
17
|
+
|
18
|
+
|calling-url
|
19
|
+
|required
|
20
|
+
|the URL to the file from which the search request originated
|
21
|
+
|www.example.com/my/doc/site/subdir/file_1.html
|
22
|
+
|
23
|
+
|search-assets-top-rel
|
24
|
+
|required
|
25
|
+
|the relative path from the originating file's directory to the top dir of the search assets. The default implementation in giblish uses the name `gibsearch_assets` for this directory.
|
26
|
+
|../../gibsearch_assets
|
27
|
+
|
28
|
+
|search-phrase
|
29
|
+
|required
|
30
|
+
|a string with the phrase to search for
|
31
|
+
|meaning of life
|
32
|
+
|
33
|
+
|css-path
|
34
|
+
|optional
|
35
|
+
a|the path to the css file to use when generating the result.
|
36
|
+
|
37
|
+
absolute::
|
38
|
+
the path is used as-is.
|
39
|
+
|
40
|
+
relative::
|
41
|
+
the relative path to the css file from the originating file's directory.
|
42
|
+
|
43
|
+
not set::
|
44
|
+
the styling is left to the search implementation.
|
45
|
+
|
46
|
+
a| * *absolute* - /var/www/html/my/site/style.css
|
47
|
+
* *relative* - ../../web_assets/css/style.css
|
48
|
+
|
49
|
+
|consider-case
|
50
|
+
|optional
|
51
|
+
a|
|
52
|
+
if set::
|
53
|
+
search case sensitive
|
54
|
+
|
55
|
+
not set::
|
56
|
+
ignore case during search
|
57
|
+
|
58
|
+
|true
|
59
|
+
|
60
|
+
|as-regexp
|
61
|
+
|optional
|
62
|
+
a|
|
63
|
+
if set::
|
64
|
+
treat the search phrase as a regexp
|
65
|
+
|
66
|
+
not set::
|
67
|
+
treat the search phrase as a string
|
68
|
+
|true
|
69
|
+
|
70
|
+
|===
|
71
|
+
|
72
|
+
== The implementation in giblish
|
73
|
+
|
74
|
+
=== At document generation
|
75
|
+
|
76
|
+
. Collect all adoc docs in a search asset directory.
|
77
|
+
. Embed html code for a search form as part of running gibish on the source tree. During generation, the following search parameters are known for each document to be generated:
|
78
|
+
.. search-assets-top-rel
|
79
|
+
.. css-path
|
80
|
+
. The `calling-url` is not known but it is possible to embed javascript code as part of the search form code that will resolve the url at runtime.
|
81
|
+
. The URL for the search service endpoint must be given by the user or hard-coded in giblish.
|
82
|
+
|
83
|
+
=== At a user search query
|
84
|
+
|
85
|
+
When a user submit a 'search' query, the following parameters must be filled in and submitted to the text search service:
|
86
|
+
|
87
|
+
. searchphrase
|
88
|
+
. usecase (optional)
|
89
|
+
. useregexp (optional)
|
90
|
+
|
91
|
+
The other required parameters comes from the generated document itself.
|
92
|
+
|
93
|
+
=== The search index
|
94
|
+
|
95
|
+
The search index is created by giblish during html generation and consists of
|
96
|
+
|
97
|
+
. the adoc source files (when `include` directives have been resolved)
|
98
|
+
. a `heading_db.json` file mapping sections in the source files to line numbers
|
99
|
+
|
100
|
+
.The storage location for the search index information
|
101
|
+
----
|
102
|
+
|- <top_path>
|
103
|
+
| |- file1.html
|
104
|
+
| |- subdir
|
105
|
+
| |- file2.html
|
106
|
+
| |- web_assets
|
107
|
+
| |- mystyle.css
|
108
|
+
| |- gibsearch_assets
|
109
|
+
| |- heading_db.json
|
110
|
+
| |- file1.adoc
|
111
|
+
| |- subdir
|
112
|
+
| |file2.adoc
|
113
|
+
----
|
114
|
+
|
115
|
+
.The format of the heading_db.json file
|
116
|
+
[source,json]
|
117
|
+
----
|
118
|
+
{
|
119
|
+
fileinfos : [
|
120
|
+
{
|
121
|
+
filepath : "file1.adoc",
|
122
|
+
title : "File 1 Title",
|
123
|
+
sections : [
|
124
|
+
{
|
125
|
+
id : "section_id_1",
|
126
|
+
title : "Purpose",
|
127
|
+
line_no : 10
|
128
|
+
},
|
129
|
+
{
|
130
|
+
id : "section_id_2",
|
131
|
+
...
|
132
|
+
}
|
133
|
+
]
|
134
|
+
},
|
135
|
+
{
|
136
|
+
filepath: "subdir/file2.adoc",
|
137
|
+
...
|
138
|
+
}
|
139
|
+
]
|
140
|
+
}
|
141
|
+
----
|
142
|
+
|
143
|
+
=== The search form
|
144
|
+
|
145
|
+
giblish inserts the below html/JavaScript at the top of each generated html document.
|
146
|
+
|
147
|
+
.A minimal search form
|
148
|
+
[source,html]
|
149
|
+
----
|
150
|
+
<script type="text/javascript">
|
151
|
+
window.onload = function () {
|
152
|
+
document.getElementById("calingurl_input").value = window.location.href;
|
153
|
+
};
|
154
|
+
</script>
|
155
|
+
|
156
|
+
<style>
|
157
|
+
#gibsearch-form {
|
158
|
+
position:fixed;
|
159
|
+
top:0.5rem;
|
160
|
+
left:70%;
|
161
|
+
width:30%;
|
162
|
+
height:3rem;
|
163
|
+
background:white;
|
164
|
+
z-index:2000;
|
165
|
+
}
|
166
|
+
</style>
|
167
|
+
|
168
|
+
<div id=gibsearch-form>
|
169
|
+
<form class="gibsearch" action="<%=action_path%>">
|
170
|
+
<input type="search" placeholder="Search the docs.." name="search-phrase" />
|
171
|
+
<button type="submit">Search</button>
|
172
|
+
<br>
|
173
|
+
|
174
|
+
<input type="checkbox" id="consider-case" name="consider-case" />
|
175
|
+
<label for="consider-case">case sensitive</label>
|
176
|
+
|
177
|
+
<input type="checkbox" id="as-regexp" name="as-regexp" />
|
178
|
+
<label for="as-regexp">use regexp</label>
|
179
|
+
|
180
|
+
<input type="hidden" name="calling-url" id=calingurl_input />
|
181
|
+
<input type="hidden" name="search-assets-top-rel" value="<%=sa_top_rel%>"/>
|
182
|
+
<input type="hidden" name="css-path" value="<%=css_path%>"/>
|
183
|
+
</form>
|
184
|
+
</div>
|
185
|
+
----
|
data/giblish.gemspec
CHANGED
@@ -1,24 +1,28 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require "giblish/version"
|
1
|
+
begin
|
2
|
+
require_relative "lib/giblish/version"
|
3
|
+
rescue LoadError
|
4
|
+
require "giblish/version"
|
5
|
+
end
|
7
6
|
|
8
7
|
Gem::Specification.new do |spec|
|
9
|
-
spec.name
|
10
|
-
spec.version
|
11
|
-
spec.
|
12
|
-
spec.
|
8
|
+
spec.name = "giblish"
|
9
|
+
spec.version = Giblish::VERSION
|
10
|
+
spec.summary = "A tool for publishing asciidoc docs stored in git repos"
|
11
|
+
spec.description = <<~EOF
|
12
|
+
giblish generates indexed and searchable documents from a tree of
|
13
|
+
asciidoc files.
|
14
|
+
EOF
|
15
|
+
spec.authors = ["Anders Rillbert"]
|
16
|
+
spec.email = ["anders.rillbert@kutso.se"]
|
17
|
+
spec.homepage = "https://github.com/rillbert/giblish"
|
18
|
+
spec.license = "MIT"
|
19
|
+
# NOTE required ruby version is informational only; it's not enforced since it can't be overridden and can cause builds to break
|
20
|
+
# spec.required_ruby_version = ">= 2.7"
|
13
21
|
|
14
|
-
spec.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
EOF
|
19
|
-
spec.homepage = "https://github.com/rillbert/giblish"
|
20
|
-
spec.license = "MIT"
|
21
|
-
spec.required_ruby_version = ">= 2.7"
|
22
|
+
spec.metadata = {
|
23
|
+
"bug_tracker_uri" => "https://github.com/rillbert/giblish/issues",
|
24
|
+
"source_code_uri" => "https://github.com/rillbert/giblish"
|
25
|
+
}
|
22
26
|
|
23
27
|
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
24
28
|
# delete this section to allow pushing this gem to any host.
|
@@ -28,22 +32,36 @@ Gem::Specification.new do |spec|
|
|
28
32
|
# raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
29
33
|
# end
|
30
34
|
|
31
|
-
|
32
|
-
spec.
|
33
|
-
|
35
|
+
# filter out files not included in the shipped gem
|
36
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
37
|
+
skip_dirs = %r{^(data|bin|test|spec|features)/}
|
38
|
+
skip_files = %r{^(Rakefile|Gemfile)}
|
39
|
+
f.match(skip_dirs) || f.match(skip_files)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Follow the bundler convention to have the exe:s in "exe" instead of 'bin'
|
43
|
+
spec.bindir = "exe"
|
44
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
34
45
|
spec.require_paths = ["lib"]
|
35
46
|
|
36
|
-
|
47
|
+
# Development deps
|
37
48
|
spec.add_development_dependency "minitest", "~> 5.0"
|
38
|
-
spec.add_development_dependency "
|
39
|
-
spec.add_development_dependency "
|
40
|
-
spec.add_development_dependency
|
49
|
+
spec.add_development_dependency "standard", "~> 1.1"
|
50
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
51
|
+
spec.add_development_dependency "oga", "~> 3.3"
|
52
|
+
spec.add_development_dependency "thor", "~> 0.20.3"
|
41
53
|
spec.add_development_dependency "asciidoctor-mathematical", "~> 0.3.5"
|
54
|
+
# needed for the sinatra-based apps
|
55
|
+
spec.add_development_dependency "sinatra", "~>2.1"
|
56
|
+
spec.add_development_dependency "thin", "~>1.8"
|
57
|
+
spec.add_development_dependency "rack", "2.2.3"
|
58
|
+
spec.add_development_dependency "rack-test", "1.1"
|
42
59
|
|
43
|
-
#
|
44
|
-
spec.add_runtime_dependency "
|
45
|
-
spec.add_runtime_dependency "asciidoctor
|
46
|
-
spec.add_runtime_dependency "asciidoctor-
|
60
|
+
# Run-time deps
|
61
|
+
spec.add_runtime_dependency "warning", "~>1.2"
|
62
|
+
spec.add_runtime_dependency "asciidoctor", "~>2.0", ">= 2.0.17"
|
63
|
+
spec.add_runtime_dependency "asciidoctor-diagram", ["~> 2.2"]
|
64
|
+
spec.add_runtime_dependency "asciidoctor-pdf", ["~> 1.6", ">= 1.6.2"]
|
47
65
|
spec.add_runtime_dependency "git", "~> 1.9"
|
48
66
|
spec.add_runtime_dependency "rouge", "~> 3.0"
|
49
67
|
spec.add_runtime_dependency "prawn-svg", "~> 0.32.0"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Giblish
|
2
|
+
class AdocSrcItf
|
3
|
+
def adoc_source(src_node, dst_node, dst_top)
|
4
|
+
raise NotImplementedError
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class SrcFromFile < AdocSrcItf
|
9
|
+
def adoc_source(src_node, dst_node, dst_top)
|
10
|
+
File.read(src_node.pathname)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class SrcFromString < AdocSrcItf
|
15
|
+
def initialize(src_str)
|
16
|
+
@adoc_source = src_str
|
17
|
+
end
|
18
|
+
|
19
|
+
def adoc_source(src_node, dst_node, dst_top)
|
20
|
+
@adoc_source
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/giblish/application.rb
CHANGED
@@ -1,68 +1,241 @@
|
|
1
1
|
require_relative "cmdline"
|
2
|
-
require_relative "
|
3
|
-
require_relative "
|
2
|
+
require_relative "configurator"
|
3
|
+
require_relative "treeconverter"
|
4
|
+
require_relative "gitrepos/checkoutmanager"
|
4
5
|
|
5
6
|
module Giblish
|
6
|
-
# The
|
7
|
+
# The app class for the giblish application
|
7
8
|
class Application
|
8
|
-
#
|
9
|
-
def run_from_cmd_line
|
10
|
-
status = run(ARGV)
|
11
|
-
exit(status)
|
12
|
-
end
|
13
|
-
|
14
|
-
# return exit status (0 for success)
|
9
|
+
# returns on success, raises otherwise
|
15
10
|
def run(args)
|
16
11
|
# force immediate output
|
17
12
|
$stdout.sync = true
|
18
13
|
|
19
14
|
# setup logging
|
20
15
|
Giblog.setup
|
16
|
+
Giblog.logger.level = Logger::INFO
|
21
17
|
|
22
18
|
# Parse cmd line
|
23
|
-
cmdline =
|
24
|
-
Giblog.logger.
|
19
|
+
cmdline = CmdLine.new.parse(args)
|
20
|
+
Giblog.logger.level = cmdline.log_level
|
21
|
+
|
22
|
+
Giblog.logger.debug { "cmd line args: #{cmdline.inspect}" }
|
23
|
+
|
24
|
+
# build a tree of files matching user's regexp selection
|
25
|
+
src_tree = PathTree.build_from_fs(cmdline.srcdir) do |p|
|
26
|
+
if cmdline.exclude_regex&.match(p.to_s)
|
27
|
+
false
|
28
|
+
else
|
29
|
+
(cmdline.include_regex =~ p.to_s)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
if src_tree.nil?
|
33
|
+
Giblog.logger.warn { "Did not find any files to convert" }
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
app = Configurator.new(cmdline, src_tree)
|
38
|
+
app.tree_converter.run
|
25
39
|
|
26
|
-
|
27
|
-
|
28
|
-
|
40
|
+
Giblog.logger.info { "Giblish is done!" }
|
41
|
+
end
|
42
|
+
|
43
|
+
# does not return, exits with status code
|
44
|
+
def run_from_cmd_line
|
45
|
+
begin
|
46
|
+
run(ARGV)
|
47
|
+
exit_code = 0
|
48
|
+
rescue => exc
|
49
|
+
Giblog.logger.error { exc.message }
|
50
|
+
Giblog.logger.error { exc.backtrace }
|
51
|
+
exit_code = 1
|
52
|
+
end
|
53
|
+
exit(exit_code)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class DirTreeConvert
|
58
|
+
# This class provides a file as the source for the asciidoc info and
|
59
|
+
# sets the document attributes required by Asciidoctor to resolve
|
60
|
+
# 'imagesdir' et al.
|
61
|
+
class AdocFileProvider
|
62
|
+
def adoc_source(src_node, dst_node, dst_top)
|
63
|
+
File.read(src_node.pathname)
|
64
|
+
end
|
65
|
+
|
66
|
+
def document_attributes(src_node, dst_node, dst_top)
|
67
|
+
p = src_node.pathname
|
68
|
+
{
|
69
|
+
"docfile" => p.to_s,
|
70
|
+
"docdir" => p.dirname.to_s,
|
71
|
+
"docname" => p.basename.to_s
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize(user_opts)
|
77
|
+
@user_opts = user_opts.dup
|
78
|
+
|
79
|
+
# get all adoc source files from disk
|
80
|
+
o = @user_opts
|
81
|
+
@src_tree = build_src_tree(o.srcdir, o.include_regex, o.exclude_regex)
|
82
|
+
end
|
83
|
+
|
84
|
+
# returns on success, raises otherwise
|
85
|
+
def run(configurator = nil)
|
86
|
+
return if @src_tree.nil?
|
87
|
+
|
88
|
+
# assign/setup a configurator containing all api options and doc attributes
|
89
|
+
build_config = configurator || Configurator.new(@user_opts)
|
90
|
+
|
91
|
+
tc = setup_converter(@src_tree, AdocFileProvider.new, build_config)
|
92
|
+
tc.run
|
29
93
|
end
|
30
94
|
|
31
95
|
private
|
32
96
|
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
97
|
+
# build a tree of files matching user's regexp selection
|
98
|
+
def build_src_tree(srcdir, include_regex, exclude_regex)
|
99
|
+
pt = PathTree.build_from_fs(srcdir) do |p|
|
100
|
+
if exclude_regex&.match(p.to_s)
|
101
|
+
false
|
102
|
+
else
|
103
|
+
include_regex =~ p.to_s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
if pt.nil?
|
107
|
+
Giblog.logger.warn { "Did not find any files to convert!" }
|
108
|
+
Giblog.logger.warn { "Built srctree using srcdir: #{srcdir} include_regex: #{include_regex} exclude_regex: #{exclude_regex}" }
|
109
|
+
end
|
110
|
+
pt
|
111
|
+
end
|
112
|
+
|
113
|
+
def setup_converter(src_tree, adoc_src_provider, configurator)
|
114
|
+
# compose the doc attribute provider.
|
115
|
+
configurator.doc_attr.add_doc_attr_providers(adoc_src_provider)
|
116
|
+
# NOTE: The order in the line below is important!
|
117
|
+
data_provider = DataDelegator.new(configurator.doc_attr, adoc_src_provider)
|
118
|
+
|
119
|
+
# associate the data providers with each source node in the tree
|
120
|
+
src_tree.traverse_preorder do |level, node|
|
121
|
+
next unless node.leaf?
|
122
|
+
|
123
|
+
node.data = data_provider
|
42
124
|
end
|
43
|
-
|
125
|
+
|
126
|
+
TreeConverter.new(src_tree, @user_opts.dstdir, configurator.build_options)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Converts a number of branches/tags in a gitrepo according to the given
|
131
|
+
# options.
|
132
|
+
#
|
133
|
+
# Each branch/tag is converted into a subdir of the given root dir and a
|
134
|
+
# summary page with links to the converted docs for each branch/tag is
|
135
|
+
# generated within the root dir.
|
136
|
+
class GitRepoConvert
|
137
|
+
def initialize(user_opts)
|
138
|
+
raise ArgumentError, "No selection for git branches or tags were found!" unless user_opts.branch_regex || user_opts.tag_regex
|
139
|
+
|
140
|
+
@user_opts = user_opts.dup
|
141
|
+
|
142
|
+
# cache the root dir
|
143
|
+
@dst_topdir = @user_opts.dstdir
|
144
|
+
|
145
|
+
@gm = GitCheckoutManager.new(@user_opts)
|
44
146
|
end
|
45
147
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
148
|
+
def run
|
149
|
+
# convert all docs found in the branches/tags that the user asked to parse
|
150
|
+
@gm.each_checkout do |name|
|
151
|
+
# tweak the destination dir to a subdir per branch/tag
|
152
|
+
@user_opts.dstdir = @dst_topdir / Giblish.to_fs_str(name)
|
153
|
+
|
154
|
+
Giblog.logger.debug { "cmdline: #{@user_opts.inspect}" }
|
155
|
+
configurator = GitRepoConfigurator.new(@user_opts, @gm.repo_root)
|
156
|
+
DirTreeConvert.new(@user_opts).run(configurator)
|
157
|
+
rescue => e
|
158
|
+
Giblog.logger.error { "Conversion of #{name} failed!" }
|
159
|
+
raise e if @user_opts.abort_on_error
|
160
|
+
Giblog.logger.error { e.message }
|
54
161
|
end
|
162
|
+
make_summary
|
163
|
+
end
|
164
|
+
|
165
|
+
def make_summary
|
166
|
+
# reset the dst dir to the user-given-top
|
167
|
+
@user_opts.dstdir = @dst_topdir
|
168
|
+
|
169
|
+
# Make sure the summary page is just 'bare-bone'
|
170
|
+
@user_opts.make_searchable = nil
|
171
|
+
@user_opts.copy_asset_folders = nil
|
172
|
+
@user_opts.no_index = true
|
173
|
+
@user_opts.resolve_docid = false
|
174
|
+
@user_opts.doc_attributes["table-caption"] = nil
|
175
|
+
|
176
|
+
# assign/setup the doc_attr and layout using the same user options as
|
177
|
+
# for the adoc source files on each checkout
|
178
|
+
conf = Configurator.new(@user_opts)
|
179
|
+
s = @gm.summary_provider
|
180
|
+
s.index_basename = conf.config_opts.index_basename
|
181
|
+
data_provider = DataDelegator.new(
|
182
|
+
SrcFromString.new(s.source),
|
183
|
+
conf.doc_attr
|
184
|
+
)
|
185
|
+
srctree = PathTree.new("/" + conf.config_opts.index_basename + ".adoc", data_provider)
|
186
|
+
TreeConverter.new(srctree, @dst_topdir, conf.build_options).run
|
55
187
|
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class EntryPoint
|
191
|
+
def initialize(args, logger = nil)
|
192
|
+
# force immediate output
|
193
|
+
# $stdout.sync = true
|
56
194
|
|
57
|
-
|
58
|
-
Giblog.logger
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
195
|
+
# setup logging
|
196
|
+
Giblog.setup(logger)
|
197
|
+
Giblog.logger.level = Logger::INFO
|
198
|
+
|
199
|
+
# Parse cmd line
|
200
|
+
user_opts = CmdLine.new.parse(args)
|
201
|
+
Giblog.logger.level = user_opts.log_level
|
202
|
+
Giblog.logger.debug { "cmd line args: #{user_opts.inspect}" }
|
203
|
+
|
204
|
+
# Select the coversion instance to use
|
205
|
+
@converter = select_conversion(user_opts)
|
206
|
+
end
|
207
|
+
|
208
|
+
def run
|
209
|
+
# do the conversion
|
210
|
+
@converter.run
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.run(args, logger = nil)
|
214
|
+
EntryPoint.new(args, logger).run
|
215
|
+
end
|
216
|
+
|
217
|
+
# does not return, exits with status code
|
218
|
+
def self.run_from_cmd_line
|
219
|
+
begin
|
220
|
+
EntryPoint.run(ARGV)
|
221
|
+
Giblog.logger.info { "Giblish is done!" }
|
222
|
+
exit_code = 0
|
223
|
+
rescue => exc
|
224
|
+
Giblog.logger.error { exc.message }
|
225
|
+
Giblog.logger.error { exc.backtrace }
|
226
|
+
exit_code = 1
|
227
|
+
end
|
228
|
+
exit(exit_code)
|
229
|
+
end
|
230
|
+
|
231
|
+
private
|
63
232
|
|
64
|
-
|
65
|
-
|
233
|
+
def select_conversion(user_opts)
|
234
|
+
case user_opts
|
235
|
+
in {branch_regex: _} | {tag_regex: _}
|
236
|
+
GitRepoConvert.new(user_opts)
|
237
|
+
else
|
238
|
+
DirTreeConvert.new(user_opts)
|
66
239
|
end
|
67
240
|
end
|
68
241
|
end
|