bookbindery 4.2.0 → 5.0.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/lib/bookbinder/cli.rb +0 -3
- data/lib/bookbinder/code_example_reader.rb +54 -36
- data/lib/bookbinder/commands/bind.rb +42 -69
- data/lib/bookbinder/commands/bind/bind_options.rb +23 -13
- data/lib/bookbinder/commands/bind/directory_preparer.rb +18 -34
- data/lib/bookbinder/commands/collection.rb +40 -8
- data/lib/bookbinder/commands/watch.rb +90 -0
- data/lib/bookbinder/config/configuration.rb +0 -4
- data/lib/bookbinder/ingest/git_accessor.rb +9 -14
- data/lib/bookbinder/ingest/local_filesystem_cloner.rb +7 -7
- data/lib/bookbinder/ingest/missing_working_copy.rb +3 -2
- data/lib/bookbinder/ingest/repo_identifier.rb +1 -1
- data/lib/bookbinder/ingest/section_repository.rb +4 -11
- data/lib/bookbinder/ingest/working_copy.rb +8 -2
- data/lib/bookbinder/local_file_system_accessor.rb +8 -1
- data/lib/bookbinder/middleman_runner.rb +25 -78
- data/lib/bookbinder/preprocessing/preprocessor.rb +5 -5
- data/master_middleman/bookbinder_helpers.rb +14 -5
- data/master_middleman/config.rb +13 -4
- data/master_middleman/{submodule_aware_assets.rb → subdirectory_aware_assets.rb} +7 -5
- metadata +34 -8
- data/lib/bookbinder/config/bind_config_factory.rb +0 -28
- data/lib/bookbinder/config/remote_bind_configuration.rb +0 -44
- data/lib/bookbinder/ingest/section_repository_factory.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 621e97dd76f614e82790228cfe022f204df2f3f3
|
4
|
+
data.tar.gz: 1555c3fe96a2231e0b850abfe6b7d98a7ca4b28e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b22cdca4d39c048af425c48d3de76bfab47c923913d00b40f9212a59d37d60ad01a36c15932d13e9c4e7555ab65e91b5a0e0cad5b252513c3b7fc60c173f502
|
7
|
+
data.tar.gz: 49b94f81e1f08e00047e5ce6be496565ca39a34f6816cf11681795f055a25590418e80d313d493a888252aa6e82ef977e8786992b25a2cd5366fc68b9127b61d
|
data/lib/bookbinder/cli.rb
CHANGED
@@ -38,9 +38,6 @@ module Bookbinder
|
|
38
38
|
begin
|
39
39
|
command_runner.run command_name, command_arguments
|
40
40
|
|
41
|
-
rescue Config::RemoteBindConfiguration::VersionUnsupportedError => e
|
42
|
-
colorized_streams[:err].puts "config.yml at version '#{e.message}' has an unsupported API."
|
43
|
-
1
|
44
41
|
rescue Config::CfCredentials::CredentialKeyError => e
|
45
42
|
colorized_streams[:err].puts "#{e.message}, in credentials.yml"
|
46
43
|
1
|
@@ -6,16 +6,14 @@ module Bookbinder
|
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@out = out
|
9
|
+
def initialize(streams, fs)
|
10
|
+
@out = streams[:out]
|
11
|
+
@fs = fs
|
11
12
|
end
|
12
13
|
|
13
14
|
def get_snippet_and_language_at(marker, working_copy)
|
14
|
-
|
15
|
-
|
16
|
-
raise InvalidSnippet.new(working_copy.full_name, marker)
|
17
|
-
elsif snippet.available?
|
18
|
-
[snippet.content, snippet.language]
|
15
|
+
if working_copy.available?
|
16
|
+
process_snippet(marker, working_copy)
|
19
17
|
else
|
20
18
|
out << " skipping (not found) #{working_copy.full_name}"
|
21
19
|
''
|
@@ -23,54 +21,74 @@ module Bookbinder
|
|
23
21
|
end
|
24
22
|
|
25
23
|
class Snippet
|
26
|
-
def initialize(
|
27
|
-
@
|
28
|
-
@
|
29
|
-
end
|
30
|
-
|
31
|
-
def available?
|
32
|
-
working_copy.available?
|
24
|
+
def initialize(text, language_pattern)
|
25
|
+
@text = text
|
26
|
+
@language_pattern = language_pattern
|
33
27
|
end
|
34
28
|
|
35
29
|
def valid?
|
36
|
-
!
|
30
|
+
! text.empty?
|
37
31
|
end
|
38
32
|
|
39
33
|
def language
|
40
|
-
|
41
|
-
language_match = lines[0].match(/code_snippet #{Regexp.escape(marker)} start (\w+)/)
|
34
|
+
language_match = lines[0].match(language_pattern)
|
42
35
|
Array(language_match)[1]
|
43
36
|
end
|
44
37
|
|
45
38
|
def content
|
46
|
-
lines
|
47
|
-
lines[1..-2].join("\n")
|
39
|
+
lines[1..-2].join("\n").strip
|
48
40
|
end
|
49
41
|
|
50
42
|
private
|
51
43
|
|
52
|
-
attr_reader :
|
44
|
+
attr_reader :text, :language_pattern
|
53
45
|
|
54
|
-
def
|
55
|
-
|
56
|
-
begin
|
57
|
-
snippet = ''
|
58
|
-
FileUtils.cd(working_copy.path) {
|
59
|
-
locale = 'LC_CTYPE=C LANG=C' # Quiets 'sed: RE error: illegal byte sequence'
|
60
|
-
result = `#{locale} find . -exec sed -ne '/code_snippet #{marker} start/,/code_snippet #{marker} end/ p' {} \\; 2> /dev/null`
|
61
|
-
snippet = if result.lines.last && result.lines.last.match(/code_snippet #{marker} end/)
|
62
|
-
result
|
63
|
-
else
|
64
|
-
""
|
65
|
-
end
|
66
|
-
}
|
67
|
-
snippet
|
68
|
-
end
|
46
|
+
def lines
|
47
|
+
text.split("\n")
|
69
48
|
end
|
70
49
|
end
|
71
50
|
|
72
51
|
private
|
73
52
|
|
74
|
-
attr_reader :out
|
53
|
+
attr_reader :out, :fs
|
54
|
+
|
55
|
+
def process_snippet(marker, working_copy)
|
56
|
+
snippet = Snippet.new(
|
57
|
+
find_text(working_copy.path, pattern_for(marker)),
|
58
|
+
language_pattern_for(marker)
|
59
|
+
)
|
60
|
+
if snippet.valid?
|
61
|
+
[snippet.content, snippet.language]
|
62
|
+
else
|
63
|
+
raise InvalidSnippet.new(working_copy.full_name, marker)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_text(start_path, pattern)
|
68
|
+
fs.find_files_recursively(start_path).
|
69
|
+
lazy.
|
70
|
+
map {|path| fs.read(path)}.
|
71
|
+
map {|contents|
|
72
|
+
begin
|
73
|
+
contents.scan(pattern)
|
74
|
+
rescue ArgumentError => e
|
75
|
+
cannot_scan
|
76
|
+
end
|
77
|
+
}.
|
78
|
+
map(&:first).
|
79
|
+
detect ->{""} {|text| text}
|
80
|
+
end
|
81
|
+
|
82
|
+
def pattern_for(marker)
|
83
|
+
/code_snippet #{Regexp.escape(marker)} start.*code_snippet #{Regexp.escape(marker)} end/m
|
84
|
+
end
|
85
|
+
|
86
|
+
def language_pattern_for(marker)
|
87
|
+
/code_snippet #{Regexp.escape(marker)} start (\w+)/
|
88
|
+
end
|
89
|
+
|
90
|
+
def cannot_scan
|
91
|
+
[]
|
92
|
+
end
|
75
93
|
end
|
76
94
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'middleman-syntax'
|
2
2
|
|
3
|
-
require_relative '../config/archive_menu_configuration'
|
4
3
|
require_relative '../errors/cli_error'
|
5
4
|
require_relative 'bind/bind_options'
|
6
5
|
require_relative 'naming'
|
@@ -12,25 +11,25 @@ module Bookbinder
|
|
12
11
|
|
13
12
|
def initialize(base_streams,
|
14
13
|
output_locations,
|
15
|
-
|
16
|
-
|
14
|
+
config_fetcher,
|
15
|
+
config_decorator,
|
17
16
|
file_system_accessor,
|
18
17
|
static_site_generator,
|
19
18
|
sitemap_writer,
|
20
19
|
preprocessor,
|
21
20
|
cloner_factory,
|
22
|
-
|
21
|
+
section_repository,
|
23
22
|
directory_preparer)
|
24
23
|
@base_streams = base_streams
|
25
24
|
@output_locations = output_locations
|
26
|
-
@
|
27
|
-
@
|
25
|
+
@config_fetcher = config_fetcher
|
26
|
+
@config_decorator = config_decorator
|
28
27
|
@file_system_accessor = file_system_accessor
|
29
28
|
@static_site_generator = static_site_generator
|
30
29
|
@sitemap_writer = sitemap_writer
|
31
30
|
@preprocessor = preprocessor
|
32
31
|
@cloner_factory = cloner_factory
|
33
|
-
@
|
32
|
+
@section_repository = section_repository
|
34
33
|
@directory_preparer = directory_preparer
|
35
34
|
end
|
36
35
|
|
@@ -48,101 +47,75 @@ module Bookbinder
|
|
48
47
|
end
|
49
48
|
|
50
49
|
def run(cli_arguments)
|
51
|
-
bind_options
|
52
|
-
|
53
|
-
|
54
|
-
bind_source, *options = cli_arguments
|
55
|
-
bind_config = config_factory.produce(bind_source)
|
56
|
-
|
57
|
-
local_repo_dir = generate_local_repo_dir(context_dir, bind_source)
|
58
|
-
cloner = cloner_factory.produce(local_repo_dir)
|
59
|
-
section_repository = section_repository_factory.produce(cloner)
|
50
|
+
bind_options = BindComponents::BindOptions.new(cli_arguments, base_streams).tap(&:validate!)
|
51
|
+
bind_config = config_fetcher.fetch_config
|
52
|
+
cloner = cloner_factory.produce(bind_options.local_repo_dir)
|
60
53
|
|
61
54
|
directory_preparer.prepare_directories(
|
62
55
|
bind_config,
|
63
56
|
File.expand_path('../../../../', __FILE__),
|
64
57
|
output_locations,
|
65
|
-
|
58
|
+
cloner
|
66
59
|
)
|
67
|
-
|
68
60
|
sections = section_repository.fetch(
|
69
61
|
configured_sections: bind_config.sections,
|
70
62
|
destination_dir: output_locations.cloned_preprocessing_dir,
|
71
|
-
ref_override: bind_options.ref_override
|
63
|
+
ref_override: bind_options.ref_override,
|
64
|
+
cloner: cloner,
|
65
|
+
streams: base_streams
|
72
66
|
)
|
73
|
-
|
74
67
|
preprocessor.preprocess(
|
75
68
|
sections,
|
76
69
|
output_locations,
|
77
|
-
options: options,
|
70
|
+
options: bind_options.options,
|
78
71
|
output_streams: bind_options.streams
|
79
72
|
)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
bind_options.
|
85
|
-
|
86
|
-
|
87
|
-
|
73
|
+
if file_system_accessor.file_exist?('redirects.rb')
|
74
|
+
file_system_accessor.copy('redirects.rb', output_locations.final_app_dir)
|
75
|
+
end
|
76
|
+
generation_result = static_site_generator.run(
|
77
|
+
["build", bind_options.verbosity].compact.join(" "),
|
78
|
+
streams: bind_options.streams,
|
79
|
+
output_locations: output_locations,
|
80
|
+
config: config_decorator.generate(bind_config, sections),
|
81
|
+
local_repo_dir: bind_options.local_repo_dir,
|
82
|
+
subnavs: subnavs(sections)
|
88
83
|
)
|
84
|
+
if generation_result.success?
|
85
|
+
file_system_accessor.copy(output_locations.build_dir, output_locations.public_dir)
|
86
|
+
result = sitemap_writer.write(
|
87
|
+
bind_config.public_host,
|
88
|
+
bind_options.streams,
|
89
|
+
bind_config.broken_link_exclusions
|
90
|
+
)
|
89
91
|
|
90
|
-
|
92
|
+
bind_options.streams[:success].puts "Bookbinder bound your book into #{output_locations.final_app_dir}"
|
93
|
+
|
94
|
+
result.has_broken_links? ? 1 : 0
|
95
|
+
else
|
96
|
+
1
|
97
|
+
end
|
91
98
|
end
|
92
99
|
|
93
100
|
private
|
94
101
|
|
95
102
|
attr_reader(
|
96
|
-
:archive_menu_config,
|
97
103
|
:base_streams,
|
98
104
|
:cloner_factory,
|
99
|
-
:
|
100
|
-
:
|
105
|
+
:config_decorator,
|
106
|
+
:config_fetcher,
|
101
107
|
:directory_preparer,
|
102
108
|
:file_system_accessor,
|
103
109
|
:final_app_directory,
|
104
110
|
:output_locations,
|
105
111
|
:preprocessor,
|
106
|
-
:
|
112
|
+
:section_repository,
|
107
113
|
:sitemap_writer,
|
108
114
|
:static_site_generator,
|
109
115
|
)
|
110
116
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
host_for_sitemap = publish_config.public_host
|
115
|
-
|
116
|
-
static_site_generator.run(output_locations,
|
117
|
-
publish_config,
|
118
|
-
cloner,
|
119
|
-
cli_options[:verbose],
|
120
|
-
subnavs)
|
121
|
-
file_system_accessor.copy output_locations.build_dir, output_locations.public_dir
|
122
|
-
|
123
|
-
result = sitemap_writer.write(
|
124
|
-
host_for_sitemap,
|
125
|
-
streams,
|
126
|
-
publish_config.broken_link_exclusions
|
127
|
-
)
|
128
|
-
|
129
|
-
streams[:success].puts "Bookbinder bound your book into #{output_locations.final_app_dir}"
|
130
|
-
|
131
|
-
!result.has_broken_links?
|
132
|
-
end
|
133
|
-
|
134
|
-
def generate_local_repo_dir(context_dir, bind_source)
|
135
|
-
File.expand_path('..', context_dir) if bind_source == 'local'
|
136
|
-
end
|
137
|
-
|
138
|
-
def layout_repo_path(config, cloner)
|
139
|
-
if config.has_option?('layout_repo')
|
140
|
-
working_copy = cloner.call(source_repo_name: config.layout_repo,
|
141
|
-
destination_parent_dir: Dir.mktmpdir)
|
142
|
-
working_copy.path
|
143
|
-
else
|
144
|
-
File.absolute_path('master_middleman')
|
145
|
-
end
|
117
|
+
def subnavs(sections)
|
118
|
+
sections.map(&:subnav).reduce({}, :merge)
|
146
119
|
end
|
147
120
|
end
|
148
121
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require_relative '../../sheller'
|
2
|
-
require_relative '../../streams/colorized_stream'
|
3
2
|
|
4
3
|
module Bookbinder
|
5
4
|
module Commands
|
@@ -14,35 +13,46 @@ module Bookbinder
|
|
14
13
|
raise CliError::InvalidArguments unless arguments_are_valid?
|
15
14
|
end
|
16
15
|
|
16
|
+
def bind_source
|
17
|
+
opts.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def local_repo_dir
|
21
|
+
File.expand_path('..') if bind_source == 'local'
|
22
|
+
end
|
23
|
+
|
24
|
+
def options
|
25
|
+
opts[1..-1]
|
26
|
+
end
|
27
|
+
|
17
28
|
def ref_override
|
18
|
-
'master' if
|
29
|
+
'master' if options.include?('--ignore-section-refs')
|
19
30
|
end
|
20
31
|
|
21
32
|
def streams
|
22
33
|
base_streams.merge(
|
23
|
-
out:
|
34
|
+
out: verbosity ? base_streams[:out] : Sheller::DevNull.new,
|
24
35
|
)
|
25
36
|
end
|
26
37
|
|
38
|
+
def verbosity
|
39
|
+
options.detect {|arg| arg == '--verbose'}
|
40
|
+
end
|
41
|
+
|
27
42
|
private
|
28
43
|
|
29
44
|
attr_accessor :base_streams, :opts
|
30
45
|
|
31
46
|
def arguments_are_valid?
|
32
|
-
|
33
|
-
%w(local remote github).include?(bind_source) && flag_names.to_set.subset?(valid_options)
|
34
|
-
end
|
35
|
-
|
36
|
-
def flag_names
|
37
|
-
options.map {|o| o.split('=').first}
|
47
|
+
%w(local remote github).include?(bind_source) && flag_names.subset?(valid_options)
|
38
48
|
end
|
39
49
|
|
40
|
-
def
|
41
|
-
|
50
|
+
def valid_options
|
51
|
+
%w(--verbose --ignore-section-refs --dita-flags).to_set
|
42
52
|
end
|
43
53
|
|
44
|
-
def
|
45
|
-
|
54
|
+
def flag_names
|
55
|
+
options.map {|o| o.split('=').first}.to_set
|
46
56
|
end
|
47
57
|
end
|
48
58
|
end
|
@@ -1,54 +1,38 @@
|
|
1
|
-
require_relative '../../directory_helpers'
|
2
|
-
require_relative '../../ingest/destination_directory'
|
3
|
-
|
4
1
|
module Bookbinder
|
5
2
|
module Commands
|
6
3
|
module BindComponents
|
7
4
|
class DirectoryPreparer
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(logger, file_system_accessor, version_control_system)
|
11
|
-
@logger = logger
|
12
|
-
@file_system_accessor = file_system_accessor
|
13
|
-
@version_control_system = version_control_system
|
5
|
+
def initialize(fs)
|
6
|
+
@fs = fs
|
14
7
|
end
|
15
8
|
|
16
|
-
def prepare_directories(config, gem_root, output_locations,
|
17
|
-
|
18
|
-
|
9
|
+
def prepare_directories(config, gem_root, output_locations, cloner)
|
10
|
+
fs.remove_directory(output_locations.output_dir)
|
11
|
+
fs.empty_directory(output_locations.final_app_dir)
|
19
12
|
|
20
13
|
copy_directory_from_gem(gem_root, 'template_app', output_locations.final_app_dir)
|
21
14
|
copy_directory_from_gem(gem_root, 'master_middleman', output_locations.site_generator_home)
|
22
|
-
file_system_accessor.copy_contents(layout_repo_dir, output_locations.site_generator_home)
|
23
15
|
|
24
|
-
config
|
25
|
-
|
26
|
-
end
|
16
|
+
layout_repo_path = fetch_layout_repo(config, cloner)
|
17
|
+
fs.copy_contents(layout_repo_path, output_locations.site_generator_home)
|
27
18
|
end
|
28
19
|
|
29
20
|
private
|
30
21
|
|
31
|
-
attr_reader :
|
32
|
-
|
33
|
-
def copy_index_file_from_version_to_master_middleman(version, dest_dir, url)
|
34
|
-
clone_dir_name = Ingest::DestinationDirectory.new(url)
|
35
|
-
Dir.mktmpdir(version) do |tmpdir|
|
36
|
-
version_control_system.clone(url,
|
37
|
-
clone_dir_name,
|
38
|
-
path: tmpdir,
|
39
|
-
checkout: version)
|
40
|
-
index_source_dir = Pathname(tmpdir).join(clone_dir_name, 'master_middleman', source_dir_name)
|
41
|
-
index_dest_dir = File.join(dest_dir, version)
|
42
|
-
file_system_accessor.make_directory(index_dest_dir)
|
22
|
+
attr_reader :fs
|
43
23
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
end
|
24
|
+
def copy_directory_from_gem(gem_root, dir, output_dir)
|
25
|
+
fs.copy_contents(File.join(gem_root, dir), output_dir)
|
48
26
|
end
|
49
27
|
|
50
|
-
def
|
51
|
-
|
28
|
+
def fetch_layout_repo(config, cloner)
|
29
|
+
if config.has_option?('layout_repo')
|
30
|
+
cloned_repo = cloner.call(source_repo_name: config.layout_repo,
|
31
|
+
destination_parent_dir: Dir.mktmpdir)
|
32
|
+
cloned_repo.path
|
33
|
+
else
|
34
|
+
File.absolute_path('master_middleman')
|
35
|
+
end
|
52
36
|
end
|
53
37
|
end
|
54
38
|
end
|