giblish 0.8.2 → 1.0.0.rc2

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 +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
data/lib/giblish/utils.rb CHANGED
@@ -1,18 +1,20 @@
1
1
  require "logger"
2
2
  require "pathname"
3
3
  require "fileutils"
4
+ require "find"
4
5
 
5
6
  # The logger used from within giblish
6
7
  class Giblog
7
8
  # Defines the format for log messages from giblish.
8
9
  class GiblogFormatter
9
10
  def call(severity, datetime, _progname, msg)
10
- "#{datetime.strftime('%H:%M:%S')} #{severity} - #{msg}\n"
11
+ "#{datetime.strftime("%H:%M:%S")} #{severity} - #{msg}\n"
11
12
  end
12
13
  end
13
14
 
14
15
  # bootstrap the application-wide logger object
15
- def self.setup
16
+ def self.setup(logger = nil)
17
+ @logger = logger unless logger.nil?
16
18
  return if defined? @logger
17
19
 
18
20
  @logger = Logger.new($stdout)
@@ -32,13 +34,24 @@ end
32
34
 
33
35
  # Public: Contains a number of generic utility methods.
34
36
  module Giblish
35
- # a logger customized to process info received from asciidoctors
36
- # stdout.
37
+ # This logger is customized to receive log messages via the Asciidoctor API.
38
+ # It parses the messages and 'source_location' objects from the Asciidoctor API
39
+ # into messages using an opinionated format.
40
+ #
41
+ # The output is written to both $stdout and an in-memory StringIO instance. The log level
42
+ # can be set separately for each of these output channels.
37
43
  class AsciidoctorLogger < ::Logger
44
+ attr_reader :max_severity, :in_mem_storage
45
+
38
46
  # log formatter specialized for formatting messages from
39
- # asciidoctor's stdout
47
+ # asciidoctor's stdout, handles the different log record types that Asciidoctor
48
+ # emits
40
49
  class UserInfoFormatter
41
- SEVERITY_LABELS = { "WARN" => "WARNING", "FATAL" => "FAILED" }.freeze
50
+ SEVERITY_LABELS = {"WARN" => "WARNING", "FATAL" => "FAILED"}.freeze
51
+
52
+ def call(severity, datetime, progname, msg)
53
+ %(#{datetime.strftime("%H:%M:%S")} #{progname}: #{SEVERITY_LABELS[severity] || severity}: #{UserInfoFormatter.adoc_to_message(msg)}\n)
54
+ end
42
55
 
43
56
  # The hash that can be emitted as the msg from asciidoctor have the
44
57
  # following format:
@@ -49,260 +62,58 @@ module Giblish
49
62
  # @path="<only file name>",
50
63
  # @lineno=<src line no>
51
64
  # }
52
- def call(severity, datetime, progname, msg)
53
- message = case msg
54
- when ::String
55
- msg
56
- when ::Hash
57
- # asciidoctor seem to emit a hash with error text and source location info
58
- # for warnings and errors
59
- str = String.new("")
60
- src_loc = msg.fetch(:source_location, nil)
61
- err_txt = msg.fetch(:text, nil)
62
- str << "Line #{src_loc.lineno} - " if src_loc
63
- str << err_txt.to_s if err_txt
64
- str
65
- else
66
- msg.inspect
67
- end
68
- %(#{datetime.strftime('%H:%M:%S')} #{progname}: #{SEVERITY_LABELS[severity] || severity}: #{message}\n)
69
- end
70
- end
71
-
72
- attr_reader :max_severity, :user_info_str
73
-
74
- def initialize(user_info_log_level)
75
- super($stdout, progname: "(from asciidoctor)", formatter: UserInfoFormatter.new)
76
- @user_info_str = StringIO.new
77
- @user_info_logger = ::Logger.new(@user_info_str, formatter: UserInfoFormatter.new, level: user_info_log_level)
78
- end
79
-
80
- def add(severity, message = nil, progname = nil)
81
- if (severity ||= UNKNOWN) > (@max_severity ||= severity)
82
- @max_severity = severity
83
- end
84
- @user_info_logger.add(severity, message, progname)
85
- super
86
- end
87
- end
88
-
89
- # returns the paths to the search assets and web assets
90
- # in the deployment machine's file system.
91
- class DeploymentPaths
92
- attr_reader :web_path
93
-
94
- def initialize(web_path, search_asset_path)
95
- @search_assets_path = if search_asset_path.nil?
96
- nil
97
- else
98
- Pathname.new("/#{search_asset_path}").cleanpath
99
- end
100
- @web_path = if web_path.nil?
101
- nil
102
- else
103
- Pathname.new("/#{web_path}/web_assets").cleanpath
104
- end
105
- end
106
-
107
- def search_assets_path(branch_dir = nil)
108
- if branch_dir.nil?
109
- @search_assets_path
110
- else
111
- @search_assets_path.join(branch_dir)
65
+ def self.adoc_to_message(msg)
66
+ case msg
67
+ when ::String
68
+ msg
69
+ when ::Hash
70
+ # asciidoctor seem to emit a hash with the following structure on errors:
71
+ # :text => String
72
+ # :source_location => Reader::Cursor with the following props:
73
+ # dir, file, lineno, path
74
+ # Only the lineno prop can be trusted when Asciidoctor is used via Giblish
75
+ #
76
+ src_loc = msg.fetch(:source_location, nil)
77
+ err_txt = msg.fetch(:text, "")
78
+ str = ""
79
+ str << "Line #{src_loc.lineno} - " if src_loc.lineno
80
+ str << err_txt
81
+ str
82
+ else
83
+ msg.inspect
84
+ end
112
85
  end
113
86
  end
114
87
 
115
- attr_writer :search_assets_path
116
- end
117
-
118
- # Helper class to ease construction of different paths for input and output
119
- # files and directories
120
- class PathManager
121
- attr_reader :src_root_abs, :dst_root_abs, :resource_dir_abs, :search_assets_abs
122
-
123
- # Public:
88
+ # The level is one of the standard ::Logger levels
124
89
  #
125
- # src_root - a string or pathname with the top directory of the input file
126
- # tree
127
- # dst_root - a string or pathname with the top directory of the output file
128
- # tree
129
- # resource_dir - a string or pathname with the directory containing
130
- # resources
131
- # create_search_asset_dir - true if this instance shall create a dir for storing
132
- # search artefacts, false otherwise
133
- def initialize(src_root, dst_root, resource_dir = nil, create_search_asset_dir = false)
134
- # Make sure that the source root exists in the file system
135
- @src_root_abs = Pathname.new(src_root).realpath
136
- self.dst_root_abs = dst_root
137
-
138
- self.search_assets_abs = (@dst_root_abs.join("search_assets") if create_search_asset_dir)
139
-
140
- # Make sure that the resource dir exists if user gives a path to it
141
- resource_dir && (@resource_dir_abs = Pathname.new(resource_dir).realpath)
142
- end
143
-
144
- def search_assets_abs=(path)
145
- if path.nil?
146
- @search_assets_abs = nil
147
- return
148
- end
149
- # Make sure that the destination root exists and expand it to an
150
- # absolute path
151
- dir = Pathname.new(path)
152
- dir.mkpath
153
- @search_assets_abs = dir.realpath
90
+ # stdout_level:: the log level to use for gating the messages to stdout
91
+ # string_level:: the log level to use for gating the messages to the in-memory string.
92
+ # defaults to 'stdout_level' if not set.
93
+ def initialize(user_logger, string_level = nil)
94
+ # def initialize(stdout_level, string_level = nil)
95
+ string_level = stdout_level if string_level.nil?
96
+ @user_logger = user_logger
97
+
98
+ @max_severity = UNKNOWN
99
+
100
+ # create a new, internal logger that echos messages to an in-memory string
101
+ @in_mem_storage = StringIO.new
102
+ # @in_mem_logger = ::Logger.new(@in_mem_storage, formatter: UserInfoFormatter.new, level: string_level)
103
+ super(@in_mem_storage, progname: "(asciidoctor)", formatter: UserInfoFormatter.new, level: string_level)
154
104
  end
155
105
 
156
- def dst_root_abs=(dst_root)
157
- # Make sure that the destination root exists and expand it to an
158
- # absolute path
159
- Pathname.new(dst_root).mkpath
160
- @dst_root_abs = Pathname.new(dst_root).realpath
161
- end
106
+ def add(severity, message = nil, progname = nil, &block)
107
+ # add message to adoc log
108
+ super(severity, message.dup, progname)
162
109
 
163
- # Public: Get the relative path from the source root dir to the
164
- # directory where the supplied path points.
165
- #
166
- # in_path - an absolute or relative path to a file or dir
167
- def reldir_from_src_root(in_path)
168
- p = self.class.closest_dir in_path
169
- p.relative_path_from(@src_root_abs)
170
- end
171
-
172
- # Public: Get the relative path from the
173
- # directory where the supplied path points to
174
- # the src root dir
175
- #
176
- # path - an absolute or relative path to a file or dir
177
- def reldir_to_src_root(path)
178
- src = self.class.closest_dir path
179
- @src_root_abs.relative_path_from(src)
180
- end
181
-
182
- # Public: Get the relative path from the dst root dir to the
183
- # directory where the supplied path points.
184
- #
185
- # path - an absolute or relative path to a file or dir
186
- def reldir_from_dst_root(path)
187
- dst = self.class.closest_dir path
188
- dst.relative_path_from(@dst_root_abs)
189
- end
190
-
191
- # Public: Get the relative path from the
192
- # directory where the supplied path points to
193
- # the dst root dir
194
- #
195
- # path - an absolute or relative path to a file or dir
196
- def reldir_to_dst_root(path)
197
- dst = self.class.closest_dir path
198
- @dst_root_abs.relative_path_from(dst)
199
- end
110
+ # add message to user log (wierd interface... see Logger::add(...))
111
+ message = yield if block
112
+ message ||= progname
113
+ @user_logger&.add(severity, "(asciidoctor) #{UserInfoFormatter.adoc_to_message(message)}")
200
114
 
201
- # return the destination dir corresponding to the given src path
202
- # the src path must exist in the file system
203
- def dst_abs_from_src_abs(src_path)
204
- src_abs = (self.class.to_pathname src_path).realpath
205
- src_rel = reldir_from_src_root src_abs
206
- @dst_root_abs.join(src_rel)
207
- end
208
-
209
- # return the relative path from a generated document to
210
- # the supplied folder given the corresponding absolute source
211
- # file path
212
- def relpath_to_dir_after_generate(src_filepath, dir_path)
213
- dst_abs = dst_abs_from_src_abs(src_filepath)
214
- dir = self.class.to_pathname(dir_path)
215
- dir.relative_path_from(dst_abs)
216
- end
217
-
218
- def adoc_output_file(infile_path, extension)
219
- # Get absolute source dir path
220
- src_dir_abs = self.class.closest_dir infile_path
221
-
222
- # Get relative path from source root dir
223
- src_dir_rel = src_dir_abs.relative_path_from(@src_root_abs)
224
-
225
- # Get the destination path relative the absolute source
226
- # root
227
- dst_dir_abs = @dst_root_abs.realpath.join(src_dir_rel)
228
-
229
- # return full file path with correct extension
230
- dst_dir_abs + get_new_basename(infile_path, extension)
231
- end
232
-
233
- # Public: Get the path to the directory where to generate the given
234
- # file. The path is given as the relative path from the source adoc
235
- # file to the desired output directory (required by the Asciidoctor
236
- # API).
237
- #
238
- # infile_path - a string or Pathname containing the absolute path of the
239
- # source adoc file
240
- #
241
- # Returns: a Pathname with the relative path from the source file to the
242
- # output directory
243
- def adoc_output_dir(infile_path)
244
- # Get absolute source dir path
245
- src_abs = self.class.closest_dir infile_path
246
-
247
- # Get relative path from source root dir
248
- src_rel = src_abs.relative_path_from(@src_root_abs)
249
-
250
- # Get the destination path relative the absolute source
251
- # root
252
- dst_abs = @dst_root_abs.realpath.join(src_rel)
253
- dst_abs.relative_path_from(src_abs)
254
- end
255
-
256
- # return a pathname, regardless if the given path is a Pathname or
257
- # a string
258
- def self.to_pathname(path)
259
- path.is_a?(Pathname) ? path : Pathname.new(path)
260
- end
261
-
262
- # Public: Get the basename for a file by replacing the file
263
- # extention of the source file with the supplied one.
264
- #
265
- # src_filepath - the full path of the source file
266
- # file_ext - the file extention of the resulting file name
267
- #
268
- # Example
269
- #
270
- # Giblish::PathManager.get_new_basename(
271
- # "/my/old/file.txt","pdf") => "file.pdf"
272
- #
273
- # Returns: the basename of a file that uses the supplied file extention.
274
- def self.get_new_basename(src_filepath, file_ext)
275
- p = Pathname.new src_filepath
276
- newname = p.basename.to_s.reverse.sub(p.extname.reverse, ".").reverse
277
- newname << file_ext
278
- end
279
-
280
- # Public: Return the absolute path to the closest directory (defined as
281
- # - the parent dir when called with an existing file
282
- # - the directory itself when called with an existing directory
283
- # - the parent dir when called with a non-existing file/directory
284
- def self.closest_dir(in_path)
285
- sr = to_pathname(in_path)
286
- if sr.exist?
287
- sr.directory? ? sr.realpath : sr.dirname.realpath
288
- else
289
- sr.parent.expand_path
290
- end
291
- end
292
-
293
- # Public: Find the root directory of the git repo in which the
294
- # given dirpath resides.
295
- #
296
- # dirpath - a relative or absolute path to a directory that resides
297
- # within a git repo.
298
- #
299
- # Returns: the root direcotry of the git repo or nil if the input path
300
- # does not reside within a git repo.
301
- def self.find_gitrepo_root(dirpath)
302
- Pathname.new(dirpath).realpath.ascend do |p|
303
- git_dir = p.join(".git")
304
- return p if git_dir.directory?
305
- end
115
+ # update the maximum severity received by this logger
116
+ @max_severity = severity if severity != UNKNOWN && severity > @max_severity
306
117
  end
307
118
  end
308
119
 
@@ -313,13 +124,15 @@ module Giblish
313
124
  # ex:
314
125
  # process_header_lines(file_path) do |line|
315
126
  # if line == "Quack!"
316
- # puts "Donald!"
127
+ # myvar = "Donald!"
317
128
  # 1
318
129
  # else
319
130
  # nil
320
131
  # end
321
132
  # end
322
- def process_header_lines(lines)
133
+ def process_header_lines(lines, &block)
134
+ return unless block
135
+
323
136
  state = "before_header"
324
137
  lines.each do |line|
325
138
  case state
@@ -338,15 +151,17 @@ module Giblish
338
151
  # ex:
339
152
  # process_header_lines_from_file(file_path) do |line|
340
153
  # if line == "Quack!"
341
- # puts "Donald!"
154
+ # myvar = "Donald!"
342
155
  # 1
343
156
  # else
344
157
  # nil
345
158
  # end
346
159
  # end
347
- def process_header_lines_from_file(path)
160
+ def process_header_lines_from_file(path, &block)
161
+ return unless block
162
+
348
163
  lines = File.readlines(path)
349
- process_header_lines(lines, &Proc.new)
164
+ process_header_lines(lines, &block)
350
165
  end
351
166
  module_function :process_header_lines_from_file
352
167
 
@@ -363,9 +178,15 @@ module Giblish
363
178
  module_function :with_captured_stderr
364
179
 
365
180
  # transforms strings to valid asciidoctor id strings
366
- def to_valid_id(input_str, id_prefix = "_", id_separator = "_")
181
+ # in some cases you want to add a semi-unique checksum. If you do, you are no longer
182
+ # compatible with asciidoctor's generated ids
183
+ def to_valid_id(input_str, id_prefix = "_", id_separator = "_", use_checksum = false)
184
+ # use a basic checksum to reduce the risk for duplicate ids
185
+ check_sum = use_checksum ? input_str.chars.reduce(0) { |sum, c| sum + c.ord } : ""
186
+
367
187
  id_str = input_str.strip.downcase.gsub(/[^a-z0-9]+/, id_separator)
368
- id_str = "#{id_prefix}#{id_str}"
188
+ id_str = "#{id_prefix}#{check_sum}#{id_prefix}#{id_str}"
189
+ id_str.gsub!(/#{Regexp.quote(id_separator)}+/, id_separator)
369
190
  id_str.chomp(id_separator)
370
191
  end
371
192
  module_function :to_valid_id
@@ -387,44 +208,71 @@ module Giblish
387
208
  end
388
209
  module_function :which
389
210
 
390
- # returns raw html that displays a search box to let the user
391
- # acces the text search functionality.
211
+ # Convert a string into a string where all characters forbidden as part of
212
+ # filenames are replaced by an underscore '_'.
392
213
  #
393
- # css - the name of the css file to use for the search result layout
394
- # cgi_path - the (uri) path to a cgi script that implements the server side
395
- # functionality of searching the text
396
- # opts:
397
- # :web_assets_top => string # the path to the 'web_assets' dir as seen when serving
398
- # the web server (eg www.mysite.com/blah/doc_root ->
399
- # web_assets_top shall be '/blah/doc_root')
400
- # :search_assets_top => string # the path to where the 'heading.json' file is located (
401
- # as seen from the local file system on the machine that
402
- # runs the search script)
403
- def generate_search_box_html(css, cgi_path, opts)
404
- # Replace the button with the below to use a text-only version of the btn
405
- # <button id="search" type="submit">Search</button>
406
- <<~SEARCH_INFO
407
- ++++
408
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
409
- <form class="example" action="#{cgi_path}" style="margin:20px 0px 20px 0px;max-width:790px">
410
- Search all documents:
411
- <input id="searchphrase" type="text" placeholder="Search.." name="searchphrase"/>
412
- <button id="search" type="submit"><i class="fa fa-search"></i></button>
413
- <br>
214
+ # returns:: a String most likely a valid filename in windows & linux
215
+ #
216
+ # A comprehensive list of forbidden chars in different file systems can be
217
+ # found here: https://stackoverflow.com/a/31976060
218
+ # In short, chars forbidden in any of Windows and Linux are:
219
+ # / < > : " \\ | ? *
220
+ def to_fs_str(str)
221
+ # printable chars -> '_'
222
+ tmp = str.gsub(/[\/<>:"\\|?*]/, "_")
223
+ # non-printable chars -> '_'
224
+ tmp.gsub!(/[\x00-\x1F]/, "_")
225
+ # remove heading/trailing spaces
226
+ tmp.strip!
227
+ # Windows disallows files ending in '.'
228
+ tmp += "_" if tmp.end_with?(".")
229
+
230
+ tmp
231
+ end
232
+ module_function :to_fs_str
414
233
 
415
- <input id="ignorecase" type="checkbox" value="true" name="ignorecase" checked/>
416
- <label for="ignorecase">Ignore Case</label>
417
- &nbsp;&nbsp;
418
- <input id="useregexp" type="checkbox" value="true" name="useregexp"/>
419
- <label for="useregexp">Use Regexp</label>
234
+ # Break a line into rows of max_length, using '-' semi-intelligently
235
+ # to split words if needed
236
+ #
237
+ # return:: an Array with the resulting rows
238
+ def break_line(line, max_length)
239
+ too_short = 3
240
+ return [line] if line.length <= too_short
241
+ raise ArgumentError, "max_length must be larger than #{too_short - 1}" if max_length < too_short
242
+
243
+ rows = []
244
+ row = ""
245
+
246
+ until line.empty?
247
+ word, _sep, _remaining = line.strip.partition(" ")
248
+ row_space = max_length - row.length
249
+
250
+ # start word with a space if row is not empty
251
+ sep = row.empty? ? "" : " "
252
+
253
+ # if word fits in row, just insert it and take next word
254
+ if row_space - (word.length + sep.length) >= 0
255
+ row = "#{row}#{sep}#{word}"
256
+ line = line.sub(word, "").strip
257
+ next
258
+ end
420
259
 
421
- <input type="hidden" name="searchassetstop" value="#{opts[:search_assets_top]}"</input>
422
- <input type="hidden" name="webassetstop" value="#{opts[:web_assets_top]}"</input>
423
- #{%(<input type="hidden" name="css" value="#{css}"</input>) unless css.nil?}
424
- </form>
425
- ++++
260
+ # shall we split word or just move it to next row?
261
+ if (row_space == max_length && word.length > row_space) ||
262
+ (word.length > too_short && (row_space > too_short) && (word.length - row_space).abs > too_short)
263
+ # we will split the word, using a '-'
264
+ first_part = word[0..row_space - (1 + sep.length)]
265
+ row = "#{row}#{sep}#{first_part}-"
266
+ line = line.sub(first_part, "").strip
267
+ end
426
268
 
427
- SEARCH_INFO
269
+ # start a new row
270
+ rows << row
271
+ row = ""
272
+ end
273
+ # need to add unfinished row if any
274
+ rows << row unless row.empty?
275
+ rows
428
276
  end
429
- module_function :generate_search_box_html
277
+ module_function :break_line
430
278
  end
@@ -1,3 +1,3 @@
1
1
  module Giblish
2
- VERSION = "0.8.2".freeze
2
+ VERSION = "1.0.0.rc2".freeze
3
3
  end
data/lib/giblish.rb CHANGED
@@ -1,18 +1,21 @@
1
1
  #!/usr/bin/env ruby
2
+ if /^2/.match?(RUBY_VERSION)
3
+ # suppress warnings for 'experimental' pattern matching
4
+ # for ruby versions < 3.x
5
+ require "warning"
6
+ Warning.ignore(/Pattern matching/)
7
+ end
2
8
 
3
9
  require_relative "giblish/version"
4
- require_relative "giblish/utils"
5
- require_relative "giblish/core"
6
- require_relative "giblish/buildindex"
7
- require_relative "giblish/cmdline"
8
- require_relative "giblish/pathtree"
9
10
  require_relative "giblish/application"
11
+ require_relative "giblish/search/request_manager"
12
+ require_relative "giblish/github_trigger/webhook_manager"
10
13
 
11
14
  module Giblish
15
+ # The main entry point to the giblish application
12
16
  class << self
13
-
14
17
  def application
15
- @application ||= Giblish::Application.new
18
+ @application ||= Giblish::EntryPoint
16
19
  end
17
20
  end
18
21
  end
@@ -0,0 +1,66 @@
1
+ #!/bin/bash
2
+ #
3
+ # this hook runs giblish on a document tree according to the
4
+ # users settings.
5
+ # Typically used to publish html documents when a push to a matching
6
+ # branch is detected.
7
+
8
+ # the git refs that should trigger a doc generation at update
9
+ TRIGGERING_REFS_REGEX=$'main'
10
+
11
+ # the relative path to a subfolder in the repo where the docs are
12
+ REPO_DOC_SUBFOLDER="docs"
13
+
14
+ # the staging repo root (where the working tree exists)
15
+ STAGING_REPO="/usr/local/git_staging/rillbert_se_staging"
16
+
17
+ # The web-server top dir for the published documents
18
+ DST_DIR="/var/www/rillbert_se/html/public/docs"
19
+
20
+ # path to a top dir of the styling css and other resources
21
+ RESOURCE_DIR="scripts/resources"
22
+
23
+ # the name of the css file to use for styling, without the 'css' extension
24
+ LAYOUT_STYLE="giblish"
25
+
26
+ # "true" runs an 'rm -rf' of the destination dir before generating new htmls
27
+ CLEAR_DST="true"
28
+
29
+ echo "post-receive hook running..."
30
+
31
+ # read the input that git sends to this hook
32
+ read oldrev newrev ref
33
+
34
+ # remove the 'refs/heads/' prefix from the git ref
35
+ ref="${ref/refs\/heads\//}"
36
+
37
+ # filter out refs that are irrelevant for doc generation
38
+ if [[ ! "${ref}" =~ "${TRIGGERING_REFS_REGEX}" ]]; then
39
+ echo "Ref '${ref}' received. Doing nothing: only refs matching the regex: /${TRIGGERING_REFS_REGEX}/ will trigger a doc generation."
40
+ exit 0
41
+ fi
42
+
43
+ echo "Document generation triggered by an update to ${ref}."
44
+ echo ""
45
+
46
+ # use a subshell with the correct working dir for the actual doc generation
47
+ (
48
+ cd "${STAGING_REPO}"
49
+
50
+ # need to unset the GIT_DIR env set by the invoking hook for giblish to work correctly
51
+ unset GIT_DIR
52
+
53
+ if [[ "${CLEAR_DST}" -eq "true" ]]; then
54
+ echo "Remove everything under ${DST_DIR}/"
55
+ rm -rf ${DST_DIR}/*
56
+ fi
57
+
58
+ # Generate html docs
59
+ echo "running giblish..."
60
+ giblish -a xrefstyle=basic \
61
+ --copy-asset-folders "_assets$" \
62
+ -g "${TRIGGERING_REFS_REGEX}" \
63
+ -r "${RESOURCE_DIR}" \
64
+ -s "${LAYOUT_STYLE}" \
65
+ "${REPO_DOC_SUBFOLDER}" "${DST_DIR}"
66
+ )
File without changes