ascii_binder 0.1.9 → 0.1.10

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