giblish 0.8.0 → 1.0.0

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 +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 +50 -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 +180 -71
  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.0".freeze
2
+ VERSION = "1.0.0".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