ascii_binder 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -0
  3. data/ascii_binder.gemspec +5 -3
  4. data/bin/asciibinder +53 -44
  5. data/features/command_help.feature +8 -0
  6. data/features/command_version.feature +8 -0
  7. data/features/repo_build.feature +34 -0
  8. data/features/repo_clean.feature +20 -0
  9. data/features/repo_clone.feature +22 -0
  10. data/features/repo_create.feature +13 -0
  11. data/features/repo_package.feature +15 -0
  12. data/features/step_definitions/steps.rb +182 -0
  13. data/features/support/_clone_distro_map.yml +14 -0
  14. data/features/support/_invalid_distro_map.yml +14 -0
  15. data/features/support/env.rb +468 -0
  16. data/features/support/test_distro/.gitignore +9 -0
  17. data/features/support/test_distro/_distro_map.yml +29 -0
  18. data/features/support/test_distro/_images/asciibinder-logo-horizontal.png +0 -0
  19. data/features/support/test_distro/_images/asciibinder_web_logo.svg +125 -0
  20. data/features/support/test_distro/_images/book_pages_bg.jpg +0 -0
  21. data/features/support/test_distro/_images/favicon.ico +0 -0
  22. data/features/support/test_distro/_images/favicon32x32.png +0 -0
  23. data/features/support/test_distro/_javascripts/.gitkeep +0 -0
  24. data/features/support/test_distro/_stylesheets/asciibinder.css +568 -0
  25. data/features/support/test_distro/_templates/_css.html.erb +3 -0
  26. data/features/support/test_distro/_templates/_nav.html.erb +31 -0
  27. data/features/support/test_distro/_templates/page.html.erb +92 -0
  28. data/features/support/test_distro/_topic_map.yml +36 -0
  29. data/features/support/test_distro/index-main.html +10 -0
  30. data/features/support/test_distro/index-test.html +10 -0
  31. data/features/support/test_distro/main_only_topic_group/index.adoc +17 -0
  32. data/features/support/test_distro/test_only_topic_group/index.adoc +17 -0
  33. data/features/support/test_distro/welcome/index.adoc +17 -0
  34. data/features/support/test_distro/welcome/subtopics/index.adoc +17 -0
  35. data/features/support/test_distro/welcome/subtopics/main_only_topic.adoc +17 -0
  36. data/features/support/test_distro/welcome/subtopics/test_only_topic.adoc +17 -0
  37. data/features/support/test_distro/welcome/subtopics/wildcard_all.adoc +17 -0
  38. data/lib/ascii_binder.rb +4 -2
  39. data/lib/ascii_binder/distro.rb +111 -0
  40. data/lib/ascii_binder/distro_branch.rb +93 -0
  41. data/lib/ascii_binder/distro_map.rb +67 -0
  42. data/lib/ascii_binder/engine.rb +581 -0
  43. data/lib/ascii_binder/helpers.rb +42 -856
  44. data/lib/ascii_binder/site.rb +52 -0
  45. data/lib/ascii_binder/site_info.rb +22 -0
  46. data/lib/ascii_binder/site_map.rb +24 -0
  47. data/lib/ascii_binder/topic_entity.rb +255 -0
  48. data/lib/ascii_binder/topic_map.rb +61 -0
  49. data/lib/ascii_binder/version.rb +1 -1
  50. data/templates/_templates/page.html.erb +1 -1
  51. metadata +118 -14
@@ -1,75 +1,5 @@
1
- require 'ascii_binder/template_renderer'
2
- require 'asciidoctor'
3
- require 'asciidoctor/cli'
4
- require 'asciidoctor-diagram'
5
- require 'fileutils'
6
- require 'find'
7
- require 'git'
8
- require 'logger'
9
- require 'pandoc-ruby'
10
- require 'pathname'
11
- require 'sitemap_generator'
12
- require 'yaml'
13
- require 'forwardable'
14
-
15
1
  module AsciiBinder
16
2
  module Helpers
17
- extend Forwardable
18
-
19
- def self.source_dir
20
- @source_dir ||= `git rev-parse --show-toplevel`.chomp
21
- end
22
-
23
- def self.gem_root_dir
24
- @gem_root_dir ||= File.expand_path("../../../", __FILE__)
25
- end
26
-
27
- def self.set_source_dir(source_dir)
28
- @source_dir = source_dir
29
- end
30
-
31
- def template_renderer
32
- @template_renderer ||= TemplateRenderer.new(source_dir, template_dir)
33
- end
34
-
35
- def self.template_dir
36
- @template_dir ||= File.join(source_dir,'_templates')
37
- end
38
-
39
- def self.preview_dir
40
- @preview_dir ||= begin
41
- lpreview_dir = File.join(source_dir,PREVIEW_DIRNAME)
42
- if not File.exists?(lpreview_dir)
43
- Dir.mkdir(lpreview_dir)
44
- end
45
- lpreview_dir
46
- end
47
- end
48
-
49
- def self.package_dir
50
- @package_dir ||= begin
51
- lpackage_dir = File.join(source_dir,PACKAGE_DIRNAME)
52
- if not File.exists?(lpackage_dir)
53
- Dir.mkdir(lpackage_dir)
54
- end
55
- lpackage_dir
56
- end
57
- end
58
-
59
- def self.stylesheet_dir
60
- @stylesheet_dir ||= File.join(source_dir,STYLESHEET_DIRNAME)
61
- end
62
-
63
- def self.javascript_dir
64
- @javascript_dir ||= File.join(source_dir,JAVASCRIPT_DIRNAME)
65
- end
66
-
67
- def self.image_dir
68
- @image_dir ||= File.join(source_dir,IMAGE_DIRNAME)
69
- end
70
-
71
- def_delegators self, :source_dir, :set_source_dir, :template_dir, :preview_dir, :package_dir, :gem_root_dir, :stylesheet_dir, :javascript_dir, :image_dir
72
-
73
3
  BUILD_FILENAME = '_build_cfg.yml'
74
4
  TOPIC_MAP_FILENAME = '_topic_map.yml'
75
5
  DISTRO_MAP_FILENAME = '_distro_map.yml'
@@ -79,823 +9,79 @@ module AsciiBinder
79
9
  JAVASCRIPT_DIRNAME = '_javascripts'
80
10
  IMAGE_DIRNAME = '_images'
81
11
  BLANK_STRING_RE = Regexp.new('^\s*$')
82
- IFDEF_STRING_RE = Regexp.new('ifdef::(.+?)\[\]')
83
-
84
- def build_date
85
- Time.now.utc
86
- end
87
-
88
- def notice(hey,message,newline = false)
89
- # TODO: (maybe) redirect everything to stderr
90
- if newline
91
- puts "\n"
92
- end
93
- puts "#{hey}: #{message}"
94
- end
95
-
96
- def warning(message,newline = false)
97
- notice("WARNING",message,newline)
98
- end
99
-
100
- def nl_warning(message)
101
- warning(message,true)
102
- end
103
-
104
- def git
105
- @git ||= Git.open(source_dir)
106
- end
107
-
108
- def git_checkout branch_name
109
- target_branch = git.branches.local.select{ |b| b.name == branch_name }[0]
110
- if not target_branch.nil? and not target_branch.current
111
- target_branch.checkout
112
- end
113
- end
114
-
115
- def git_stash_all
116
- # See if there are any changes in need of stashing
117
- @stash_needed = `cd #{source_dir} && git status --porcelain` !~ /^\s*$/
118
- if @stash_needed
119
- puts "\nNOTICE: Stashing uncommited changes and files in working branch."
120
- `cd #{source_dir} && git stash -u`
121
- end
122
- end
123
-
124
- def git_apply_and_drop
125
- return unless @stash_needed
126
- puts "\nNOTE: Re-applying uncommitted changes and files to working branch."
127
- if system("cd #{source_dir} && git stash pop")
128
- puts "NOTE: Stash application successful."
129
- else
130
- puts "ERROR: Could not apply stashed code. Run `git stash apply` manually."
131
- end
132
- @stash_needed = false
133
- end
134
-
135
- # Returns the local git branches; current branch is always first
136
- def local_branches
137
- @local_branches ||= begin
138
- branches = []
139
- if not git.branches.local.empty?
140
- branches << git.branches.local.select{ |b| b.current }[0].name
141
- branches << git.branches.local.select{ |b| not b.current }.map{ |b| b.name }
142
- end
143
- branches.flatten
144
- end
145
- end
146
-
147
- def working_branch
148
- @working_branch ||= local_branches[0]
149
- end
150
-
151
- def build_config_file
152
- use_file = TOPIC_MAP_FILENAME
153
- unless File.exist?(File.join(source_dir,TOPIC_MAP_FILENAME))
154
- # The new filename '_topic_map.yml' couldn't be found;
155
- # switch to the old one and warn the user.
156
- use_file = BUILD_FILENAME
157
- warning "'#{BUILD_FILENAME}' is a deprecated filename. Rename this to '#{TOPIC_MAP_FILENAME}'."
158
- end
159
- use_file
160
- end
161
-
162
- def distro_map_file
163
- @distro_map_file ||= File.join(source_dir, DISTRO_MAP_FILENAME)
164
- end
165
-
166
- def dir_empty?(dir)
167
- Dir.entries(dir).select{ |f| not f.start_with?('.') }.empty?
168
- end
169
-
170
- # Protip: Don't cache this! It needs to be reread every time we change branches.
171
- def build_config
172
- validate_config(YAML.load_stream(open(File.join(source_dir,build_config_file))))
173
- end
174
-
175
- def create_new_repo
176
- gem_template_dir = File.join(gem_root_dir,"templates")
177
-
178
- # Create the new repo dir
179
- FileUtils.mkdir_p(source_dir)
180
-
181
- # Copy the basic repo content into the new repo dir
182
- Find.find(gem_template_dir).each do |path|
183
- next if path == gem_template_dir
184
- src_path = Pathname.new(path)
185
- tgt_path = src_path.sub(gem_template_dir,source_dir)
186
- if src_path.directory?
187
- FileUtils.mkdir_p(tgt_path.to_s)
188
- else
189
- FileUtils.cp src_path.to_s, tgt_path.to_s
190
- end
191
- end
192
-
193
- # Initialize the git repo
194
- Git.init(source_dir)
195
- end
196
-
197
- def find_topic_files
198
- file_list = []
199
- Find.find(source_dir).each do |path|
200
- # Only consider .adoc files and ignore README, and anything in
201
- # directories whose names begin with 'old' or '_' (underscore)
202
- next if path.nil? or not path =~ /.*\.adoc/ or path =~ /README/ or path =~ /\/old\// or path =~ /\/_/
203
- src_path = Pathname.new(path).sub(source_dir,'').to_s
204
- next if src_path.split('/').length < 3
205
- file_list << src_path
206
- end
207
- file_list.map{ |path|
208
- parts = path.split('/').slice(1..-1);
209
- parts.slice(0..-2).join('/') + '/' + parts[-1].split('.')[0]
210
- }
211
- end
212
-
213
- def remove_found_config_files(branch,branch_build_config,branch_topic_files)
214
- nonexistent_topics = []
215
- branch_build_config.each do |topic_group|
216
- tg_dir = topic_group['Dir']
217
- topic_group['Topics'].each do |topic|
218
- if topic.has_key?('File')
219
- topic_path = tg_dir + '/' + topic['File']
220
- result = branch_topic_files.delete(topic_path)
221
- if result.nil?
222
- nonexistent_topics << topic_path
223
- end
224
- elsif topic.has_key?('Dir')
225
- topic_path = tg_dir + '/' + topic['Dir'] + '/'
226
- topic['Topics'].each do |subtopic|
227
- result = branch_topic_files.delete(topic_path + subtopic['File'])
228
- if result.nil?
229
- nonexistent_topics << topic_path + subtopic['File']
230
- end
231
- end
232
- end
233
- end
234
- end
235
- if nonexistent_topics.length > 0
236
- nl_warning "The #{build_config_file} file on branch '#{branch}' references nonexistant topics:\n" + nonexistent_topics.map{ |topic| "- #{topic}" }.join("\n")
237
- end
238
- end
239
-
240
- def distro_map
241
- @distro_map ||= YAML.load_file(distro_map_file)
242
- end
243
-
244
- def site_map
245
- site_map = {}
246
- distro_map.each do |distro,distro_config|
247
- if not site_map.has_key?(distro_config["site"])
248
- site_map[distro_config["site"]] = { :distros => {}, :name => distro_config['site_name'], :url => distro_config['site_url'], :branches => ['master'] }
249
- end
250
- site_map[distro_config["site"]][:distros][distro] = distro_config["branches"]
251
- distro_config["branches"].keys.each do |branch_key|
252
- next if site_map[distro_config["site"]][:branches].include?(branch_key)
253
- site_map[distro_config["site"]][:branches] << branch_key
254
- end
255
- end
256
- site_map
257
- end
258
-
259
- def distro_branches(use_distro='')
260
- use_distro_list = use_distro == '' ? distro_map.keys : [use_distro]
261
- distro_map.select{ |dkey,dval| use_distro_list.include?(dkey) }.map{ |distro,dconfig| dconfig["branches"].keys }.flatten.uniq
262
- end
263
-
264
- def branch_group_branches
265
- @branch_group_branches ||= begin
266
- group_branches = Hash.new
267
- group_branches[:working_only] = [local_branches[0]]
268
- group_branches[:publish] = distro_branches
269
- site_map.each do |site,site_config|
270
- group_branches["publish_#{site}".to_sym] = site_config[:branches]
271
- end
272
- group_branches[:all] = local_branches
273
- group_branches
274
- end
275
- end
276
-
277
- def page(args)
278
- # TODO: This process of rebuilding the entire nav for every page will not scale well.
279
- # As the doc set increases, we will need to think about refactoring this.
280
- args[:breadcrumb_root], args[:breadcrumb_group], args[:breadcrumb_subgroup], args[:breadcrumb_topic] = extract_breadcrumbs(args)
281
-
282
- args[:breadcrumb_subgroup_block] = ''
283
- args[:subtopic_shim] = ''
284
- if args[:breadcrumb_subgroup]
285
- args[:breadcrumb_subgroup_block] = "<li class=\"hidden-xs active\">#{args[:breadcrumb_subgroup]}</li>"
286
- args[:subtopic_shim] = '../'
287
- end
288
-
289
- template_path = File.expand_path("#{source_dir}/_templates/page.html.erb")
290
- template_renderer.render(template_path, args)
291
- end
12
+ ID_STRING_RE = Regexp.new('^[A-Za-z0-9\-\_]+$')
292
13
 
293
- def extract_breadcrumbs(args)
294
- breadcrumb_root = breadcrumb_group = breadcrumb_subgroup = breadcrumb_topic = nil
295
-
296
- root_group = args[:navigation].first
297
- selected_group = args[:navigation].detect { |group| group[:id] == args[:group_id] }
298
- selected_subgroup = selected_group[:topics].detect { |subgroup| subgroup[:id] == args[:subgroup_id] }
299
- current_is_subtopic = selected_subgroup ? true : false
300
-
301
- if root_group
302
- root_topic = root_group[:topics].first
303
- breadcrumb_root = linkify_breadcrumb(root_topic[:path], "#{args[:distro]} #{args[:version]}", current_is_subtopic) if root_topic
304
- end
305
-
306
- if selected_group
307
- group_topic = selected_group[:topics].first
308
- breadcrumb_group = linkify_breadcrumb(group_topic[:path], selected_group[:name], current_is_subtopic) if group_topic
309
-
310
- if selected_subgroup
311
- subgroup_topic = selected_subgroup[:topics].first
312
- breadcrumb_subgroup = linkify_breadcrumb(subgroup_topic[:path], selected_subgroup[:name], current_is_subtopic) if subgroup_topic
313
-
314
- selected_topic = selected_subgroup[:topics].detect { |topic| topic[:id] == args[:topic_id] }
315
- breadcrumb_topic = linkify_breadcrumb(nil, selected_topic[:name], current_is_subtopic) if selected_topic
316
- else
317
- selected_topic = selected_group[:topics].detect { |topic| topic[:id] == args[:topic_id] }
318
- breadcrumb_topic = linkify_breadcrumb(nil, selected_topic[:name], current_is_subtopic) if selected_topic
319
- end
320
- end
321
-
322
- return breadcrumb_root, breadcrumb_group, breadcrumb_subgroup, breadcrumb_topic
14
+ def valid_id?(check_id)
15
+ return false unless check_id.is_a?(String)
16
+ return false unless check_id.match ID_STRING_RE
17
+ return true
323
18
  end
324
19
 
325
- def linkify_breadcrumb(href, text, extra_level)
326
- addl_level = extra_level ? '../' : ''
327
- href ? "<a href=\"#{addl_level}#{href}\">#{text}</a>" : text
20
+ def valid_string?(check_string)
21
+ return false unless check_string.is_a?(String)
22
+ return false unless check_string.length > 0
23
+ return false if check_string.match BLANK_STRING_RE
24
+ return true
328
25
  end
329
26
 
330
- def parse_distros distros_string, for_validation=false
331
- values = distros_string.split(',').map(&:strip)
332
- # Don't bother with glob expansion if 'all' is in the list.
333
- return distro_map.keys if values.include?('all')
334
-
335
- expanded = expand_distro_globs(values)
336
- return expanded if for_validation
337
- return expanded.uniq
27
+ def camelize(text)
28
+ text.gsub(/[^0-9a-zA-Z ]/i, '').split(' ').map{ |t| t.capitalize }.join
338
29
  end
339
30
 
340
- def expand_distro_globs(values)
341
- values.flat_map do |value|
342
- value_regex = Regexp.new("\\A#{value.gsub("*", ".*")}\\z")
343
- distro_map.keys.select { |k| value_regex.match(k) }
344
- end.uniq
31
+ def git_root_dir
32
+ @git_root_dir ||= `git rev-parse --show-toplevel`.chomp
345
33
  end
346
34
 
347
- def validate_distros distros_string
348
- return false if not distros_string.is_a?(String)
349
- values = parse_distros(distros_string, true)
350
- values.each do |v|
351
- return false if not v == 'all' and not distro_map.keys.include?(v)
352
- end
353
- return true
35
+ def gem_root_dir
36
+ @gem_root_dir ||= File.expand_path("../../../", __FILE__)
354
37
  end
355
38
 
356
- def validate_topic_group group, info
357
- # Check for presence of topic group keys
358
- ['Name','Dir','Topics'].each do |group_key|
359
- if not group.has_key?(group_key)
360
- raise "One of the topic groups in #{build_config_file} is missing the '#{group_key}' key."
361
- end
362
- end
363
- # Check for right format of topic group values
364
- ['Name','Dir'].each do |group_key|
365
- if [true, false].include?(group[group_key])
366
- raise "One of the topic groups in #{build_config_file} is using a reserved YAML keyword for the #{group_key} setting. In order to prevent your text from being turned into a true/false value, wrap it in quotes."
367
- end
368
- if not group[group_key].kind_of?(String)
369
- raise "One of the topic groups in #{build_config_file} is not using a string for the #{group_key} setting; current value is #{group[group_key].inspect}"
370
- end
371
- if group[group_key].empty? or group[group_key].match BLANK_STRING_RE
372
- raise "One of the topic groups in #{build_config_file} is using a blank value for the #{group_key} setting."
373
- end
374
- end
375
- if not File.exists?(File.join(source_dir,info[:path]))
376
- raise "In #{build_config_file}, the directory path '#{info[:path]}' for topic group #{group['Name']} does not exist under #{source_dir}"
377
- end
378
- # Validate the Distros setting
379
- if group.has_key?('Distros')
380
- if not validate_distros(group['Distros'])
381
- key_list = distro_map.keys.map{ |k| "'#{k}'" }.sort.join(', ')
382
- raise "In #{build_config_file}, the Distros value #{group['Distros'].inspect} for topic group #{group['Name']} is not valid. Legal values are 'all', #{key_list}, or a comma-separated list of legal values."
383
- end
384
- group['Distros'] = parse_distros(group['Distros'])
385
- else
386
- group['Distros'] = parse_distros('all')
387
- end
388
- if not group['Topics'].is_a?(Array)
389
- raise "The #{group['Name']} topic group in #{build_config_file} is malformed; the build system is expecting an array of 'Topic' definitions."
390
- end
391
- # Generate an ID for this topic group
392
- group['ID'] = camelize group['Name']
393
- if info.has_key?(:parent_id)
394
- group['ID'] = "#{info[:parent_id]}::#{group['ID']}"
395
- end
39
+ def set_docs_root_dir(docs_root_dir)
40
+ AsciiBinder.const_set("DOCS_ROOT_DIR", docs_root_dir)
396
41
  end
397
42
 
398
- def validate_topic_item item, info
399
- ['Name','File'].each do |topic_key|
400
- if not item[topic_key].is_a?(String)
401
- raise "In #{build_config_file}, topic group #{info[:group]}, one of the topics is not using a string for the '#{topic_key}' setting; current value is #{item[topic_key].inspect}"
402
- end
403
- if item[topic_key].empty? or item[topic_key].match BLANK_STRING_RE
404
- raise "In #{build_config_file}, topic group #{topic_group['Name']}, one of the topics is using a blank value for the '#{topic_key}' setting"
405
- end
406
- end
407
- # Normalize the filenames
408
- if item['File'].end_with?('.adoc')
409
- item['File'] = item['File'][0..-6]
410
- end
411
- if not File.exists?(File.join(source_dir,info[:path],"#{item['File']}.adoc"))
412
- raise "In #{build_config_file}, could not find file #{item['File']} under directory #{info[:path]} for topic #{item['Name']} in topic group #{info[:group]}."
413
- end
414
- if item.has_key?('Distros')
415
- if not validate_distros(item['Distros'])
416
- key_list = distro_map.keys.map{ |k| "'#{k}'" }.sort.join(', ')
417
- raise "In #{build_config_file}, the Distros value #{item['Distros'].inspect} for topic item #{item['Name']} in topic group #{info[:group]} is not valid. Legal values are 'all', #{key_list}, or a comma-separated list of legal values."
418
- end
419
- item['Distros'] = parse_distros(item['Distros'])
420
- else
421
- item['Distros'] = parse_distros('all')
422
- end
423
- # Generate an ID for this topic
424
- item['ID'] = "#{info[:group_id]}::#{camelize(item['Name'])}"
43
+ def docs_root_dir
44
+ AsciiBinder::DOCS_ROOT_DIR
425
45
  end
426
46
 
427
- def validate_config config_data
428
- # Validate/normalize the config file straight away
429
- if not config_data.is_a?(Array)
430
- raise "The configuration in #{build_config_file} is malformed; the build system is expecting an array of topic groups."
431
- end
432
- config_data.each do |topic_group|
433
- validate_topic_group(topic_group, { :path => topic_group['Dir'] })
434
- # Now buzz through the topics
435
- topic_group['Topics'].each do |topic|
436
- # Is this an actual topic or a subtopic group?
437
- is_subtopic_group = topic.has_key?('Dir') and topic.has_key?('Topics') and not topic.has_key?('File')
438
- is_topic_item = topic.has_key?('File') and not topic.has_key?('Dir') and not topic.has_key?('Topics')
439
- if not is_subtopic_group and not is_topic_item
440
- raise "This topic could not definitively be determined to be a topic item or a subtopic group:\n#{topic.inspect}"
441
- end
442
- if is_topic_item
443
- validate_topic_item(topic, { :group => topic_group['Name'], :group_id => topic_group['ID'], :path => topic_group['Dir'] })
444
- elsif is_subtopic_group
445
- topic_path = "#{topic_group['Dir']}/#{topic['Dir']}"
446
- validate_topic_group(topic, { :path => topic_path, :parent_id => topic_group['ID'] })
447
- topic['Topics'].each do |subtopic|
448
- validate_topic_item(subtopic, { :group => "#{topic_group['Name']}/#{topic['Name']}", :group_id => topic['ID'], :path => topic_path })
449
- end
450
- end
451
- end
452
- end
453
- config_data
47
+ def template_renderer
48
+ @template_renderer ||= TemplateRenderer.new(docs_root_dir, template_dir)
454
49
  end
455
50
 
456
- def camelize text
457
- text.gsub(/[^0-9a-zA-Z ]/i, '').split(' ').map{ |t| t.capitalize }.join
51
+ def template_dir
52
+ @template_dir ||= File.join(docs_root_dir,'_templates')
458
53
  end
459
54
 
460
- def nav_tree distro, branch_build_config
461
- navigation = []
462
- branch_build_config.each do |topic_group|
463
- next if not topic_group['Distros'].include?(distro)
464
- next if topic_group['Topics'].select{ |t| t['Distros'].include?(distro) }.length == 0
465
- topic_list = []
466
- topic_group['Topics'].each do |topic|
467
- next if not topic['Distros'].include?(distro)
468
- if topic.has_key?('File')
469
- topic_list << {
470
- :path => "../#{topic_group['Dir']}/#{topic['File']}.html",
471
- :name => topic['Name'],
472
- :id => topic['ID'],
473
- }
474
- elsif topic.has_key?('Dir')
475
- next if topic['Topics'].select{ |t| t['Distros'].include?(distro) }.length == 0
476
- subtopic_list = []
477
- topic['Topics'].each do |subtopic|
478
- next if not subtopic['Distros'].include?(distro)
479
- subtopic_list << {
480
- :path => "../#{topic_group['Dir']}/#{topic['Dir']}/#{subtopic['File']}.html",
481
- :name => subtopic['Name'],
482
- :id => subtopic['ID'],
483
- }
484
- end
485
- topic_list << { :name => topic['Name'], :id => topic['ID'], :topics => subtopic_list }
486
- end
55
+ def preview_dir
56
+ @preview_dir ||= begin
57
+ lpreview_dir = File.join(docs_root_dir,PREVIEW_DIRNAME)
58
+ if not File.exists?(lpreview_dir)
59
+ Dir.mkdir(lpreview_dir)
487
60
  end
488
- navigation << { :name => topic_group['Name'], :id => topic_group['ID'], :topics => topic_list }
61
+ lpreview_dir
489
62
  end
490
- navigation
491
63
  end
492
64
 
493
- def asciidoctor_page_attrs(more_attrs=[])
494
- [
495
- 'source-highlighter=coderay',
496
- 'coderay-css=style',
497
- 'linkcss!',
498
- 'icons=font',
499
- 'idprefix=',
500
- 'idseparator=-',
501
- 'sectanchors',
502
- 'data-uri',
503
- ].concat(more_attrs)
504
- end
505
-
506
- def generate_docs(branch_group,build_distro,single_page)
507
- # First, test to see if the docs repo has any commits. If the user has just
508
- # run `asciibinder create`, there will be no commits to work from, yet.
509
- if local_branches.empty?
510
- raise "Before you can build the docs, you need at least one commit in your docs repo."
511
- end
512
-
513
- single_page_dir = []
514
- single_page_file = nil
515
- if not single_page.nil?
516
- single_page_dir = single_page.split(':')[0].split('/')
517
- single_page_file = single_page.split(':')[1]
518
- puts "Rebuilding '#{single_page_dir.join('/')}/#{single_page_file}' on branch '#{working_branch}'."
519
- end
520
-
521
- if not build_distro == ''
522
- if not distro_map.has_key?(build_distro)
523
- exit
524
- else
525
- puts "Building only the #{distro_map[build_distro]["name"]} distribution."
526
- end
527
- elsif single_page.nil?
528
- puts "Building all distributions."
529
- end
530
-
531
- # First, notify the user of missing local branches
532
- missing_branches = []
533
- distro_branches(build_distro).sort.each do |dbranch|
534
- next if local_branches.include?(dbranch)
535
- missing_branches << dbranch
536
- end
537
- if missing_branches.length > 0 and single_page.nil?
538
- puts "\nNOTE: The following branches do not exist in your local git repo:"
539
- missing_branches.each do |mbranch|
540
- puts "- #{mbranch}"
541
- end
542
- puts "The build will proceed but these branches will not be generated."
543
- end
544
-
545
- # Generate all distros for all branches in the indicated branch group
546
- branch_group_branches[branch_group].each do |local_branch|
547
- # Skip known missing branches; this will only come up for the :publish branch group
548
- next if missing_branches.include?(local_branch)
549
-
550
- # Single-page regen only occurs for the working branch
551
- if not local_branch == working_branch
552
- if single_page.nil?
553
- # Checkout the branch
554
- puts "\nCHANGING TO BRANCH '#{local_branch}'"
555
- git_checkout(local_branch)
556
- else
557
- next
558
- end
559
- end
560
-
561
- # Note the image files checked in to this branch.
562
- branch_image_files = Find.find(source_dir).select{ |path| not path.nil? and (path =~ /.*\.png$/ or path =~ /.*\.png\.cache$/) }
563
-
564
- first_branch = single_page.nil?
565
-
566
- if local_branch =~ /^\(detached from .*\)/
567
- local_branch = 'detached'
568
- end
569
-
570
- # The branch_orphan_files list starts with the set of all
571
- # .adoc files found in the repo, and will be whittled
572
- # down from there.
573
- branch_orphan_files = find_topic_files
574
- branch_build_config = build_config
575
- remove_found_config_files(local_branch,branch_build_config,branch_orphan_files)
576
-
577
- if branch_orphan_files.length > 0 and single_page.nil?
578
- nl_warning "Branch '#{local_branch}' includes the following .adoc files that are not referenced in the #{build_config_file} file:\n" + branch_orphan_files.map{ |file| "- #{file}" }.join("\n")
579
- end
580
-
581
- # Run all distros.
582
- distro_map.each do |distro,distro_config|
583
- if not build_distro == ''
584
- # Only building a single distro; build for all indicated branches, skip the others.
585
- if not build_distro == distro
586
- next
587
- end
588
- else
589
- current_distro_branches = distro_branches(distro)
590
-
591
- # In publish mode we only build "valid" distro-branch combos from the distro map
592
- if branch_group.to_s.start_with?("publish") and not current_distro_branches.include?(local_branch)
593
- next
594
- end
595
-
596
- # In "build all" mode we build every distro on the working branch plus the publish distro-branch combos
597
- if branch_group == :all and not local_branch == working_branch and not current_distro_branches.include?(local_branch)
598
- next
599
- end
600
- end
601
-
602
- site_name = distro_config["site_name"]
603
-
604
- branch_config = { "name" => "Branch Build", "dir" => local_branch }
605
- dev_branch = true
606
- if distro_config["branches"].has_key?(local_branch)
607
- branch_config = distro_config["branches"][local_branch]
608
- dev_branch = false
609
- end
610
-
611
- if first_branch
612
- puts "\nBuilding #{distro_config["name"]} for branch '#{local_branch}'"
613
- first_branch = false
614
- end
615
-
616
- # Create the target dir
617
- branch_path = File.join(preview_dir,distro,branch_config["dir"])
618
- branch_stylesheet_dir = File.join(branch_path,STYLESHEET_DIRNAME)
619
- branch_javascript_dir = File.join(branch_path,JAVASCRIPT_DIRNAME)
620
- branch_image_dir = File.join(branch_path,IMAGE_DIRNAME)
621
-
622
- # Copy files into the preview area.
623
- [[stylesheet_dir, '*css', branch_stylesheet_dir],
624
- [javascript_dir, '*js', branch_javascript_dir],
625
- [image_dir, '*', branch_image_dir]].each do |dgroup|
626
- src_dir = dgroup[0]
627
- glob = dgroup[1]
628
- tgt_dir = dgroup[2]
629
- if Dir.exist?(src_dir) and not dir_empty?(src_dir)
630
- FileUtils.mkdir_p tgt_dir
631
- FileUtils.cp_r Dir.glob(File.join(src_dir,glob)), tgt_dir
632
- end
633
- end
634
-
635
- # Build the landing page
636
- navigation = nav_tree(distro,branch_build_config)
637
-
638
- # Build the topic files for this branch & distro
639
- branch_build_config.each do |topic_group|
640
- next if not topic_group['Distros'].include?(distro)
641
- next if topic_group['Topics'].select{ |t| t['Distros'].include?(distro) }.length == 0
642
- next if not single_page.nil? and not single_page_dir[0] == topic_group['Dir']
643
- topic_group['Topics'].each do |topic|
644
- src_group_path = File.join(source_dir,topic_group['Dir'])
645
- tgt_group_path = File.join(branch_path,topic_group['Dir'])
646
- if not File.exists?(tgt_group_path)
647
- Dir.mkdir(tgt_group_path)
648
- end
649
- next if not topic['Distros'].include?(distro)
650
- if topic.has_key?('File')
651
- next if not single_page.nil? and not topic['File'] == single_page_file
652
- topic_path = File.join(topic_group['Dir'],topic['File'])
653
- configure_and_generate_page({
654
- :distro => distro,
655
- :distro_config => distro_config,
656
- :branch_config => branch_config,
657
- :navigation => navigation,
658
- :topic => topic,
659
- :topic_group => topic_group,
660
- :topic_path => topic_path,
661
- :src_group_path => src_group_path,
662
- :tgt_group_path => tgt_group_path,
663
- :single_page => single_page,
664
- :site_name => site_name,
665
- })
666
- elsif topic.has_key?('Dir')
667
- next if not single_page.nil? and not single_page_dir.join('/') == topic_group['Dir'] + '/' + topic['Dir']
668
- topic['Topics'].each do |subtopic|
669
- next if not subtopic['Distros'].include?(distro)
670
- next if not single_page.nil? and not subtopic['File'] == single_page_file
671
- src_group_path = File.join(source_dir,topic_group['Dir'],topic['Dir'])
672
- tgt_group_path = File.join(branch_path,topic_group['Dir'],topic['Dir'])
673
- if not File.exists?(tgt_group_path)
674
- Dir.mkdir(tgt_group_path)
675
- end
676
- topic_path = File.join(topic_group['Dir'],topic['Dir'],subtopic['File'])
677
- configure_and_generate_page({
678
- :distro => distro,
679
- :distro_config => distro_config,
680
- :branch_config => branch_config,
681
- :navigation => navigation,
682
- :topic => subtopic,
683
- :topic_group => topic_group,
684
- :topic_subgroup => topic,
685
- :topic_path => topic_path,
686
- :src_group_path => src_group_path,
687
- :tgt_group_path => tgt_group_path,
688
- :single_page => single_page,
689
- :site_name => site_name,
690
- })
691
- end
692
- end
693
- end
694
- end
695
-
696
- if not single_page.nil?
697
- next
698
- end
699
-
700
- # Create a distro landing page
701
- # This is backwards compatible code. We can remove it when no
702
- # official repo uses index.adoc. We are moving to flat HTML
703
- # files for index.html
704
- src_file_path = File.join(source_dir,'index.adoc')
705
- if File.exists?(src_file_path)
706
- topic_adoc = File.open(src_file_path,'r').read
707
- page_attrs = asciidoctor_page_attrs([
708
- "imagesdir=#{File.join(source_dir,'_site_images')}",
709
- distro,
710
- "product-title=#{distro_config["name"]}",
711
- "product-version=Updated #{build_date}",
712
- "product-author=#{distro_config["author"]}"
713
- ])
714
- topic_html = Asciidoctor.render topic_adoc, :header_footer => true, :safe => :unsafe, :attributes => page_attrs
715
- File.write(File.join(preview_dir,distro,'index.html'),topic_html)
716
- end
717
- end
718
-
719
- if not single_page.nil?
720
- return
721
- end
722
-
723
- # Remove DITAA-generated images
724
- ditaa_image_files = Find.find(source_dir).select{ |path| not path.nil? and not (path =~ /_preview/ or path =~ /_package/) and (path =~ /.*\.png$/ or path =~ /.*\.png\.cache$/) and not branch_image_files.include?(path) }
725
- if not ditaa_image_files.empty?
726
- puts "\nRemoving ditaa-generated files from repo before changing branches."
727
- ditaa_image_files.each do |dfile|
728
- File.unlink(dfile)
729
- end
730
- end
731
-
732
- if local_branch == working_branch
733
- # We're moving away from the working branch, so save off changed files
734
- git_stash_all
65
+ def package_dir
66
+ @package_dir ||= begin
67
+ lpackage_dir = File.join(docs_root_dir,PACKAGE_DIRNAME)
68
+ if not File.exists?(lpackage_dir)
69
+ Dir.mkdir(lpackage_dir)
735
70
  end
71
+ lpackage_dir
736
72
  end
737
-
738
- # Return to the original branch
739
- git_checkout(working_branch)
740
-
741
- # If necessary, restore temporarily stashed files
742
- git_apply_and_drop
743
-
744
- puts "\nAll builds completed."
745
73
  end
746
74
 
747
- def configure_and_generate_page options
748
- distro = options[:distro]
749
- distro_config = options[:distro_config]
750
- branch_config = options[:branch_config]
751
- navigation = options[:navigation]
752
- topic = options[:topic]
753
- topic_group = options[:topic_group]
754
- topic_subgroup = options[:topic_subgroup]
755
- topic_path = options[:topic_path]
756
- src_group_path = options[:src_group_path]
757
- tgt_group_path = options[:tgt_group_path]
758
- single_page = options[:single_page]
759
- site_name = options[:site_name]
760
-
761
- # Distro Map settings can be overridden on a per-branch
762
- # basis. This only works for top-level (string) values
763
- # of the distro config and -not- the 'site' key.
764
- branchwise_distro_config = {}
765
- distro_config.each do |key,value|
766
- next unless distro_config[key].kind_of?(String)
767
- branchwise_distro_config[key] = value
768
- end
769
- if branch_config.has_key?('distro-overrides')
770
- branch_config['distro-overrides'].each do |key,value|
771
- if key == 'site'
772
- puts "WARNING: The 'site' value of the distro config cannot be overriden on a branch-by-branch basis."
773
- next
774
- end
775
- branchwise_distro_config[key] = value
776
- end
777
- end
778
-
779
- src_file_path = File.join(src_group_path,"#{topic['File']}.adoc")
780
- tgt_file_path = File.join(tgt_group_path,"#{topic['File']}.html")
781
- if single_page.nil?
782
- puts " - #{topic_path}"
783
- end
784
- topic_adoc = File.open(src_file_path,'r').read
785
- page_attrs = asciidoctor_page_attrs([
786
- "imagesdir=#{src_group_path}/images",
787
- distro,
788
- "product-title=#{branchwise_distro_config["name"]}",
789
- "product-version=#{branch_config["name"]}",
790
- "product-author=#{branchwise_distro_config["author"]}"
791
- ])
792
-
793
- doc = Asciidoctor.load topic_adoc, :header_footer => false, :safe => :unsafe, :attributes => page_attrs
794
- article_title = doc.doctitle || topic['Name']
795
-
796
- topic_html = doc.render
797
- dir_depth = ''
798
- if branch_config['dir'].split('/').length > 1
799
- dir_depth = '../' * (branch_config['dir'].split('/').length - 1)
800
- end
801
- if not topic_subgroup.nil?
802
- dir_depth = '../' + dir_depth
803
- end
804
- page_args = {
805
- :distro_key => distro,
806
- :distro => branchwise_distro_config["name"],
807
- :site_name => site_name,
808
- :site_url => branchwise_distro_config["site_url"],
809
- :topic_url => "#{branch_config['dir']}/#{topic_path}.html",
810
- :version => branch_config["name"],
811
- :group_title => topic_group['Name'],
812
- :subgroup_title => topic_subgroup && topic_subgroup['Name'],
813
- :topic_title => topic['Name'],
814
- :article_title => article_title,
815
- :content => topic_html,
816
- :navigation => navigation,
817
- :group_id => topic_group['ID'],
818
- :subgroup_id => topic_subgroup && topic_subgroup['ID'],
819
- :topic_id => topic['ID'],
820
- :css_path => "../../#{dir_depth}#{branch_config["dir"]}/#{STYLESHEET_DIRNAME}/",
821
- :javascripts_path => "../../#{dir_depth}#{branch_config["dir"]}/#{JAVASCRIPT_DIRNAME}/",
822
- :images_path => "../../#{dir_depth}#{branch_config["dir"]}/#{IMAGE_DIRNAME}/",
823
- :site_home_path => "../../#{dir_depth}index.html",
824
- :template_path => template_dir,
825
- }
826
- full_file_text = page(page_args)
827
- File.write(tgt_file_path,full_file_text)
75
+ def stylesheet_dir
76
+ @stylesheet_dir ||= File.join(docs_root_dir,STYLESHEET_DIRNAME)
828
77
  end
829
78
 
830
- # package_docs
831
- # This method generates the docs and then organizes them the way they will be arranged
832
- # for the production websites.
833
- def package_docs(package_site)
834
- site_map.each do |site,site_config|
835
- next if not package_site == '' and not package_site == site
836
- site_config[:distros].each do |distro,branches|
837
- branches.each do |branch,branch_config|
838
- src_dir = File.join(preview_dir,distro,branch_config["dir"])
839
- tgt_tdir = branch_config["dir"].split('/')
840
- tgt_tdir.pop
841
- tgt_dir = ''
842
- if tgt_tdir.length > 0
843
- tgt_dir = File.join(package_dir,site,tgt_tdir.join('/'))
844
- else
845
- tgt_dir = File.join(package_dir,site)
846
- end
847
- next if not File.directory?(src_dir)
848
- FileUtils.mkdir_p(tgt_dir)
849
- FileUtils.cp_r(src_dir,tgt_dir)
850
- end
851
- site_dir = File.join(package_dir,site)
852
- if File.directory?(site_dir)
853
- puts "\nBuilding #{site} site."
854
-
855
- # Any files in the root of the docs repo with names ending in:
856
- # *-#{site}.html
857
- # will get copied into the root dir of the packaged site with
858
- # the site name stripped out.
859
- #
860
- # Example: for site name 'commercial', the files:
861
- # * index-commercial.html would end up as #{site_root}/index.html
862
- # * search-commercial.html would end up as #{site_root}/search.html
863
- # * index-community.html would be ignored
864
- site_files = Dir.glob(File.join(source_dir, '*-' + site + '.html'))
865
- unless site_files.empty?
866
- site_files.each do |fpath|
867
- target_basename = File.basename(fpath).gsub(/-#{site}\.html$/, '.html')
868
- FileUtils.cp(fpath,File.join(package_dir,site,target_basename))
869
- end
870
- else
871
- FileUtils.cp(File.join(preview_dir,distro,'index.html'),File.join(package_dir,site,'index.html'))
872
- end
873
- ['_images','_stylesheets'].each do |support_dir|
874
- FileUtils.cp_r(File.join(source_dir,support_dir),File.join(package_dir,site,support_dir))
875
- end
876
-
877
- # Now build a sitemap
878
- site_dir_path = Pathname.new(site_dir)
879
- SitemapGenerator::Sitemap.create(
880
- :default_host => site_config[:url],
881
- :public_path => site_dir_path,
882
- :compress => false,
883
- :filename => File.join(site_dir,'sitemap')
884
- ) do
885
- file_list = Find.find(site_dir).select{ |path| not path.nil? and path =~ /.*\.html$/ }.map{ |path| '/' + Pathname.new(path).relative_path_from(site_dir_path).to_s }
886
- file_list.each do |file|
887
- add(file, :changefreq => 'daily')
888
- end
889
- end
890
- end
891
- end
892
- end
79
+ def javascript_dir
80
+ @javascript_dir ||= File.join(docs_root_dir,JAVASCRIPT_DIRNAME)
893
81
  end
894
82
 
895
- def clean_up
896
- if not system("rm -rf #{source_dir}/_preview/* #{source_dir}/_package/*")
897
- puts "Nothing to clean."
898
- end
83
+ def image_dir
84
+ @image_dir ||= File.join(docs_root_dir,IMAGE_DIRNAME)
899
85
  end
900
86
  end
901
87
  end