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.
@@ -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/bind_config_factory'
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/section_repository_factory'
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
- Sheller.new,
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
- Config::BindConfigFactory.new(version_control_system, configuration_fetcher),
92
+ configuration_fetcher,
92
93
  Config::ArchiveMenuConfiguration.new(loader: config_loader, config_filename: 'bookbinder.yml'),
93
94
  local_file_system_accessor,
94
- MiddlemanRunner.new(logger, version_control_system),
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
- Sheller.new
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::SectionRepositoryFactory.new(logger),
107
- Commands::BindComponents::DirectoryPreparer.new(logger, local_file_system_accessor, version_control_system)
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
@@ -73,10 +73,6 @@ module Bookbinder
73
73
  config.fetch(:template_variables, {})
74
74
  end
75
75
 
76
- def versions
77
- config.fetch(:versions, [])
78
- end
79
-
80
76
  def merge(other_configuration)
81
77
  Configuration.new(config.merge(other_configuration.instance_variable_get(:@config)))
82
78
  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 = _clone(from_repo, temp_name("read-file"), path)
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 = _clone(url, temp_name("tag"), path)
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
- cache[[url, name, path]] ||= _clone(url, name, path)
77
- end
78
-
79
- def _clone(url, name, path)
80
- Git.clone(url, name, path: path)
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
- copy!(
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 copy!(source_repo_name, source_dir, dest_dir)
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
- announce_copy(source_dir)
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
- announce_copy(source_dir)
40
- filesystem.copy_contents(source_dir, dest_dir)
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 announce_copy(source_dir)
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("/this/doesnt/actually/exist/#{SecureRandom.uuid}")
14
+ Pathname(@source_dir)
14
15
  end
15
16
 
16
17
  def available?
@@ -10,7 +10,7 @@ module Bookbinder
10
10
  def to_str
11
11
  if input_identifier.nil?
12
12
  ""
13
- elsif input_identifier.include?(':')
13
+ elsif input_identifier.include?(':') || input_identifier.match(/^\//)
14
14
  input_identifier
15
15
  else
16
16
  "#{DEFAULT_VCS_PREFIX}#{input_identifier}"
@@ -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
- logger.log "Gathering #{section_config.repo_name.cyan}"
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
- require_relative 'code_example_reader'
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(logger, git_accessor)
35
- @logger = logger
36
- @git_accessor = git_accessor
8
+ def initialize(fs, sheller)
9
+ @fs = fs
10
+ @sheller = sheller
37
11
  end
38
12
 
39
- def run(output_locations,
40
- config,
41
- cloner,
42
- verbose = false,
43
- subnav_templates_by_directory = {})
44
- @logger.log "\nRunning middleman...\n\n"
45
-
46
- within(output_locations.master_dir) do
47
- invoke_against_current_dir(output_locations.workspace_dir,
48
- config.public_host,
49
- subnav_templates_by_directory,
50
- config.template_variables,
51
- config.archive_menu,
52
- verbose,
53
- cloner)
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 :git_accessor
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