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