bookbindery 2.1.5 → 3.0.1
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/lib/bookbinder.rb +0 -4
- data/lib/bookbinder/cf_command_runner.rb +11 -5
- data/lib/bookbinder/cli.rb +8 -12
- data/lib/bookbinder/colorizer.rb +1 -2
- data/lib/bookbinder/command_runner.rb +0 -2
- data/lib/bookbinder/commands/bind.rb +96 -99
- data/lib/bookbinder/commands/bind/directory_preparer.rb +60 -0
- data/lib/bookbinder/commands/build_and_push_tarball.rb +5 -4
- data/lib/bookbinder/commands/push_from_local.rb +56 -2
- data/lib/bookbinder/commands/push_to_prod.rb +6 -2
- data/lib/bookbinder/commands/tag.rb +15 -3
- data/lib/bookbinder/config/aws_credentials.rb +21 -0
- data/lib/bookbinder/config/cf_credentials.rb +87 -0
- data/lib/bookbinder/configuration.rb +4 -140
- data/lib/bookbinder/configuration_fetcher.rb +28 -4
- data/lib/bookbinder/configuration_validator.rb +11 -164
- data/lib/bookbinder/distributor.rb +16 -12
- data/lib/bookbinder/{dita_to_html_converter.rb → dita_command_creator.rb} +5 -17
- data/lib/bookbinder/dita_preprocessor.rb +14 -12
- data/lib/bookbinder/git_accessor.rb +21 -2
- data/lib/bookbinder/git_hub_repository.rb +0 -43
- data/lib/bookbinder/ingest/cloner_factory.rb +5 -4
- data/lib/bookbinder/ingest/destination_directory.rb +15 -0
- data/lib/bookbinder/ingest/git_hub_repository_cloner.rb +22 -13
- data/lib/bookbinder/ingest/local_filesystem_cloner.rb +38 -14
- data/lib/bookbinder/ingest/working_copy.rb +31 -0
- data/lib/bookbinder/local_dita_section_gatherer.rb +4 -3
- data/lib/bookbinder/local_file_system_accessor.rb +1 -4
- data/lib/bookbinder/middleman_runner.rb +22 -26
- data/lib/bookbinder/remote_yaml_credential_provider.rb +10 -10
- data/lib/bookbinder/repositories/command_repository.rb +18 -12
- data/lib/bookbinder/repositories/section_repository.rb +8 -8
- data/lib/bookbinder/server_director.rb +16 -33
- data/lib/bookbinder/sheller.rb +33 -7
- data/lib/bookbinder/spider.rb +3 -0
- data/lib/bookbinder/streams/switchable_stdout_and_red_stderr.rb +38 -0
- data/lib/bookbinder/terminal.rb +11 -1
- data/lib/bookbinder/validation_checkers/archive_menu_checker.rb +31 -0
- data/lib/bookbinder/validation_checkers/config_version_checker.rb +91 -0
- data/lib/bookbinder/validation_checkers/dita_section_checker.rb +20 -0
- data/lib/bookbinder/validation_checkers/duplicate_section_name_checker.rb +25 -0
- data/lib/bookbinder/validation_checkers/repository_name_presence_checker.rb +33 -0
- data/lib/bookbinder/validation_checkers/required_keys_checker.rb +43 -0
- data/lib/bookbinder/values/dita_section.rb +5 -1
- data/lib/bookbinder/values/output_locations.rb +25 -2
- data/lib/bookbinder/values/user_message.rb +2 -2
- data/master_middleman/bookbinder_helpers.rb +5 -15
- data/template_app/Gemfile.lock +1 -1
- metadata +60 -80
- data/lib/bookbinder/commands/generate_pdf.rb +0 -141
- data/lib/bookbinder/pdf_generator.rb +0 -73
- data/lib/bookbinder/publisher.rb +0 -58
- data/lib/bookbinder/user_message_presenter.rb +0 -21
@@ -1,4 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'puma'
|
2
|
+
require 'rack/rewrite'
|
3
|
+
require 'vienna'
|
2
4
|
|
3
5
|
module Bookbinder
|
4
6
|
class ServerDirector
|
@@ -10,16 +12,14 @@ module Bookbinder
|
|
10
12
|
|
11
13
|
def use_server
|
12
14
|
Dir.chdir(@directory) do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
stop_server(pid)
|
22
|
-
end
|
15
|
+
events = Puma::Events.new $stdout, $stderr
|
16
|
+
server = Puma::Server.new app, events
|
17
|
+
server.add_tcp_listener "localhost", @port
|
18
|
+
server.run
|
19
|
+
begin
|
20
|
+
result = yield @port
|
21
|
+
ensure
|
22
|
+
server.stop(true)
|
23
23
|
end
|
24
24
|
result
|
25
25
|
end
|
@@ -27,28 +27,11 @@ module Bookbinder
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
@logger.log "Vienna says, #{line}"
|
37
|
-
end until line.include?('Listening on')
|
38
|
-
|
39
|
-
@logger.log 'Vienna is lovely this time of year.'
|
40
|
-
end
|
41
|
-
|
42
|
-
def stop_server(pid)
|
43
|
-
Process.kill 'KILL', pid
|
44
|
-
end
|
45
|
-
|
46
|
-
# avoids deadlocks by ensuring rack doesn't hang waiting to write to stderr
|
47
|
-
def consume_stream_in_separate_thread(stream)
|
48
|
-
Thread.new do
|
49
|
-
s = nil
|
50
|
-
while stream.read(1024, s)
|
51
|
-
end
|
30
|
+
def app
|
31
|
+
if File.exists?('redirects.rb')
|
32
|
+
Rack::Rewrite.new(Vienna) { eval(File.read('redirects.rb')) }
|
33
|
+
else
|
34
|
+
Vienna
|
52
35
|
end
|
53
36
|
end
|
54
37
|
end
|
data/lib/bookbinder/sheller.rb
CHANGED
@@ -1,17 +1,43 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
1
3
|
module Bookbinder
|
2
4
|
class Sheller
|
3
5
|
ShelloutFailure = Class.new(RuntimeError)
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
+
class DevNull
|
8
|
+
def puts(_)
|
9
|
+
end
|
7
10
|
end
|
8
11
|
|
9
|
-
def run_command(command)
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
def run_command(*command)
|
13
|
+
out, err =
|
14
|
+
if Hash === command.last
|
15
|
+
command.last.values_at(:out, :err)
|
16
|
+
else
|
17
|
+
[DevNull.new, DevNull.new]
|
18
|
+
end
|
13
19
|
|
14
|
-
|
20
|
+
env_vars, executable =
|
21
|
+
if Hash === command.first
|
22
|
+
command[0..1]
|
23
|
+
else
|
24
|
+
[{}, command[0]]
|
25
|
+
end
|
26
|
+
|
27
|
+
exit_status = nil
|
28
|
+
Open3.popen3(env_vars, executable) do |stdin, stdout, stderr, wait_thr|
|
29
|
+
t = Thread.new do
|
30
|
+
stdout.each do |line|
|
31
|
+
out.puts(line)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
stderr.each do |line|
|
35
|
+
err.puts(line)
|
36
|
+
end
|
37
|
+
t.join
|
38
|
+
exit_status = wait_thr.value
|
39
|
+
end
|
40
|
+
exit_status
|
15
41
|
end
|
16
42
|
|
17
43
|
attr_reader :view_updater
|
data/lib/bookbinder/spider.rb
CHANGED
@@ -79,6 +79,9 @@ module Bookbinder
|
|
79
79
|
Anemone.crawl(url) do |anemone|
|
80
80
|
dont_visit_fragments(anemone)
|
81
81
|
anemone.on_every_page do |page|
|
82
|
+
if $sitemap_debug
|
83
|
+
puts "\n\n********** Visiting page: #{page.url}\n\n#{page.body}"
|
84
|
+
end
|
82
85
|
broken, working = sieve.links_from Stabilimentum.new(page), is_first_pass
|
83
86
|
broken_links.concat broken
|
84
87
|
sitemap.concat working
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative '../colorizer'
|
2
|
+
|
3
|
+
module Bookbinder
|
4
|
+
module Streams
|
5
|
+
class SwitchableStdoutAndRedStderr
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_h
|
11
|
+
{
|
12
|
+
out: options.include?('--verbose') ? $stdout : Sheller::DevNull.new,
|
13
|
+
err: ColorizedStream.new(Colorizer::Colors.red, $stderr)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :options
|
20
|
+
end
|
21
|
+
|
22
|
+
class ColorizedStream
|
23
|
+
def initialize(color, stream)
|
24
|
+
@color = color
|
25
|
+
@stream = stream
|
26
|
+
@colorizer = Colorizer.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def puts(line)
|
30
|
+
stream << colorizer.colorize(line, color)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :color, :colorizer, :stream
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/bookbinder/terminal.rb
CHANGED
@@ -3,8 +3,18 @@ require_relative 'colorizer'
|
|
3
3
|
|
4
4
|
module Bookbinder
|
5
5
|
class Terminal
|
6
|
+
def initialize(colorizer)
|
7
|
+
@colorizer = colorizer
|
8
|
+
end
|
9
|
+
|
6
10
|
def update(user_message)
|
7
|
-
|
11
|
+
if user_message.error?
|
12
|
+
error_message = @colorizer.colorize(user_message.message, Colorizer::Colors.red)
|
13
|
+
$stderr.puts error_message
|
14
|
+
elsif user_message.warn?
|
15
|
+
warning_message = @colorizer.colorize(user_message.message, Colorizer::Colors.yellow)
|
16
|
+
puts warning_message
|
17
|
+
end
|
8
18
|
end
|
9
19
|
end
|
10
20
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Bookbinder
|
2
|
+
class ArchiveMenuChecker
|
3
|
+
MissingArchiveMenuPartialError = Class.new(RuntimeError)
|
4
|
+
ArchiveMenuNotDefinedError = Class.new(RuntimeError)
|
5
|
+
EmptyArchiveItemsError = Class.new(RuntimeError)
|
6
|
+
|
7
|
+
def initialize(file_system_accessor)
|
8
|
+
@file_system_accessor = file_system_accessor
|
9
|
+
end
|
10
|
+
|
11
|
+
def check(config)
|
12
|
+
partial_location = './master_middleman/source/archive_menus/_default.erb'
|
13
|
+
if config.has_key?("archive_menu") && config["archive_menu"].nil?
|
14
|
+
ArchiveMenuNotDefinedError.new 'Did you mean to provide an archive menu value to display? If you use the archive_menu key, you must provide at least one value.'
|
15
|
+
elsif archive_items(config).include?(nil)
|
16
|
+
EmptyArchiveItemsError.new 'Did you forget to add a value to the archive_menu?'
|
17
|
+
elsif config.has_key?("archive_menu") && !file_system_accessor.file_exist?(partial_location)
|
18
|
+
MissingArchiveMenuPartialError.new "You must provide a template partial named at #{partial_location}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :file_system_accessor
|
25
|
+
|
26
|
+
def archive_items(config)
|
27
|
+
config.fetch('archive_menu', [])
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
require_relative '../configuration'
|
3
|
+
|
4
|
+
module Bookbinder
|
5
|
+
class ConfigVersionChecker
|
6
|
+
def initialize(bookbinder_schema_version, starting_schema_version, messages, view_updater)
|
7
|
+
@bookbinder_schema_version = bookbinder_schema_version
|
8
|
+
@starting_schema_version = starting_schema_version
|
9
|
+
@messages = messages
|
10
|
+
@view_updater = view_updater
|
11
|
+
end
|
12
|
+
|
13
|
+
def check(config)
|
14
|
+
user_schema_version = Version.parse(config['schema_version'])
|
15
|
+
if user_schema_version.valid?
|
16
|
+
if user_schema_version.major > bookbinder_schema_version.major
|
17
|
+
raise Configuration::ConfigSchemaUnsupportedError.new messages.unrecognized_schema_version_message
|
18
|
+
elsif user_schema_version.minor > bookbinder_schema_version.minor
|
19
|
+
raise Configuration::ConfigSchemaUnsupportedError.new messages.unrecognized_schema_version_message
|
20
|
+
elsif user_schema_version.patch > bookbinder_schema_version.patch
|
21
|
+
raise Configuration::ConfigSchemaUnsupportedError.new messages.unrecognized_schema_version_message
|
22
|
+
elsif user_schema_version.major < bookbinder_schema_version.major
|
23
|
+
raise Configuration::ConfigSchemaUnsupportedError.new messages.incompatible_schema_message
|
24
|
+
elsif user_schema_version.minor < bookbinder_schema_version.minor
|
25
|
+
view_updater.warn nonbreaking_schema_message_for("minor")
|
26
|
+
elsif user_schema_version.patch < bookbinder_schema_version.patch
|
27
|
+
view_updater.warn nonbreaking_schema_message_for("patch")
|
28
|
+
end
|
29
|
+
elsif bookbinder_schema_version != starting_schema_version
|
30
|
+
raise Configuration::ConfigSchemaUnsupportedError.new messages.schema_now_required_message
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :bookbinder_schema_version, :starting_schema_version, :messages, :view_updater
|
37
|
+
|
38
|
+
def nonbreaking_schema_message_for(version_level)
|
39
|
+
"[WARNING] Your schema is valid, but there exists a new #{version_level} version. Consider updating your config.yml."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Version = Struct.new(:major, :minor, :patch) do
|
44
|
+
class << self
|
45
|
+
def parse(raw_version)
|
46
|
+
if raw_version
|
47
|
+
new(*raw_version.split('.'))
|
48
|
+
else
|
49
|
+
new(nil, nil, nil)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid?
|
55
|
+
[major, minor, patch].all?(&:present?)
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_s
|
59
|
+
[major, minor, patch].compact.join('.')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class VersionCheckerMessages
|
64
|
+
def initialize(user_schema_version, bookbinder_schema_version)
|
65
|
+
@user_schema_version = user_schema_version
|
66
|
+
@bookbinder_schema_version = bookbinder_schema_version
|
67
|
+
end
|
68
|
+
|
69
|
+
def schema_now_required_message
|
70
|
+
"[ERROR] Bookbinder now requires a certain schema. Please see README " +
|
71
|
+
"and provide a schema version."
|
72
|
+
end
|
73
|
+
|
74
|
+
def incompatible_schema_message
|
75
|
+
"[ERROR] Your config.yml format, schema version #{user_schema_version}, " +
|
76
|
+
"is older than this version of Bookbinder can support. Please update " +
|
77
|
+
"your config.yml keys and format to version #{bookbinder_schema_version} " +
|
78
|
+
"and try again."
|
79
|
+
end
|
80
|
+
|
81
|
+
def unrecognized_schema_version_message
|
82
|
+
"[ERROR] The config schema version #{user_schema_version} is " +
|
83
|
+
"unrecognized by this version of Bookbinder. The latest schema version " +
|
84
|
+
"is #{bookbinder_schema_version}."
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
attr_reader :user_schema_version, :bookbinder_schema_version
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Bookbinder
|
2
|
+
class DitaSectionChecker
|
3
|
+
DitamapLocationError = Class.new(RuntimeError)
|
4
|
+
|
5
|
+
def check(config)
|
6
|
+
dita_sections = config['dita_sections'].to_a
|
7
|
+
|
8
|
+
sum = 0
|
9
|
+
dita_sections.each do |section|
|
10
|
+
if section['ditamap_location']
|
11
|
+
sum += 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
if !dita_sections.empty? && (sum < 1 || sum > 1)
|
16
|
+
DitamapLocationError.new "You must have exactly one 'ditamap_location' key in dita_sections."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Bookbinder
|
2
|
+
class DuplicateSectionNameChecker
|
3
|
+
DuplicateSectionNameError = Class.new(RuntimeError)
|
4
|
+
|
5
|
+
def check(config)
|
6
|
+
if duplicate_section_names?(config)
|
7
|
+
DuplicateSectionNameError.new error_message
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def duplicate_section_names?(config)
|
14
|
+
sections = config['sections'].to_a + config['dita_sections'].to_a
|
15
|
+
directory_names = sections.map {|section| section['directory']}
|
16
|
+
directory_names.length != directory_names.uniq.length
|
17
|
+
end
|
18
|
+
|
19
|
+
def error_message
|
20
|
+
<<-ERROR
|
21
|
+
Duplicate repository names are not allowed.
|
22
|
+
ERROR
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Bookbinder
|
2
|
+
class RepositoryNamePresenceChecker
|
3
|
+
MissingRepositoryNameError = Class.new(RuntimeError)
|
4
|
+
|
5
|
+
def check(config)
|
6
|
+
all_sections = config['sections'].to_a + config['dita_sections'].to_a
|
7
|
+
failures = all_sections.map do |section|
|
8
|
+
if !section['repository'] || !section['repository']['name']
|
9
|
+
true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
if failures.compact.empty?
|
14
|
+
nil
|
15
|
+
else
|
16
|
+
MissingRepositoryNameError.new error_message
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def error_message
|
23
|
+
<<-ERROR
|
24
|
+
Cannot locate a specific section.
|
25
|
+
All sections must provide the section 'name' key under the 'repository' key:
|
26
|
+
|
27
|
+
sections:
|
28
|
+
- repository:
|
29
|
+
name: 'your-org/your-repo'
|
30
|
+
ERROR
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative '../configuration'
|
2
|
+
|
3
|
+
module Bookbinder
|
4
|
+
class RequiredKeysChecker
|
5
|
+
MissingRequiredKeyError = Class.new(RuntimeError)
|
6
|
+
SectionAbsenceError = Class.new(RuntimeError)
|
7
|
+
|
8
|
+
def check(config)
|
9
|
+
missing_keys = []
|
10
|
+
|
11
|
+
Configuration::CONFIG_REQUIRED_KEYS.map do |required_key|
|
12
|
+
config_keys = config.keys
|
13
|
+
unless config_keys.include?(required_key)
|
14
|
+
missing_keys.push(required_key)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if missing_keys.length > 0
|
19
|
+
MissingRequiredKeyError.new("Your config.yml is missing required key(s). Required keys are #{missing_keys.join(", ")}.")
|
20
|
+
elsif !config['sections'] && !config['dita_sections']
|
21
|
+
SectionAbsenceError.new error_message
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def error_message
|
28
|
+
<<-ERROR
|
29
|
+
Cannot locate your sections.
|
30
|
+
Must specify at least one of 'sections' and/or 'dita_sections' in config.yml:
|
31
|
+
|
32
|
+
sections:
|
33
|
+
- repository:
|
34
|
+
name: 'your-org/your-repo'
|
35
|
+
|
36
|
+
dita_sections:
|
37
|
+
- repository:
|
38
|
+
name: 'dita-org/dita-repo'
|
39
|
+
ditamap_location: 'example.ditamap'
|
40
|
+
ERROR
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -4,7 +4,7 @@ module Bookbinder
|
|
4
4
|
:ditaval_location,
|
5
5
|
:full_name,
|
6
6
|
:target_ref,
|
7
|
-
:
|
7
|
+
:directory_name,
|
8
8
|
:output_locations) do
|
9
9
|
def subnav
|
10
10
|
namespace = directory.gsub('/', '_')
|
@@ -31,5 +31,9 @@ module Bookbinder
|
|
31
31
|
def absolute_path_to_ditaval
|
32
32
|
ditaval_location ? File.join(path_to_local_repo, ditaval_location) : nil
|
33
33
|
end
|
34
|
+
|
35
|
+
def directory
|
36
|
+
directory_name || full_name.split('/').last
|
37
|
+
end
|
34
38
|
end
|
35
39
|
end
|