bookbindery 4.2.0 → 5.0.0

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