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
@@ -3,7 +3,7 @@ Dir.glob(File.expand_path('../../commands/*.rb', __FILE__)).each do |command_fil
|
|
3
3
|
end
|
4
4
|
|
5
5
|
require_relative '../commands/bind/directory_preparer'
|
6
|
-
require_relative '../config/
|
6
|
+
require_relative '../config/archive_menu_configuration'
|
7
7
|
require_relative '../config/fetcher'
|
8
8
|
require_relative '../config/remote_yaml_credential_provider'
|
9
9
|
require_relative '../config/validator'
|
@@ -12,7 +12,7 @@ require_relative '../dita_command_creator'
|
|
12
12
|
require_relative '../dita_html_to_middleman_formatter'
|
13
13
|
require_relative '../html_document_manipulator'
|
14
14
|
require_relative '../ingest/cloner_factory'
|
15
|
-
require_relative '../ingest/
|
15
|
+
require_relative '../ingest/section_repository'
|
16
16
|
require_relative '../local_file_system_accessor'
|
17
17
|
require_relative '../middleman_runner'
|
18
18
|
require_relative '../postprocessing/sitemap_writer'
|
@@ -61,7 +61,7 @@ module Bookbinder
|
|
61
61
|
@standard_commands ||= [
|
62
62
|
Commands::Generate.new(
|
63
63
|
local_file_system_accessor,
|
64
|
-
|
64
|
+
sheller,
|
65
65
|
Dir.pwd,
|
66
66
|
streams
|
67
67
|
),
|
@@ -77,6 +77,7 @@ module Bookbinder
|
|
77
77
|
configuration_fetcher,
|
78
78
|
version_control_system
|
79
79
|
),
|
80
|
+
watch
|
80
81
|
]
|
81
82
|
end
|
82
83
|
|
@@ -88,23 +89,38 @@ module Bookbinder
|
|
88
89
|
@bind ||= Commands::Bind.new(
|
89
90
|
streams,
|
90
91
|
OutputLocations.new(final_app_dir: final_app_directory, context_dir: File.absolute_path('.')),
|
91
|
-
|
92
|
+
configuration_fetcher,
|
92
93
|
Config::ArchiveMenuConfiguration.new(loader: config_loader, config_filename: 'bookbinder.yml'),
|
93
94
|
local_file_system_accessor,
|
94
|
-
|
95
|
+
runner,
|
95
96
|
Postprocessing::SitemapWriter.build(logger, final_app_directory, sitemap_port),
|
96
97
|
Preprocessing::Preprocessor.new(
|
97
98
|
Preprocessing::DitaPreprocessor.new(
|
98
99
|
DitaHtmlToMiddlemanFormatter.new(local_file_system_accessor, subnav_formatter, html_document_manipulator),
|
99
100
|
local_file_system_accessor,
|
100
101
|
DitaCommandCreator.new(ENV['PATH_TO_DITA_OT_LIBRARY']),
|
101
|
-
|
102
|
+
sheller
|
102
103
|
),
|
103
104
|
Preprocessing::LinkToSiteGenDir.new(local_file_system_accessor),
|
104
105
|
),
|
105
106
|
Ingest::ClonerFactory.new(streams, local_file_system_accessor, version_control_system),
|
106
|
-
Ingest::
|
107
|
-
|
107
|
+
Ingest::SectionRepository.new,
|
108
|
+
directory_preparer
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def watch
|
113
|
+
@watch ||= Commands::Watch.new(
|
114
|
+
streams,
|
115
|
+
middleman_runner: runner,
|
116
|
+
output_locations: OutputLocations.new(final_app_dir: final_app_directory, context_dir: File.absolute_path('.')),
|
117
|
+
config_fetcher: configuration_fetcher,
|
118
|
+
config_decorator: Config::ArchiveMenuConfiguration.new(loader: config_loader, config_filename: 'bookbinder.yml'),
|
119
|
+
file_system_accessor: local_file_system_accessor,
|
120
|
+
preprocessor: Preprocessing::Preprocessor.new(Preprocessing::LinkToSiteGenDir.new(local_file_system_accessor)),
|
121
|
+
cloner: local_file_system_cloner,
|
122
|
+
section_repository: Ingest::SectionRepository.new,
|
123
|
+
directory_preparer: directory_preparer
|
108
124
|
)
|
109
125
|
end
|
110
126
|
|
@@ -138,6 +154,10 @@ module Bookbinder
|
|
138
154
|
@config_loader ||= Config::YAMLLoader.new
|
139
155
|
end
|
140
156
|
|
157
|
+
def directory_preparer
|
158
|
+
Commands::BindComponents::DirectoryPreparer.new(local_file_system_accessor)
|
159
|
+
end
|
160
|
+
|
141
161
|
def final_app_directory
|
142
162
|
@final_app_directory ||= File.absolute_path('final_app')
|
143
163
|
end
|
@@ -154,9 +174,21 @@ module Bookbinder
|
|
154
174
|
@local_file_system_accessor ||= LocalFileSystemAccessor.new
|
155
175
|
end
|
156
176
|
|
177
|
+
def sheller
|
178
|
+
@sheller ||= Sheller.new
|
179
|
+
end
|
180
|
+
|
157
181
|
def sitemap_port
|
158
182
|
41722
|
159
183
|
end
|
184
|
+
|
185
|
+
def runner
|
186
|
+
MiddlemanRunner.new(local_file_system_accessor, sheller)
|
187
|
+
end
|
188
|
+
|
189
|
+
def local_file_system_cloner
|
190
|
+
Ingest::LocalFilesystemCloner.new(streams, local_file_system_accessor, File.expand_path('..'))
|
191
|
+
end
|
160
192
|
end
|
161
193
|
end
|
162
194
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require_relative 'bind/bind_options'
|
2
|
+
require_relative 'naming'
|
3
|
+
|
4
|
+
module Bookbinder
|
5
|
+
module Commands
|
6
|
+
class Watch
|
7
|
+
include Commands::Naming
|
8
|
+
|
9
|
+
def initialize(streams,
|
10
|
+
middleman_runner: nil,
|
11
|
+
output_locations: nil,
|
12
|
+
config_fetcher: nil,
|
13
|
+
config_decorator: nil,
|
14
|
+
file_system_accessor: nil,
|
15
|
+
preprocessor: nil,
|
16
|
+
cloner: nil,
|
17
|
+
section_repository: nil,
|
18
|
+
directory_preparer: nil)
|
19
|
+
@streams = streams
|
20
|
+
@middleman_runner = middleman_runner
|
21
|
+
@output_locations = output_locations
|
22
|
+
@config_fetcher = config_fetcher
|
23
|
+
@config_decorator = config_decorator
|
24
|
+
@file_system_accessor = file_system_accessor
|
25
|
+
@preprocessor = preprocessor
|
26
|
+
@cloner = cloner
|
27
|
+
@section_repository = section_repository
|
28
|
+
@directory_preparer = directory_preparer
|
29
|
+
end
|
30
|
+
|
31
|
+
def usage
|
32
|
+
["watch",
|
33
|
+
"Bind and serve a local book, watching for changes"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def run(_)
|
37
|
+
watch_config = config_fetcher.fetch_config
|
38
|
+
|
39
|
+
directory_preparer.prepare_directories(
|
40
|
+
watch_config,
|
41
|
+
File.expand_path('../../../../', __FILE__),
|
42
|
+
output_locations,
|
43
|
+
cloner
|
44
|
+
)
|
45
|
+
sections = section_repository.fetch(
|
46
|
+
configured_sections: watch_config.sections,
|
47
|
+
destination_dir: output_locations.cloned_preprocessing_dir,
|
48
|
+
cloner: cloner,
|
49
|
+
streams: streams
|
50
|
+
)
|
51
|
+
preprocessor.preprocess(
|
52
|
+
sections,
|
53
|
+
output_locations,
|
54
|
+
output_streams: streams
|
55
|
+
)
|
56
|
+
if file_system_accessor.file_exist?('redirects.rb')
|
57
|
+
file_system_accessor.copy('redirects.rb', output_locations.final_app_dir)
|
58
|
+
end
|
59
|
+
|
60
|
+
middleman_runner.run("server --force-polling --latency=5.0",
|
61
|
+
output_locations: output_locations,
|
62
|
+
config: config_decorator.generate(watch_config, sections),
|
63
|
+
local_repo_dir: File.expand_path('..'),
|
64
|
+
streams: streams,
|
65
|
+
subnavs: subnavs(sections)
|
66
|
+
).exitstatus
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
attr_reader(
|
72
|
+
:streams,
|
73
|
+
:middleman_runner,
|
74
|
+
:output_locations,
|
75
|
+
:config_fetcher,
|
76
|
+
:config_decorator,
|
77
|
+
:file_system_accessor,
|
78
|
+
:preprocessor,
|
79
|
+
:cloner,
|
80
|
+
:section_repository,
|
81
|
+
:directory_preparer
|
82
|
+
)
|
83
|
+
|
84
|
+
def subnavs(sections)
|
85
|
+
sections.map(&:subnav).reduce({}, :merge)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -8,12 +8,8 @@ module Bookbinder
|
|
8
8
|
TagExists = Class.new(RuntimeError)
|
9
9
|
InvalidTagRef = Class.new(RuntimeError)
|
10
10
|
|
11
|
-
def initialize
|
12
|
-
@cache = {}
|
13
|
-
end
|
14
|
-
|
15
11
|
def clone(url, name, path: nil, checkout: 'master')
|
16
|
-
cached_clone(url, name, path).tap do |git|
|
12
|
+
cached_clone(url, name, Pathname(path)).tap do |git|
|
17
13
|
git.checkout(checkout)
|
18
14
|
end
|
19
15
|
end
|
@@ -35,7 +31,7 @@ module Bookbinder
|
|
35
31
|
def read_file(filename, from_repo: nil, checkout: 'master')
|
36
32
|
Dir.mktmpdir do |dir|
|
37
33
|
path = Pathname(dir)
|
38
|
-
git =
|
34
|
+
git = cached_clone(from_repo, temp_name("read-file"), path)
|
39
35
|
git.checkout(checkout)
|
40
36
|
path.join(temp_name("read-file"), filename).read
|
41
37
|
end
|
@@ -44,7 +40,7 @@ module Bookbinder
|
|
44
40
|
def remote_tag(url, tagname, commit_or_object)
|
45
41
|
Dir.mktmpdir do |dir|
|
46
42
|
path = Pathname(dir)
|
47
|
-
git =
|
43
|
+
git = cached_clone(url, temp_name("tag"), path)
|
48
44
|
git.config('user.name', 'Bookbinder')
|
49
45
|
git.config('user.email', 'bookbinder@cloudfoundry.org')
|
50
46
|
begin
|
@@ -66,18 +62,17 @@ module Bookbinder
|
|
66
62
|
|
67
63
|
private
|
68
64
|
|
69
|
-
attr_reader :cache
|
70
|
-
|
71
65
|
def temp_name(purpose)
|
72
66
|
"bookbinder-git-accessor-#{purpose}"
|
73
67
|
end
|
74
68
|
|
75
69
|
def cached_clone(url, name, path)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
70
|
+
dest_dir = path.join(name)
|
71
|
+
if dest_dir.exist?
|
72
|
+
Git.open(dest_dir)
|
73
|
+
else
|
74
|
+
Git.clone(url, name, path: path)
|
75
|
+
end
|
81
76
|
end
|
82
77
|
end
|
83
78
|
end
|
@@ -15,7 +15,7 @@ module Bookbinder
|
|
15
15
|
source_ref: nil,
|
16
16
|
destination_parent_dir: nil,
|
17
17
|
destination_dir_name: nil)
|
18
|
-
|
18
|
+
link!(
|
19
19
|
source_repo_name,
|
20
20
|
Pathname(user_repo_dir).join(source_repo_name.split('/').last),
|
21
21
|
Pathname(destination_parent_dir).join(DestinationDirectory.new(source_repo_name, destination_dir_name))
|
@@ -26,29 +26,29 @@ module Bookbinder
|
|
26
26
|
|
27
27
|
attr_reader :streams, :filesystem, :user_repo_dir
|
28
28
|
|
29
|
-
def
|
29
|
+
def link!(source_repo_name, source_dir, dest_dir)
|
30
30
|
source_exists = filesystem.file_exist?(source_dir)
|
31
31
|
|
32
32
|
if source_exists && filesystem.file_exist?(dest_dir)
|
33
|
-
|
33
|
+
announce(source_dir)
|
34
34
|
WorkingCopy.new(
|
35
35
|
copied_to: dest_dir,
|
36
36
|
full_name: source_repo_name,
|
37
37
|
)
|
38
38
|
elsif source_exists
|
39
|
-
|
40
|
-
filesystem.
|
39
|
+
announce(source_dir)
|
40
|
+
filesystem.link_creating_intermediate_dirs(source_dir, dest_dir)
|
41
41
|
WorkingCopy.new(
|
42
42
|
copied_to: dest_dir,
|
43
43
|
full_name: source_repo_name,
|
44
44
|
)
|
45
45
|
else
|
46
46
|
streams[:out].puts " skipping (not found) #{source_dir}"
|
47
|
-
MissingWorkingCopy.new(source_repo_name)
|
47
|
+
MissingWorkingCopy.new(source_repo_name, source_dir)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
def
|
51
|
+
def announce(source_dir)
|
52
52
|
streams[:out].puts " copying #{source_dir}"
|
53
53
|
end
|
54
54
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module Bookbinder
|
2
2
|
module Ingest
|
3
3
|
class MissingWorkingCopy
|
4
|
-
def initialize(source_repo_name)
|
4
|
+
def initialize(source_repo_name, source_dir)
|
5
5
|
@source_repo_name = source_repo_name
|
6
|
+
@source_dir= source_dir
|
6
7
|
end
|
7
8
|
|
8
9
|
def full_name
|
@@ -10,7 +11,7 @@ module Bookbinder
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def path
|
13
|
-
Pathname(
|
14
|
+
Pathname(@source_dir)
|
14
15
|
end
|
15
16
|
|
16
17
|
def available?
|
@@ -5,16 +5,13 @@ require_relative '../values/section'
|
|
5
5
|
module Bookbinder
|
6
6
|
module Ingest
|
7
7
|
class SectionRepository
|
8
|
-
def initialize(logger, cloner)
|
9
|
-
@logger = logger
|
10
|
-
@cloner = cloner
|
11
|
-
end
|
12
|
-
|
13
8
|
def fetch(configured_sections: [],
|
14
9
|
destination_dir: nil,
|
15
|
-
ref_override: nil
|
10
|
+
ref_override: nil,
|
11
|
+
cloner: nil,
|
12
|
+
streams: nil)
|
16
13
|
configured_sections.map do |section_config|
|
17
|
-
|
14
|
+
streams[:success].puts("Gathering #{section_config.repo_name}")
|
18
15
|
working_copy = cloner.call(source_repo_name: section_config.repo_name,
|
19
16
|
source_ref: ref_override || section_config.repo_ref,
|
20
17
|
destination_parent_dir: destination_dir,
|
@@ -29,10 +26,6 @@ module Bookbinder
|
|
29
26
|
)
|
30
27
|
end
|
31
28
|
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
attr_reader :logger, :cloner
|
36
29
|
end
|
37
30
|
end
|
38
31
|
end
|
@@ -3,6 +3,8 @@ require_relative '../errors/programmer_mistake'
|
|
3
3
|
module Bookbinder
|
4
4
|
module Ingest
|
5
5
|
class WorkingCopy
|
6
|
+
attr_reader :full_name
|
7
|
+
|
6
8
|
def initialize(copied_to: nil,
|
7
9
|
full_name: nil)
|
8
10
|
if [copied_to, full_name].none?
|
@@ -13,8 +15,6 @@ module Bookbinder
|
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
16
|
-
attr_reader :full_name
|
17
|
-
|
18
18
|
def available?
|
19
19
|
!! @copied_to
|
20
20
|
end
|
@@ -22,6 +22,12 @@ module Bookbinder
|
|
22
22
|
def path
|
23
23
|
Pathname(@copied_to)
|
24
24
|
end
|
25
|
+
|
26
|
+
def ==(other)
|
27
|
+
[@copied_to, @full_name] ==
|
28
|
+
[other.instance_variable_get(:@copied_to),
|
29
|
+
other.instance_variable_get(:@full_name)]
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
@@ -72,6 +72,13 @@ module Bookbinder
|
|
72
72
|
relative_path.to_s
|
73
73
|
end
|
74
74
|
|
75
|
+
def find_files_recursively(from)
|
76
|
+
`find -L #{from}`.
|
77
|
+
lines.
|
78
|
+
map(&:chomp).
|
79
|
+
map(&Pathname.method(:new)).
|
80
|
+
reject {|p| p.to_s.match %r{/\.}}.
|
81
|
+
reject(&:directory?)
|
82
|
+
end
|
75
83
|
end
|
76
|
-
|
77
84
|
end
|
@@ -1,94 +1,41 @@
|
|
1
|
-
require 'git/lib'
|
2
1
|
require 'middleman-core'
|
3
2
|
require 'middleman-core/cli'
|
4
3
|
require 'middleman-core/profiling'
|
5
|
-
|
6
|
-
|
7
|
-
class Middleman::Cli::BuildAction
|
8
|
-
def handle_error(file_name, response, e=Thor::Error.new(response))
|
9
|
-
our_errors = [Bookbinder::CodeExampleReader::InvalidSnippet,
|
10
|
-
QuicklinksRenderer::BadHeadingLevelError,
|
11
|
-
Git::GitExecuteError]
|
12
|
-
raise e if our_errors.include?(e.class)
|
13
|
-
|
14
|
-
original_handle_error(e, file_name, response)
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def original_handle_error(e, file_name, response)
|
20
|
-
base.had_errors = true
|
21
|
-
|
22
|
-
base.say_status :error, file_name, :red
|
23
|
-
if base.debugging
|
24
|
-
raise e
|
25
|
-
exit(1)
|
26
|
-
elsif base.options["verbose"]
|
27
|
-
base.shell.say response, :red
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
4
|
+
require 'yaml'
|
31
5
|
|
32
6
|
module Bookbinder
|
33
7
|
class MiddlemanRunner
|
34
|
-
def initialize(
|
35
|
-
@
|
36
|
-
@
|
8
|
+
def initialize(fs, sheller)
|
9
|
+
@fs = fs
|
10
|
+
@sheller = sheller
|
37
11
|
end
|
38
12
|
|
39
|
-
def run(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
13
|
+
def run(command,
|
14
|
+
streams: nil,
|
15
|
+
output_locations: nil,
|
16
|
+
config: nil,
|
17
|
+
local_repo_dir: nil,
|
18
|
+
subnavs: nil)
|
19
|
+
streams[:out].puts "\nRunning middleman...\n\n"
|
20
|
+
Dir.chdir(output_locations.master_dir) do
|
21
|
+
config = {
|
22
|
+
archive_menu: config.archive_menu,
|
23
|
+
production_host: config.public_host,
|
24
|
+
subnav_templates: subnavs,
|
25
|
+
template_variables: config.template_variables,
|
26
|
+
local_repo_dir: local_repo_dir,
|
27
|
+
workspace: output_locations.workspace_dir,
|
28
|
+
}
|
29
|
+
fs.write(to: "bookbinder_config.yml", text: YAML.dump(config))
|
30
|
+
sheller.run_command({'MM_ROOT' => output_locations.master_dir.to_s},
|
31
|
+
"middleman #{command}",
|
32
|
+
streams)
|
54
33
|
end
|
55
34
|
end
|
56
35
|
|
57
36
|
private
|
58
37
|
|
59
|
-
attr_reader :
|
60
|
-
|
61
|
-
def within(temp_root, &block)
|
62
|
-
Middleman::Cli::Build.instance_variable_set(:@_shared_instance, nil)
|
63
|
-
original_mm_root = ENV['MM_ROOT']
|
64
|
-
ENV['MM_ROOT'] = temp_root.to_s
|
65
|
-
|
66
|
-
Dir.chdir(temp_root) { block.call }
|
67
|
-
|
68
|
-
ENV['MM_ROOT'] = original_mm_root
|
69
|
-
end
|
70
|
-
|
71
|
-
def invoke_against_current_dir(workspace_dir,
|
72
|
-
production_host,
|
73
|
-
subnav_templates,
|
74
|
-
template_variables,
|
75
|
-
archive_menu,
|
76
|
-
verbose,
|
77
|
-
cloner)
|
78
|
-
builder = Middleman::Cli::Build.shared_instance(verbose)
|
38
|
+
attr_reader :streams, :fs, :sheller
|
79
39
|
|
80
|
-
config = {
|
81
|
-
archive_menu: archive_menu,
|
82
|
-
cloner: cloner,
|
83
|
-
production_host: production_host,
|
84
|
-
relative_links: false,
|
85
|
-
subnav_templates: subnav_templates,
|
86
|
-
template_variables: template_variables,
|
87
|
-
workspace: workspace_dir,
|
88
|
-
}
|
89
|
-
|
90
|
-
config.each { |k, v| builder.config[k] = v }
|
91
|
-
Middleman::Cli::Build.new([], {quiet: !verbose}, {}).invoke :build, [], {verbose: verbose}
|
92
|
-
end
|
93
40
|
end
|
94
41
|
end
|