giblish 0.2.12 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d124070b2a70ba613898e4ec4a55c0077b4721f8
4
- data.tar.gz: 9ea41006b11273f084ae4afd2172b0e0ee5c0679
2
+ SHA256:
3
+ metadata.gz: 9db70ccddaf7473a9da59c81a9a592635a027faa4ffbec31a7d30a976c9fa7c6
4
+ data.tar.gz: a2c1034a4ef601d1f37ec1402d07de6258d1273a8524e4b6347418f0fb42cd2e
5
5
  SHA512:
6
- metadata.gz: 8c0bbd5e18a496e0405fcc9fb752102bb294d433914e46de814ad3923391b267ec8767711de17dd6258e235f2feb26126f3fc8107b8eb3040215c39a851ffe8f
7
- data.tar.gz: 507dc447a1d08255a81c2cf678e3e7e0571be4317da4bc7ab2286da17ac76f93f7f21d0a2aa25eb2304a20f7c68e676cfb42dfa067e43f745a3db725beac520c
6
+ metadata.gz: 05d9414c48c69d13eec80cbedc5d5a6049d711e53af054a7d26af9192e7845ec114667459ab090af3c0fab610f1c3f6b50629b15a51024fc5f15b01dc546d87d
7
+ data.tar.gz: da0330a4f1fe0fd9b009fa2689dda4b2f6f9e95e76acd9ba6755055d252e8b1b62d0ed974cbb7ca5ddbf0dd408781d9915dff68f843c9b8cec472115d7287d1d
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.3
data/Rakefile CHANGED
@@ -7,11 +7,10 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.test_files = FileList["test/**/*_test.rb"]
8
8
  end
9
9
 
10
- Rake::TestTask.new(:current_test) do |t|
10
+ Rake::TestTask.new(:current) do |t|
11
11
  t.libs << "test"
12
12
  t.libs << "lib"
13
- t.test_files = FileList["test/**/run_test.rb"]
14
- # t.test_files = FileList["test/**/docid_test.rb"]
13
+ t.test_files = FileList["test/**/depgraph_test.rb"]
15
14
  end
16
15
 
17
16
  Rake::TestTask.new(:sandbox) do |t|
data/giblish.gemspec CHANGED
@@ -36,6 +36,7 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  # Usage: spec.add_runtime_dependency "[gem name]", [[version]]
38
38
  spec.add_runtime_dependency "asciidoctor", "~>1.5", ">= 1.5.7.1"
39
+ spec.add_runtime_dependency "asciidoctor-diagram", ["~> 1.5"]
39
40
  spec.add_runtime_dependency "asciidoctor-pdf", [">= 1.5.0.alpha.16"]
40
41
  spec.add_runtime_dependency "asciidoctor-rouge", ["~> 0.3"]
41
42
  spec.add_runtime_dependency "git", "~> 1.3"
@@ -6,15 +6,22 @@ require_relative "utils"
6
6
  module Giblish
7
7
  class Application
8
8
 
9
+ # return exit status (0 for success)
9
10
  def run_with_args(args)
10
11
  run args
11
12
  end
12
13
 
14
+ # does not return, exits with status code
13
15
  def run_from_cmd_line
14
- run ARGV
16
+ status = run ARGV
17
+ exit(status)
15
18
  end
16
19
 
20
+ # return exit status (0 for success)
17
21
  def run(args)
22
+ # force immediate output
23
+ $stdout.sync = true
24
+
18
25
  # setup logging
19
26
  Giblog.setup
20
27
 
@@ -27,15 +34,17 @@ module Giblish
27
34
  begin
28
35
  if cmdline.args[:gitRepoRoot]
29
36
  Giblog.logger.info { "User asked to parse a git repo" }
30
- GitRepoParser.new cmdline.args
37
+ gc = GitRepoConverter.new cmdline.args
38
+ gc.convert
31
39
  else
32
- tc = TreeConverter.new cmdline.args
33
- tc.walk_dirs
40
+ tc = FileTreeConverter.new cmdline.args
41
+ tc.convert
34
42
  end
35
43
  Giblog.logger.info { "Giblish is done!" }
44
+ 0
36
45
  rescue Exception => e
37
46
  log_error e
38
- exit(1)
47
+ 1
39
48
  end
40
49
  end
41
50
 
@@ -0,0 +1,179 @@
1
+
2
+ module Giblish
3
+ # Builds an asciidoc page with an svg image with a
4
+ # digraph showing how documents reference each other.
5
+ #
6
+ # Graphviz is used as the graph generator and must be available
7
+ # as a valid engine via asciidoctor-diagram for this class to work.
8
+ class GraphBuilderGraphviz
9
+
10
+ # the dependency graph relies on graphwiz (dot), check if we can access that
11
+ def self.supported
12
+ return !Giblish.which('dot').nil?
13
+ end
14
+
15
+ # Supported options:
16
+ # :extension - file extension for URL links (default is .html)
17
+ def initialize(processed_docs, paths, options = {})
18
+
19
+ # this class relies on graphwiz (dot), make sure we can access that
20
+ raise "Could not find the 'dot' tool needed to generate a dependency graph!" unless GraphBuilderGraphviz.supported
21
+
22
+ # require asciidoctor module needed for generating diagrams
23
+ require "asciidoctor-diagram/graphviz"
24
+
25
+ @noid_docs = {}
26
+ @next_id = 0
27
+ @processed_docs = processed_docs
28
+ @paths = paths
29
+ @options = options.dup
30
+ @extension = options.key?(:extension) ? options[:extension] : "html"
31
+ @docid_cache = DocidCollector.docid_cache
32
+ @docid_deps = DocidCollector.docid_deps
33
+ @dep_graph = build_dep_graph
34
+ end
35
+
36
+ # get the asciidoc source for the document.
37
+ def source
38
+ <<~DOC_STR
39
+ #{generate_header}
40
+ #{generate_labels}
41
+ #{generate_deps}
42
+ #{generate_footer}
43
+ DOC_STR
44
+ end
45
+
46
+ private
47
+
48
+ # build a hash with {DocInfo => [doc_id array]}
49
+ def build_dep_graph
50
+ result = {}
51
+ @docid_deps.each do |src_file, id_array|
52
+ d = @processed_docs.find do |doc|
53
+ doc.src_file.to_s.eql? src_file
54
+ end
55
+ raise "Inconsistent docs when building graph!! found no match for #{src_file}" if d.nil?
56
+ result[d] = id_array
57
+ end
58
+ result
59
+ end
60
+
61
+ def generate_header
62
+ t = Time.now
63
+ <<~DOC_STR
64
+ = Document-id reference graph
65
+ from #{@paths.src_root_abs}
66
+
67
+ Generated by Giblish at::
68
+ #{t.strftime('%Y-%m-%d %H:%M')}
69
+
70
+ Below is a graph that visualizes what documents (by doc-id) a specific
71
+ document references.
72
+
73
+ [graphviz,"docdeps","svg",options="inline"]
74
+ ....
75
+ digraph notebook {
76
+ bgcolor="#33333310"
77
+ node [shape=note,
78
+ fillcolor="#ebf26680",
79
+ style="filled,solid"
80
+ ]
81
+
82
+ rankdir="LR"
83
+
84
+ DOC_STR
85
+ end
86
+
87
+ def generate_footer
88
+ <<~DOC_STR
89
+ }
90
+ ....
91
+ DOC_STR
92
+ end
93
+
94
+ def make_dot_entry(doc_dict, info)
95
+ # split title into multiple rows if it is too long
96
+ line_length = 15
97
+ lines = [""]
98
+ info.title.split(" ").inject("") do |l,w|
99
+ line = l + " " + w
100
+ lines[-1] = line
101
+ if line.length > line_length
102
+ # create a new, empty, line
103
+ lines << ""
104
+ ""
105
+ else
106
+ line
107
+ end
108
+ end unless info.title.nil?
109
+ title = lines.select { |l| l.length > 0 }.map {|l| l}.join("\n")
110
+
111
+ # create the label used to display the node in the graph
112
+ dot_entry = if info.doc_id.nil?
113
+ doc_id = next_fake_id
114
+ @noid_docs[info] = doc_id
115
+ "\"#{doc_id}\"[label=\"-\\n#{title}\""
116
+ else
117
+ doc_id = info.doc_id
118
+ "\"#{info.doc_id}\"[label=\"#{info.doc_id}\\n#{title}\""
119
+ end
120
+ # add clickable links in the case of html output (this is not supported
121
+ # out-of-the-box for pdf).
122
+ rp = info.rel_path.sub_ext(".#{@extension}")
123
+ case @extension
124
+ when "html"
125
+ dot_entry += ", URL=\"#{rp}\" ]"
126
+ else
127
+ dot_entry += " ]"
128
+ end
129
+ doc_dict[doc_id] = dot_entry
130
+ end
131
+
132
+ def generate_labels
133
+ # create an entry in the 'dot' description for each
134
+ # document, sort them according to descending doc id to
135
+ # get them displayed in the opposite order in the graph
136
+ node_dict = {}
137
+ @dep_graph.each_key do |info|
138
+ make_dot_entry node_dict, info
139
+ end
140
+ # sort the nodes by reverse doc id
141
+ node_dict = node_dict.sort.reverse.to_h
142
+
143
+ # produce the string with all node entries
144
+ node_str = node_dict.map do |k,v|
145
+ v
146
+ end.join("\n")
147
+ node_str
148
+ end
149
+
150
+ def generate_deps
151
+ dep_str = ""
152
+ @dep_graph.each do |info, targets|
153
+ # set either the real or the generated id as source
154
+ src_part = if info.doc_id.nil?
155
+ "\"#{@noid_docs[info]}\""
156
+ else
157
+ "\"#{info.doc_id}\""
158
+ end
159
+
160
+ if targets.length.zero?
161
+ dep_str += "#{src_part}\n"
162
+ next
163
+ end
164
+
165
+ dep_str += "#{src_part} -> {" + targets.reduce("") do |acc, target|
166
+ acc + " \"#{target}\""
167
+ end
168
+ # replace last comma with newline
169
+ dep_str += "}\n"
170
+ end
171
+ dep_str
172
+ end
173
+
174
+ def next_fake_id
175
+ @next_id += 1
176
+ "_generated_id_#{@next_id.to_s.rjust(4, '0')}"
177
+ end
178
+ end
179
+ end
@@ -1,504 +1,451 @@
1
- #!/usr/bin/env ruby
2
- #
3
-
4
1
  require "pathname"
5
2
  require "git"
6
- require_relative "cmdline"
3
+
7
4
  require_relative "pathtree"
8
5
  require_relative "gititf"
6
+ require_relative "docinfo"
7
+
8
+ module Giblish
9
+
10
+ # Base class with common functionality for all index builders
11
+ class BasicIndexBuilder
12
+ # set up the basic index building info
13
+ def initialize(processed_docs, path_manager, handle_docid = false)
14
+ @paths = path_manager
15
+ @nof_missing_titles = 0
16
+ @processed_docs = processed_docs
17
+ @src_str = ""
18
+ @manage_docid = handle_docid
19
+ end
9
20
 
10
- # Container class for bundling together the data we cache for
11
- # each asciidoc file we come across
12
- class DocInfo
13
- # Cache git info
14
- class DocHistory
15
- attr_accessor :date
16
- attr_accessor :author
17
- attr_accessor :message
18
- end
21
+ def source(dep_graph_exists = false)
22
+ <<~DOC_STR
23
+ #{generate_header}
24
+ #{generate_tree(dep_graph_exists)}
25
+ #{generate_details}
26
+ #{generate_footer}
27
+ DOC_STR
28
+ end
19
29
 
20
- attr_accessor :converted
21
- attr_accessor :title
22
- attr_accessor :doc_id
23
- attr_accessor :purpose_str
24
- attr_accessor :status
25
- attr_accessor :history
26
- attr_accessor :error_msg
27
- attr_accessor :stderr
28
- # these two members can have encoding issues when
29
- # running in a mixed Windows/Linux setting.
30
- # that is why the explicit utf-8 read methods are
31
- # provided.
32
- attr_accessor :relPath
33
- attr_accessor :srcFile
34
-
35
- def relPath_utf8
36
- return nil if @relPath.nil?
37
- @relPath.to_s.encode("utf-8")
38
- end
30
+ protected
31
+ # return the adoc string for displaying the source file
32
+ def display_source_file(doc_info)
33
+ <<~SRC_FILE_TXT
34
+ Source file::
35
+ #{doc_info.srcFile_utf8}
39
36
 
40
- def srcFile_utf8
41
- return nil if @srcFile.nil?
42
- @srcFile.to_s.encode("utf-8")
43
- end
37
+ SRC_FILE_TXT
38
+ end
44
39
 
45
- def initialize
46
- @history = []
47
- end
40
+ def generate_header
41
+ t = Time.now
42
+ <<~DOC_HEADER
43
+ = Document index
44
+ from #{@paths.src_root_abs}
48
45
 
49
- def to_s
50
- "DocInfo: title: #{@title} srcFile: #{srcFile_utf8}"
51
- end
52
- end
53
-
54
- # Base class with common functionality for all index builders
55
- class BasicIndexBuilder
56
- # set up the basic index building info
57
- def initialize(path_manager, handle_docid = false)
58
- @paths = path_manager
59
- @nof_missing_titles = 0
60
- @added_docs = []
61
- @src_str = ""
62
- @manage_docid = handle_docid
63
- end
46
+ Generated by Giblish at::
64
47
 
65
- # creates a DocInfo instance, fills it with basic info and
66
- # returns the filled in instance so that derived implementations can
67
- # add more data
68
- def add_doc(adoc, adoc_stderr)
69
- Giblog.logger.debug { "Adding adoc: #{adoc} Asciidoctor stderr: #{adoc_stderr}" }
70
- Giblog.logger.debug {"Doc attributes: #{adoc.attributes}"}
71
-
72
- info = DocInfo.new
73
- info.converted = true
74
- info.stderr = adoc_stderr
75
-
76
- # Get the purpose info if it exists
77
- info.purpose_str = get_purpose_info adoc
78
-
79
- # Get the relative path beneath the root dir to the doc
80
- d_attr = adoc.attributes
81
- info.relPath = Pathname.new(
82
- "#{d_attr['outdir']}/#{d_attr['docname']}#{d_attr['docfilesuffix']}"
83
- ).relative_path_from(
84
- @paths.dst_root_abs
85
- )
86
-
87
- # Get the doc id if it exists
88
- info.doc_id = adoc.attributes["docid"]
89
-
90
- # Get the source file path
91
- info.srcFile = adoc.attributes["docfile"]
92
-
93
- # If a docid exists, set titel to docid - title if we care about
94
- # doc ids.
95
- info.title = if !info.doc_id.nil? && @manage_docid
96
- "#{info.doc_id} - #{adoc.doctitle}"
97
- else
98
- adoc.doctitle
99
- end
100
-
101
- # Cache the created DocInfo
102
- @added_docs << info
103
- info
104
- end
48
+ #{t.strftime('%Y-%m-%d %H:%M')}
105
49
 
106
- def add_doc_fail(filepath, exception)
107
- info = DocInfo.new
50
+ DOC_HEADER
51
+ end
108
52
 
109
- # the only info we have is the source file name
110
- info.converted = false
111
- info.srcFile = filepath
112
- info.error_msg = exception.message
53
+ def get_docid_statistics
54
+ largest = ""
55
+ clash = []
56
+ @processed_docs.each do |d|
57
+ # get the lexically largest doc id
58
+ largest = d.doc_id if !d.doc_id.nil? && d.doc_id > largest
113
59
 
114
- # Cache the DocInfo
115
- @added_docs << info
116
- info
117
- end
60
+ # collect all ids in an array to find duplicates later on
61
+ clash << d.doc_id unless d.doc_id.nil?
62
+ end
63
+ # find the duplicate doc ids (if any)
64
+ duplicates = clash.select { |id| clash.count(id) > 1 }.uniq.sort
118
65
 
119
- def index_source
120
- <<~DOC_STR
121
- #{generate_header}
122
- #{generate_tree}
123
- #{generate_details}
124
- #{generate_footer}
125
- DOC_STR
126
- end
66
+ return largest,duplicates
67
+ end
127
68
 
128
- protected
69
+ def generate_doc_id_info(dep_graph_exists)
70
+ largest,duplicates = get_docid_statistics
71
+ docid_info_str = if ! @manage_docid
72
+ ""
73
+ else
74
+ "The 'largest' document id found when resolving :docid: tags is *#{largest}*."
75
+ end
129
76
 
130
- def generate_header
131
- t = Time.now
132
- <<~DOC_HEADER
133
- = Document index
134
- from #{@paths.src_root_abs}
77
+ docid_warn_str = if duplicates.length.zero?
78
+ ""
79
+ else
80
+ "WARNING: The following document ids are used for more than one document. " +
81
+ "_#{duplicates.map {|id| id.to_s}.join(",") }_"
82
+ end
135
83
 
136
- Generated by Giblish at::
84
+ # include link to dependency graph if it exists
85
+ dep_graph_str = if dep_graph_exists
86
+ "_(a visual graph of document dependencies can be found " \
87
+ "<<./graph.adoc#,here>>)_"
88
+ else
89
+ ""
90
+ end
91
+
92
+ if @manage_docid
93
+ <<~DOC_ID_INFO
94
+ Document id numbers::
95
+ The generation of this repository uses document id numbers. #{docid_info_str} #{dep_graph_str}
96
+
97
+ #{docid_warn_str}
98
+
99
+ DOC_ID_INFO
100
+ else
101
+ ""
102
+ end
103
+ end
137
104
 
138
- #{t.strftime('%Y-%m-%d %H:%M')}
105
+ def generate_tree(dep_graph_exists)
106
+ # output tree intro
107
+ tree_string = <<~DOC_HEADER
108
+ == Document Overview
139
109
 
140
- DOC_HEADER
141
- end
110
+ _Click on the title to open the document or on `details` to see more
111
+ info about the document. A `(warn)` label indicates that there were
112
+ warnings while converting the document from its asciidoc format._
142
113
 
143
- def generate_footer
144
- ""
145
- end
114
+ #{generate_doc_id_info dep_graph_exists}
146
115
 
147
- private
148
-
149
- def get_purpose_info(adoc)
150
- # Get the 'Purpose' section if it exists
151
- purpose_str = ""
152
- adoc.blocks.each do |section|
153
- next unless section.is_a?(Asciidoctor::Section) &&
154
- (section.level == 1) &&
155
- (section.name =~ /^Purpose$/)
156
- purpose_str = "Purpose::\n\n"
157
-
158
- # filter out 'odd' text, such as lists etc...
159
- section.blocks.each do |bb|
160
- next unless bb.is_a?(Asciidoctor::Block)
161
- purpose_str << "#{bb.source}\n+\n"
162
- end
163
- end
164
- purpose_str
165
- end
116
+ [subs=\"normal\"]
117
+ ----
118
+ DOC_HEADER
166
119
 
167
- def generate_conversion_info(d)
168
- return "" if d.stderr.empty?
169
- # extract conversion warnings from asciddoctor std err
170
- conv_warnings = d.stderr.gsub("asciidoctor:", "\n * asciidoctor:")
171
- Giblog.logger.warn { "Conversion warnings: #{conv_warnings}" }
120
+ # build up tree of paths
121
+ root = PathTree.new
122
+ @processed_docs.each do |d|
123
+ root.add_path(d.rel_path.to_s, d)
124
+ end
172
125
 
173
- # assemble info to index page
174
- <<~CONV_INFO
175
- Conversion info::
126
+ # generate each tree entry string
127
+ root.traverse_top_down do |level, node|
128
+ tree_string << tree_entry_string(level, node)
129
+ end
176
130
 
177
- #{conv_warnings}
178
- CONV_INFO
179
- end
131
+ # generate the tree footer
132
+ tree_string << "\n----\n"
133
+ end
180
134
 
181
- # Private: Return adoc elements for displaying a clickable title
182
- # and a 'details' ref that points to a section that uses the title as an id.
183
- #
184
- # Returns [ clickableTitleStr, clickableDetailsStr ]
185
- def format_title_and_ref(doc_info)
186
- unless doc_info.title
187
- @nof_missing_titles += 1
188
- doc_info.title = "NO TITLE FOUND (#{@nof_missing_titles}) !"
135
+ def generate_footer
136
+ ""
189
137
  end
190
- return "<<#{doc_info.relPath_utf8}#,#{doc_info.title}>>".encode("utf-8"),
191
- "<<#{Giblish.to_valid_id(doc_info.title)},details>>\n".encode("utf-8")
192
- end
193
138
 
194
- # Generate an adoc string that will display as
195
- # DocTitle (warn) details
196
- # Where the DocTitle and details are links to the doc itself and a section
197
- # identified with the doc's title respectively.
198
- def tree_entry_converted(prefix_str, doc_info)
199
- # Get the elements of the entry
200
- doc_title, doc_details = format_title_and_ref doc_info
201
- warning_label = doc_info.stderr.empty? ? "" : "(warn)"
202
-
203
- # Calculate padding to get (warn) and details aligned between entries
204
- padding = 80
205
- [doc_info.title, prefix_str, warning_label].each { |p| padding -= p.length }
206
- padding = 0 unless padding.positive?
207
- "#{prefix_str} #{doc_title}#{' ' * padding}#{warning_label} #{doc_details}"
208
- end
139
+ private
209
140
 
210
- def tree_entry_string(level, node)
211
- # indent 2 * level
212
- prefix_str = " " * (level + 1)
141
+ def generate_conversion_info(d)
142
+ return "" if d.stderr.empty?
143
+ # extract conversion warnings from asciddoctor std err
144
+ conv_warnings = d.stderr.gsub("asciidoctor:", "\n * asciidoctor:")
145
+ Giblog.logger.warn {"Conversion warnings: #{conv_warnings}"}
213
146
 
214
- # return only name for directories
215
- return "#{prefix_str} #{node.name}\n" unless node.leaf?
147
+ # assemble info to index page
148
+ <<~CONV_INFO
149
+ Conversion info::
216
150
 
217
- # return links to content and details for files
218
- d = node.data
219
- if d.converted
220
- tree_entry_converted prefix_str, d
221
- else
222
- # no converted file exists, show what we know
223
- "#{prefix_str} FAIL: #{d.srcFile_utf8} <<#{d.srcFile_utf8},details>>\n"
151
+ #{conv_warnings}
152
+ CONV_INFO
224
153
  end
225
- end
226
154
 
227
- def generate_tree
228
- # build up tree of paths
229
- root = PathTree.new
230
- @added_docs.each do |d|
231
- root.add_path(d.relPath.to_s, d)
232
- end
155
+ # Private: Return adoc elements for displaying a clickable title
156
+ # and a 'details' ref that points to a section that uses the title as an id.
157
+ #
158
+ # Returns [ title, clickableTitleStr, clickableDetailsStr ]
159
+ def format_title_and_ref(doc_info)
160
+ unless doc_info.title
161
+ @nof_missing_titles += 1
162
+ doc_info.title = "NO TITLE FOUND (#{@nof_missing_titles}) !"
163
+ end
233
164
 
234
- # output tree intro
235
- tree_string = <<~DOC_HEADER
236
- == Document Overview
165
+ # Manipulate the doc title if we have a doc id
166
+ title = if !doc_info.doc_id.nil? && @manage_docid
167
+ "#{doc_info.doc_id} - #{doc_info.title}"
168
+ else
169
+ doc_info.title
170
+ end
237
171
 
238
- _Click on the title to open the document or on `details` to see more
239
- info about the document. A `(warn)` label indicates that there were
240
- warnings while converting the document._
172
+ [title, "<<#{doc_info.rel_path}#,#{title}>>".encode("utf-8"),
173
+ "<<#{Giblish.to_valid_id(doc_info.title)},details>>\n".encode("utf-8")]
174
+ end
241
175
 
242
- [subs=\"normal\"]
243
- ----
244
- DOC_HEADER
176
+ # Generate an adoc string that will display as
177
+ # DocTitle (warn) details
178
+ # Where the DocTitle and details are links to the doc itself and a section
179
+ # identified with the doc's title respectively.
180
+ def tree_entry_converted(prefix_str, doc_info)
181
+ # Get the elements of the entry
182
+ doc_title, doc_link, doc_details = format_title_and_ref doc_info
183
+ warning_label = doc_info.stderr.empty? ? "" : "(warn)"
184
+
185
+ # Calculate padding to get (warn) and details aligned between entries
186
+ padding = 70
187
+ [doc_title, prefix_str, warning_label].each {|p| padding -= p.length}
188
+ padding = 0 unless padding.positive?
189
+ "#{prefix_str} #{doc_link}#{' ' * padding}#{warning_label} #{doc_details}"
190
+ end
245
191
 
246
- # generate each tree entry string
247
- root.traverse_top_down do |level, node|
248
- tree_string << tree_entry_string(level, node)
192
+ def tree_entry_string(level, node)
193
+ # indent 2 * level
194
+ prefix_str = " " * (level + 1)
195
+
196
+ # return only name for directories
197
+ return "#{prefix_str} #{node.name}\n" unless node.leaf?
198
+
199
+ # return links to content and details for files
200
+ # node.data is a DocInfo instance
201
+ d = node.data
202
+ if d.converted
203
+ tree_entry_converted prefix_str, d
204
+ else
205
+ # no converted file exists, show what we know
206
+ "#{prefix_str} FAIL: #{d.srcFile_utf8} <<#{d.srcFile_utf8},details>>\n"
207
+ end
249
208
  end
250
209
 
251
- # generate the tree footer
252
- tree_string << "\n----\n"
253
- end
210
+ # Derived classes can override this with useful info
211
+ def generate_history_info(_d)
212
+ ""
213
+ end
254
214
 
255
- # Derived classes can override this with useful info
256
- def generate_history_info(_d)
257
- ""
258
- end
215
+ def generate_detail_fail(d)
216
+ <<~FAIL_INFO
217
+ === #{d.srcFile_utf8}
259
218
 
260
- def generate_detail_fail(d)
261
- <<~FAIL_INFO
262
- === #{d.srcFile_utf8}
219
+ #{display_source_file(d)}
263
220
 
264
- Source file::
221
+ Error detail::
222
+ #{d.stderr}
265
223
 
266
- #{d.srcFile_utf8}
224
+ ''''
267
225
 
268
- Error detail::
269
- #{d.stderr}
226
+ FAIL_INFO
227
+ end
270
228
 
271
- ''''
229
+ def generate_detail(d)
230
+ # Generate detail info
231
+ purpose_str = if d.purpose_str.nil?
232
+ ""
233
+ else
234
+ "Purpose::\n#{d.purpose_str}"
235
+ end
272
236
 
273
- FAIL_INFO
274
- end
237
+ doc_id_str = if !d.doc_id.nil? && @manage_docid
238
+ "Doc id::\n_#{d.doc_id}_"
239
+ else
240
+ ""
241
+ end
275
242
 
276
- def generate_detail(d)
277
- # Generate detail info
278
- <<~DETAIL_SRC
279
- [[#{Giblish.to_valid_id(d.title.encode("utf-8"))}]]
280
- === #{d.title.encode("utf-8")}
243
+ <<~DETAIL_SRC
244
+ [[#{Giblish.to_valid_id(d.title.encode("utf-8"))}]]
245
+ === #{d.title.encode("utf-8")}
281
246
 
282
- #{d.purpose_str}
247
+ #{doc_id_str}
283
248
 
284
- #{generate_conversion_info d}
249
+ #{purpose_str}
285
250
 
286
- Source file::
287
- #{d.srcFile_utf8}
251
+ #{generate_conversion_info d}
288
252
 
289
- #{generate_history_info d}
253
+ #{display_source_file(d)}
290
254
 
291
- ''''
255
+ #{generate_history_info d}
292
256
 
293
- DETAIL_SRC
294
- end
257
+ ''''
295
258
 
296
- def generate_details
297
- root = PathTree.new
298
- @added_docs.each do |d|
299
- root.add_path(d.relPath.to_s, d)
259
+ DETAIL_SRC
300
260
  end
301
261
 
302
- details_str = "== Document details\n\n"
262
+ def generate_details
263
+ root = PathTree.new
264
+ @processed_docs.each do |d|
265
+ root.add_path(d.rel_path.to_s, d)
266
+ end
303
267
 
304
- root.traverse_top_down do |_level, node|
305
- details_str << if node.leaf?
306
- d = node.data
307
- if d.converted
308
- generate_detail(d)
268
+ details_str = "== Document details\n\n"
269
+
270
+ root.traverse_top_down do |_level, node|
271
+ details_str << if node.leaf?
272
+ d = node.data
273
+ if d.converted
274
+ generate_detail(d)
275
+ else
276
+ generate_detail_fail(d)
277
+ end
309
278
  else
310
- generate_detail_fail(d)
279
+ ""
311
280
  end
312
- else
313
- ""
314
- end
315
- end
316
- details_str
317
- end
318
- end
319
-
320
- # A simple index generator that shows a table with the generated documents
321
- class SimpleIndexBuilder < BasicIndexBuilder
322
- def initialize(path_manager, manage_docid = false)
323
- super path_manager, manage_docid
324
- end
325
-
326
- def add_doc(adoc, adoc_stderr)
327
- super(adoc, adoc_stderr)
328
- end
329
- end
330
-
331
- # Builds an index of the generated documents and includes some git metadata
332
- # repository
333
- class GitRepoIndexBuilder < BasicIndexBuilder
334
- def initialize(path_manager, manage_docid, git_repo_root)
335
- super path_manager, manage_docid
336
-
337
- # initialize state variables
338
- @git_repo_root = git_repo_root
339
-
340
- # no repo root given...
341
- return unless @git_repo_root
342
-
343
- begin
344
- # Make sure that we can "talk" to git if user feeds us
345
- # a git repo root
346
- @git_repo = Git.open(@git_repo_root)
347
- rescue Exception => e
348
- Giblog.logger.error { "No git repo! exception: #{e.message}" }
281
+ end
282
+ details_str
349
283
  end
350
284
  end
351
285
 
352
- def add_doc(adoc, adoc_stderr)
353
- info = super(adoc, adoc_stderr)
354
-
355
- # Redefine the srcFile to mean the relative path to the git repo root
356
- info.srcFile = Pathname.new(info.srcFile).relative_path_from(@git_repo_root).to_s
357
-
358
- # Get the commit history of the doc
359
- # (use a homegrown git log to get 'follow' flag)
360
- gi = Giblish::GitItf.new(@git_repo_root)
361
- gi.file_log(info.srcFile_utf8).each do |i|
362
- h = DocInfo::DocHistory.new
363
- h.date = i["date"]
364
- h.message = i["message"]
365
- h.author = i["author"]
366
- info.history << h
286
+ # A simple index generator that shows a table with the generated documents
287
+ class SimpleIndexBuilder < BasicIndexBuilder
288
+ def initialize(processed_docs, path_manager, manage_docid = false)
289
+ super processed_docs, path_manager, manage_docid
367
290
  end
368
291
  end
369
292
 
370
- protected
371
-
372
- def generate_header
373
- t = Time.now
374
- <<~DOC_HEADER
375
- = Document index
376
- #{@git_repo.current_branch}
377
-
378
- Generated by Giblish at::
379
-
380
- #{t.strftime('%Y-%m-%d %H:%M')}
381
-
382
- DOC_HEADER
383
- end
384
-
385
- def generate_history_info(d)
386
- str = <<~HISTORY_HEADER
387
- File history::
388
-
389
- [cols=\"2,3,8\",options=\"header\"]
390
- |===
391
- |Date |Author |Message
392
- HISTORY_HEADER
293
+ # Builds an index of the generated documents and includes some git metadata
294
+ # from the repository
295
+ class GitRepoIndexBuilder < BasicIndexBuilder
296
+ def initialize(processed_docs, path_manager, manage_docid, git_repo_root)
297
+ super processed_docs, path_manager, manage_docid
393
298
 
394
- # Generate table rows of history information
395
- d.history.each do |h|
396
- str << <<~HISTORY_ROW
397
- |#{h.date.strftime('%Y-%m-%d')}
398
- |#{h.author}
399
- |#{h.message}
299
+ # no repo root given...
300
+ return unless git_repo_root
400
301
 
401
- HISTORY_ROW
302
+ begin
303
+ # Make sure that we can "talk" to git if user feeds us
304
+ # a git repo root
305
+ @git_repo = Git.open(git_repo_root)
306
+ @git_repo_root = git_repo_root
307
+ rescue Exception => e
308
+ Giblog.logger.error {"No git repo! exception: #{e.message}"}
309
+ end
402
310
  end
403
- str << "|===\n\n"
404
- end
405
- end
406
-
407
- # Builds an index page with a summary of what branches have
408
- # been generated
409
- class GitSummaryIndexBuilder
410
- def initialize(repo)
411
- @branches = []
412
- @tags = []
413
- @git_repo = repo
414
- @repo_url = repo.remote.url
415
- end
416
311
 
417
- def add_branch(b)
418
- @branches << b
419
- end
312
+ protected
313
+ # override basic version and use the relative path to the
314
+ # git repo root instead
315
+ def display_source_file(doc_info)
316
+ # Use the path relative to the git repo root as display
317
+ src_file = Pathname.
318
+ new(doc_info.src_file).
319
+ relative_path_from(@git_repo_root).to_s
320
+ <<~SRC_FILE_TXT
321
+ Source file::
322
+ #{src_file}
323
+
324
+ SRC_FILE_TXT
325
+ end
420
326
 
421
- def add_tag(t)
422
- @tags << t
423
- end
424
327
 
425
- def index_source
426
- <<~ADOC_SRC
427
- #{generate_header}
428
- #{generate_branch_info}
429
- #{generate_tag_info}
430
- #{generate_footer}
431
- ADOC_SRC
432
- end
328
+ def generate_header
329
+ t = Time.now
330
+ <<~DOC_HEADER
331
+ = Document index
332
+ #{@git_repo.current_branch}
433
333
 
434
- private
334
+ Generated by Giblish at::
335
+ #{t.strftime('%Y-%m-%d %H:%M')}
435
336
 
436
- def generate_header
437
- t = Time.now
438
- <<~DOC_HEADER
439
- = Document repository
440
- From #{@repo_url}
337
+ DOC_HEADER
338
+ end
441
339
 
442
- Generated by Giblish at::
340
+ def generate_history_info(d)
341
+ str = <<~HISTORY_HEADER
342
+ File history::
443
343
 
444
- #{t.strftime('%Y-%m-%d %H:%M')}
344
+ [cols=\"2,3,8\",options=\"header\"]
345
+ |===
346
+ |Date |Author |Message
347
+ HISTORY_HEADER
445
348
 
446
- DOC_HEADER
447
- end
349
+ # Generate table rows of history information
350
+ d.history.each do |h|
351
+ str << <<~HISTORY_ROW
352
+ |#{h.date.strftime('%Y-%m-%d')}
353
+ |#{h.author}
354
+ |#{h.message}
448
355
 
449
- def generate_footer
450
- ""
356
+ HISTORY_ROW
357
+ end
358
+ str << "|===\n\n"
359
+ end
451
360
  end
452
361
 
453
- def generate_branch_info
454
- return "" if @branches.empty?
362
+ # Builds an index page with a summary of what branches have
363
+ # been generated
364
+ class GitSummaryIndexBuilder
365
+ def initialize(repo, branches, tags)
366
+ @branches = branches
367
+ @tags = tags
368
+ @git_repo = repo
369
+ @repo_url = repo.remote.url
370
+ end
455
371
 
456
- # get the branch-unique dst-dir
457
- str = <<~BRANCH_INFO
458
- == Branches
372
+ def source
373
+ <<~ADOC_SRC
374
+ #{generate_header}
375
+ #{generate_branch_info}
376
+ #{generate_tag_info}
377
+ #{generate_footer}
378
+ ADOC_SRC
379
+ end
459
380
 
460
- BRANCH_INFO
381
+ private
461
382
 
462
- @branches.each do |b|
463
- dirname = b.name.tr "/", "_"
464
- str << " * link:#{dirname}/index.html[#{b.name}]\n"
465
- end
466
- str
467
- end
383
+ def generate_header
384
+ t = Time.now
385
+ <<~DOC_HEADER
386
+ = Document repository
387
+ From #{@repo_url}
468
388
 
469
- def generate_tag_info
470
- return "" if @tags.empty?
389
+ Generated by Giblish at::
390
+ #{t.strftime('%Y-%m-%d %H:%M')}
471
391
 
472
- # get the branch-unique dst-dir
473
- str = <<~TAG_INFO
474
- == Tags
392
+ DOC_HEADER
393
+ end
475
394
 
476
- |===
477
- |Tag |Tag comment |Creator |Tagged commit
395
+ def generate_footer
396
+ ""
397
+ end
478
398
 
479
- TAG_INFO
399
+ def generate_branch_info
400
+ return "" if @branches.empty?
480
401
 
481
- str << @tags.collect do |t|
482
- dirname = t.name.tr "/", "_"
483
- c = @git_repo.gcommit(t.sha)
402
+ # get the branch-unique dst-dir
403
+ str = <<~BRANCH_INFO
404
+ == Branches
484
405
 
485
- <<~A_ROW
486
- |link:#{dirname}/index.html[#{t.name}]
487
- |#{t.annotated? ? t.message : "-"}
488
- |#{t.annotated? ? t.tagger.name : "-"}
489
- |#{t.sha[0,8]}... committed at #{c.author.date}
490
- A_ROW
491
- end.join("\n")
406
+ BRANCH_INFO
492
407
 
493
- str << "|===\n"
408
+ @branches.each do |b|
409
+ dirname = b.name.tr "/", "_"
410
+ str << " * link:#{dirname}/index.html[#{b.name}]\n"
411
+ end
412
+ str
413
+ end
494
414
 
495
- # @tags.each do |t|
496
- # dirname = t.name.tr "/", "_"
497
- # str << " * link:#{dirname}/index.html[#{t.name}]"
498
- # if t.annotated?
499
- # str << "created at #{t.tagger.date} by #{t.tagger.name} with message: #{t.message}"
500
- # end
501
- # end
502
- str
415
+ def generate_tag_info
416
+ return "" if @tags.empty?
417
+
418
+ # get the branch-unique dst-dir
419
+ str = <<~TAG_INFO
420
+ == Tags
421
+
422
+ |===
423
+ |Tag |Tag comment |Creator |Tagged commit
424
+
425
+ TAG_INFO
426
+
427
+ str << @tags.collect do |t|
428
+ dirname = t.name.tr "/", "_"
429
+ c = @git_repo.gcommit(t.sha)
430
+
431
+ <<~A_ROW
432
+ |link:#{dirname}/index.html[#{t.name}]
433
+ |#{t.annotated? ? t.message : "-"}
434
+ |#{t.annotated? ? t.tagger.name : "-"}
435
+ |#{t.sha[0, 8]}... committed at #{c.author.date}
436
+ A_ROW
437
+ end.join("\n")
438
+
439
+ str << "|===\n"
440
+
441
+ # @tags.each do |t|
442
+ # dirname = t.name.tr "/", "_"
443
+ # str << " * link:#{dirname}/index.html[#{t.name}]"
444
+ # if t.annotated?
445
+ # str << "created at #{t.tagger.date} by #{t.tagger.name} with message: #{t.message}"
446
+ # end
447
+ # end
448
+ str
449
+ end
503
450
  end
504
- end
451
+ end