ascii_binder 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.adoc +221 -0
- data/Rakefile +1 -0
- data/ascii_binder.gemspec +36 -0
- data/lib/ascii_binder.rb +3 -0
- data/lib/ascii_binder/helpers.rb +708 -0
- data/lib/ascii_binder/tasks/guards.rb +15 -0
- data/lib/ascii_binder/tasks/tasks.rb +34 -0
- data/lib/ascii_binder/template_renderer.rb +25 -0
- data/lib/ascii_binder/version.rb +3 -0
- metadata +252 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2712179d57dd943569d10c85468d8c29695778a4
|
4
|
+
data.tar.gz: ff3209d960df6d6fb660396de2e9ece06a6d5e80
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cb44c1f68095c9d03d3cdc595d1b110ea6e99b5bdff5acb831ac318e0aae1f397594e7ed1c36842a0b124c6b9c169ea8a01ac18c52250c7832f53f4c43993d90
|
7
|
+
data.tar.gz: 4a8ff2bde4269cb0b71818d7338f2b5694cc3c19635dbe69226824687a0012073ebd5bf41798a1e02c316b5c5b1de396e17f486b36e232a39e938d8f3066289f
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Red Hat, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.adoc
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
= AsciiBinder
|
2
|
+
|
3
|
+
This repo contains the documentation for
|
4
|
+
|
5
|
+
* http://origin.openshift.com/[OpenShift Origin]
|
6
|
+
* http://openshift.com/[OpenShift Online]
|
7
|
+
* http://www.redhat.com/products/cloud-computing/openshift-enterprise/[OpenShift Enterprise]
|
8
|
+
|
9
|
+
The documentation is sourced in http://www.methods.co.nz/asciidoc/[AsciiDoc] and transformed into HTML/CSS and other formats through http://asciidoctor.org/[AsciiDoctor]-based automation.
|
10
|
+
|
11
|
+
== Repo Organization
|
12
|
+
|
13
|
+
Each directory of the repo represents a different collection of topics (you can think of directories as books). The exceptions to this rule are directories whose names start with an underscore (like `_builder_lib` and `_javascripts`), which contain the assets used to generate the finished documentation. Within each 'book' directory, topics exist as separate asciidoc files and an `images` directory contains any images that are included in the topics.
|
14
|
+
|
15
|
+
----
|
16
|
+
/
|
17
|
+
/book1
|
18
|
+
/book1/topic1.adoc
|
19
|
+
/book1/topicN.adoc
|
20
|
+
/book1/images
|
21
|
+
/book1/images/img1.png
|
22
|
+
/book1/images/imgN.png
|
23
|
+
...
|
24
|
+
/bookN
|
25
|
+
----
|
26
|
+
|
27
|
+
== Version Management
|
28
|
+
The overlap of documentation across OpenShift Origin, Online and Enterprise is no less than 80%. In many cases, this means that individual topics may need to include or exclude individual paragraphs with respect to a specific OpenShift distribution. While it is _possible_ to accomplish this solely by using git branches to maintain slightly different versions of a given topic, doing so would make the task of maintaining internal consistency extremely difficult for content contributors.
|
29
|
+
|
30
|
+
Git branching is still extremely valuable, and serves the important role of tracking the release versions of documentation for the various OpenShift distributions.
|
31
|
+
|
32
|
+
=== Distribution-Specific Conditionals
|
33
|
+
OpenShift documentation uses AsciiDoc's `ifdef/endif` macro to conditionalize document segments for specific OpenShift distributions down to the single-line level.
|
34
|
+
|
35
|
+
The supported distribution attributes used in the OpenShift document generator are:
|
36
|
+
|
37
|
+
* `openshift-origin`
|
38
|
+
* `openshift-online`
|
39
|
+
* `openshift-enterprise`
|
40
|
+
|
41
|
+
These attributes can be used alone or together to conditionalize text within a topic document.
|
42
|
+
|
43
|
+
Here is an example of this concept in use:
|
44
|
+
|
45
|
+
----
|
46
|
+
This first line is unconditionalized, and will appear for all versions.
|
47
|
+
|
48
|
+
\ifdef::openshift-online[]
|
49
|
+
This line will only appear for OpenShift Online.
|
50
|
+
\endif::[]
|
51
|
+
|
52
|
+
\ifdef::openshift-enterprise[]
|
53
|
+
This line will only appear for OpenShift Enterprise.
|
54
|
+
\endif::[]
|
55
|
+
|
56
|
+
\ifdef::openshift-origin,openshift-enterprise[]
|
57
|
+
This line will appear for OpenShift Origin and Enterprise, but not for OpenShift Online.
|
58
|
+
\endif::[]
|
59
|
+
----
|
60
|
+
|
61
|
+
Two important points to keep in mind:
|
62
|
+
|
63
|
+
* The `ifdef/endif` blocks have no size limit, however they should _not_ be used to conditionalize an entire topic. If an entire topic file is specific to a given OpenShift distribution, refer to the link:#document-set-metadata[Document Set Metadata] section for information on how to conditionalize at the whole-topic level.
|
64
|
+
|
65
|
+
* The `ifdef/endif` blocks _cannot be nested_. In other words, one conditional block cannot contain other conditional blocks.
|
66
|
+
|
67
|
+
=== Release Branches
|
68
|
+
Through the use of link:#distribution-specific-conditionals[Distribution-Specific Conditionals] and link:#document-set-metadata[Document Set Metadata], the master branch of this repository always contains a complete set of documentation that includes all of the OpenShift distributions. However, when and as new versions of the OpenShift distros are released, the master branch is merged down to new or existing release branches. Here is the general naming scheme used in the branches:
|
69
|
+
|
70
|
+
* `master` - OpenShift Origin latest code
|
71
|
+
* `origin-N.N` - OpenShift Origin most recent stable release
|
72
|
+
* `online` - OpenShift Online most recent release
|
73
|
+
* `enterprise-N.N` - OpenShift Enterprise support releases
|
74
|
+
|
75
|
+
On a nightly basis, the documentation web sites are rebuilt for each of these branches. In this manner, documentation for released versions of OpenShift will remain the same even as development continues on master. Additionally, any corrections or additions that are "cherry-picked" into the release branches will show up in the release documentation the next day.
|
76
|
+
|
77
|
+
== Document Set Metadata
|
78
|
+
In order to construct the documentation site from these sources, the build system looks at the `_build_cfg.yml` metadata file. The build system _only_ looks in this file for information on which files to include, so any new file submissions must be accompanied by an update to this metadata file.
|
79
|
+
|
80
|
+
=== File Format
|
81
|
+
The format of this file is as indicated:
|
82
|
+
|
83
|
+
----
|
84
|
+
--- <1>
|
85
|
+
Name: Origin of the Species <2>
|
86
|
+
Dir: origin_of_the_species <3>
|
87
|
+
Distros: all <4>
|
88
|
+
Topics:
|
89
|
+
- Name: The Majestic Marmoset <5>
|
90
|
+
File: the_majestic_marmoset <6>
|
91
|
+
Distros: all
|
92
|
+
- Name: The Curious Crocodile
|
93
|
+
File: the_curious_crocodile
|
94
|
+
Distros: openshift-online,openshift-enterprise <7>
|
95
|
+
- Name: The Numerous Nematodes
|
96
|
+
Dir: the_numerous_nematodes <8>
|
97
|
+
Topics:
|
98
|
+
- Name: The Wily Worm <9>
|
99
|
+
File: the_wily_worm
|
100
|
+
- Name: The Acrobatic Ascarid <= Sub-topic 2 name
|
101
|
+
File: the_acrobatic_ascarid <= Sub-topic 2 file under <group dir>/<subtopic dir>
|
102
|
+
----
|
103
|
+
<1> Record separator at the top of each topic group
|
104
|
+
<2> Display name of topic group
|
105
|
+
<3> Directory name of topic group
|
106
|
+
<4> Which OpenShift versions this topic group is part of
|
107
|
+
<5> Topic name
|
108
|
+
<6> Topic file under the topic group dir without '.adoc'
|
109
|
+
<7> Which OpenShift versions this topic is part of
|
110
|
+
<8> This topic is actually a subtopic group. Instead of a `File` path it has a `Dir` path and `Topics`, just like a top-level topic group.
|
111
|
+
<9> Topics belonging to a subtopic group are listed just like regular topics with a `Name` and `File`.
|
112
|
+
|
113
|
+
=== Notes on "Distros"
|
114
|
+
|
115
|
+
* The "Distros" setting is optional for topic groups and topic items. When the "Distros" setting is absent, the system treats the topic group or topic as though the user had set "Distros: all".
|
116
|
+
* The "all" value for "Distros" is a synonym for "openshift-origin,openshift-enterprise,openshift-online".
|
117
|
+
* The "all" value trumps other values, so "openshift-online,all" is treated as "all"
|
118
|
+
|
119
|
+
== Understanding the Complete Distribution Condition Chain
|
120
|
+
It is important to understand the ordering of distribution conditionals in determining whether or not a specific piece of content appears in the documentation set. The hierarchy is fairly straightforward:
|
121
|
+
|
122
|
+
1. Topic group "Distros" setting from `_build_cfg.yml`
|
123
|
+
2. Topic item "Distros" setting from `_build_cfg.yml`
|
124
|
+
3. Document-level `ifdef/endif` blocks
|
125
|
+
|
126
|
+
In this manner:
|
127
|
+
|
128
|
+
* If a topic group is configured with "Distros: openshift-online", the entire group will be skipped for OpenShift Enterprise and OpenShift Origin, regardless of the Topic-level and document-level content rules within that group.
|
129
|
+
|
130
|
+
* When a topic group is available to all Distros, but a specific topic item is limited, the topic group will appear for all distros and the specific topic item will only appear for the indicated distros.
|
131
|
+
|
132
|
+
== Live Editing
|
133
|
+
If you would like to work on one of the documentation files in an editing environment that automatically redraws the resulting HTML, follow these steps.
|
134
|
+
|
135
|
+
=== Prerequisites
|
136
|
+
You will need the following tools in your editing environment:
|
137
|
+
|
138
|
+
* A bash shell environment (Linux distributions and OS X include these out of the box, for Windows consider http://cygwin.com/[Cygwin])
|
139
|
+
* https://www.ruby-lang.org/en/[Ruby]
|
140
|
+
* http://www.git-scm.com/[git]
|
141
|
+
* A web browser (Firefox, Chrome or Safari) with the http://livereload.com/[LiveReload] extension
|
142
|
+
|
143
|
+
With these tools available, first perform a one-time setup:
|
144
|
+
|
145
|
+
1. Clone the https://github.com/openshift/openshift-docs[openshift-docs] repo from GitHub:
|
146
|
+
+
|
147
|
+
----
|
148
|
+
$ git clone https://github.com/openshift/openshift-docs.git
|
149
|
+
----
|
150
|
+
2. From the cloned directory, run a bundle install:
|
151
|
+
+
|
152
|
+
----
|
153
|
+
$ cd openshift-docs
|
154
|
+
$ bundle install
|
155
|
+
----
|
156
|
+
+
|
157
|
+
TIP: If you don't have bundler installed, you can get it by running `gem install bundler`
|
158
|
+
|
159
|
+
That's it for setup, the next section explains how to run the LiveReload system.
|
160
|
+
|
161
|
+
=== Running with LiveReload
|
162
|
+
Once you've installed the link:#prerequisites[prerequisites] you can fire up the LiveReload setup as follows:
|
163
|
+
|
164
|
+
1. From the `openshift-docs` directory, run a preliminary build:
|
165
|
+
+
|
166
|
+
----
|
167
|
+
$ cd openshift-docs
|
168
|
+
$ bundle exec rake build
|
169
|
+
----
|
170
|
+
2. Now open the generated HTML file in your browser. It will be under `openshift-docs/_preview/<distro>/<branch>` with the same path and filename as the original file. The only difference will be the name ending in '.html' instead of '.adoc'.
|
171
|
+
3. Now start up the `guard` utility:
|
172
|
+
+
|
173
|
+
----
|
174
|
+
$ bundle exec guard
|
175
|
+
----
|
176
|
+
+
|
177
|
+
TIP: This utility will run in the terminal where you started it, so you should leave it running off to the side and use other terminals for regular tasks.
|
178
|
+
4. Finally, back in your browser, enable the LiveReload plugin in the same tab where the preview file is displayed. You will know this step succeeded if the LiveReload icon changes, and if you see output similar to the following in the terminal where `guard` is running:
|
179
|
+
+
|
180
|
+
----
|
181
|
+
[1] guard(main)> 17:29:22 - INFO - Browser connected.
|
182
|
+
----
|
183
|
+
|
184
|
+
That's it. Now any changes that you make to the source file will automatically trigger a rebuild of the target HTML file.
|
185
|
+
|
186
|
+
=== Clean Up
|
187
|
+
The `.gitignore` file is set up to prevent anything under `_preview` and `_package` from being committed. However, you can reset the environment manually by running:
|
188
|
+
|
189
|
+
----
|
190
|
+
$ bundle exec rake clean
|
191
|
+
----
|
192
|
+
|
193
|
+
== Creating New Topic Pages
|
194
|
+
The layout and style rules for new documentation are largely described in an upcoming style guide (delivery date TBD). However, a few important rules are listed here because they affect the way that the pages are rendered.
|
195
|
+
|
196
|
+
The top matter of any new topic page must have the following format:
|
197
|
+
|
198
|
+
----
|
199
|
+
= Human-Readable Topic Title
|
200
|
+
{product-author}
|
201
|
+
{product-version}
|
202
|
+
:data-uri:
|
203
|
+
:icons:
|
204
|
+
----
|
205
|
+
|
206
|
+
* The article title goes on the first line with a level 1 header markup (=)
|
207
|
+
* The [x-]`{product-author}` and [x-]`{product-version}` are AsciiDoc attributes that get replaced dynamically when the docs are generated.
|
208
|
+
* The `:data-uri:` attribute tells AsciiDoctor to embed any images directly in the HTML.
|
209
|
+
* The `:icons:` attribute tells AsciiDoctor to use cool icons for admonition blocks.
|
210
|
+
|
211
|
+
After the heading block and a single whitespace line, you can include any content for the topic.
|
212
|
+
|
213
|
+
NOTE: Any section headers within the article must be level 2 (==) or lower. Try to be consistent about level-nesting; it won't break AsciiDoctor to jump from a level 1 section header down to level 3, but it isn't good form.
|
214
|
+
|
215
|
+
|
216
|
+
== Contacts
|
217
|
+
|
218
|
+
For questions or comments about the documentation system:
|
219
|
+
|
220
|
+
* OpenShift team members can be found on the http://webchat.freenode.net/?randomnick=1&channels=openshift&uio=d4[#openshift] and http://webchat.freenode.net/?randomnick=1&channels=openshift-dev&uio=d4[#openshift-dev channels] on http://www.freenode.net/[FreeNode].
|
221
|
+
* You can also join the http://lists.openshift.redhat.com/openshiftmm/listinfo/users[Users] or http://lists.openshift.redhat.com/openshiftmm/listinfo/dev[Developers] mailing list.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ascii_binder/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ascii_binder"
|
8
|
+
spec.version = AsciiBinder::VERSION
|
9
|
+
spec.authors = ["N. Harrison Ripps"]
|
10
|
+
spec.email = ["nhr@redhat.com"]
|
11
|
+
spec.summary = %q{Builder for multi product documention websites.}
|
12
|
+
spec.description = %q{Builder for multi product documention websites.}
|
13
|
+
spec.homepage = "http://github.com/redhataccess/ascii_binder"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_dependency "rake", "~> 10.0"
|
23
|
+
|
24
|
+
spec.add_dependency 'asciidoctor'
|
25
|
+
spec.add_dependency 'asciidoctor-diagram'
|
26
|
+
spec.add_dependency 'git'
|
27
|
+
spec.add_dependency 'guard'
|
28
|
+
spec.add_dependency 'guard-shell'
|
29
|
+
spec.add_dependency 'guard-livereload'
|
30
|
+
spec.add_dependency 'haml'
|
31
|
+
spec.add_dependency 'json'
|
32
|
+
spec.add_dependency 'pandoc-ruby'
|
33
|
+
spec.add_dependency 'sitemap_generator', '~> 5.1.0'
|
34
|
+
spec.add_dependency 'yajl-ruby'
|
35
|
+
spec.add_dependency 'tilt'
|
36
|
+
end
|
data/lib/ascii_binder.rb
ADDED
@@ -0,0 +1,708 @@
|
|
1
|
+
require 'asciidoctor'
|
2
|
+
require 'asciidoctor/cli'
|
3
|
+
require 'asciidoctor-diagram'
|
4
|
+
require 'find'
|
5
|
+
require 'git'
|
6
|
+
require 'logger'
|
7
|
+
require 'pandoc-ruby'
|
8
|
+
require 'pathname'
|
9
|
+
require 'sitemap_generator'
|
10
|
+
require 'yaml'
|
11
|
+
require 'forwardable'
|
12
|
+
|
13
|
+
module AsciiBinder
|
14
|
+
module Helpers
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
def self.source_dir
|
18
|
+
@source_dir ||= `git rev-parse --show-toplevel`.chomp
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.template_dir
|
22
|
+
@template_dir ||= File.join(source_dir,'_templates')
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.preview_dir
|
26
|
+
@preview_dir ||= begin
|
27
|
+
lpreview_dir = File.join(source_dir,PREVIEW_DIRNAME)
|
28
|
+
if not File.exists?(lpreview_dir)
|
29
|
+
Dir.mkdir(lpreview_dir)
|
30
|
+
end
|
31
|
+
lpreview_dir
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.package_dir
|
36
|
+
@package_dir ||= begin
|
37
|
+
lpackage_dir = File.join(source_dir,PACKAGE_DIRNAME)
|
38
|
+
if not File.exists?(lpackage_dir)
|
39
|
+
Dir.mkdir(lpackage_dir)
|
40
|
+
end
|
41
|
+
lpackage_dir
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def_delegators self, :source_dir, :template_dir, :preview_dir, :package_dir
|
46
|
+
|
47
|
+
TemplateRenderer.initialize_cache(template_dir)
|
48
|
+
|
49
|
+
BUILD_FILENAME = '_build_cfg.yml'
|
50
|
+
DISTRO_MAP_FILENAME = '_distro_map.yml'
|
51
|
+
BUILDER_DIRNAME = '_build_system'
|
52
|
+
PREVIEW_DIRNAME = '_preview'
|
53
|
+
PACKAGE_DIRNAME = '_package'
|
54
|
+
BLANK_STRING_RE = Regexp.new('^\s*$')
|
55
|
+
|
56
|
+
def build_date
|
57
|
+
Time.now.utc
|
58
|
+
end
|
59
|
+
|
60
|
+
def git
|
61
|
+
@git ||= Git.open(source_dir)
|
62
|
+
end
|
63
|
+
|
64
|
+
def git_checkout branch_name
|
65
|
+
target_branch = git.branches.local.select{ |b| b.name == branch_name }[0]
|
66
|
+
if not target_branch.nil? and not target_branch.current
|
67
|
+
target_branch.checkout
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def git_stash_all
|
72
|
+
# See if there are any changes in need of stashing
|
73
|
+
@stash_needed = `git status --porcelain` !~ /^\s*$/
|
74
|
+
if @stash_needed
|
75
|
+
puts "\nNOTICE: Stashing uncommited changes and files in working branch."
|
76
|
+
`git stash -u`
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def git_apply_and_drop
|
81
|
+
return unless @stash_needed
|
82
|
+
puts "\nNOTE: Re-applying uncommitted changes and files to working branch."
|
83
|
+
if system("git stash pop")
|
84
|
+
puts "NOTE: Stash application successful."
|
85
|
+
else
|
86
|
+
puts "ERROR: Could not apply stashed code. Run `git stash apply` manually."
|
87
|
+
end
|
88
|
+
@stash_needed = false
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the local git branches; current branch is always first
|
92
|
+
def local_branches
|
93
|
+
@local_branches ||= begin
|
94
|
+
branches = []
|
95
|
+
branches << git.branches.local.select{ |b| b.current }[0].name
|
96
|
+
branches << git.branches.local.select{ |b| not b.current }.map{ |b| b.name }
|
97
|
+
branches.flatten
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def working_branch
|
102
|
+
@working_branch ||= local_branches[0]
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_config_file
|
106
|
+
@build_config_file ||= File.join(source_dir,BUILD_FILENAME)
|
107
|
+
end
|
108
|
+
|
109
|
+
def distro_map_file
|
110
|
+
@distro_map_file ||= File.join(source_dir, DISTRO_MAP_FILENAME)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Protip: Don't cache this! It needs to be reread every time we change branches.
|
114
|
+
def build_config
|
115
|
+
validate_config(YAML.load_stream(open(build_config_file)))
|
116
|
+
end
|
117
|
+
|
118
|
+
def find_topic_files
|
119
|
+
file_list = Find.find('.').select{ |path| not path.nil? and path =~ /.*\.adoc$/ and not path =~ /README/ and not path =~ /\/old\// and not path.split('/').length < 3 }
|
120
|
+
file_list.map{ |path|
|
121
|
+
parts = path.split('/').slice(1..-1);
|
122
|
+
parts.slice(0..-2).join('/') + '/' + parts[-1].split('.')[0]
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def remove_found_config_files(branch,branch_build_config,branch_topic_files)
|
127
|
+
nonexistent_topics = []
|
128
|
+
branch_build_config.each do |topic_group|
|
129
|
+
tg_dir = topic_group['Dir']
|
130
|
+
topic_group['Topics'].each do |topic|
|
131
|
+
if topic.has_key?('File')
|
132
|
+
topic_path = tg_dir + '/' + topic['File']
|
133
|
+
result = branch_topic_files.delete(topic_path)
|
134
|
+
if result.nil?
|
135
|
+
nonexistent_topics << topic_path
|
136
|
+
end
|
137
|
+
elsif topic.has_key?('Dir')
|
138
|
+
topic_path = tg_dir + '/' + topic['Dir'] + '/'
|
139
|
+
topic['Topics'].each do |subtopic|
|
140
|
+
result = branch_topic_files.delete(topic_path + subtopic['File'])
|
141
|
+
if result.nil?
|
142
|
+
nonexistent_topics << topic_path + subtopic['File']
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
if nonexistent_topics.length > 0
|
149
|
+
puts "\nWARNING: The _build_cfg.yml file on branch '#{branch}' references nonexistant topics:\n" + nonexistent_topics.map{ |topic| "- #{topic}" }.join("\n")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def distro_map
|
154
|
+
@distro_map ||= YAML.load_file(distro_map_file)
|
155
|
+
end
|
156
|
+
|
157
|
+
def site_map
|
158
|
+
site_map = {}
|
159
|
+
distro_map.each do |distro,distro_config|
|
160
|
+
if not site_map.has_key?(distro_config["site"])
|
161
|
+
site_map[distro_config["site"]] = { :distros => {}, :name => distro_config['site_name'], :url => distro_config['site_url'] }
|
162
|
+
end
|
163
|
+
site_map[distro_config["site"]][:distros][distro] = distro_config["branches"]
|
164
|
+
end
|
165
|
+
site_map
|
166
|
+
end
|
167
|
+
|
168
|
+
def distro_branches(use_distro='')
|
169
|
+
@distro_branches ||= begin
|
170
|
+
use_distro_list = use_distro == '' ? distro_map.keys : [use_distro]
|
171
|
+
distro_map.select{ |dkey,dval| use_distro_list.include?(dkey) }.map{ |distro,dconfig| dconfig["branches"].keys }.flatten
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def page(args)
|
176
|
+
# TODO: This process of rebuilding the entire nav for every page will not scale well.
|
177
|
+
# As the doc set increases, we will need to think about refactoring this.
|
178
|
+
args[:breadcrumb_root], args[:breadcrumb_group], args[:breadcrumb_subgroup], args[:breadcrumb_topic] = extract_breadcrumbs(args)
|
179
|
+
|
180
|
+
args[:breadcrumb_subgroup_block] = ''
|
181
|
+
args[:subtopic_shim] = ''
|
182
|
+
if args[:breadcrumb_subgroup]
|
183
|
+
args[:breadcrumb_subgroup_block] = "<li class=\"hidden-xs active\">#{args[:breadcrumb_subgroup]}</li>"
|
184
|
+
args[:subtopic_shim] = '../'
|
185
|
+
end
|
186
|
+
|
187
|
+
TemplateRenderer.new.render("_templates/page.html.erb", args)
|
188
|
+
end
|
189
|
+
|
190
|
+
def extract_breadcrumbs(args)
|
191
|
+
breadcrumb_root = breadcrumb_group = breadcrumb_subgroup = breadcrumb_topic = nil
|
192
|
+
|
193
|
+
root_group = args[:navigation].first
|
194
|
+
selected_group = args[:navigation].detect { |group| group[:id] == args[:group_id] }
|
195
|
+
selected_subgroup = selected_group[:topics].detect { |subgroup| subgroup[:id] == args[:subgroup_id] }
|
196
|
+
current_is_subtopic = selected_subgroup ? true : false
|
197
|
+
|
198
|
+
if root_group
|
199
|
+
root_topic = root_group[:topics].first
|
200
|
+
breadcrumb_root = linkify_breadcrumb(root_topic[:path], "#{args[:distro]} #{args[:version]}", current_is_subtopic) if root_topic
|
201
|
+
end
|
202
|
+
|
203
|
+
if selected_group
|
204
|
+
group_topic = selected_group[:topics].first
|
205
|
+
breadcrumb_group = linkify_breadcrumb(group_topic[:path], selected_group[:name], current_is_subtopic) if group_topic
|
206
|
+
|
207
|
+
if selected_subgroup
|
208
|
+
subgroup_topic = selected_subgroup[:topics].first
|
209
|
+
breadcrumb_subgroup = linkify_breadcrumb(subgroup_topic[:path], selected_subgroup[:name], current_is_subtopic) if subgroup_topic
|
210
|
+
|
211
|
+
selected_topic = selected_subgroup[:topics].detect { |topic| topic[:id] == args[:topic_id] }
|
212
|
+
breadcrumb_topic = linkify_breadcrumb(nil, selected_topic[:name], current_is_subtopic) if selected_topic
|
213
|
+
else
|
214
|
+
selected_topic = selected_group[:topics].detect { |topic| topic[:id] == args[:topic_id] }
|
215
|
+
breadcrumb_topic = linkify_breadcrumb(nil, selected_topic[:name], current_is_subtopic) if selected_topic
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
return breadcrumb_root, breadcrumb_group, breadcrumb_subgroup, breadcrumb_topic
|
220
|
+
end
|
221
|
+
|
222
|
+
def linkify_breadcrumb(href, text, extra_level)
|
223
|
+
addl_level = extra_level ? '../' : ''
|
224
|
+
href ? "<a href=\"#{addl_level}#{href}\">#{text}</a>" : text
|
225
|
+
end
|
226
|
+
|
227
|
+
def parse_distros distros_string, for_validation=false
|
228
|
+
values = distros_string.split(',').map{ |v| v.strip }
|
229
|
+
return values if for_validation
|
230
|
+
return distro_map.keys if values.include?('all')
|
231
|
+
return values.uniq
|
232
|
+
end
|
233
|
+
|
234
|
+
def validate_distros distros_string
|
235
|
+
return false if not distros_string.is_a?(String)
|
236
|
+
values = parse_distros(distros_string, true)
|
237
|
+
values.each do |v|
|
238
|
+
return false if not v == 'all' and not distro_map.keys.include?(v)
|
239
|
+
end
|
240
|
+
return true
|
241
|
+
end
|
242
|
+
|
243
|
+
def validate_topic_group group, info
|
244
|
+
# Check for presence of topic group keys
|
245
|
+
['Name','Dir','Topics'].each do |group_key|
|
246
|
+
if not group.has_key?(group_key)
|
247
|
+
raise "One of the topic groups in #{build_config_file} is missing the '#{group_key}' key."
|
248
|
+
end
|
249
|
+
end
|
250
|
+
# Check for right format of topic group values
|
251
|
+
['Name','Dir'].each do |group_key|
|
252
|
+
if not group[group_key].is_a?(String)
|
253
|
+
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}"
|
254
|
+
end
|
255
|
+
if group[group_key].empty? or group[group_key].match BLANK_STRING_RE
|
256
|
+
raise "One of the topic groups in #{build_config_file} is using a blank value for the #{group_key} setting."
|
257
|
+
end
|
258
|
+
end
|
259
|
+
if not File.exists?(File.join(source_dir,info[:path]))
|
260
|
+
raise "In #{build_config_file}, the directory path '#{info[:path]}' for topic group #{group['Name']} does not exist under #{source_dir}"
|
261
|
+
end
|
262
|
+
# Validate the Distros setting
|
263
|
+
if group.has_key?('Distros')
|
264
|
+
if not validate_distros(group['Distros'])
|
265
|
+
key_list = distro_map.keys.map{ |k| "'#{k}'" }.sort.join(', ')
|
266
|
+
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."
|
267
|
+
end
|
268
|
+
group['Distros'] = parse_distros(group['Distros'])
|
269
|
+
else
|
270
|
+
group['Distros'] = parse_distros('all')
|
271
|
+
end
|
272
|
+
if not group['Topics'].is_a?(Array)
|
273
|
+
raise "The #{group['Name']} topic group in #{build_config_file} is malformed; the build system is expecting an array of 'Topic' definitions."
|
274
|
+
end
|
275
|
+
# Generate an ID for this topic group
|
276
|
+
group['ID'] = camelize group['Name']
|
277
|
+
if info.has_key?(:parent_id)
|
278
|
+
group['ID'] = "#{info[:parent_id]}::#{group['ID']}"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def validate_topic_item item, info
|
283
|
+
['Name','File'].each do |topic_key|
|
284
|
+
if not item[topic_key].is_a?(String)
|
285
|
+
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}"
|
286
|
+
end
|
287
|
+
if item[topic_key].empty? or item[topic_key].match BLANK_STRING_RE
|
288
|
+
raise "In #{build_config_file}, topic group #{topic_group['Name']}, one of the topics is using a blank value for the '#{topic_key}' setting"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
# Normalize the filenames
|
292
|
+
if item['File'].end_with?('.adoc')
|
293
|
+
item['File'] = item['File'][0..-6]
|
294
|
+
end
|
295
|
+
if not File.exists?(File.join(source_dir,info[:path],"#{item['File']}.adoc"))
|
296
|
+
raise "In #{build_config_file}, could not find file #{item['File']} under directory #{info[:path]} for topic #{item['Name']} in topic group #{info[:group]}."
|
297
|
+
end
|
298
|
+
if item.has_key?('Distros')
|
299
|
+
if not validate_distros(item['Distros'])
|
300
|
+
key_list = distro_map.keys.map{ |k| "'#{k}'" }.sort.join(', ')
|
301
|
+
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."
|
302
|
+
end
|
303
|
+
item['Distros'] = parse_distros(item['Distros'])
|
304
|
+
else
|
305
|
+
item['Distros'] = parse_distros('all')
|
306
|
+
end
|
307
|
+
# Generate an ID for this topic
|
308
|
+
item['ID'] = "#{info[:group_id]}::#{camelize(item['Name'])}"
|
309
|
+
end
|
310
|
+
|
311
|
+
def validate_config config_data
|
312
|
+
# Validate/normalize the config file straight away
|
313
|
+
if not config_data.is_a?(Array)
|
314
|
+
raise "The configuration in #{build_config_file} is malformed; the build system is expecting an array of topic groups."
|
315
|
+
end
|
316
|
+
config_data.each do |topic_group|
|
317
|
+
validate_topic_group(topic_group, { :path => topic_group['Dir'] })
|
318
|
+
# Now buzz through the topics
|
319
|
+
topic_group['Topics'].each do |topic|
|
320
|
+
# Is this an actual topic or a subtopic group?
|
321
|
+
is_subtopic_group = topic.has_key?('Dir') and topic.has_key?('Topics') and not topic.has_key?('File')
|
322
|
+
is_topic_item = topic.has_key?('File') and not topic.has_key?('Dir') and not topic.has_key?('Topics')
|
323
|
+
if not is_subtopic_group and not is_topic_item
|
324
|
+
raise "This topic could not definitively be determined to be a topic item or a subtopic group:\n#{topic.inspect}"
|
325
|
+
end
|
326
|
+
if is_topic_item
|
327
|
+
validate_topic_item(topic, { :group => topic_group['Name'], :group_id => topic_group['ID'], :path => topic_group['Dir'] })
|
328
|
+
elsif is_subtopic_group
|
329
|
+
topic_path = "#{topic_group['Dir']}/#{topic['Dir']}"
|
330
|
+
validate_topic_group(topic, { :path => topic_path, :parent_id => topic_group['ID'] })
|
331
|
+
topic['Topics'].each do |subtopic|
|
332
|
+
validate_topic_item(subtopic, { :group => "#{topic_group['Name']}/#{topic['Name']}", :group_id => topic['ID'], :path => topic_path })
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
config_data
|
338
|
+
end
|
339
|
+
|
340
|
+
def camelize text
|
341
|
+
text.gsub(/[^0-9a-zA-Z ]/i, '').split(' ').map{ |t| t.capitalize }.join
|
342
|
+
end
|
343
|
+
|
344
|
+
def nav_tree distro, branch_build_config
|
345
|
+
navigation = []
|
346
|
+
branch_build_config.each do |topic_group|
|
347
|
+
next if not topic_group['Distros'].include?(distro)
|
348
|
+
next if topic_group['Topics'].select{ |t| t['Distros'].include?(distro) }.length == 0
|
349
|
+
topic_list = []
|
350
|
+
topic_group['Topics'].each do |topic|
|
351
|
+
next if not topic['Distros'].include?(distro)
|
352
|
+
if topic.has_key?('File')
|
353
|
+
topic_list << {
|
354
|
+
:path => "../#{topic_group['Dir']}/#{topic['File']}.html",
|
355
|
+
:name => topic['Name'],
|
356
|
+
:id => topic['ID'],
|
357
|
+
}
|
358
|
+
elsif topic.has_key?('Dir')
|
359
|
+
next if topic['Topics'].select{ |t| t['Distros'].include?(distro) }.length == 0
|
360
|
+
subtopic_list = []
|
361
|
+
topic['Topics'].each do |subtopic|
|
362
|
+
next if not subtopic['Distros'].include?(distro)
|
363
|
+
subtopic_list << {
|
364
|
+
:path => "../#{topic_group['Dir']}/#{topic['Dir']}/#{subtopic['File']}.html",
|
365
|
+
:name => subtopic['Name'],
|
366
|
+
:id => subtopic['ID'],
|
367
|
+
}
|
368
|
+
end
|
369
|
+
topic_list << { :name => topic['Name'], :id => topic['ID'], :topics => subtopic_list }
|
370
|
+
end
|
371
|
+
end
|
372
|
+
navigation << { :name => topic_group['Name'], :id => topic_group['ID'], :topics => topic_list }
|
373
|
+
end
|
374
|
+
navigation
|
375
|
+
end
|
376
|
+
|
377
|
+
def asciidoctor_page_attrs(more_attrs=[])
|
378
|
+
[
|
379
|
+
'source-highlighter=coderay',
|
380
|
+
'coderay-css=style',
|
381
|
+
'linkcss!',
|
382
|
+
'icons=font',
|
383
|
+
'idprefix=',
|
384
|
+
'idseparator=-',
|
385
|
+
'sectanchors',
|
386
|
+
].concat(more_attrs)
|
387
|
+
end
|
388
|
+
|
389
|
+
def generate_docs(build_distro,single_page=nil)
|
390
|
+
single_page_dir = []
|
391
|
+
single_page_file = nil
|
392
|
+
if not single_page.nil?
|
393
|
+
single_page_dir = single_page.split(':')[0].split('/')
|
394
|
+
single_page_file = single_page.split(':')[1]
|
395
|
+
puts "Rebuilding '#{single_page_dir.join('/')}/#{single_page_file}' on branch '#{working_branch}'."
|
396
|
+
end
|
397
|
+
|
398
|
+
if not build_distro == ''
|
399
|
+
if not distro_map.has_key?(build_distro)
|
400
|
+
exit
|
401
|
+
else
|
402
|
+
puts "Building only the #{distro_map[build_distro]["name"]} distribution."
|
403
|
+
end
|
404
|
+
elsif single_page.nil?
|
405
|
+
puts "Building all distributions."
|
406
|
+
end
|
407
|
+
|
408
|
+
# First, notify the user of missing local branches
|
409
|
+
missing_branches = []
|
410
|
+
distro_branches(build_distro).sort.each do |dbranch|
|
411
|
+
next if local_branches.include?(dbranch)
|
412
|
+
missing_branches << dbranch
|
413
|
+
end
|
414
|
+
if missing_branches.length > 0 and single_page.nil?
|
415
|
+
puts "\nNOTE: The following branches do not exist in your local git repo:"
|
416
|
+
missing_branches.each do |mbranch|
|
417
|
+
puts "- #{mbranch}"
|
418
|
+
end
|
419
|
+
puts "The build will proceed but these branches will not be generated."
|
420
|
+
end
|
421
|
+
|
422
|
+
# Generate all distros for every local branch
|
423
|
+
local_branches.each do |local_branch|
|
424
|
+
# Single-page regen only occurs for the working branch
|
425
|
+
if not local_branch == working_branch
|
426
|
+
if single_page.nil?
|
427
|
+
# Checkout the branch
|
428
|
+
puts "\nCHANGING TO BRANCH '#{local_branch}'"
|
429
|
+
git_checkout(local_branch)
|
430
|
+
else
|
431
|
+
next
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
first_branch = single_page.nil?
|
436
|
+
|
437
|
+
if local_branch =~ /^\(detached from .*\)/
|
438
|
+
local_branch = 'detached'
|
439
|
+
end
|
440
|
+
|
441
|
+
# The branch_orphan_files list starts with the set of all
|
442
|
+
# .adoc files found in the repo, and will be whittled
|
443
|
+
# down from there.
|
444
|
+
branch_orphan_files = find_topic_files
|
445
|
+
branch_build_config = build_config
|
446
|
+
remove_found_config_files(local_branch,branch_build_config,branch_orphan_files)
|
447
|
+
|
448
|
+
if branch_orphan_files.length > 0 and single_page.nil?
|
449
|
+
puts "\nWARNING: Branch '#{local_branch}' includes the following .adoc files that are not referenced in the _build_cfg.yml file:\n" + branch_orphan_files.map{ |file| "- #{file}" }.join("\n")
|
450
|
+
end
|
451
|
+
|
452
|
+
# Run all distros.
|
453
|
+
distro_map.each do |distro,distro_config|
|
454
|
+
# Only building a single distro; skip the others.
|
455
|
+
if not build_distro == '' and not build_distro == distro
|
456
|
+
next
|
457
|
+
end
|
458
|
+
|
459
|
+
site_name = distro_config["site_name"]
|
460
|
+
|
461
|
+
branch_config = { "name" => "Branch Build", "dir" => local_branch }
|
462
|
+
dev_branch = true
|
463
|
+
if distro_config["branches"].has_key?(local_branch)
|
464
|
+
branch_config = distro_config["branches"][local_branch]
|
465
|
+
dev_branch = false
|
466
|
+
end
|
467
|
+
|
468
|
+
if first_branch
|
469
|
+
puts "\nBuilding #{distro_config["name"]} for branch '#{local_branch}'"
|
470
|
+
first_branch = false
|
471
|
+
end
|
472
|
+
|
473
|
+
# Create the target dir
|
474
|
+
branch_path = File.join(preview_dir,distro,branch_config["dir"])
|
475
|
+
system("mkdir -p #{branch_path}/stylesheets")
|
476
|
+
system("mkdir -p #{branch_path}/javascripts")
|
477
|
+
system("mkdir -p #{branch_path}/images")
|
478
|
+
|
479
|
+
# Copy stylesheets into preview area
|
480
|
+
system("cp -r _stylesheets/*css #{branch_path}/stylesheets")
|
481
|
+
|
482
|
+
# Copy javascripts into preview area
|
483
|
+
system("cp -r _javascripts/*js #{branch_path}/javascripts")
|
484
|
+
|
485
|
+
# Copy images into preview area
|
486
|
+
system("cp -r _images/* #{branch_path}/images")
|
487
|
+
|
488
|
+
# Build the landing page
|
489
|
+
navigation = nav_tree(distro,branch_build_config)
|
490
|
+
|
491
|
+
# Build the topic files for this branch & distro
|
492
|
+
branch_build_config.each do |topic_group|
|
493
|
+
next if not topic_group['Distros'].include?(distro)
|
494
|
+
next if topic_group['Topics'].select{ |t| t['Distros'].include?(distro) }.length == 0
|
495
|
+
next if not single_page.nil? and not single_page_dir[0] == topic_group['Dir']
|
496
|
+
topic_group['Topics'].each do |topic|
|
497
|
+
src_group_path = File.join(source_dir,topic_group['Dir'])
|
498
|
+
tgt_group_path = File.join(branch_path,topic_group['Dir'])
|
499
|
+
if not File.exists?(tgt_group_path)
|
500
|
+
Dir.mkdir(tgt_group_path)
|
501
|
+
end
|
502
|
+
next if not topic['Distros'].include?(distro)
|
503
|
+
if topic.has_key?('File')
|
504
|
+
next if not single_page.nil? and not topic['File'] == single_page_file
|
505
|
+
topic_path = File.join(topic_group['Dir'],topic['File'])
|
506
|
+
configure_and_generate_page({
|
507
|
+
:distro => distro,
|
508
|
+
:distro_config => distro_config,
|
509
|
+
:branch_config => branch_config,
|
510
|
+
:navigation => navigation,
|
511
|
+
:topic => topic,
|
512
|
+
:topic_group => topic_group,
|
513
|
+
:topic_path => topic_path,
|
514
|
+
:src_group_path => src_group_path,
|
515
|
+
:tgt_group_path => tgt_group_path,
|
516
|
+
:single_page => single_page,
|
517
|
+
:site_name => site_name,
|
518
|
+
})
|
519
|
+
elsif topic.has_key?('Dir')
|
520
|
+
next if not single_page.nil? and not single_page_dir.join('/') == topic_group['Dir'] + '/' + topic['Dir']
|
521
|
+
topic['Topics'].each do |subtopic|
|
522
|
+
next if not subtopic['Distros'].include?(distro)
|
523
|
+
next if not single_page.nil? and not subtopic['File'] == single_page_file
|
524
|
+
src_group_path = File.join(source_dir,topic_group['Dir'],topic['Dir'])
|
525
|
+
tgt_group_path = File.join(branch_path,topic_group['Dir'],topic['Dir'])
|
526
|
+
if not File.exists?(tgt_group_path)
|
527
|
+
Dir.mkdir(tgt_group_path)
|
528
|
+
end
|
529
|
+
topic_path = File.join(topic_group['Dir'],topic['Dir'],subtopic['File'])
|
530
|
+
configure_and_generate_page({
|
531
|
+
:distro => distro,
|
532
|
+
:distro_config => distro_config,
|
533
|
+
:branch_config => branch_config,
|
534
|
+
:navigation => navigation,
|
535
|
+
:topic => subtopic,
|
536
|
+
:topic_group => topic_group,
|
537
|
+
:topic_subgroup => topic,
|
538
|
+
:topic_path => topic_path,
|
539
|
+
:src_group_path => src_group_path,
|
540
|
+
:tgt_group_path => tgt_group_path,
|
541
|
+
:single_page => single_page,
|
542
|
+
:site_name => site_name,
|
543
|
+
})
|
544
|
+
end
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
if not single_page.nil?
|
550
|
+
next
|
551
|
+
end
|
552
|
+
|
553
|
+
# Create a distro landing page
|
554
|
+
# This is backwards compatible code. We can remove it when no
|
555
|
+
# official repo uses index.adoc. We are moving to flat HTML
|
556
|
+
# files for index.html
|
557
|
+
src_file_path = File.join(source_dir,'index.adoc')
|
558
|
+
if File.exists?(src_file_path)
|
559
|
+
topic_adoc = File.open(src_file_path,'r').read
|
560
|
+
page_attrs = asciidoctor_page_attrs([
|
561
|
+
"imagesdir=#{File.join(source_dir,'_site_images')}",
|
562
|
+
distro,
|
563
|
+
"product-title=#{distro_config["name"]}",
|
564
|
+
"product-version=Updated #{build_date}",
|
565
|
+
"product-author=#{distro_config["author"]}"
|
566
|
+
])
|
567
|
+
topic_html = Asciidoctor.render topic_adoc, :header_footer => true, :safe => :unsafe, :attributes => page_attrs
|
568
|
+
File.write(File.join(preview_dir,distro,'index.html'),topic_html)
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
if not single_page.nil?
|
573
|
+
return
|
574
|
+
end
|
575
|
+
|
576
|
+
if local_branch == working_branch
|
577
|
+
# We're moving away from the working branch, so save off changed files
|
578
|
+
git_stash_all
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
# Return to the original branch
|
583
|
+
git_checkout(working_branch)
|
584
|
+
|
585
|
+
# If necessary, restore temporarily stashed files
|
586
|
+
git_apply_and_drop
|
587
|
+
|
588
|
+
puts "\nAll builds completed."
|
589
|
+
end
|
590
|
+
|
591
|
+
def configure_and_generate_page options
|
592
|
+
distro = options[:distro]
|
593
|
+
distro_config = options[:distro_config]
|
594
|
+
branch_config = options[:branch_config]
|
595
|
+
navigation = options[:navigation]
|
596
|
+
topic = options[:topic]
|
597
|
+
topic_group = options[:topic_group]
|
598
|
+
topic_subgroup = options[:topic_subgroup]
|
599
|
+
topic_path = options[:topic_path]
|
600
|
+
src_group_path = options[:src_group_path]
|
601
|
+
tgt_group_path = options[:tgt_group_path]
|
602
|
+
single_page = options[:single_page]
|
603
|
+
site_name = options[:site_name]
|
604
|
+
|
605
|
+
src_file_path = File.join(src_group_path,"#{topic['File']}.adoc")
|
606
|
+
tgt_file_path = File.join(tgt_group_path,"#{topic['File']}.html")
|
607
|
+
if single_page.nil?
|
608
|
+
puts " - #{topic_path}"
|
609
|
+
end
|
610
|
+
topic_adoc = File.open(src_file_path,'r').read
|
611
|
+
page_attrs = asciidoctor_page_attrs([
|
612
|
+
"imagesdir=#{src_group_path}/images",
|
613
|
+
distro,
|
614
|
+
"product-title=#{distro_config["name"]}",
|
615
|
+
"product-version=#{branch_config["name"]}",
|
616
|
+
"product-author=#{distro_config["author"]}"
|
617
|
+
])
|
618
|
+
|
619
|
+
# Because we render only the body of the article with AsciiDoctor, the full article title
|
620
|
+
# would be lost in conversion. So, use the _build_cfg.yml 'Name' as a fallback but try
|
621
|
+
# to read the full article title out of the file itself.
|
622
|
+
file_lines = topic_adoc.split("\n")
|
623
|
+
article_title = topic['Name']
|
624
|
+
if file_lines.length > 0
|
625
|
+
article_title = file_lines[0].gsub(/^\=\s+/, '').gsub(/\s+$/, '').gsub(/\{product-title\}/, distro_config["name"]).gsub(/\{product-version\}/, branch_config["name"])
|
626
|
+
end
|
627
|
+
|
628
|
+
topic_html = Asciidoctor.render topic_adoc, :header_footer => false, :safe => :unsafe, :attributes => page_attrs
|
629
|
+
dir_depth = ''
|
630
|
+
if branch_config['dir'].split('/').length > 1
|
631
|
+
dir_depth = '../' * (branch_config['dir'].split('/').length - 1)
|
632
|
+
end
|
633
|
+
if not topic_subgroup.nil?
|
634
|
+
dir_depth = '../' + dir_depth
|
635
|
+
end
|
636
|
+
page_args = {
|
637
|
+
:distro_key => distro,
|
638
|
+
:distro => distro_config["name"],
|
639
|
+
:site_name => site_name,
|
640
|
+
:version => branch_config["name"],
|
641
|
+
:group_title => topic_group['Name'],
|
642
|
+
:subgroup_title => topic_subgroup && topic_subgroup['Name'],
|
643
|
+
:topic_title => topic['Name'],
|
644
|
+
:article_title => article_title,
|
645
|
+
:content => topic_html,
|
646
|
+
:navigation => navigation,
|
647
|
+
:group_id => topic_group['ID'],
|
648
|
+
:subgroup_id => topic_subgroup && topic_subgroup['ID'],
|
649
|
+
:topic_id => topic['ID'],
|
650
|
+
:css_path => "../../#{dir_depth}#{branch_config["dir"]}/stylesheets/",
|
651
|
+
:javascripts_path => "../../#{dir_depth}#{branch_config["dir"]}/javascripts/",
|
652
|
+
:images_path => "../../#{dir_depth}#{branch_config["dir"]}/images/",
|
653
|
+
:site_home_path => "../../#{dir_depth}index.html",
|
654
|
+
:css => ['docs.css'],
|
655
|
+
}
|
656
|
+
full_file_text = page(page_args)
|
657
|
+
File.write(tgt_file_path,full_file_text)
|
658
|
+
end
|
659
|
+
|
660
|
+
# package_docs
|
661
|
+
# This method generates the docs and then organizes them the way they will be arranged
|
662
|
+
# for the production websites.
|
663
|
+
def package_docs(package_site)
|
664
|
+
site_map.each do |site,site_config|
|
665
|
+
next if not package_site == '' and not package_site == site
|
666
|
+
puts "\nBuilding #{site} site."
|
667
|
+
site_config[:distros].each do |distro,branches|
|
668
|
+
branches.each do |branch,branch_config|
|
669
|
+
src_dir = File.join(preview_dir,distro,branch_config["dir"])
|
670
|
+
tgt_tdir = branch_config["dir"].split('/')
|
671
|
+
tgt_tdir.pop
|
672
|
+
tgt_dir = ''
|
673
|
+
if tgt_tdir.length > 0
|
674
|
+
tgt_dir = File.join(package_dir,site,tgt_tdir.join('/'))
|
675
|
+
else
|
676
|
+
tgt_dir = File.join(package_dir,site)
|
677
|
+
end
|
678
|
+
next if not File.directory?(src_dir)
|
679
|
+
FileUtils.mkdir_p(tgt_dir)
|
680
|
+
FileUtils.cp_r(src_dir,tgt_dir)
|
681
|
+
end
|
682
|
+
site_dir = File.join(package_dir,site)
|
683
|
+
if File.directory?(site_dir)
|
684
|
+
# With this update, site index files will always come from the master branch
|
685
|
+
working_branch_site_index = File.join(source_dir,'index-' + site + '.html')
|
686
|
+
if File.exists?(working_branch_site_index)
|
687
|
+
FileUtils.cp(working_branch_site_index,File.join(package_dir,site,'index.html'))
|
688
|
+
['_images','_stylesheets'].each do |support_dir|
|
689
|
+
FileUtils.cp_r(File.join(source_dir,support_dir),File.join(package_dir,site,support_dir))
|
690
|
+
end
|
691
|
+
else
|
692
|
+
FileUtils.cp(File.join(preview_dir,distro,'index.html'),File.join(package_dir,site,'index.html'))
|
693
|
+
end
|
694
|
+
end
|
695
|
+
# Now build a sitemap
|
696
|
+
site_dir_path = Pathname.new(site_dir)
|
697
|
+
SitemapGenerator::Sitemap.default_host = site_config[:url]
|
698
|
+
SitemapGenerator::Sitemap.create( :compress => false, :filename => File.join(site_dir,'sitemap') ) do
|
699
|
+
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 }
|
700
|
+
file_list.each do |file|
|
701
|
+
add(file, :changefreq => 'daily')
|
702
|
+
end
|
703
|
+
end
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
end
|
708
|
+
end
|