bookbindery 2.1.5 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|