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.
- checksums.yaml +4 -4
- data/.travis.yml +16 -0
- data/ascii_binder.gemspec +5 -3
- data/bin/asciibinder +53 -44
- data/features/command_help.feature +8 -0
- data/features/command_version.feature +8 -0
- data/features/repo_build.feature +34 -0
- data/features/repo_clean.feature +20 -0
- data/features/repo_clone.feature +22 -0
- data/features/repo_create.feature +13 -0
- data/features/repo_package.feature +15 -0
- data/features/step_definitions/steps.rb +182 -0
- data/features/support/_clone_distro_map.yml +14 -0
- data/features/support/_invalid_distro_map.yml +14 -0
- data/features/support/env.rb +468 -0
- data/features/support/test_distro/.gitignore +9 -0
- data/features/support/test_distro/_distro_map.yml +29 -0
- data/features/support/test_distro/_images/asciibinder-logo-horizontal.png +0 -0
- data/features/support/test_distro/_images/asciibinder_web_logo.svg +125 -0
- data/features/support/test_distro/_images/book_pages_bg.jpg +0 -0
- data/features/support/test_distro/_images/favicon.ico +0 -0
- data/features/support/test_distro/_images/favicon32x32.png +0 -0
- data/features/support/test_distro/_javascripts/.gitkeep +0 -0
- data/features/support/test_distro/_stylesheets/asciibinder.css +568 -0
- data/features/support/test_distro/_templates/_css.html.erb +3 -0
- data/features/support/test_distro/_templates/_nav.html.erb +31 -0
- data/features/support/test_distro/_templates/page.html.erb +92 -0
- data/features/support/test_distro/_topic_map.yml +36 -0
- data/features/support/test_distro/index-main.html +10 -0
- data/features/support/test_distro/index-test.html +10 -0
- data/features/support/test_distro/main_only_topic_group/index.adoc +17 -0
- data/features/support/test_distro/test_only_topic_group/index.adoc +17 -0
- data/features/support/test_distro/welcome/index.adoc +17 -0
- data/features/support/test_distro/welcome/subtopics/index.adoc +17 -0
- data/features/support/test_distro/welcome/subtopics/main_only_topic.adoc +17 -0
- data/features/support/test_distro/welcome/subtopics/test_only_topic.adoc +17 -0
- data/features/support/test_distro/welcome/subtopics/wildcard_all.adoc +17 -0
- data/lib/ascii_binder.rb +4 -2
- data/lib/ascii_binder/distro.rb +111 -0
- data/lib/ascii_binder/distro_branch.rb +93 -0
- data/lib/ascii_binder/distro_map.rb +67 -0
- data/lib/ascii_binder/engine.rb +581 -0
- data/lib/ascii_binder/helpers.rb +42 -856
- data/lib/ascii_binder/site.rb +52 -0
- data/lib/ascii_binder/site_info.rb +22 -0
- data/lib/ascii_binder/site_map.rb +24 -0
- data/lib/ascii_binder/topic_entity.rb +255 -0
- data/lib/ascii_binder/topic_map.rb +61 -0
- data/lib/ascii_binder/version.rb +1 -1
- data/templates/_templates/page.html.erb +1 -1
- metadata +118 -14
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'ascii_binder/distro'
|
2
|
+
require 'trollop'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module AsciiBinder
|
6
|
+
class DistroMap
|
7
|
+
def initialize(distro_map_filepath)
|
8
|
+
@distro_yaml = YAML.load_file(distro_map_filepath)
|
9
|
+
@distro_map = {}
|
10
|
+
@distro_yaml.each do |distro_key,distro_config|
|
11
|
+
if @distro_map.has_key?(distro_key)
|
12
|
+
Trollop::die "Error parsing '#{distro_map_filepath}': distro key '#{distro_key}' is used more than once."
|
13
|
+
end
|
14
|
+
distro = AsciiBinder::Distro.new(distro_map_filepath,distro_key,distro_config)
|
15
|
+
@distro_map[distro_key] = distro
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_distro(distro_key)
|
20
|
+
unless @distro_map.has_key?(distro_key)
|
21
|
+
Trollop::die "Distro key '#{distro_key}' does not exist"
|
22
|
+
end
|
23
|
+
@distro_map[distro_key]
|
24
|
+
end
|
25
|
+
|
26
|
+
def include_distro_key?(distro_key)
|
27
|
+
@distro_map.has_key?(distro_key)
|
28
|
+
end
|
29
|
+
|
30
|
+
def distro_keys
|
31
|
+
@distro_map.keys
|
32
|
+
end
|
33
|
+
|
34
|
+
def distros
|
35
|
+
@distro_map.values
|
36
|
+
end
|
37
|
+
|
38
|
+
def distro_branches(distro_key='')
|
39
|
+
if distro_key == ''
|
40
|
+
branch_list = []
|
41
|
+
distros.each do |distro|
|
42
|
+
branch_list.concat(distro.branch_ids)
|
43
|
+
end
|
44
|
+
return branch_list.uniq
|
45
|
+
else
|
46
|
+
return get_distro(distro_key).branch_ids
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def is_valid?
|
51
|
+
@distro_map.values.each do |distro|
|
52
|
+
next if distro.is_valid?
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
|
58
|
+
def errors
|
59
|
+
errors = []
|
60
|
+
@distro_map.values.each do |distro|
|
61
|
+
next if distro.is_valid?
|
62
|
+
errors << distro.errors
|
63
|
+
end
|
64
|
+
return errors
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,581 @@
|
|
1
|
+
require 'ascii_binder/distro_branch'
|
2
|
+
require 'ascii_binder/distro_map'
|
3
|
+
require 'ascii_binder/helpers'
|
4
|
+
require 'ascii_binder/site_map'
|
5
|
+
require 'ascii_binder/template_renderer'
|
6
|
+
require 'ascii_binder/topic_map'
|
7
|
+
require 'asciidoctor'
|
8
|
+
require 'asciidoctor/cli'
|
9
|
+
require 'asciidoctor-diagram'
|
10
|
+
require 'fileutils'
|
11
|
+
require 'find'
|
12
|
+
require 'git'
|
13
|
+
require 'logger'
|
14
|
+
require 'pandoc-ruby'
|
15
|
+
require 'pathname'
|
16
|
+
require 'sitemap_generator'
|
17
|
+
require 'trollop'
|
18
|
+
require 'yaml'
|
19
|
+
|
20
|
+
include AsciiBinder::Helpers
|
21
|
+
|
22
|
+
module AsciiBinder
|
23
|
+
module Engine
|
24
|
+
|
25
|
+
def build_date
|
26
|
+
Time.now.utc
|
27
|
+
end
|
28
|
+
|
29
|
+
def notice(hey,message,newline = false)
|
30
|
+
# TODO: (maybe) redirect everything to stderr
|
31
|
+
if newline
|
32
|
+
puts "\n"
|
33
|
+
end
|
34
|
+
puts "#{hey}: #{message}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def warning(message,newline = false)
|
38
|
+
notice("WARNING",message,newline)
|
39
|
+
end
|
40
|
+
|
41
|
+
def nl_warning(message)
|
42
|
+
warning(message,true)
|
43
|
+
end
|
44
|
+
|
45
|
+
def git
|
46
|
+
@git ||= Git.open(git_root_dir)
|
47
|
+
end
|
48
|
+
|
49
|
+
def git_checkout branch_name
|
50
|
+
target_branch = git.branches.local.select{ |b| b.name == branch_name }[0]
|
51
|
+
if not target_branch.nil? and not target_branch.current
|
52
|
+
target_branch.checkout
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def git_stash_all
|
57
|
+
# See if there are any changes in need of stashing
|
58
|
+
@stash_needed = `cd #{git_root_dir} && git status --porcelain` !~ /^\s*$/
|
59
|
+
if @stash_needed
|
60
|
+
puts "\nNOTICE: Stashing uncommited changes and files in working branch."
|
61
|
+
`cd #{docs_root_dir} && git stash -u`
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def git_apply_and_drop
|
66
|
+
return unless @stash_needed
|
67
|
+
puts "\nNOTE: Re-applying uncommitted changes and files to working branch."
|
68
|
+
if system("cd #{docs_root_dir} && git stash pop")
|
69
|
+
puts "NOTE: Stash application successful."
|
70
|
+
else
|
71
|
+
puts "ERROR: Could not apply stashed code. Run `git stash apply` manually."
|
72
|
+
end
|
73
|
+
@stash_needed = false
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns the local git branches; current branch is always first
|
77
|
+
def local_branches
|
78
|
+
@local_branches ||= begin
|
79
|
+
branches = []
|
80
|
+
if not git.branches.local.empty?
|
81
|
+
branches << git.branches.local.select{ |b| b.current }[0].name
|
82
|
+
branches << git.branches.local.select{ |b| not b.current }.map{ |b| b.name }
|
83
|
+
end
|
84
|
+
branches.flatten
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def working_branch
|
89
|
+
@working_branch ||= local_branches[0]
|
90
|
+
end
|
91
|
+
|
92
|
+
def dir_empty?(dir)
|
93
|
+
Dir.entries(dir).select{ |f| not f.start_with?('.') }.empty?
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# Protip: Don't cache these! The topic map needs to be reread every time we change branches.
|
98
|
+
def topic_map_file
|
99
|
+
topic_file = TOPIC_MAP_FILENAME
|
100
|
+
unless File.exist?(File.join(docs_root_dir,topic_file))
|
101
|
+
# The new filename '_topic_map.yml' couldn't be found;
|
102
|
+
# switch to the old one and warn the user.
|
103
|
+
topic_file = BUILD_FILENAME
|
104
|
+
unless File.exist?(File.join(docs_root_dir,topic_file))
|
105
|
+
# Critical error - no topic map file at all.
|
106
|
+
Trollop::die "Could not find any topic map file ('#{TOPIC_MAP_FILENAME}' or '#{BUILD_FILENAME}') at #{docs_root_dir} in branch '#{git.branch}'"
|
107
|
+
end
|
108
|
+
warning "'#{BUILD_FILENAME}' is a deprecated filename. Rename this to '#{TOPIC_MAP_FILENAME}'."
|
109
|
+
end
|
110
|
+
topic_file
|
111
|
+
end
|
112
|
+
|
113
|
+
def topic_map
|
114
|
+
topic_map = AsciiBinder::TopicMap.new(topic_map_file,distro_map.distro_keys)
|
115
|
+
unless topic_map.is_valid?
|
116
|
+
errors = topic_map.errors
|
117
|
+
Trollop::die "The topic map file at '#{topic_map_file}' contains the following errors:\n- " + errors.join("\n- ") + "\n"
|
118
|
+
end
|
119
|
+
return topic_map
|
120
|
+
end
|
121
|
+
|
122
|
+
def create_new_repo
|
123
|
+
gem_template_dir = File.join(gem_root_dir,"templates")
|
124
|
+
|
125
|
+
# Create the new repo dir
|
126
|
+
FileUtils.mkdir_p(docs_root_dir)
|
127
|
+
|
128
|
+
# Copy the basic repo content into the new repo dir
|
129
|
+
Find.find(gem_template_dir).each do |path|
|
130
|
+
next if path == gem_template_dir
|
131
|
+
src_path = Pathname.new(path)
|
132
|
+
tgt_path = src_path.sub(gem_template_dir,docs_root_dir)
|
133
|
+
if src_path.directory?
|
134
|
+
FileUtils.mkdir_p(tgt_path.to_s)
|
135
|
+
else
|
136
|
+
FileUtils.cp src_path.to_s, tgt_path.to_s
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Initialize the git repo
|
141
|
+
Git.init(docs_root_dir)
|
142
|
+
end
|
143
|
+
|
144
|
+
def find_topic_files
|
145
|
+
file_list = []
|
146
|
+
Find.find(docs_root_dir).each do |path|
|
147
|
+
# Only consider .adoc files and ignore README, and anything in
|
148
|
+
# directories whose names begin with 'old' or '_' (underscore)
|
149
|
+
next if path.nil? or not path =~ /.*\.adoc/ or path =~ /README/ or path =~ /\/old\// or path =~ /\/_/
|
150
|
+
src_path = Pathname.new(path).sub(docs_root_dir,'').to_s
|
151
|
+
next if src_path.split('/').length < 3
|
152
|
+
file_list << src_path
|
153
|
+
end
|
154
|
+
file_list.map{ |path|
|
155
|
+
parts = path.split('/').slice(1..-1);
|
156
|
+
parts.slice(0..-2).join('/') + '/' + parts[-1].split('.')[0]
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
def remove_found_topic_files(branch,branch_topic_map,branch_topic_files)
|
161
|
+
nonexistent_topics = []
|
162
|
+
branch_topic_map.filepaths.each do |topic_map_filepath|
|
163
|
+
result = branch_topic_files.delete(topic_map_filepath)
|
164
|
+
if result.nil?
|
165
|
+
nonexistent_topics << topic_map_filepath
|
166
|
+
end
|
167
|
+
end
|
168
|
+
if nonexistent_topics.length > 0
|
169
|
+
nl_warning "The #{topic_map_file} file on branch '#{branch}' references nonexistent topics:\n" + nonexistent_topics.map{ |topic| "- #{topic}" }.join("\n")
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def distro_map
|
174
|
+
@distro_map ||= begin
|
175
|
+
distro_map_file = File.join(docs_root_dir, DISTRO_MAP_FILENAME)
|
176
|
+
distro_map = AsciiBinder::DistroMap.new(distro_map_file)
|
177
|
+
unless distro_map.is_valid?
|
178
|
+
errors = distro_map.errors
|
179
|
+
Trollop::die "The distro map file at '#{distro_map_file}' contains the following errors:\n- " + errors.join("\n- ") + "\n"
|
180
|
+
end
|
181
|
+
distro_map
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def site_map
|
186
|
+
@site_map ||= AsciiBinder::SiteMap.new(distro_map)
|
187
|
+
end
|
188
|
+
|
189
|
+
def branch_group_branches
|
190
|
+
@branch_group_branches ||= begin
|
191
|
+
group_branches = Hash.new
|
192
|
+
group_branches[:working_only] = [local_branches[0]]
|
193
|
+
group_branches[:publish] = distro_map.distro_branches
|
194
|
+
site_map.sites.each do |site|
|
195
|
+
group_branches["publish_#{site.id}".to_sym] = site.branches
|
196
|
+
end
|
197
|
+
group_branches[:all] = local_branches
|
198
|
+
group_branches
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def page(args)
|
203
|
+
# TODO: This process of rebuilding the entire nav for every page will not scale well.
|
204
|
+
# As the doc set increases, we will need to think about refactoring this.
|
205
|
+
args[:breadcrumb_root], args[:breadcrumb_group], args[:breadcrumb_subgroup], args[:breadcrumb_topic] = extract_breadcrumbs(args)
|
206
|
+
|
207
|
+
args[:breadcrumb_subgroup_block] = ''
|
208
|
+
args[:subtopic_shim] = ''
|
209
|
+
if args[:breadcrumb_subgroup]
|
210
|
+
args[:breadcrumb_subgroup_block] = "<li class=\"hidden-xs active\">#{args[:breadcrumb_subgroup]}</li>"
|
211
|
+
args[:subtopic_shim] = '../'
|
212
|
+
end
|
213
|
+
|
214
|
+
template_path = File.expand_path("#{docs_root_dir}/_templates/page.html.erb")
|
215
|
+
template_renderer.render(template_path, args)
|
216
|
+
end
|
217
|
+
|
218
|
+
def extract_breadcrumbs(args)
|
219
|
+
breadcrumb_root = breadcrumb_group = breadcrumb_subgroup = breadcrumb_topic = nil
|
220
|
+
|
221
|
+
root_group = args[:navigation].first
|
222
|
+
selected_group = args[:navigation].detect { |group| group[:id] == args[:group_id] }
|
223
|
+
selected_subgroup = selected_group[:topics].detect { |subgroup| subgroup[:id] == args[:subgroup_id] }
|
224
|
+
current_is_subtopic = selected_subgroup ? true : false
|
225
|
+
|
226
|
+
if root_group
|
227
|
+
root_topic = root_group[:topics].first
|
228
|
+
breadcrumb_root = linkify_breadcrumb(root_topic[:path], "#{args[:distro]} #{args[:version]}", current_is_subtopic) if root_topic
|
229
|
+
end
|
230
|
+
|
231
|
+
if selected_group
|
232
|
+
group_topic = selected_group[:topics].first
|
233
|
+
breadcrumb_group = linkify_breadcrumb(group_topic[:path], selected_group[:name], current_is_subtopic) if group_topic
|
234
|
+
|
235
|
+
if selected_subgroup
|
236
|
+
subgroup_topic = selected_subgroup[:topics].first
|
237
|
+
breadcrumb_subgroup = linkify_breadcrumb(subgroup_topic[:path], selected_subgroup[:name], current_is_subtopic) if subgroup_topic
|
238
|
+
|
239
|
+
selected_topic = selected_subgroup[:topics].detect { |topic| topic[:id] == args[:topic_id] }
|
240
|
+
breadcrumb_topic = linkify_breadcrumb(nil, selected_topic[:name], current_is_subtopic) if selected_topic
|
241
|
+
else
|
242
|
+
selected_topic = selected_group[:topics].detect { |topic| topic[:id] == args[:topic_id] }
|
243
|
+
breadcrumb_topic = linkify_breadcrumb(nil, selected_topic[:name], current_is_subtopic) if selected_topic
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
return breadcrumb_root, breadcrumb_group, breadcrumb_subgroup, breadcrumb_topic
|
248
|
+
end
|
249
|
+
|
250
|
+
def linkify_breadcrumb(href, text, extra_level)
|
251
|
+
addl_level = extra_level ? '../' : ''
|
252
|
+
href ? "<a href=\"#{addl_level}#{href}\">#{text}</a>" : text
|
253
|
+
end
|
254
|
+
|
255
|
+
def asciidoctor_page_attrs(more_attrs=[])
|
256
|
+
[
|
257
|
+
'source-highlighter=coderay',
|
258
|
+
'coderay-css=style',
|
259
|
+
'linkcss!',
|
260
|
+
'icons=font',
|
261
|
+
'idprefix=',
|
262
|
+
'idseparator=-',
|
263
|
+
'sectanchors',
|
264
|
+
'data-uri',
|
265
|
+
].concat(more_attrs)
|
266
|
+
end
|
267
|
+
|
268
|
+
def generate_docs(branch_group,build_distro,single_page)
|
269
|
+
# First, test to see if the docs repo has any commits. If the user has just
|
270
|
+
# run `asciibinder create`, there will be no commits to work from, yet.
|
271
|
+
if local_branches.empty?
|
272
|
+
raise "Before you can build the docs, you need at least one commit in your docs repo."
|
273
|
+
end
|
274
|
+
|
275
|
+
# Make a filepath in list form from the single_page argument
|
276
|
+
single_page_path = []
|
277
|
+
if not single_page.nil?
|
278
|
+
single_page_path = single_page.split(':')[0].split('/')
|
279
|
+
single_page_path << single_page.split(':')[1]
|
280
|
+
puts "Rebuilding '#{single_page_path.join('/')}' on branch '#{working_branch}'."
|
281
|
+
end
|
282
|
+
|
283
|
+
if not build_distro == ''
|
284
|
+
if not distro_map.include_distro_key?(build_distro)
|
285
|
+
exit
|
286
|
+
else
|
287
|
+
puts "Building only the #{distro_map.get_distro(build_distro).name} distribution."
|
288
|
+
end
|
289
|
+
elsif single_page.nil?
|
290
|
+
puts "Building all distributions."
|
291
|
+
end
|
292
|
+
|
293
|
+
# Notify the user of missing local branches
|
294
|
+
missing_branches = []
|
295
|
+
distro_map.distro_branches(build_distro).sort.each do |dbranch|
|
296
|
+
next if local_branches.include?(dbranch)
|
297
|
+
missing_branches << dbranch
|
298
|
+
end
|
299
|
+
if missing_branches.length > 0 and single_page.nil?
|
300
|
+
puts "\nNOTE: The following branches do not exist in your local git repo:"
|
301
|
+
missing_branches.each do |mbranch|
|
302
|
+
puts "- #{mbranch}"
|
303
|
+
end
|
304
|
+
puts "The build will proceed but these branches will not be generated."
|
305
|
+
end
|
306
|
+
|
307
|
+
# Generate all distros for all branches in the indicated branch group
|
308
|
+
branch_group_branches[branch_group].each do |local_branch|
|
309
|
+
# Skip known missing branches; this will only come up for the :publish branch group
|
310
|
+
next if missing_branches.include?(local_branch)
|
311
|
+
|
312
|
+
# Single-page regen only occurs for the working branch
|
313
|
+
if not local_branch == working_branch
|
314
|
+
if single_page.nil?
|
315
|
+
# Checkout the branch
|
316
|
+
puts "\nCHANGING TO BRANCH '#{local_branch}'"
|
317
|
+
git_checkout(local_branch)
|
318
|
+
else
|
319
|
+
next
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# Note the image files checked in to this branch.
|
324
|
+
branch_image_files = Find.find(docs_root_dir).select{ |path| not path.nil? and (path =~ /.*\.png$/ or path =~ /.*\.png\.cache$/) }
|
325
|
+
|
326
|
+
first_branch = single_page.nil?
|
327
|
+
|
328
|
+
if local_branch =~ /^\(detached from .*\)/
|
329
|
+
local_branch = 'detached'
|
330
|
+
end
|
331
|
+
|
332
|
+
# The branch_orphan_files list starts with the set of all
|
333
|
+
# .adoc files found in the repo, and will be whittled
|
334
|
+
# down from there.
|
335
|
+
branch_orphan_files = find_topic_files
|
336
|
+
branch_topic_map = topic_map
|
337
|
+
remove_found_topic_files(local_branch,branch_topic_map,branch_orphan_files)
|
338
|
+
|
339
|
+
if branch_orphan_files.length > 0 and single_page.nil?
|
340
|
+
nl_warning "Branch '#{local_branch}' includes the following .adoc files that are not referenced in the #{topic_map_file} file:\n" + branch_orphan_files.map{ |file| "- #{file}" }.join("\n")
|
341
|
+
end
|
342
|
+
|
343
|
+
# Run all distros.
|
344
|
+
distro_map.distros.each do |distro|
|
345
|
+
if not build_distro == ''
|
346
|
+
# Only building a single distro; build for all indicated branches, skip the others.
|
347
|
+
next unless build_distro == distro.id
|
348
|
+
else
|
349
|
+
current_distro_branches = distro_map.distro_branches(distro.id)
|
350
|
+
|
351
|
+
# In publish mode we only build "valid" distro-branch combos from the distro map
|
352
|
+
if branch_group.to_s.start_with?("publish") and not current_distro_branches.include?(local_branch)
|
353
|
+
next
|
354
|
+
end
|
355
|
+
|
356
|
+
# In "build all" mode we build every distro on the working branch plus the publish distro-branch combos
|
357
|
+
if branch_group == :all and not local_branch == working_branch and not current_distro_branches.include?(local_branch)
|
358
|
+
next
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
# Get the current distro / branch object
|
363
|
+
branch_config = AsciiBinder::DistroBranch.new('',{ "name" => "Branch Build", "dir" => local_branch },distro)
|
364
|
+
dev_branch = true
|
365
|
+
if distro.branch_ids.include?(local_branch)
|
366
|
+
branch_config = distro.branch(local_branch)
|
367
|
+
dev_branch = false
|
368
|
+
end
|
369
|
+
|
370
|
+
if first_branch
|
371
|
+
puts "\nBuilding #{distro.name} for branch '#{local_branch}'"
|
372
|
+
first_branch = false
|
373
|
+
end
|
374
|
+
|
375
|
+
# Copy files into the preview area.
|
376
|
+
[[stylesheet_dir, '*css', branch_config.branch_stylesheet_dir],
|
377
|
+
[javascript_dir, '*js', branch_config.branch_javascript_dir],
|
378
|
+
[image_dir, '*', branch_config.branch_image_dir]].each do |dgroup|
|
379
|
+
src_dir = dgroup[0]
|
380
|
+
glob = dgroup[1]
|
381
|
+
tgt_dir = dgroup[2]
|
382
|
+
if Dir.exist?(src_dir) and not dir_empty?(src_dir)
|
383
|
+
FileUtils.mkdir_p tgt_dir
|
384
|
+
FileUtils.cp_r Dir.glob(File.join(src_dir,glob)), tgt_dir
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# Build the navigation structure for this branch / distro
|
389
|
+
navigation = branch_topic_map.nav_tree(distro.id)
|
390
|
+
|
391
|
+
# Build the topic files for this branch & distro
|
392
|
+
process_topic_entity_list(branch_config,single_page_path,navigation,branch_topic_map.list)
|
393
|
+
end
|
394
|
+
|
395
|
+
# In single-page context, we're done.
|
396
|
+
if not single_page.nil?
|
397
|
+
#exit 200
|
398
|
+
return
|
399
|
+
end
|
400
|
+
|
401
|
+
# Remove DITAA-generated images
|
402
|
+
ditaa_image_files = Find.find(docs_root_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) }
|
403
|
+
if not ditaa_image_files.empty?
|
404
|
+
puts "\nRemoving ditaa-generated files from repo before changing branches."
|
405
|
+
ditaa_image_files.each do |dfile|
|
406
|
+
File.unlink(dfile)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
if local_branch == working_branch
|
411
|
+
# We're moving away from the working branch, so save off changed files
|
412
|
+
git_stash_all
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# Return to the original branch
|
417
|
+
git_checkout(working_branch)
|
418
|
+
|
419
|
+
# If necessary, restore temporarily stashed files
|
420
|
+
git_apply_and_drop
|
421
|
+
|
422
|
+
puts "\nAll builds completed."
|
423
|
+
end
|
424
|
+
|
425
|
+
def process_topic_entity_list(branch_config,single_page_path,navigation,topic_entity_list,preview_path='')
|
426
|
+
# When called from a topic group entity, create the preview dir for that group
|
427
|
+
Dir.mkdir(preview_path) unless preview_path == '' or File.exists?(preview_path)
|
428
|
+
|
429
|
+
topic_entity_list.each do |topic_entity|
|
430
|
+
# If this topic entity or any potential subentities are outside of the distro or single-page params, skip it.
|
431
|
+
next unless topic_entity.include?(branch_config.distro.id,single_page_path)
|
432
|
+
|
433
|
+
if topic_entity.is_group?
|
434
|
+
preview_path = topic_entity.preview_path(branch_config.distro.id,branch_config.dir)
|
435
|
+
process_topic_entity_list(branch_config,single_page_path,navigation,topic_entity.subitems,preview_path)
|
436
|
+
elsif topic_entity.is_topic?
|
437
|
+
if single_page_path.length == 0
|
438
|
+
puts " - #{topic_entity.repo_path}"
|
439
|
+
end
|
440
|
+
configure_and_generate_page(topic_entity,branch_config,navigation)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
def configure_and_generate_page(topic,branch_config,navigation)
|
446
|
+
distro = branch_config.distro
|
447
|
+
topic_adoc = File.open(topic.source_path,'r').read
|
448
|
+
|
449
|
+
page_attrs = asciidoctor_page_attrs([
|
450
|
+
"imagesdir=#{File.join(topic.parent.source_path,'images')}",
|
451
|
+
branch_config.distro.id,
|
452
|
+
"product-title=#{branch_config.distro_name}",
|
453
|
+
"product-version=#{branch_config.name}",
|
454
|
+
"product-author=#{branch_config.distro_author}"
|
455
|
+
])
|
456
|
+
|
457
|
+
doc = Asciidoctor.load topic_adoc, :header_footer => false, :safe => :unsafe, :attributes => page_attrs
|
458
|
+
article_title = doc.doctitle || topic.name
|
459
|
+
|
460
|
+
topic_html = doc.render
|
461
|
+
dir_depth = ''
|
462
|
+
if branch_config.dir.split('/').length > 1
|
463
|
+
dir_depth = '../' * (branch_config.dir.split('/').length - 1)
|
464
|
+
end
|
465
|
+
|
466
|
+
# This is logic bridges newer arbitrary-depth-tolerant code to
|
467
|
+
# older depth-limited code. Truly removing depth limitations will
|
468
|
+
# require changes to page templates in user docs repos.
|
469
|
+
breadcrumb = topic.breadcrumb
|
470
|
+
group_title = breadcrumb[0][:name]
|
471
|
+
group_id = breadcrumb[0][:id]
|
472
|
+
topic_title = breadcrumb[-1][:name]
|
473
|
+
topic_id = breadcrumb[-1][:id]
|
474
|
+
subgroup_title = nil
|
475
|
+
subgroup_id = nil
|
476
|
+
if breadcrumb.length == 3
|
477
|
+
subgroup_title = breadcrumb[1][:name]
|
478
|
+
subgroup_id = breadcrumb[1][:id]
|
479
|
+
dir_depth = '../' + dir_depth
|
480
|
+
end
|
481
|
+
|
482
|
+
preview_path = topic.preview_path(distro.id,branch_config.dir)
|
483
|
+
|
484
|
+
page_args = {
|
485
|
+
:distro_key => distro.id,
|
486
|
+
:distro => branch_config.distro_name,
|
487
|
+
:site_name => distro.site.name,
|
488
|
+
:site_url => distro.site.url,
|
489
|
+
:topic_url => preview_path,
|
490
|
+
:version => branch_config.name,
|
491
|
+
:group_title => group_title,
|
492
|
+
:subgroup_title => subgroup_title,
|
493
|
+
:topic_title => topic_title,
|
494
|
+
:article_title => article_title,
|
495
|
+
:content => topic_html,
|
496
|
+
:navigation => navigation,
|
497
|
+
:group_id => group_id,
|
498
|
+
:subgroup_id => subgroup_id,
|
499
|
+
:topic_id => topic_id,
|
500
|
+
:css_path => "../../#{dir_depth}#{branch_config.dir}/#{STYLESHEET_DIRNAME}/",
|
501
|
+
:javascripts_path => "../../#{dir_depth}#{branch_config.dir}/#{JAVASCRIPT_DIRNAME}/",
|
502
|
+
:images_path => "../../#{dir_depth}#{branch_config.dir}/#{IMAGE_DIRNAME}/",
|
503
|
+
:site_home_path => "../../#{dir_depth}index.html",
|
504
|
+
:template_path => template_dir,
|
505
|
+
}
|
506
|
+
full_file_text = page(page_args)
|
507
|
+
File.write(preview_path,full_file_text)
|
508
|
+
end
|
509
|
+
|
510
|
+
# package_docs
|
511
|
+
# This method generates the docs and then organizes them the way they will be arranged
|
512
|
+
# for the production websites.
|
513
|
+
def package_docs(package_site)
|
514
|
+
site_map.sites.each do |site|
|
515
|
+
next if not package_site == '' and not package_site == site.id
|
516
|
+
site.distros.each do |distro_id,branches|
|
517
|
+
branches.each do |branch|
|
518
|
+
src_dir = File.join(preview_dir,distro_id,branch.dir)
|
519
|
+
tgt_tdir = branch.dir.split('/')
|
520
|
+
tgt_tdir.pop
|
521
|
+
tgt_dir = ''
|
522
|
+
if tgt_tdir.length > 0
|
523
|
+
tgt_dir = File.join(package_dir,site.id,tgt_tdir.join('/'))
|
524
|
+
else
|
525
|
+
tgt_dir = File.join(package_dir,site.id)
|
526
|
+
end
|
527
|
+
next if not File.directory?(src_dir)
|
528
|
+
FileUtils.mkdir_p(tgt_dir)
|
529
|
+
FileUtils.cp_r(src_dir,tgt_dir)
|
530
|
+
end
|
531
|
+
site_dir = File.join(package_dir,site.id)
|
532
|
+
if File.directory?(site_dir)
|
533
|
+
puts "\nPackaging #{distro_id} for #{site.id} site."
|
534
|
+
|
535
|
+
# Any files in the root of the docs repo with names ending in:
|
536
|
+
# *-#{site}.html
|
537
|
+
# will get copied into the root dir of the packaged site with
|
538
|
+
# the site name stripped out.
|
539
|
+
#
|
540
|
+
# Example: for site name 'commercial', the files:
|
541
|
+
# * index-commercial.html would end up as #{site_root}/index.html
|
542
|
+
# * search-commercial.html would end up as #{site_root}/search.html
|
543
|
+
# * index-community.html would be ignored
|
544
|
+
site_files = Dir.glob(File.join(docs_root_dir, '*-' + site.id + '.html'))
|
545
|
+
unless site_files.empty?
|
546
|
+
site_files.each do |fpath|
|
547
|
+
target_basename = File.basename(fpath).gsub(/-#{site.id}\.html$/, '.html')
|
548
|
+
FileUtils.cp(fpath,File.join(package_dir,site.id,target_basename))
|
549
|
+
end
|
550
|
+
else
|
551
|
+
FileUtils.cp(File.join(preview_dir,distro_id,'index.html'),File.join(package_dir,site.id,'index.html'))
|
552
|
+
end
|
553
|
+
['_images','_stylesheets'].each do |support_dir|
|
554
|
+
FileUtils.cp_r(File.join(docs_root_dir,support_dir),File.join(package_dir,site.id,support_dir))
|
555
|
+
end
|
556
|
+
|
557
|
+
# Now build a sitemap
|
558
|
+
site_dir_path = Pathname.new(site_dir)
|
559
|
+
SitemapGenerator::Sitemap.create(
|
560
|
+
:default_host => site.url,
|
561
|
+
:public_path => site_dir_path,
|
562
|
+
:compress => false,
|
563
|
+
:filename => File.join(site_dir,'sitemap')
|
564
|
+
) do
|
565
|
+
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 }
|
566
|
+
file_list.each do |file|
|
567
|
+
add(file, :changefreq => 'daily')
|
568
|
+
end
|
569
|
+
end
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
def clean_up
|
576
|
+
if not system("rm -rf #{docs_root_dir}/_preview/* #{docs_root_dir}/_package/*")
|
577
|
+
puts "Nothing to clean."
|
578
|
+
end
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|