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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/unit_tests.yml +30 -0
  3. data/.gitignore +7 -3
  4. data/.ruby-version +1 -1
  5. data/Changelog.adoc +61 -0
  6. data/README.adoc +267 -0
  7. data/docs/concepts/text_search.adoc +213 -0
  8. data/docs/concepts/text_search_im/cgi-search_request.puml +35 -0
  9. data/docs/concepts/text_search_im/cgi-search_request.svg +397 -0
  10. data/docs/concepts/text_search_im/search_request.puml +40 -0
  11. data/docs/concepts/text_search_im/search_request.svg +408 -0
  12. data/docs/howtos/trigger_generation.adoc +180 -0
  13. data/docs/{setup_server_assets → howtos/trigger_generation_im}/Render Documents.png +0 -0
  14. data/docs/{setup_server_assets → howtos/trigger_generation_im}/View Documents.png +0 -0
  15. data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_hooks.graphml +0 -0
  16. data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_hooks.svg +0 -0
  17. data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_jenkins.graphml +0 -0
  18. data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_jenkins.svg +0 -0
  19. data/docs/howtos/trigger_generation_im/docgen_github.puml +51 -0
  20. data/docs/{setup_server_assets → howtos/trigger_generation_im}/giblish_deployment.graphml +0 -0
  21. data/docs/howtos/trigger_generation_im/post-receive-example.sh +50 -0
  22. data/docs/reference/box_flow_spec.adoc +22 -0
  23. data/docs/reference/search_spec.adoc +185 -0
  24. data/giblish.gemspec +47 -29
  25. data/lib/giblish/adocsrc_providers.rb +23 -0
  26. data/lib/giblish/application.rb +214 -41
  27. data/lib/giblish/cmdline.rb +273 -259
  28. data/lib/giblish/config_utils.rb +41 -0
  29. data/lib/giblish/configurator.rb +163 -0
  30. data/lib/giblish/conversion_info.rb +120 -0
  31. data/lib/giblish/docattr_providers.rb +125 -0
  32. data/lib/giblish/docid/docid.rb +181 -0
  33. data/lib/giblish/github_trigger/webhook_manager.rb +64 -0
  34. data/lib/giblish/gitrepos/checkoutmanager.rb +124 -0
  35. data/lib/giblish/{gititf.rb → gitrepos/gititf.rb} +30 -4
  36. data/lib/giblish/gitrepos/gitsummary.erb +61 -0
  37. data/lib/giblish/gitrepos/gitsummaryprovider.rb +78 -0
  38. data/lib/giblish/gitrepos/history_pb.rb +41 -0
  39. data/lib/giblish/indexbuilders/d3treegraph.rb +88 -0
  40. data/lib/giblish/indexbuilders/depgraphbuilder.rb +109 -0
  41. data/lib/giblish/indexbuilders/dotdigraphadoc.rb +174 -0
  42. data/lib/giblish/indexbuilders/standard_index.erb +10 -0
  43. data/lib/giblish/indexbuilders/subtree_indices.rb +132 -0
  44. data/lib/giblish/indexbuilders/templates/circles.html.erb +111 -0
  45. data/lib/giblish/indexbuilders/templates/flame.html.erb +61 -0
  46. data/lib/giblish/indexbuilders/templates/tree.html.erb +366 -0
  47. data/lib/giblish/indexbuilders/templates/treemap.html.erb +127 -0
  48. data/lib/giblish/indexbuilders/verbatimtree.rb +94 -0
  49. data/lib/giblish/pathtree.rb +473 -74
  50. data/lib/giblish/resourcepaths.rb +150 -0
  51. data/lib/giblish/search/expand_adoc.rb +55 -0
  52. data/lib/giblish/search/headingindexer.rb +312 -0
  53. data/lib/giblish/search/request_manager.rb +110 -0
  54. data/lib/giblish/search/searchquery.rb +68 -0
  55. data/lib/giblish/search/textsearcher.rb +349 -0
  56. data/lib/giblish/subtreeinfobuilder.rb +77 -0
  57. data/lib/giblish/treeconverter.rb +272 -0
  58. data/lib/giblish/utils.rb +142 -294
  59. data/lib/giblish/version.rb +1 -1
  60. data/lib/giblish.rb +10 -7
  61. data/scripts/hooks/post-receive.example +66 -0
  62. data/{docgen/scripts/githook_examples → scripts/hooks}/post-update.example +0 -0
  63. data/{docgen → scripts}/resources/css/adoc-colony.css +0 -0
  64. data/scripts/resources/css/giblish-serif.css +419 -0
  65. data/scripts/resources/css/giblish.css +1979 -419
  66. data/{docgen → scripts}/resources/fonts/Ubuntu-B.ttf +0 -0
  67. data/{docgen → scripts}/resources/fonts/Ubuntu-BI.ttf +0 -0
  68. data/{docgen → scripts}/resources/fonts/Ubuntu-R.ttf +0 -0
  69. data/{docgen → scripts}/resources/fonts/Ubuntu-RI.ttf +0 -0
  70. data/{docgen → scripts}/resources/fonts/mplus1p-regular-fallback.ttf +0 -0
  71. data/{docgen → scripts}/resources/images/giblish_logo.png +0 -0
  72. data/{docgen → scripts}/resources/images/giblish_logo.svg +0 -0
  73. data/{docgen → scripts}/resources/themes/giblish.yml +0 -0
  74. data/scripts/wserv_development.rb +32 -0
  75. data/web_apps/cgi_search/gibsearch.rb +43 -0
  76. data/web_apps/gh_webhook_trigger/config.ru +2 -0
  77. data/web_apps/gh_webhook_trigger/gh_webhook_trigger.rb +73 -0
  78. data/web_apps/gh_webhook_trigger/public/dummy.txt +3 -0
  79. data/web_apps/sinatra_search/config.ru +2 -0
  80. data/web_apps/sinatra_search/public/dummy.txt +3 -0
  81. data/web_apps/sinatra_search/sinatra_search.rb +34 -0
  82. data/web_apps/sinatra_search/tmp/restart.txt +0 -0
  83. metadata +168 -73
  84. data/.rubocop.yml +0 -7
  85. data/.travis.yml +0 -3
  86. data/Changelog +0 -16
  87. data/Gemfile +0 -4
  88. data/README.adoc +0 -1
  89. data/Rakefile +0 -41
  90. data/bin/console +0 -14
  91. data/bin/setup +0 -8
  92. data/data/testdocs/malformed/no_header.adoc +0 -5
  93. data/data/testdocs/toplevel.adoc +0 -19
  94. data/data/testdocs/wellformed/adorned_purpose.adoc +0 -17
  95. data/data/testdocs/wellformed/docidtest/docid_1.adoc +0 -24
  96. data/data/testdocs/wellformed/docidtest/docid_2.adoc +0 -8
  97. data/data/testdocs/wellformed/simple.adoc +0 -14
  98. data/data/testdocs/wellformed/source_highlighting/highlight_source.adoc +0 -38
  99. data/docgen/resources/css/giblish.css +0 -1979
  100. data/docgen/scripts/Jenkinsfile +0 -18
  101. data/docgen/scripts/gen_adoc_org.sh +0 -58
  102. data/docs/README.adoc +0 -387
  103. data/docs/setup_server.adoc +0 -202
  104. data/lib/giblish/buildgraph.rb +0 -216
  105. data/lib/giblish/buildindex.rb +0 -459
  106. data/lib/giblish/core.rb +0 -451
  107. data/lib/giblish/docconverter.rb +0 -308
  108. data/lib/giblish/docid.rb +0 -180
  109. data/lib/giblish/docinfo.rb +0 -75
  110. data/lib/giblish/indexheadings.rb +0 -251
  111. data/lib/giblish-search.cgi +0 -459
  112. data/scripts/hooks/post-receive +0 -57
  113. 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
+ &nbsp;&nbsp;
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
- # coding: utf-8
2
-
3
- lib = File.expand_path("../lib", __FILE__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
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 = "giblish"
10
- spec.version = Giblish::VERSION
11
- spec.authors = ["Anders Rillbert"]
12
- spec.email = ["anders.rillbert@kutso.se"]
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.summary = "A tool for publishing asciidoc docs stored in git repos"
15
- spec.description = <<~EOF
16
- giblish generates indexed and searchable documents from a tree of
17
- asciidoc files.
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
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
- spec.bindir = "exe"
33
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
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
- spec.add_development_dependency "bundler", "~> 2.0"
47
+ # Development deps
37
48
  spec.add_development_dependency "minitest", "~> 5.0"
38
- spec.add_development_dependency "rake", "~> 11.0"
39
- spec.add_development_dependency "oga", "~> 2.15"
40
- spec.add_development_dependency 'thor', '~> 0.20.3'
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
- # Usage: spec.add_runtime_dependency "[gem name]", [[version]]
44
- spec.add_runtime_dependency "asciidoctor", "~>2.0", ">= 2.0.16"
45
- spec.add_runtime_dependency "asciidoctor-diagram", ["~> 2.1"]
46
- spec.add_runtime_dependency "asciidoctor-pdf", ["~> 1.6", ">= 1.6.0"]
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
@@ -1,68 +1,241 @@
1
1
  require_relative "cmdline"
2
- require_relative "core"
3
- require_relative "utils"
2
+ require_relative "configurator"
3
+ require_relative "treeconverter"
4
+ require_relative "gitrepos/checkoutmanager"
4
5
 
5
6
  module Giblish
6
- # The 'main' class of giblish
7
+ # The app class for the giblish application
7
8
  class Application
8
- # does not return, exits with status code
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 = CmdLineParser.new args
24
- Giblog.logger.debug { "cmd line args: #{cmdline.args}" }
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
- exit_code = execute_conversion(cmdline)
27
- Giblog.logger.info { "Giblish is done!" } if exit_code.zero?
28
- exit_code
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
- # Convert using given args
34
- # return exit code (0 for success)
35
- def execute_conversion(cmdline)
36
- conv_error = false
37
- begin
38
- conv_error = converter_factory(cmdline).convert
39
- rescue StandardError => e
40
- log_error e
41
- conv_error = true
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
- conv_error ? 1 : 0
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
- # return the converter corresponding to the given cmd line
47
- # options
48
- def converter_factory(cmdline)
49
- if cmdline.args[:gitRepoRoot]
50
- Giblog.logger.info { "User asked to parse a git repo" }
51
- GitRepoConverter.new(cmdline.args)
52
- else
53
- FileTreeConverter.new(cmdline.args)
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
- def log_error(exc)
58
- Giblog.logger.error do
59
- <<~ERR_MSG
60
- Error: #{exc.message}
61
- Backtrace:
62
- \t#{exc.backtrace.join("\n\t")}
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
- cmdline.usage
65
- ERR_MSG
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