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.
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 +59 -0
  6. data/README.adoc +261 -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 +54 -32
  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 +188 -85
  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,23 +32,41 @@ 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"
37
- 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'
47
+ # Development deps
48
+ spec.add_development_dependency "minitest", "~> 5.16"
49
+ spec.add_development_dependency "standard", "~> 1.16"
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"
53
+ spec.add_development_dependency "thor", "~> 1.2"
41
54
  spec.add_development_dependency "asciidoctor-mathematical", "~> 0.3.5"
55
+ # needed for the sinatra-based apps
56
+ spec.add_development_dependency "sinatra", "~>2.1"
57
+ spec.add_development_dependency "thin", "~>1.8"
58
+ spec.add_development_dependency "rack", "2.2.3"
59
+ spec.add_development_dependency "rack-test", "1.1"
42
60
 
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"]
47
- spec.add_runtime_dependency "git", "~> 1.9"
48
- spec.add_runtime_dependency "rouge", "~> 3.0"
61
+ # Run-time deps
62
+ # 'matrix' needed because of incompatibilities between prawn v2.4
63
+ # and ruby 3.1
64
+ spec.add_runtime_dependency "matrix", "~>0.4"
65
+ spec.add_runtime_dependency "warning", "~>1.2"
66
+ spec.add_runtime_dependency "asciidoctor", "~>2.0", ">= 2.0.17"
67
+ spec.add_runtime_dependency "asciidoctor-diagram", ["~> 2.2"]
68
+ spec.add_runtime_dependency "asciidoctor-pdf", ["~> 2.3"]
69
+ spec.add_runtime_dependency "git", "~> 1.12"
70
+ spec.add_runtime_dependency "rouge", "~> 3.30"
49
71
  spec.add_runtime_dependency "prawn-svg", "~> 0.32.0"
50
72
  end
@@ -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
39
+
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
25
65
 
26
- exit_code = execute_conversion(cmdline)
27
- Giblog.logger.info { "Giblish is done!" } if exit_code.zero?
28
- exit_code
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}" }
42
109
  end
43
- conv_error ? 1 : 0
110
+ pt
44
111
  end
45
112
 
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)
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
124
+ end
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)
146
+ end
147
+
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 }
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
187
+ end
188
+ end
189
+
190
+ class EntryPoint
191
+ def initialize(args, logger = nil)
192
+ # force immediate output
193
+ # $stdout.sync = true
194
+
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
54
227
  end
228
+ exit(exit_code)
55
229
  end
56
230
 
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")}
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