giblish 0.2.12 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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