bookwatch 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bookwatch.gemspec +40 -0
- data/install_bin/bookwatch +5 -0
- data/lib/bookwatch/cli.rb +109 -0
- data/lib/bookwatch/code_example_reader.rb +95 -0
- data/lib/bookwatch/colorizer.rb +16 -0
- data/lib/bookwatch/commands/bind.rb +119 -0
- data/lib/bookwatch/commands/collection.rb +181 -0
- data/lib/bookwatch/commands/components/bind/directory_preparer.rb +33 -0
- data/lib/bookwatch/commands/components/bind/layout_preparer.rb +27 -0
- data/lib/bookwatch/commands/components/command_options.rb +45 -0
- data/lib/bookwatch/commands/components/imprint/directory_preparer.rb +24 -0
- data/lib/bookwatch/commands/generate.rb +92 -0
- data/lib/bookwatch/commands/imprint.rb +55 -0
- data/lib/bookwatch/commands/punch.rb +33 -0
- data/lib/bookwatch/commands/update_local_doc_repos.rb +42 -0
- data/lib/bookwatch/commands/watch.rb +100 -0
- data/lib/bookwatch/config/checkers/archive_menu_checker.rb +29 -0
- data/lib/bookwatch/config/checkers/ditamap_presence_checker.rb +27 -0
- data/lib/bookwatch/config/checkers/duplicate_section_name_checker.rb +33 -0
- data/lib/bookwatch/config/checkers/products_checker.rb +34 -0
- data/lib/bookwatch/config/checkers/repository_name_presence_checker.rb +34 -0
- data/lib/bookwatch/config/checkers/required_keys_checker.rb +18 -0
- data/lib/bookwatch/config/checkers/section_presence_checker.rb +15 -0
- data/lib/bookwatch/config/configuration.rb +119 -0
- data/lib/bookwatch/config/configuration_decorator.rb +54 -0
- data/lib/bookwatch/config/dita_config_generator.rb +61 -0
- data/lib/bookwatch/config/fetcher.rb +64 -0
- data/lib/bookwatch/config/imprint/configuration.rb +24 -0
- data/lib/bookwatch/config/product_config.rb +34 -0
- data/lib/bookwatch/config/section_config.rb +85 -0
- data/lib/bookwatch/config/validator.rb +33 -0
- data/lib/bookwatch/config/yaml_loader.rb +34 -0
- data/lib/bookwatch/css_link_checker.rb +67 -0
- data/lib/bookwatch/directory_helpers.rb +15 -0
- data/lib/bookwatch/dita_command_creator.rb +95 -0
- data/lib/bookwatch/dita_html_for_middleman_formatter.rb +45 -0
- data/lib/bookwatch/errors/programmer_mistake.rb +5 -0
- data/lib/bookwatch/html_document_manipulator.rb +21 -0
- data/lib/bookwatch/ingest/cloner_factory.rb +26 -0
- data/lib/bookwatch/ingest/destination_directory.rb +21 -0
- data/lib/bookwatch/ingest/git_accessor.rb +102 -0
- data/lib/bookwatch/ingest/git_cloner.rb +36 -0
- data/lib/bookwatch/ingest/local_filesystem_cloner.rb +66 -0
- data/lib/bookwatch/ingest/missing_working_copy.rb +27 -0
- data/lib/bookwatch/ingest/repo_identifier.rb +45 -0
- data/lib/bookwatch/ingest/section_repository.rb +49 -0
- data/lib/bookwatch/ingest/update_failure.rb +15 -0
- data/lib/bookwatch/ingest/update_success.rb +12 -0
- data/lib/bookwatch/ingest/working_copy.rb +36 -0
- data/lib/bookwatch/local_filesystem_accessor.rb +122 -0
- data/lib/bookwatch/middleman_runner.rb +48 -0
- data/lib/bookwatch/postprocessing/link_checker.rb +125 -0
- data/lib/bookwatch/postprocessing/redirection.rb +38 -0
- data/lib/bookwatch/preprocessing/dita_html_preprocessor.rb +91 -0
- data/lib/bookwatch/preprocessing/dita_pdf_preprocessor.rb +48 -0
- data/lib/bookwatch/preprocessing/link_to_site_gen_dir.rb +39 -0
- data/lib/bookwatch/preprocessing/preprocessor.rb +26 -0
- data/lib/bookwatch/server_director.rb +30 -0
- data/lib/bookwatch/sheller.rb +52 -0
- data/lib/bookwatch/streams/colorized_stream.rb +25 -0
- data/lib/bookwatch/streams/filter_stream.rb +22 -0
- data/lib/bookwatch/subnav/navigation_entries_from_html_toc.rb +59 -0
- data/lib/bookwatch/subnav/navigation_entries_from_markdown_root.rb +116 -0
- data/lib/bookwatch/subnav/pdf_config_creator.rb +50 -0
- data/lib/bookwatch/subnav/subnav_generator.rb +28 -0
- data/lib/bookwatch/subnav/subnav_generator_factory.rb +29 -0
- data/lib/bookwatch/subnav/template_creator.rb +71 -0
- data/lib/bookwatch/terminal.rb +19 -0
- data/lib/bookwatch/values/output_locations.rb +91 -0
- data/lib/bookwatch/values/product_info.rb +11 -0
- data/lib/bookwatch/values/section.rb +58 -0
- data/lib/bookwatch/values/subnav_template.rb +4 -0
- data/lib/bookwatch/values/user_message.rb +15 -0
- data/master_middleman/archive_drop_down_menu.rb +50 -0
- data/master_middleman/bookwatch_helpers.rb +259 -0
- data/master_middleman/compass_runner.rb +0 -0
- data/master_middleman/config.rb +34 -0
- data/master_middleman/quicklinks_renderer.rb +80 -0
- data/master_middleman/source/javascripts/all.js +2 -0
- data/master_middleman/source/javascripts/book.js +1 -0
- data/master_middleman/source/javascripts/bookwatch.js +103 -0
- data/master_middleman/source/layouts/_additional-scripts.erb +0 -0
- data/master_middleman/source/layouts/_book-footer.erb +0 -0
- data/master_middleman/source/layouts/_book-search.erb +0 -0
- data/master_middleman/source/layouts/_book-title.erb +3 -0
- data/master_middleman/source/layouts/_header.erb +34 -0
- data/master_middleman/source/layouts/_local-header.erb +0 -0
- data/master_middleman/source/layouts/_page-footer.erb +1 -0
- data/master_middleman/source/layouts/_title.erb +5 -0
- data/master_middleman/source/layouts/layout.erb +69 -0
- data/master_middleman/source/stylesheets/all.css.scss +3 -0
- data/master_middleman/source/stylesheets/base.scss +380 -0
- data/master_middleman/source/stylesheets/book-styles.css.scss +0 -0
- data/master_middleman/source/stylesheets/layout-styles.scss +0 -0
- data/master_middleman/source/stylesheets/partials/_book-base-values.scss +0 -0
- data/master_middleman/source/stylesheets/partials/_book-vars.scss +0 -0
- data/master_middleman/source/stylesheets/partials/_default.scss +300 -0
- data/master_middleman/source/stylesheets/partials/_footer.scss +64 -0
- data/master_middleman/source/stylesheets/partials/_header.scss +419 -0
- data/master_middleman/source/stylesheets/partials/_layout-vars.scss +0 -0
- data/master_middleman/source/stylesheets/partials/_mixins.scss +53 -0
- data/master_middleman/source/stylesheets/partials/_reset.scss +233 -0
- data/master_middleman/source/stylesheets/partials/_search.scss +78 -0
- data/master_middleman/source/stylesheets/partials/_sidenav.scss +191 -0
- data/master_middleman/source/stylesheets/partials/_syntax-highlight.scss +64 -0
- data/master_middleman/source/stylesheets/partials/_vars.scss +64 -0
- data/master_middleman/source/stylesheets/print.css.scss +58 -0
- data/master_middleman/source/subnavs/_default.erb +0 -0
- data/master_middleman/source/subnavs/_nav-links.erb +10 -0
- data/master_middleman/source/subnavs/_subnav_template.erb +8 -0
- data/master_middleman/subdirectory_aware_assets.rb +47 -0
- data/template_app/Gemfile +10 -0
- data/template_app/Gemfile.lock +43 -0
- data/template_app/config.ru +9 -0
- data/template_app/lib/rack_static_if_exists.rb +19 -0
- data/template_app/lib/search/handler.rb +47 -0
- data/template_app/lib/search/hit.rb +21 -0
- data/template_app/lib/search/query.rb +74 -0
- data/template_app/lib/search/renderer.rb +29 -0
- data/template_app/lib/server.rb +52 -0
- data/template_app/mail_sender.rb +69 -0
- data/template_app/rack_app.rb +110 -0
- data/template_app/search-results.html.erb +75 -0
- data/template_app/search.yml +22 -0
- metadata +491 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'pathname'
|
3
|
+
require_relative 'errors/programmer_mistake'
|
4
|
+
|
5
|
+
module Bookwatch
|
6
|
+
|
7
|
+
class LocalFilesystemAccessor
|
8
|
+
def file_exist?(path)
|
9
|
+
File.exist?(path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def is_file?(path)
|
13
|
+
File.file?(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def is_dir?(path)
|
17
|
+
Dir.exists?(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(to: nil, text: nil)
|
21
|
+
make_directory(File.dirname to)
|
22
|
+
|
23
|
+
File.open(to, 'a') do |f|
|
24
|
+
f.write(text)
|
25
|
+
end
|
26
|
+
|
27
|
+
to
|
28
|
+
end
|
29
|
+
|
30
|
+
def overwrite(to: nil, text: nil)
|
31
|
+
File.delete(to) if file_exist?(to)
|
32
|
+
write(to: to, text: text)
|
33
|
+
end
|
34
|
+
|
35
|
+
def read(path)
|
36
|
+
File.read(path)
|
37
|
+
end
|
38
|
+
|
39
|
+
def empty_directory(path)
|
40
|
+
FileUtils.rm_rf(File.join(path, '.'))
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove_directory(path)
|
44
|
+
FileUtils.rm_rf(path)
|
45
|
+
end
|
46
|
+
|
47
|
+
def make_directory(path)
|
48
|
+
FileUtils.mkdir_p(path)
|
49
|
+
end
|
50
|
+
|
51
|
+
def copy(src, dest)
|
52
|
+
make_directory(dest)
|
53
|
+
FileUtils.cp_r src, dest
|
54
|
+
end
|
55
|
+
|
56
|
+
def copy_and_rename(src, dest)
|
57
|
+
make_directory(Pathname(dest).dirname)
|
58
|
+
FileUtils.cp_r src, dest
|
59
|
+
end
|
60
|
+
|
61
|
+
def copy_contents(src, dest)
|
62
|
+
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)
|
63
|
+
copy "#{src}/.", dest
|
64
|
+
end
|
65
|
+
|
66
|
+
def copy_including_intermediate_dirs(file, root, dest)
|
67
|
+
path_within_destination = relative_path_from(root, file)
|
68
|
+
extended_dest = File.dirname(File.join dest, path_within_destination)
|
69
|
+
copy file, extended_dest
|
70
|
+
end
|
71
|
+
|
72
|
+
def link_creating_intermediate_dirs(src, dst)
|
73
|
+
FileUtils.mkdir_p(File.dirname(dst))
|
74
|
+
File.symlink(src, dst)
|
75
|
+
end
|
76
|
+
|
77
|
+
def rename_file(path, new_name)
|
78
|
+
new_path = File.expand_path File.join path, '..', new_name
|
79
|
+
File.rename(path, new_path)
|
80
|
+
end
|
81
|
+
|
82
|
+
def find_files_with_ext(ext, path)
|
83
|
+
all_files = find_files_recursively(path)
|
84
|
+
matching_files = all_files.select {|p| p.to_s.match(/\.#{ext}/) }
|
85
|
+
matching_files.map(&:to_s)
|
86
|
+
end
|
87
|
+
|
88
|
+
def relative_path_from(src, target)
|
89
|
+
target_path = Pathname(File.absolute_path target)
|
90
|
+
relative_path = target_path.relative_path_from(Pathname(File.absolute_path src))
|
91
|
+
relative_path.to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def find_files_recursively(from)
|
95
|
+
`find -L #{from} -type f`.
|
96
|
+
lines.
|
97
|
+
map(&:chomp).
|
98
|
+
map(&Pathname.method(:new)).
|
99
|
+
reject {|p| p.to_s.match %r{/\.}}.
|
100
|
+
reject(&:directory?)
|
101
|
+
end
|
102
|
+
|
103
|
+
def find_files_extension_agnostically(pattern, directory='.')
|
104
|
+
extensionless_pattern = File.join(File.dirname(pattern), File.basename(pattern).split('.').first)
|
105
|
+
|
106
|
+
`find -L #{directory} -path '*/#{extensionless_pattern}.*' -type f`.
|
107
|
+
lines.
|
108
|
+
map(&:chomp).
|
109
|
+
map(&Pathname.method(:new))
|
110
|
+
end
|
111
|
+
|
112
|
+
def source_file_exists?(directory, path_to_file)
|
113
|
+
path = Pathname(path_to_file.split('/').last)
|
114
|
+
source_file_found = false
|
115
|
+
|
116
|
+
Pathname(directory).ascend do |dir|
|
117
|
+
source_file_found = true if dir.entries.any? { |entry| entry == path }
|
118
|
+
end
|
119
|
+
source_file_found
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'middleman-core'
|
2
|
+
require 'middleman-core/cli'
|
3
|
+
require 'middleman-core/profiling'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
module Bookwatch
|
7
|
+
class MiddlemanRunner
|
8
|
+
def initialize(fs, sheller)
|
9
|
+
@fs = fs
|
10
|
+
@sheller = sheller
|
11
|
+
end
|
12
|
+
|
13
|
+
def run(command,
|
14
|
+
streams: nil,
|
15
|
+
output_locations: nil,
|
16
|
+
config: nil,
|
17
|
+
local_repo_dir: nil,
|
18
|
+
subnavs: nil,
|
19
|
+
product_info: nil)
|
20
|
+
streams[:out].puts "\nRunning middleman...\n\n"
|
21
|
+
Dir.chdir(output_locations.master_dir) do
|
22
|
+
config = {
|
23
|
+
archive_menu: config.archive_menu,
|
24
|
+
production_host: config.public_host,
|
25
|
+
subnav_templates: subnavs,
|
26
|
+
template_variables: config.template_variables,
|
27
|
+
local_repo_dir: local_repo_dir,
|
28
|
+
workspace: output_locations.workspace_dir,
|
29
|
+
feedback_enabled: config.feedback_enabled,
|
30
|
+
repo_link_enabled: config.repo_link_enabled,
|
31
|
+
repo_links: config.repo_links,
|
32
|
+
product_info: product_info,
|
33
|
+
elastic_search: config.elastic_search?
|
34
|
+
}
|
35
|
+
|
36
|
+
fs.write(to: "bookwatch_config.yml", text: YAML.dump(config))
|
37
|
+
sheller.run_command({'MM_ROOT' => output_locations.master_dir.to_s},
|
38
|
+
"middleman #{command}",
|
39
|
+
streams)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
attr_reader :streams, :fs, :sheller
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require_relative '../css_link_checker'
|
3
|
+
require_relative 'redirection'
|
4
|
+
|
5
|
+
module Bookwatch
|
6
|
+
module Postprocessing
|
7
|
+
class LinkChecker
|
8
|
+
def initialize(fs, root_path, output_streams)
|
9
|
+
@fs = fs
|
10
|
+
@root_path = root_path
|
11
|
+
@output_streams = output_streams
|
12
|
+
@broken_link_count = 0
|
13
|
+
|
14
|
+
@convert_to_relative = %r{\A.*#{root_path.to_s}/public}
|
15
|
+
@default_link_exclusions = %r{\A(?:https?://|javascript:|mailto:)}
|
16
|
+
@excluded_pages = %r{\A/(?:404\.html|subnavs|javascripts|stylesheets|style_guide)}
|
17
|
+
end
|
18
|
+
|
19
|
+
def check!(link_exclusions = /(?!.*)/)
|
20
|
+
@output_streams[:out].puts "\nChecking for broken links..."
|
21
|
+
@redirects = Redirection.new(@fs, File.join(@root_path, 'redirects.rb'))
|
22
|
+
load_page_links
|
23
|
+
|
24
|
+
report_broken_links!(link_exclusions)
|
25
|
+
report_orphaned_pages!
|
26
|
+
|
27
|
+
if has_errors?
|
28
|
+
err "\nFound #{@broken_link_count} broken links!"
|
29
|
+
else
|
30
|
+
out "\nNo broken links!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_errors?
|
35
|
+
@broken_link_count > 0
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def report_broken_links!(link_exclusions)
|
41
|
+
@page_links.each do |page, links|
|
42
|
+
links.each do |link|
|
43
|
+
next if skip?(link, link_exclusions)
|
44
|
+
|
45
|
+
absolute_link, fragment = normalize_link(link, page)
|
46
|
+
|
47
|
+
if !page_exists?(absolute_link) && !file_exists?(absolute_link)
|
48
|
+
@broken_link_count += 1
|
49
|
+
err "#{page} => #{absolute_link}#{fragment ? "##{fragment}" : ''}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
broken_css_links = Dir.chdir(@root_path) { CssLinkChecker.new.broken_links_in_all_stylesheets }
|
55
|
+
broken_css_links.reject! { |link| link_exclusions.match(link) }
|
56
|
+
|
57
|
+
@broken_link_count += broken_css_links.size
|
58
|
+
broken_css_links.each do |link|
|
59
|
+
err link
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def report_orphaned_pages!
|
64
|
+
linked_pages = @page_links.map do |page, links|
|
65
|
+
links.map do |link|
|
66
|
+
normalize_link(link, page)[0]
|
67
|
+
end
|
68
|
+
end.flatten.uniq
|
69
|
+
|
70
|
+
orphaned_pages = @page_links.keys.reject { |page| page == '/index.html' || linked_pages.include?(page) }
|
71
|
+
if orphaned_pages.size > 0
|
72
|
+
err "\nOrphaned pages"
|
73
|
+
orphaned_pages.each do |page|
|
74
|
+
err "No links to => #{page}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def skip?(link_path, link_exclusions)
|
80
|
+
@default_link_exclusions.match(link_path) || link_path.match(link_exclusions)
|
81
|
+
end
|
82
|
+
|
83
|
+
def page_exists?(link)
|
84
|
+
@page_links.has_key?(link) || @redirects.redirected?(link)
|
85
|
+
end
|
86
|
+
|
87
|
+
def normalize_link(link, page)
|
88
|
+
return [page, link.sub(/\A#/, '')] if link[0] == '#'
|
89
|
+
|
90
|
+
absolute_link = link[0] == '/' ? link : File.expand_path(link, File.dirname(page))
|
91
|
+
absolute_link.split('#')
|
92
|
+
end
|
93
|
+
|
94
|
+
def file_exists?(link)
|
95
|
+
full_path = File.join(@root_path, 'public', link)
|
96
|
+
@fs.is_file?(full_path) || (@fs.is_dir?(full_path) && @fs.is_file?(File.join(full_path, 'index.html')))
|
97
|
+
end
|
98
|
+
|
99
|
+
def load_page_links
|
100
|
+
files = @fs.find_files_with_ext('html', File.join(@root_path, 'public'))
|
101
|
+
|
102
|
+
@page_links = files.each.with_object({}) do |file_path, links|
|
103
|
+
public_path = file_path.sub(@convert_to_relative, '')
|
104
|
+
|
105
|
+
if !@excluded_pages.match(public_path)
|
106
|
+
html = Nokogiri::HTML(@fs.read(file_path))
|
107
|
+
|
108
|
+
links[public_path] = [
|
109
|
+
html.css('a[href]').map { |link| link['href'] },
|
110
|
+
html.css('img').map { |image| image['src'] }
|
111
|
+
].flatten
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def out(str)
|
117
|
+
@output_streams[:out].puts(str)
|
118
|
+
end
|
119
|
+
|
120
|
+
def err(str)
|
121
|
+
@output_streams[:err].puts(str)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Bookwatch
|
2
|
+
module Postprocessing
|
3
|
+
class Redirection
|
4
|
+
def initialize(fs, file_path)
|
5
|
+
@redirect_regexes = {}
|
6
|
+
@redirect_strings = {}
|
7
|
+
load!(fs, file_path)
|
8
|
+
end
|
9
|
+
|
10
|
+
def redirected?(url)
|
11
|
+
@redirect_strings.has_key?(url) ||
|
12
|
+
@redirect_regexes.keys.detect {|regex| regex.match(url)}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def load!(fs, file_path)
|
18
|
+
if fs.is_file?(file_path)
|
19
|
+
contents = fs.read(file_path)
|
20
|
+
instance_eval contents
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def r301(source, dest, options={})
|
25
|
+
return if options.has_key?(:if)
|
26
|
+
|
27
|
+
case source
|
28
|
+
when Regexp
|
29
|
+
@redirect_regexes[source] = dest
|
30
|
+
when String
|
31
|
+
@redirect_strings[source] = dest
|
32
|
+
end
|
33
|
+
end
|
34
|
+
alias r302 r301
|
35
|
+
alias rewrite r301
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative '../values/subnav_template'
|
2
|
+
require_relative '../../../lib/bookwatch/subnav/navigation_entries_from_html_toc'
|
3
|
+
|
4
|
+
module Bookwatch
|
5
|
+
module Preprocessing
|
6
|
+
class DitaHTMLPreprocessor
|
7
|
+
DitaToHtmlLibraryFailure = Class.new(RuntimeError)
|
8
|
+
|
9
|
+
ACCEPTED_IMAGE_FORMATS = %w(png jpeg jpg svg gif bmp tif tiff eps)
|
10
|
+
|
11
|
+
def initialize(fs, subnav_gen_factory, dita_formatter, command_creator, sheller)
|
12
|
+
@fs = fs
|
13
|
+
@subnav_gen_factory = subnav_gen_factory
|
14
|
+
@dita_formatter = dita_formatter
|
15
|
+
@command_creator = command_creator
|
16
|
+
@sheller = sheller
|
17
|
+
end
|
18
|
+
|
19
|
+
def applicable_to?(section)
|
20
|
+
section.subnav_template.include?('dita_subnav') if section.subnav_template
|
21
|
+
end
|
22
|
+
|
23
|
+
def preprocess(sections, output_locations, options: {}, output_streams: nil, **_)
|
24
|
+
@output_locations = output_locations
|
25
|
+
|
26
|
+
sections.each do |section|
|
27
|
+
if section.path_to_preprocessor_attribute('ditamap_location')
|
28
|
+
convert_dita_files(section,
|
29
|
+
command_creator,
|
30
|
+
options[:dita_flags],
|
31
|
+
section_html_dir(section),
|
32
|
+
sheller,
|
33
|
+
output_streams)
|
34
|
+
|
35
|
+
subnav_generator.generate(section)
|
36
|
+
end
|
37
|
+
|
38
|
+
dita_formatter.format_html(section_html_dir(section), formatted_dir(section))
|
39
|
+
copy_images(section.path_to_repo_dir, formatted_dir(section))
|
40
|
+
fs.copy_contents(formatted_dir(section), source_for_site_gen_dir(section))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
attr_reader :fs, :subnav_gen_factory, :dita_formatter, :command_creator, :sheller, :output_locations
|
47
|
+
|
48
|
+
def section_html_dir(section)
|
49
|
+
output_locations.html_from_preprocessing_dir.join(section.destination_directory)
|
50
|
+
end
|
51
|
+
|
52
|
+
def formatted_dir(section)
|
53
|
+
output_locations.formatted_dir.join(section.destination_directory)
|
54
|
+
end
|
55
|
+
|
56
|
+
def source_for_site_gen_dir(section)
|
57
|
+
output_locations.source_for_site_generator.join(section.destination_directory)
|
58
|
+
end
|
59
|
+
|
60
|
+
def convert_dita_files(section, command_creator, options, section_html_dir, sheller, output_streams)
|
61
|
+
command = command_creator.convert_to_html_command(
|
62
|
+
section,
|
63
|
+
dita_flags: options,
|
64
|
+
write_to: section_html_dir
|
65
|
+
)
|
66
|
+
status = sheller.run_command(command, output_streams.to_h)
|
67
|
+
unless status.success?
|
68
|
+
raise DitaToHtmlLibraryFailure.new 'The DITA-to-HTML conversion failed. ' +
|
69
|
+
'Please check that you have specified the path to your DITA-OT library in the ENV, ' +
|
70
|
+
'that your DITA-specific keys/values in config.yml are set, ' +
|
71
|
+
'and that your DITA toolkit is correctly configured.'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def copy_images(src, dest)
|
76
|
+
image_paths = ACCEPTED_IMAGE_FORMATS.map do |format|
|
77
|
+
fs.find_files_with_ext(format, src)
|
78
|
+
end.flatten
|
79
|
+
|
80
|
+
image_paths.each do |image_path|
|
81
|
+
fs.copy_including_intermediate_dirs(image_path, src, dest)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def subnav_generator
|
87
|
+
@subnav_generator ||= subnav_gen_factory.produce(Subnav::NavigationEntriesFromHtmlToc.new(fs))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Bookwatch
|
2
|
+
module Preprocessing
|
3
|
+
class DitaPDFPreprocessor
|
4
|
+
DitaToPDFLibraryFailure = Class.new(RuntimeError)
|
5
|
+
|
6
|
+
def initialize(fs, command_creator, sheller)
|
7
|
+
@fs = fs
|
8
|
+
@command_creator = command_creator
|
9
|
+
@sheller = sheller
|
10
|
+
end
|
11
|
+
|
12
|
+
def applicable_to?(section)
|
13
|
+
!!section.pdf_output_filename
|
14
|
+
end
|
15
|
+
|
16
|
+
def preprocess(sections, output_locations, options: {}, output_streams: nil, **_)
|
17
|
+
sections.each do |section|
|
18
|
+
command = command_creator.convert_to_pdf_command(
|
19
|
+
section,
|
20
|
+
dita_flags: options[:dita_flags],
|
21
|
+
write_to: output_locations.pdf_from_preprocessing_dir
|
22
|
+
)
|
23
|
+
status = sheller.run_command(command, output_streams.to_h)
|
24
|
+
|
25
|
+
if status.success?
|
26
|
+
pdf_path = most_recent_pdf(output_locations.pdf_from_preprocessing_dir)
|
27
|
+
pdf_destination = output_locations.pdf_artifact_dir.join(section.pdf_output_filename)
|
28
|
+
fs.copy_and_rename(pdf_path, pdf_destination)
|
29
|
+
else
|
30
|
+
raise DitaToPDFLibraryFailure.new 'The DITA-to-PDF conversion failed. ' +
|
31
|
+
'Please check that you have specified the path to your DITA-OT library in the ENV, ' +
|
32
|
+
'that your DITA-specific keys/values in config.yml are set, ' +
|
33
|
+
'and that your DITA toolkit is correctly configured.'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def most_recent_pdf(dir_path)
|
39
|
+
pdfs_by_modified_date = Dir.glob(dir_path + '**/*.pdf').sort_by{ |f| File.mtime(f) }
|
40
|
+
pdfs_by_modified_date.last
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
attr_reader :command_creator, :sheller, :fs
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|