bookbindery 7.4.4 → 7.5.0
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/bookbinder.gemspec +1 -1
- data/lib/bookbinder/cli.rb +1 -1
- data/lib/bookbinder/commands/bind.rb +17 -17
- data/lib/bookbinder/commands/collection.rb +48 -26
- data/lib/bookbinder/commands/components/bind/directory_preparer.rb +33 -0
- data/lib/bookbinder/commands/components/bind/layout_preparer.rb +27 -0
- data/lib/bookbinder/commands/{bind/bind_options.rb → components/command_options.rb} +2 -2
- data/lib/bookbinder/commands/components/imprint/directory_preparer.rb +24 -0
- data/lib/bookbinder/commands/imprint.rb +62 -0
- data/lib/bookbinder/commands/watch.rb +0 -1
- data/lib/bookbinder/config/checkers/ditamap_presence_checker.rb +27 -0
- data/lib/bookbinder/config/checkers/section_presence_checker.rb +15 -0
- data/lib/bookbinder/config/configuration.rb +18 -27
- data/lib/bookbinder/config/dita_config_generator.rb +61 -0
- data/lib/bookbinder/config/fetcher.rb +4 -3
- data/lib/bookbinder/config/imprint/configuration.rb +24 -0
- data/lib/bookbinder/config/section_config.rb +4 -0
- data/lib/bookbinder/config/validator.rb +4 -2
- data/lib/bookbinder/dita_command_creator.rb +31 -16
- data/lib/bookbinder/ingest/section_repository.rb +2 -1
- data/lib/bookbinder/local_filesystem_accessor.rb +9 -2
- data/lib/bookbinder/preprocessing/dita_html_preprocessor.rb +94 -0
- data/lib/bookbinder/preprocessing/dita_pdf_preprocessor.rb +50 -0
- data/lib/bookbinder/preprocessing/dita_preprocessor.rb +2 -86
- data/lib/bookbinder/values/output_locations.rb +12 -0
- data/lib/bookbinder/values/section.rb +3 -1
- data/master_middleman/bookbinder_helpers.rb +7 -6
- metadata +13 -6
- data/lib/bookbinder/commands/bind/directory_preparer.rb +0 -31
- data/lib/bookbinder/commands/bind/layout_preparer.rb +0 -25
- data/lib/bookbinder/config/checkers/dita_section_checker.rb +0 -31
@@ -0,0 +1,15 @@
|
|
1
|
+
module Bookbinder
|
2
|
+
module Config
|
3
|
+
module Checkers
|
4
|
+
class SectionPresenceChecker
|
5
|
+
NoSectionsError = Class.new(RuntimeError)
|
6
|
+
|
7
|
+
def check(config)
|
8
|
+
if config.sections.none?
|
9
|
+
NoSectionsError.new('No sections found in your config.yml. Add sections under the appropriate key(s) and try again.')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative '../../../lib/bookbinder/config/dita_config_generator'
|
1
2
|
require_relative '../ingest/destination_directory'
|
2
3
|
require_relative '../ingest/repo_identifier'
|
3
4
|
require_relative 'section_config'
|
@@ -8,13 +9,18 @@ module Bookbinder
|
|
8
9
|
class Configuration
|
9
10
|
class << self
|
10
11
|
def parse(input_config)
|
12
|
+
section_configs = to_section_configs(combined_sections(input_config))
|
13
|
+
parse_sections(input_config, section_configs)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def parse_sections(input_config, section_configs)
|
11
19
|
new(symbolize_keys(input_config).
|
12
20
|
merge(expand_repo_identifiers(input_config)).
|
13
|
-
merge(sections:
|
21
|
+
merge(sections: section_configs))
|
14
22
|
end
|
15
23
|
|
16
|
-
private
|
17
|
-
|
18
24
|
def symbolize_keys(h)
|
19
25
|
h.reduce({}) {|acc, (k, v)| acc.merge(k.to_sym => v) }
|
20
26
|
end
|
@@ -24,9 +30,14 @@ module Bookbinder
|
|
24
30
|
reduce({}) {|h, (k, v)| h.merge(:"#{k}_url" => Ingest::RepoIdentifier.new(v))}
|
25
31
|
end
|
26
32
|
|
33
|
+
def to_section_configs sections
|
34
|
+
sections.map { |section| Config::SectionConfig.new(section) }
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
27
39
|
def combined_sections(input_config)
|
28
|
-
|
29
|
-
map { |section| Config::SectionConfig.new(section) }
|
40
|
+
regular_sections(input_config) + dita_sections(input_config)
|
30
41
|
end
|
31
42
|
|
32
43
|
def regular_sections(input_config)
|
@@ -34,30 +45,10 @@ module Bookbinder
|
|
34
45
|
end
|
35
46
|
|
36
47
|
def dita_sections(input_config)
|
37
|
-
|
38
|
-
|
39
|
-
dita_section.merge(
|
40
|
-
'preprocessor_config' => {
|
41
|
-
'ditamap_location' => dita_section['ditamap_location'],
|
42
|
-
'ditaval_location' => dita_section['ditaval_location']
|
43
|
-
},
|
44
|
-
'subnav_template' => dita_subnav_template(dita_sections, dita_section)
|
45
|
-
).reject { |k, _|
|
46
|
-
%w(ditamap_location ditaval_location).include?(k)
|
47
|
-
}
|
48
|
+
(input_config['dita_sections'] || []).map { |dita_section|
|
49
|
+
DitaConfigGenerator.new(dita_section).to_hash
|
48
50
|
}
|
49
51
|
end
|
50
|
-
|
51
|
-
def dita_subnav_template(all_sections, current_section)
|
52
|
-
subnav_sections = all_sections.select { |section| section['ditamap_location'] }
|
53
|
-
if subnav_sections.any?
|
54
|
-
subnav_section = subnav_sections.include?(current_section) ? current_section : subnav_sections.first
|
55
|
-
dest_dir = Ingest::DestinationDirectory.new(
|
56
|
-
subnav_section.fetch('repository', {})['name'], subnav_section['directory'])
|
57
|
-
|
58
|
-
"dita_subnav_#{dest_dir}"
|
59
|
-
end
|
60
|
-
end
|
61
52
|
end
|
62
53
|
|
63
54
|
def initialize(config)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../../../lib/bookbinder/ingest/destination_directory'
|
2
|
+
|
3
|
+
module Bookbinder
|
4
|
+
module Config
|
5
|
+
class DitaConfigGenerator
|
6
|
+
|
7
|
+
def initialize(section_hash)
|
8
|
+
@section_hash = section_hash
|
9
|
+
end
|
10
|
+
|
11
|
+
def subnav_template
|
12
|
+
dest_dir = Ingest::DestinationDirectory.new(section_hash.fetch('repository', {})['name'], section_hash['directory'])
|
13
|
+
|
14
|
+
"dita_subnav_#{dest_dir}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def ditamap_location
|
18
|
+
section_hash['ditamap_location'] if section_hash['ditamap_location'] && !section_hash['ditamap_location'].empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def pdf_output_filename
|
22
|
+
if present?(section_hash['output_filename'])
|
23
|
+
filename = section_hash['output_filename']
|
24
|
+
elsif ditamap_location
|
25
|
+
filename = ditamap_location.gsub(/\.ditamap/, '')
|
26
|
+
else
|
27
|
+
return
|
28
|
+
end
|
29
|
+
|
30
|
+
filename + '.pdf'
|
31
|
+
end
|
32
|
+
|
33
|
+
def preprocessor_config
|
34
|
+
{
|
35
|
+
'preprocessor_config' => {
|
36
|
+
'ditamap_location' => ditamap_location,
|
37
|
+
'ditaval_location' => section_hash['ditaval_location']
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_hash
|
43
|
+
section_hash.tap do |hash|
|
44
|
+
hash.merge!(preprocessor_config)
|
45
|
+
.merge!('subnav_template' => subnav_template, 'output_filename' => pdf_output_filename)
|
46
|
+
|
47
|
+
hash.delete('ditaval_location')
|
48
|
+
hash.delete('ditamap_location')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_reader :section_hash
|
55
|
+
|
56
|
+
def present?(value)
|
57
|
+
value && !value.empty?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -6,10 +6,11 @@ require_relative 'yaml_loader'
|
|
6
6
|
module Bookbinder
|
7
7
|
module Config
|
8
8
|
class Fetcher
|
9
|
-
def initialize(configuration_validator, loader, credentials_provider)
|
9
|
+
def initialize(configuration_validator, loader, credentials_provider, config_class)
|
10
10
|
@loader = loader
|
11
11
|
@configuration_validator = configuration_validator
|
12
12
|
@credentials_provider = credentials_provider
|
13
|
+
@config_class = config_class
|
13
14
|
end
|
14
15
|
|
15
16
|
def fetch_config
|
@@ -43,7 +44,7 @@ module Bookbinder
|
|
43
44
|
private
|
44
45
|
|
45
46
|
attr_reader(:loader, :configuration_validator, :config, :config_file_path, :config_dir_path,
|
46
|
-
:credentials_provider)
|
47
|
+
:credentials_provider, :config_class)
|
47
48
|
|
48
49
|
def read_config_file
|
49
50
|
loader.load(config_file_path)
|
@@ -65,7 +66,7 @@ module Bookbinder
|
|
65
66
|
def validate(base_hash, optional_hash)
|
66
67
|
raise 'Your config.yml appears to be empty. Please check and try again.' unless base_hash
|
67
68
|
|
68
|
-
|
69
|
+
config_class.parse(base_hash.merge(optional_hash)).tap do |config|
|
69
70
|
errors = configuration_validator.exceptions(config)
|
70
71
|
raise errors.first if errors.any?
|
71
72
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative '../configuration'
|
2
|
+
|
3
|
+
module Bookbinder
|
4
|
+
module Config
|
5
|
+
module Imprint
|
6
|
+
class Configuration < Config::Configuration
|
7
|
+
class << self
|
8
|
+
def parse(input_config)
|
9
|
+
section_configs = to_section_configs(pdf_sections(input_config))
|
10
|
+
parse_sections(input_config, section_configs)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def pdf_sections(input_config)
|
16
|
+
(input_config['pdf_sections'] || []).map { |pdf_section|
|
17
|
+
DitaConfigGenerator.new(pdf_section).to_hash
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -2,7 +2,8 @@ require_relative 'checkers/duplicate_section_name_checker'
|
|
2
2
|
require_relative 'checkers/archive_menu_checker'
|
3
3
|
require_relative 'checkers/required_keys_checker'
|
4
4
|
require_relative 'checkers/repository_name_presence_checker'
|
5
|
-
require_relative 'checkers/
|
5
|
+
require_relative 'checkers/ditamap_presence_checker'
|
6
|
+
require_relative 'checkers/section_presence_checker'
|
6
7
|
require_relative 'checkers/subnavs_checker'
|
7
8
|
require_relative 'checkers/topics_checker'
|
8
9
|
|
@@ -18,7 +19,8 @@ module Bookbinder
|
|
18
19
|
Checkers::RequiredKeysChecker.new,
|
19
20
|
Checkers::DuplicateSectionNameChecker.new,
|
20
21
|
Checkers::RepositoryNamePresenceChecker.new,
|
21
|
-
Checkers::
|
22
|
+
Checkers::SectionPresenceChecker.new,
|
23
|
+
Checkers::DitamapPresenceChecker.new,
|
22
24
|
Checkers::ArchiveMenuChecker.new(@file_system_accessor),
|
23
25
|
Checkers::SubnavsChecker.new,
|
24
26
|
Checkers::TopicsChecker.new
|
@@ -6,36 +6,38 @@ module Bookbinder
|
|
6
6
|
@path_to_dita_ot_library = path_to_dita_ot_library
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
def convert_to_pdf_command(dita_section, dita_flags: nil, write_to: nil)
|
10
|
+
"export CLASSPATH=#{classpath}; " +
|
11
|
+
"ant -f #{path_to_dita_ot_library} " +
|
12
|
+
unduplicated_flags(
|
13
|
+
write_to: write_to,
|
14
|
+
dita_flags: dita_flags,
|
15
|
+
ditamap_path: dita_section.path_to_preprocessor_attribute('ditamap_location'),
|
16
|
+
ditaval_path: dita_section.path_to_preprocessor_attribute('ditaval_location'),
|
17
|
+
default_transtype: 'pdf2'
|
18
|
+
)
|
19
|
+
end
|
20
20
|
|
21
|
+
def convert_to_html_command(dita_section, dita_flags: nil, write_to: nil)
|
21
22
|
"export CLASSPATH=#{classpath}; " +
|
22
23
|
"ant -f #{path_to_dita_ot_library} " +
|
23
24
|
unduplicated_flags(
|
24
25
|
write_to: write_to,
|
25
26
|
dita_flags: dita_flags,
|
26
27
|
ditamap_path: dita_section.path_to_preprocessor_attribute('ditamap_location'),
|
27
|
-
ditaval_path: dita_section.path_to_preprocessor_attribute('ditaval_location')
|
28
|
+
ditaval_path: dita_section.path_to_preprocessor_attribute('ditaval_location'),
|
29
|
+
default_transtype: 'tocjs'
|
28
30
|
)
|
29
31
|
end
|
30
32
|
|
31
33
|
private
|
32
34
|
|
33
|
-
def unduplicated_flags(write_to: nil, ditamap_path: nil, ditaval_path: nil, dita_flags: nil)
|
35
|
+
def unduplicated_flags(write_to: nil, ditamap_path: nil, ditaval_path: nil, dita_flags: nil, default_transtype: nil)
|
34
36
|
arg_flags = {
|
35
37
|
'output.dir' => write_to,
|
36
38
|
'args.input' => ditamap_path,
|
37
39
|
}.merge(filter(ditaval_path))
|
38
|
-
all_flags = arg_flags.merge(base_flags.merge(optional_flags
|
40
|
+
all_flags = arg_flags.merge(base_flags(default_transtype: default_transtype).merge(optional_flags(dita_flags)))
|
39
41
|
format(all_flags)
|
40
42
|
end
|
41
43
|
|
@@ -43,10 +45,10 @@ module Bookbinder
|
|
43
45
|
ditaval_path ? { 'args.filter' => ditaval_path } : {}
|
44
46
|
end
|
45
47
|
|
46
|
-
def base_flags
|
48
|
+
def base_flags(default_transtype: nil)
|
47
49
|
{
|
48
50
|
'basedir' => '/',
|
49
|
-
'transtype' =>
|
51
|
+
'transtype' => default_transtype,
|
50
52
|
'dita.temp.dir' => '/tmp/bookbinder_dita',
|
51
53
|
'generate.copy.outer' => '2',
|
52
54
|
'outer.control' => 'warn'
|
@@ -75,6 +77,19 @@ module Bookbinder
|
|
75
77
|
v.to_s.gsub(/['|"]/, "")
|
76
78
|
end
|
77
79
|
|
80
|
+
def classpath
|
81
|
+
"#{path_to_dita_ot_library}/lib/xercesImpl.jar:" +
|
82
|
+
"#{path_to_dita_ot_library}/lib/xml-apis.jar:" +
|
83
|
+
"#{path_to_dita_ot_library}/lib/resolver.jar:" +
|
84
|
+
"#{path_to_dita_ot_library}/lib/commons-codec-1.4.jar:" +
|
85
|
+
"#{path_to_dita_ot_library}/lib/icu4j.jar:" +
|
86
|
+
"#{path_to_dita_ot_library}/lib/saxon/saxon9-dom.jar:" +
|
87
|
+
"#{path_to_dita_ot_library}/lib/saxon/saxon9.jar:target/classes:" +
|
88
|
+
"#{path_to_dita_ot_library}:" +
|
89
|
+
"#{path_to_dita_ot_library}/lib/:" +
|
90
|
+
"#{path_to_dita_ot_library}/lib/dost.jar"
|
91
|
+
end
|
92
|
+
|
78
93
|
attr_reader :path_to_dita_ot_library
|
79
94
|
end
|
80
95
|
end
|
@@ -46,6 +46,11 @@ module Bookbinder
|
|
46
46
|
FileUtils.cp_r src, dest
|
47
47
|
end
|
48
48
|
|
49
|
+
def copy_and_rename(src, dest)
|
50
|
+
make_directory(Pathname(dest).dirname)
|
51
|
+
FileUtils.cp_r src, dest
|
52
|
+
end
|
53
|
+
|
49
54
|
def copy_contents(src, dest)
|
50
55
|
raise Errors::ProgrammerMistake.new("The method copy_contents cannot copy the contents of the directory '#{src}' because it was not found.") unless Dir.exists?(src)
|
51
56
|
copy "#{src}/.", dest
|
@@ -68,7 +73,9 @@ module Bookbinder
|
|
68
73
|
end
|
69
74
|
|
70
75
|
def find_files_with_ext(ext, path)
|
71
|
-
|
76
|
+
all_files = find_files_recursively(path)
|
77
|
+
matching_files = all_files.select {|p| p.to_s.match(/\.#{ext}/) }
|
78
|
+
matching_files.map(&:to_s)
|
72
79
|
end
|
73
80
|
|
74
81
|
def relative_path_from(src, target)
|
@@ -78,7 +85,7 @@ module Bookbinder
|
|
78
85
|
end
|
79
86
|
|
80
87
|
def find_files_recursively(from)
|
81
|
-
`find -L #{from}`.
|
88
|
+
`find -L #{from} -type f`.
|
82
89
|
lines.
|
83
90
|
map(&:chomp).
|
84
91
|
map(&Pathname.method(:new)).
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require_relative '../values/subnav_template'
|
2
|
+
require_relative '../../../lib/bookbinder/subnav/json_from_html_toc'
|
3
|
+
require_relative 'dita_preprocessor'
|
4
|
+
|
5
|
+
module Bookbinder
|
6
|
+
module Preprocessing
|
7
|
+
class DitaHTMLPreprocessor < DitaPreprocessor
|
8
|
+
DitaToHtmlLibraryFailure = Class.new(RuntimeError)
|
9
|
+
|
10
|
+
ACCEPTED_IMAGE_FORMATS = %w(png jpeg jpg svg gif bmp tif tiff eps)
|
11
|
+
|
12
|
+
def initialize(fs, subnav_gen_factory, dita_formatter, command_creator, sheller)
|
13
|
+
@fs = fs
|
14
|
+
@subnav_gen_factory = subnav_gen_factory
|
15
|
+
@dita_formatter = dita_formatter
|
16
|
+
@command_creator = command_creator
|
17
|
+
@sheller = sheller
|
18
|
+
end
|
19
|
+
|
20
|
+
def applicable_to?(section)
|
21
|
+
section.subnav_template.include?('dita_subnav') if section.subnav_template
|
22
|
+
end
|
23
|
+
|
24
|
+
def preprocess(sections, output_locations, options: [], output_streams: nil, **_)
|
25
|
+
@output_locations = output_locations
|
26
|
+
|
27
|
+
dita_options = dita_flags(options)
|
28
|
+
|
29
|
+
sections.each do |section|
|
30
|
+
if section.path_to_preprocessor_attribute('ditamap_location')
|
31
|
+
convert_dita_files(section,
|
32
|
+
command_creator,
|
33
|
+
dita_options,
|
34
|
+
section_html_dir(section),
|
35
|
+
sheller,
|
36
|
+
output_streams)
|
37
|
+
|
38
|
+
subnav_generator.generate(section)
|
39
|
+
end
|
40
|
+
|
41
|
+
dita_formatter.format_html(section_html_dir(section), formatted_dir(section))
|
42
|
+
copy_images(section.path_to_repo_dir, formatted_dir(section))
|
43
|
+
fs.copy_contents(formatted_dir(section), source_for_site_gen_dir(section))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
attr_reader :fs, :subnav_gen_factory, :dita_formatter, :command_creator, :sheller, :subnav_generator, :output_locations
|
50
|
+
|
51
|
+
def section_html_dir(section)
|
52
|
+
output_locations.html_from_preprocessing_dir.join(section.destination_directory)
|
53
|
+
end
|
54
|
+
|
55
|
+
def formatted_dir(section)
|
56
|
+
output_locations.formatted_dir.join(section.destination_directory)
|
57
|
+
end
|
58
|
+
|
59
|
+
def source_for_site_gen_dir(section)
|
60
|
+
output_locations.source_for_site_generator.join(section.destination_directory)
|
61
|
+
end
|
62
|
+
|
63
|
+
def convert_dita_files(section, command_creator, options, section_html_dir, sheller, output_streams)
|
64
|
+
command = command_creator.convert_to_html_command(
|
65
|
+
section,
|
66
|
+
dita_flags: options,
|
67
|
+
write_to: section_html_dir
|
68
|
+
)
|
69
|
+
status = sheller.run_command(command, output_streams.to_h)
|
70
|
+
unless status.success?
|
71
|
+
raise DitaToHtmlLibraryFailure.new 'The DITA-to-HTML conversion failed. ' +
|
72
|
+
'Please check that you have specified the path to your DITA-OT library in the ENV, ' +
|
73
|
+
'that your DITA-specific keys/values in config.yml are set, ' +
|
74
|
+
'and that your DITA toolkit is correctly configured.'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def copy_images(src, dest)
|
79
|
+
image_paths = ACCEPTED_IMAGE_FORMATS.map do |format|
|
80
|
+
fs.find_files_with_ext(format, src)
|
81
|
+
end.flatten
|
82
|
+
|
83
|
+
image_paths.each do |image_path|
|
84
|
+
fs.copy_including_intermediate_dirs(image_path, src, dest)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def subnav_generator
|
90
|
+
@subnav_generator ||= subnav_gen_factory.produce(Subnav::JsonFromHtmlToc.new(fs))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|