bookbindery 1.0.3 → 2.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/{bin → install_bin}/bookbinder +0 -0
  3. data/lib/bookbinder.rb +2 -9
  4. data/lib/bookbinder/archive.rb +1 -1
  5. data/lib/bookbinder/archive_menu_configuration.rb +34 -0
  6. data/lib/bookbinder/book.rb +17 -17
  7. data/lib/bookbinder/cli.rb +25 -36
  8. data/lib/bookbinder/code_example.rb +5 -38
  9. data/lib/bookbinder/code_example_reader.rb +40 -0
  10. data/lib/bookbinder/colorizer.rb +14 -0
  11. data/lib/bookbinder/command_runner.rb +9 -16
  12. data/lib/bookbinder/command_validator.rb +14 -7
  13. data/lib/bookbinder/commands/bind.rb +321 -0
  14. data/lib/bookbinder/commands/build_and_push_tarball.rb +7 -6
  15. data/lib/bookbinder/commands/chain.rb +11 -0
  16. data/lib/bookbinder/commands/generate_pdf.rb +4 -3
  17. data/lib/bookbinder/commands/help.rb +49 -10
  18. data/lib/bookbinder/commands/naming.rb +9 -1
  19. data/lib/bookbinder/commands/push_local_to_staging.rb +4 -3
  20. data/lib/bookbinder/commands/push_to_prod.rb +36 -4
  21. data/lib/bookbinder/commands/run_publish_ci.rb +21 -24
  22. data/lib/bookbinder/commands/tag.rb +3 -3
  23. data/lib/bookbinder/commands/update_local_doc_repos.rb +5 -4
  24. data/lib/bookbinder/commands/version.rb +11 -8
  25. data/lib/bookbinder/configuration.rb +8 -3
  26. data/lib/bookbinder/configuration_fetcher.rb +7 -25
  27. data/lib/bookbinder/configuration_validator.rb +21 -0
  28. data/lib/bookbinder/distributor.rb +1 -1
  29. data/lib/bookbinder/dita_html_to_middleman_formatter.rb +37 -0
  30. data/lib/bookbinder/dita_section.rb +7 -0
  31. data/lib/bookbinder/dita_section_gatherer.rb +28 -0
  32. data/lib/bookbinder/git_accessor.rb +17 -0
  33. data/lib/bookbinder/git_client.rb +10 -7
  34. data/lib/bookbinder/git_hub_repository.rb +46 -41
  35. data/lib/bookbinder/local_dita_preprocessor.rb +27 -0
  36. data/lib/bookbinder/local_dita_to_html_converter.rb +49 -0
  37. data/lib/bookbinder/local_file_system_accessor.rb +68 -0
  38. data/lib/bookbinder/middleman_runner.rb +30 -17
  39. data/lib/bookbinder/publisher.rb +16 -80
  40. data/lib/bookbinder/remote_yaml_credential_provider.rb +2 -3
  41. data/lib/bookbinder/repositories/command_repository.rb +156 -0
  42. data/lib/bookbinder/repositories/section_repository.rb +31 -0
  43. data/lib/bookbinder/section.rb +5 -67
  44. data/lib/bookbinder/shell_out.rb +1 -0
  45. data/lib/bookbinder/sheller.rb +19 -0
  46. data/lib/bookbinder/sieve.rb +6 -1
  47. data/lib/bookbinder/terminal.rb +10 -0
  48. data/lib/bookbinder/user_message.rb +6 -0
  49. data/lib/bookbinder/user_message_presenter.rb +21 -0
  50. data/lib/bookbinder/yaml_loader.rb +18 -7
  51. data/master_middleman/archive_drop_down_menu.rb +46 -0
  52. data/master_middleman/bookbinder_helpers.rb +47 -40
  53. metadata +33 -87
  54. data/lib/bookbinder/commands/publish.rb +0 -138
  55. data/lib/bookbinder/usage_messenger.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 07f71ad52807a1f8b6a85bd211883dd095c8262f
4
- data.tar.gz: 7a6157d356da84da49236483507377e2c393c671
3
+ metadata.gz: 56679c8bf251f348c3dd66d86317c0c848b35706
4
+ data.tar.gz: e6a280ed228236c2fa381393d5bdeb5f3710f8e1
5
5
  SHA512:
6
- metadata.gz: 8eef0dce3fe1834608202017de1eb0ef06caf7638a70d329a97f19f08d3420399e2eac074cdf3b9f51ae71d7070ef54e85c53bbb00dbd35fd708cc61d4314592
7
- data.tar.gz: f0dff29b6cb65e19bf479f636fa22108a9e06e8ecd113ae5baf7316e036703332a0d1304064064efe6db352ede94cb49a1ca9e44dfdf9b2fc940d02b4b1499d3
6
+ metadata.gz: b28159d61a3847f29100709af210253bc25e90ed5770273d4891ea928a24f643f7537832c36e8e3efe2780b5dfdab773b4dd3c41ab994a3ce4c8cddfcedc9cb9
7
+ data.tar.gz: 3463e88ed1b0044e735c0e0ffd25c572b4258cc0906985f0b74c6bfca47d1e2269895700f4ca07c694c83c2a4ee25268be1c9dd9be2e5c8284cb286564510097
File without changes
@@ -1,10 +1,7 @@
1
- require 'fog'
1
+ require 'fog/aws'
2
2
  require 'tmpdir'
3
3
  require 'ansi'
4
- require 'faraday'
5
- require 'faraday_middleware'
6
4
  require 'octokit'
7
- require 'padrino-contrib'
8
5
  require 'middleman-syntax'
9
6
  require 'middleman-core/cli'
10
7
  require 'middleman-core/profiling'
@@ -14,10 +11,8 @@ require 'vienna'
14
11
  require 'popen4'
15
12
  require 'puma'
16
13
 
17
- #require_relative 'bookbinder/shell_out'
18
14
  require_relative 'bookbinder/bookbinder_logger'
19
15
  require_relative 'bookbinder/git_client'
20
- #require_relative 'bookbinder/repository'
21
16
  require_relative 'bookbinder/section'
22
17
  require_relative 'bookbinder/book'
23
18
  require_relative 'bookbinder/code_example'
@@ -43,7 +38,7 @@ require_relative 'bookbinder/distributor'
43
38
 
44
39
  require_relative 'bookbinder/commands/bookbinder_command'
45
40
  require_relative 'bookbinder/commands/build_and_push_tarball'
46
- require_relative 'bookbinder/commands/publish'
41
+ require_relative 'bookbinder/commands/bind'
47
42
  require_relative 'bookbinder/commands/push_local_to_staging'
48
43
  require_relative 'bookbinder/commands/push_to_prod'
49
44
  require_relative 'bookbinder/commands/run_publish_ci'
@@ -51,8 +46,6 @@ require_relative 'bookbinder/commands/update_local_doc_repos'
51
46
  require_relative 'bookbinder/commands/tag'
52
47
  require_relative 'bookbinder/commands/generate_pdf'
53
48
 
54
- require_relative 'bookbinder/usage_messenger'
55
-
56
49
  require_relative 'bookbinder/cli'
57
50
 
58
51
  # Finds the project root for both spec & production
@@ -1,4 +1,4 @@
1
- require 'fog'
1
+ require 'fog/aws'
2
2
  require 'tmpdir'
3
3
  require_relative 'bookbinder_logger'
4
4
  require_relative 'artifact_namer'
@@ -0,0 +1,34 @@
1
+ module Bookbinder
2
+ class ArchiveMenuConfiguration
3
+ def initialize(loader: nil, config_filename: nil)
4
+ @loader = loader
5
+ @config_filename = config_filename
6
+ end
7
+
8
+ def generate(base_config, sections)
9
+ base_config.merge(
10
+ archive_menu: root_config(base_config).merge(section_config(sections))
11
+ )
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :loader, :config_filename
17
+
18
+ def root_config(base_config)
19
+ { '.' => base_config[:archive_menu] }
20
+ end
21
+
22
+ def section_config(sections)
23
+ sections.reduce({}) {|config, section|
24
+ config_path = section.path_to_repository.join(config_filename)
25
+ archive_config = loader.load_key(config_path, 'archive_menu')
26
+ if archive_config
27
+ config.merge(section.directory_name => archive_config)
28
+ else
29
+ config
30
+ end
31
+ }
32
+ end
33
+ end
34
+ end
@@ -4,7 +4,6 @@ require_relative 'directory_helpers'
4
4
  module Bookbinder
5
5
  class Book
6
6
  include DirectoryHelperMethods
7
- attr_reader :sections
8
7
 
9
8
  def self.from_remote(logger: nil, full_name: nil, destination_dir: nil, ref: nil, git_accessor: Git)
10
9
  book = new(logger: logger, full_name: full_name, target_ref: ref, git_accessor: git_accessor)
@@ -12,12 +11,23 @@ module Bookbinder
12
11
  book
13
12
  end
14
13
 
15
- def initialize(logger: nil, full_name: nil, target_ref: nil, github_token: nil, sections: [], git_accessor: Git)
16
- @sections = sections.map do |section|
17
- GitHubRepository.new logger: logger, full_name: section['repository']['name']
14
+ def initialize(logger: nil,
15
+ full_name: nil,
16
+ target_ref: nil,
17
+ github_token: nil,
18
+ sections: [],
19
+ git_accessor: Git)
20
+ @section_vcs_repos = sections.map do |section|
21
+ GitHubRepository.new(logger: logger,
22
+ full_name: section['repository']['name'],
23
+ git_accessor: git_accessor)
18
24
  end
19
25
 
20
- @repository = GitHubRepository.new(logger: logger, full_name: full_name, target_ref: target_ref, github_token: github_token)
26
+ @repository = GitHubRepository.new(logger: logger,
27
+ full_name: full_name,
28
+ target_ref: target_ref,
29
+ github_token: github_token,
30
+ git_accessor: git_accessor)
21
31
  @git_accessor = git_accessor
22
32
  end
23
33
 
@@ -33,22 +43,12 @@ module Bookbinder
33
43
  @repository.directory
34
44
  end
35
45
 
36
- def get_modification_date_for(file: nil, full_path: nil)
37
- git_directory, file_relative_path = full_path.split(output_dir_name+'/')
38
- begin
39
- git_base_object = Git.open(git_directory)
40
- rescue => e
41
- raise "Invalid git repository! #{git_directory} is not a .git directory"
42
- end
43
- @repository.get_modification_date_for(file: file_relative_path, git: git_base_object)
44
- end
45
-
46
46
  def copy_from_remote(destination_dir)
47
- @repository.copy_from_remote(destination_dir, @git_accessor)
47
+ @repository.copy_from_remote(destination_dir)
48
48
  end
49
49
 
50
50
  def tag_self_and_sections_with(tag)
51
- (@sections + [@repository]).each { |repo| repo.tag_with tag }
51
+ (@section_vcs_repos + [@repository]).each { |repo| repo.tag_with tag }
52
52
  end
53
53
  end
54
54
  end
@@ -1,53 +1,42 @@
1
+ require_relative 'colorizer'
1
2
  require_relative 'command_runner'
2
- require_relative 'local_file_system_accessor'
3
3
  require_relative 'command_validator'
4
-
5
- require_relative 'commands/build_and_push_tarball'
6
- require_relative 'commands/generate_pdf'
7
- require_relative 'commands/publish'
8
- require_relative 'commands/version'
9
- require_relative 'commands/help'
4
+ require_relative 'configuration'
5
+ require_relative 'repositories/command_repository'
6
+ require_relative 'terminal'
7
+ require_relative 'user_message_presenter'
10
8
 
11
9
  module Bookbinder
12
10
  class Cli
13
- FLAGS = [
14
- Commands::Version,
15
- Commands::Help
16
- ]
17
-
18
- COMMANDS = [
19
- Commands::BuildAndPushTarball,
20
- Commands::GeneratePDF,
21
- Commands::Publish,
22
- Commands::PushLocalToStaging,
23
- Commands::PushToProd,
24
- Commands::RunPublishCI,
25
- Commands::Tag,
26
- Commands::UpdateLocalDocRepos,
27
- ].freeze
28
-
29
11
  def run(args)
30
12
  command_name = args[0]
31
13
  command_arguments = args[1..-1]
32
14
 
33
15
  logger = BookbinderLogger.new
34
- yaml_loader = YAMLLoader.new
35
- local_file_system_accessor = LocalFileSystemAccessor.new
36
- configuration_validator = ConfigurationValidator.new(logger, local_file_system_accessor)
37
- configuration_fetcher = ConfigurationFetcher.new(logger, configuration_validator, yaml_loader)
38
- configuration_fetcher.set_config_file_path './config.yml'
39
- usage_messenger = UsageMessenger.new
40
- usage_message = usage_messenger.construct_for(COMMANDS, FLAGS)
41
- command_validator = CommandValidator.new usage_messenger, COMMANDS + FLAGS, usage_message
42
-
43
- command_runner = CommandRunner.new(configuration_fetcher, usage_message, logger, COMMANDS + FLAGS)
16
+ commands = Repositories::CommandRepository.new(logger)
17
+
18
+ command_validator = CommandValidator.new(commands, commands.help.usage_message)
19
+ command_runner = CommandRunner.new(logger, commands)
20
+ command_name = command_name ? command_name : '--help'
21
+
22
+ colorizer = Colorizer.new
23
+ user_message_presenter = UserMessagePresenter.new(colorizer)
24
+ terminal = Terminal.new
25
+
26
+ user_message = command_validator.validate(command_name)
27
+ if user_message.escalation_type == EscalationType.error
28
+ error_message = user_message_presenter.get_error(user_message)
29
+ terminal.update(error_message)
30
+ return 1
31
+ elsif user_message.escalation_type == EscalationType.warn
32
+ warning_message = user_message_presenter.get_warning(user_message)
33
+ terminal.update(warning_message)
34
+ end
44
35
 
45
36
  begin
46
- command_name ? command_validator.validate!(command_name) : command_name = '--help'
47
-
48
37
  command_runner.run command_name, command_arguments
49
38
 
50
- rescue Commands::Publish::VersionUnsupportedError => e
39
+ rescue Commands::Bind::VersionUnsupportedError => e
51
40
  logger.error "config.yml at version '#{e.message}' has an unsupported API."
52
41
  1
53
42
  rescue Configuration::CredentialKeyError => e
@@ -1,40 +1,7 @@
1
- require_relative 'section'
2
-
3
1
  module Bookbinder
4
- class CodeExample < Section
5
- class InvalidSnippet < StandardError
6
- def initialize(repo, marker)
7
- super "Error with marker #{marker.cyan} #{'in'.red} #{repo.cyan}#{'.'.red}"
8
- end
9
- end
10
-
11
- def get_snippet_and_language_at(marker)
12
- unless @repository.copied?
13
- @repository.announce_skip
14
- return ''
15
- end
16
-
17
- prepared_snippet_at(marker)
18
- end
19
-
20
- private
21
-
22
- def prepared_snippet_at(marker)
23
- snippet = ''
24
- FileUtils.cd(@repository.copied_to) { snippet = scrape_for(marker) }
25
-
26
- raise InvalidSnippet.new(full_name, marker) if snippet.empty?
27
- lines = snippet.split("\n")
28
- language_match = lines[0].match(/code_snippet #{Regexp.escape(marker)} start (\w+)/)
29
- language = language_match[1] if language_match
30
- [lines[1..-2].join("\n"), language]
31
- end
32
-
33
- def scrape_for(marker)
34
- locale = 'LC_CTYPE=C LANG=C' # Quiets 'sed: RE error: illegal byte sequence'
35
- result = `#{locale} find . -exec sed -ne '/code_snippet #{marker} start/,/code_snippet #{marker} end/ p' {} \\; 2> /dev/null`
36
- result = "" unless result.lines.last && result.lines.last.match(/code_snippet #{marker} end/)
37
- result
38
- end
39
- end
2
+ CodeExample = Struct.new(:path_to_repository,
3
+ :full_name,
4
+ :copied,
5
+ :destination_dir,
6
+ :directory_name)
40
7
  end
@@ -0,0 +1,40 @@
1
+ require_relative '../../lib/bookbinder/bookbinder_logger'
2
+
3
+ module Bookbinder
4
+ class CodeExampleReader
5
+ class InvalidSnippet < StandardError
6
+ def initialize(repo, marker)
7
+ super "Error with marker #{marker.cyan} #{'in'.red} #{repo.cyan}#{'.'.red}"
8
+ end
9
+ end
10
+
11
+ def initialize(logger)
12
+ @logger = logger
13
+ end
14
+
15
+ def get_snippet_and_language_at(marker, path_to_repository, copied, repo_name)
16
+ unless copied
17
+ logger.log ' skipping (not found) '.magenta + repo_name
18
+ return ''
19
+ end
20
+
21
+ snippet = ''
22
+ FileUtils.cd(path_to_repository) { locale = 'LC_CTYPE=C LANG=C' # Quiets 'sed: RE error: illegal byte sequence'
23
+ result = `#{locale} find . -exec sed -ne '/code_snippet #{marker} start/,/code_snippet #{marker} end/ p' {} \\; 2> /dev/null`
24
+ result = "" unless result.lines.last && result.lines.last.match(/code_snippet #{marker} end/)
25
+ scrape_for_value = result
26
+ snippet = scrape_for_value }
27
+
28
+ raise InvalidSnippet.new(repo_name, marker) if snippet.empty?
29
+ lines = snippet.split("\n")
30
+ language_match = lines[0].match(/code_snippet #{Regexp.escape(marker)} start (\w+)/)
31
+ language = language_match[1] if language_match
32
+ [lines[1..-2].join("\n"), language]
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :logger
38
+
39
+ end
40
+ end
@@ -0,0 +1,14 @@
1
+ require 'ansi/code'
2
+ require 'ostruct'
3
+
4
+ module Bookbinder
5
+
6
+ class Colorizer
7
+ Colors = OpenStruct.new(red: Proc.new { |msg| ANSI.red {msg} },
8
+ yellow: Proc.new { |msg| ANSI.yellow {msg} })
9
+
10
+ def colorize(string, color)
11
+ color.call string.to_s
12
+ end
13
+ end
14
+ end
@@ -1,32 +1,25 @@
1
1
  require_relative 'cli_error'
2
+ require_relative 'local_dita_to_html_converter'
3
+ require_relative 'sheller'
2
4
 
3
5
  module Bookbinder
4
6
  class CommandRunner
5
- def initialize(configuration_fetcher, usage_message, logger, commands)
6
- @configuration_fetcher = configuration_fetcher
7
- @usage_message = usage_message
7
+ def initialize(logger, commands)
8
8
  @logger = logger
9
9
  @commands = commands
10
10
  end
11
11
 
12
12
  def run(command_name, command_arguments)
13
- command = commands.detect { |known_command| known_command.command_name == command_name }
14
- begin
15
- if command_name == '--help'
16
- command.new(logger, usage_message).run command_arguments
17
- else
18
- command.new(logger, @configuration_fetcher).run command_arguments
19
- end
20
- rescue CliError::InvalidArguments
21
- logger.log command.usage
22
- 1
23
- end
13
+ command = commands.detect { |known_command| known_command.command_for?(command_name) }
14
+ command.run(command_arguments)
15
+ rescue CliError::InvalidArguments
16
+ logger.log command.usage
17
+ 1
24
18
  end
25
19
 
26
20
  private
27
21
 
28
- attr_reader :logger, :usage_message, :commands
29
-
22
+ attr_reader :logger, :commands
30
23
  end
31
24
  end
32
25
 
@@ -1,24 +1,31 @@
1
1
  require_relative 'cli_error'
2
+ require 'ostruct'
3
+ require_relative 'user_message'
2
4
 
3
5
  module Bookbinder
4
6
  class CommandValidator
5
- def initialize(usage_messenger, commands, usage_text)
6
- @usage_messenger = usage_messenger
7
+ def initialize(commands, usage_text)
7
8
  @commands = commands
8
9
  @usage_text = usage_text
9
10
  end
10
11
 
11
- def validate! command_name
12
- known_command_names = commands.map(&:command_name)
12
+ def validate command_name
13
13
  command_type = "#{command_name}".match(/^--/) ? 'flag' : 'command'
14
- if !known_command_names.include?(command_name)
15
- raise CliError::UnknownCommand.new "Unrecognized #{command_type} '#{command_name}'\n" + usage_text
14
+ if commands.none? { |command| command.command_for?(command_name) }
15
+ UserMessage.new "Unrecognized #{command_type} '#{command_name}'\n" + usage_text, EscalationType.error
16
+ elsif command = commands.find { |command| (command.respond_to? :deprecated_command_for?) &&
17
+ (command.deprecated_command_for? command_name) }
18
+ UserMessage.new "Use of #{command_name} is deprecated. " +
19
+ "The preferred usage is below: \n#{command.usage}",
20
+ EscalationType.warn
21
+ else
22
+ UserMessage.new "Success", EscalationType.success
16
23
  end
17
24
  end
18
25
 
19
26
  private
20
27
 
21
- attr_reader :usage_messenger, :commands, :usage_text
28
+ attr_reader :commands, :usage_text
22
29
  end
23
30
  end
24
31
 
@@ -0,0 +1,321 @@
1
+ require_relative '../archive_menu_configuration'
2
+ require_relative '../book'
3
+ require_relative '../cli_error'
4
+ require_relative '../directory_helpers'
5
+ require_relative '../publisher'
6
+ require_relative '../section'
7
+ require_relative '../dita_section'
8
+ require_relative '../dita_section_gatherer'
9
+ require_relative 'naming'
10
+
11
+ module Bookbinder
12
+ module Commands
13
+ class Bind
14
+ VersionUnsupportedError = Class.new(RuntimeError)
15
+
16
+ include Bookbinder::DirectoryHelperMethods
17
+ include Commands::Naming
18
+
19
+ def initialize(logger,
20
+ config_fetcher,
21
+ archive_menu_config,
22
+ version_control_system,
23
+ file_system_accessor,
24
+ static_site_generator,
25
+ sitemap_generator,
26
+ final_app_directory,
27
+ server_director,
28
+ context_dir,
29
+ dita_preprocessor)
30
+ @logger = logger
31
+ @config_fetcher = config_fetcher
32
+ @archive_menu_config = archive_menu_config
33
+ @version_control_system = version_control_system
34
+ @file_system_accessor = file_system_accessor
35
+ @static_site_generator = static_site_generator
36
+ @sitemap_generator = sitemap_generator
37
+ @final_app_directory = final_app_directory
38
+ @server_director = server_director
39
+ @context_dir = context_dir
40
+ @dita_preprocessor = dita_preprocessor
41
+ end
42
+
43
+ def usage
44
+ ["bind <local|github> [--verbose]",
45
+ "Bind the sections specified in config.yml from <local> or <github> into the final_app directory"]
46
+ end
47
+
48
+ def command_for?(test_command_name)
49
+ %w(bind publish).include?(test_command_name)
50
+ end
51
+
52
+ def deprecated_command_for?(command_name)
53
+ %w(publish).include?(command_name)
54
+ end
55
+
56
+ def run(cli_arguments)
57
+ raise CliError::InvalidArguments unless arguments_are_valid?(cli_arguments)
58
+ @section_repository = Repositories::SectionRepository.new(logger)
59
+ @gem_root = File.expand_path('../../../../', __FILE__)
60
+
61
+ @publisher = Publisher.new(logger, sitemap_generator, static_site_generator, server_director, file_system_accessor)
62
+
63
+ location = cli_arguments[0]
64
+
65
+ output_paths = output_directory_paths(location)
66
+ publish_config = publish_config(location)
67
+ @versions = publish_config.fetch(:versions, [])
68
+ @book_repo = publish_config[:book_repo]
69
+
70
+ master_middleman_dir = output_paths.fetch(:master_middleman_dir)
71
+ output_dir = output_paths.fetch(:output_dir)
72
+
73
+ dita_processing_dir = File.join output_dir, 'dita'
74
+ dita_section_dir = File.join dita_processing_dir, 'dita_sections'
75
+ dita_processed_dir = File.join dita_processing_dir, 'html_from_dita'
76
+ formatted_dir = File.join dita_processing_dir, 'site_generator_ready'
77
+
78
+ master_dir = File.join output_dir, 'master_middleman'
79
+ workspace_dir = File.join master_dir, 'source'
80
+ prepare_directories(final_app_directory,
81
+ output_dir,
82
+ workspace_dir,
83
+ master_middleman_dir,
84
+ master_dir,
85
+ dita_processing_dir,
86
+ formatted_dir)
87
+
88
+ dita_section_config_hash = config.dita_sections || {}
89
+ dita_sections = dita_section_config_hash.map do |dita_section_config|
90
+ relative_path_to_dita_map = dita_section_config['ditamap_location']
91
+ full_name = dita_section_config.fetch('repository', {}).fetch('name')
92
+ target_ref = dita_section_config.fetch('repository', {})['ref']
93
+ directory = dita_section_config['directory']
94
+
95
+ DitaSection.new(nil, relative_path_to_dita_map, full_name, target_ref, directory)
96
+ end
97
+
98
+ if location == 'github'
99
+ dita_section_gatherer = DitaSectionGatherer.new(version_control_system, logger)
100
+ final_dita_sections = dita_section_gatherer.gather(dita_sections, to: dita_section_dir)
101
+ else
102
+ final_dita_sections = dita_sections.map do |dita_section|
103
+ relative_path_to_dita_map = dita_section.ditamap_location
104
+ full_name = dita_section.full_name
105
+ target_ref = dita_section.target_ref
106
+ directory = dita_section.directory
107
+
108
+ path_to_local_copy = File.join output_paths[:local_repo_dir], directory
109
+
110
+ DitaSection.new(path_to_local_copy, relative_path_to_dita_map, full_name, target_ref, directory)
111
+ end
112
+ end
113
+
114
+ dita_preprocessor.preprocess final_dita_sections, dita_processed_dir, formatted_dir, workspace_dir
115
+
116
+ sections = gather_sections(workspace_dir, output_paths)
117
+
118
+ subnavs = subnavs_by_dir_name(sections)
119
+
120
+ success = publisher.publish(
121
+ subnavs,
122
+ {verbose: cli_arguments.include?('--verbose')},
123
+ output_paths,
124
+ archive_menu_config.generate(publish_config, sections)
125
+ )
126
+
127
+ success ? 0 : 1
128
+ end
129
+
130
+ private
131
+
132
+ attr_reader :publisher,
133
+ :version_control_system,
134
+ :config_fetcher,
135
+ :archive_menu_config,
136
+ :logger,
137
+ :file_system_accessor,
138
+ :static_site_generator,
139
+ :final_app_directory,
140
+ :sitemap_generator,
141
+ :server_director,
142
+ :context_dir,
143
+ :dita_preprocessor
144
+
145
+ def gather_sections(workspace, output_paths)
146
+ config.sections.map do |attributes|
147
+
148
+ local_repo_dir = output_paths[:local_repo_dir]
149
+ vcs_repo =
150
+ if local_repo_dir
151
+ GitHubRepository.
152
+ build_from_local(logger, attributes, local_repo_dir, version_control_system).
153
+ tap { |repo| repo.copy_from_local(workspace) }
154
+ else
155
+ GitHubRepository.
156
+ build_from_remote(logger, attributes, nil, version_control_system).
157
+ tap { |repo| repo.copy_from_remote(workspace) }
158
+ end
159
+
160
+ @section_repository.get_instance(attributes,
161
+ vcs_repo: vcs_repo,
162
+ destination_dir: workspace,
163
+ build: ->(*args) { Section.new(*args) })
164
+ end
165
+ end
166
+
167
+ def prepare_directories(final_app,
168
+ output_dir,
169
+ middleman_source,
170
+ master_middleman_dir,
171
+ middleman_dir,
172
+ dita_processing_dir,
173
+ formatted_dir)
174
+ forget_sections(output_dir)
175
+ file_system_accessor.remove_directory File.join final_app, '.'
176
+ file_system_accessor.remove_directory dita_processing_dir
177
+ file_system_accessor.make_directory output_dir
178
+ file_system_accessor.make_directory formatted_dir
179
+ file_system_accessor.make_directory File.join dita_processing_dir, 'dita_sections'
180
+ file_system_accessor.make_directory File.join final_app, 'public'
181
+ file_system_accessor.make_directory middleman_source
182
+
183
+ copy_directory_from_gem 'template_app', final_app
184
+ copy_directory_from_gem 'master_middleman', middleman_dir
185
+ file_system_accessor.copy File.join(master_middleman_dir, '.'), middleman_dir
186
+
187
+ copy_version_master_middleman(middleman_source)
188
+ end
189
+
190
+ def forget_sections(middleman_scratch)
191
+ file_system_accessor.remove_directory File.join middleman_scratch, '.'
192
+ end
193
+
194
+ def copy_directory_from_gem(dir, output_dir)
195
+ file_system_accessor.copy File.join(@gem_root, "#{dir}/."), output_dir
196
+ end
197
+
198
+ # Copy the index file from each version into the version's directory. Because version
199
+ # subdirectories are sections, this is the only way they get content from their master
200
+ # middleman directory.
201
+ def copy_version_master_middleman(dest_dir)
202
+ @versions.each do |version|
203
+ Dir.mktmpdir(version) do |tmpdir|
204
+ book = Book.from_remote(logger: logger,
205
+ full_name: @book_repo,
206
+ destination_dir: tmpdir,
207
+ ref: version,
208
+ git_accessor: version_control_system)
209
+ index_source_dir = File.join(tmpdir, book.directory, 'master_middleman', source_dir_name)
210
+ index_dest_dir = File.join(dest_dir, version)
211
+ file_system_accessor.make_directory(index_dest_dir)
212
+
213
+ Dir.glob(File.join(index_source_dir, 'index.*')) do |f|
214
+ file_system_accessor.copy(File.expand_path(f), index_dest_dir)
215
+ end
216
+ end
217
+ end
218
+ end
219
+
220
+ def output_directory_paths(location)
221
+ local_repo_dir = (location == 'local') ? File.expand_path('..', context_dir) : nil
222
+
223
+ {
224
+ final_app_dir: final_app_directory,
225
+ local_repo_dir: local_repo_dir,
226
+ output_dir: File.join(context_dir, output_dir_name),
227
+ master_middleman_dir: layout_repo_path(local_repo_dir)
228
+ }
229
+ end
230
+
231
+ def publish_config(location)
232
+ arguments = {
233
+ sections: config.sections,
234
+ book_repo: config.book_repo,
235
+ host_for_sitemap: config.public_host,
236
+ archive_menu: config.archive_menu
237
+ }
238
+
239
+ optional_arguments = {}
240
+ optional_arguments.merge!(template_variables: config.template_variables) if config.respond_to?(:template_variables)
241
+ if publishing_to_github? location
242
+ config.versions.each { |version| arguments[:sections].concat sections_from version }
243
+ optional_arguments.merge!(versions: config.versions)
244
+ end
245
+
246
+ arguments.merge! optional_arguments
247
+ end
248
+
249
+ def config
250
+ config_fetcher.fetch_config
251
+ end
252
+
253
+ def sections_from(version)
254
+ Dir.mktmpdir('book_checkout') do |temp_workspace|
255
+ book = Book.from_remote(logger: logger,
256
+ full_name: config.book_repo,
257
+ destination_dir: temp_workspace,
258
+ ref: version,
259
+ git_accessor: version_control_system,
260
+ )
261
+
262
+ book_checkout_value = File.join temp_workspace, book.directory
263
+ config_file = File.join book_checkout_value, 'config.yml'
264
+ attrs = YAML.load(File.read(config_file))['sections']
265
+ raise VersionUnsupportedError.new(version) if attrs.nil?
266
+
267
+ attrs.map do |section_hash|
268
+ section_hash['repository']['ref'] = version
269
+ section_hash['directory'] = File.join(version, section_hash['directory'])
270
+ section_hash
271
+ end
272
+ end
273
+ end
274
+
275
+ def layout_repo_path(local_repo_dir)
276
+ if config.has_option?('layout_repo')
277
+ if local_repo_dir
278
+ File.join(local_repo_dir, config.layout_repo.split('/').last)
279
+ else
280
+ section = {'repository' => {'name' => config.layout_repo}}
281
+ destination_dir = Dir.mktmpdir
282
+ repository = GitHubRepository.build_from_remote(logger,
283
+ section,
284
+ 'master',
285
+ version_control_system)
286
+ repository.copy_from_remote(destination_dir)
287
+ if repository
288
+ File.join(destination_dir, repository.directory)
289
+ else
290
+ raise 'failed to fetch repository'
291
+ end
292
+ end
293
+ else
294
+ File.absolute_path('master_middleman')
295
+ end
296
+ end
297
+
298
+ def arguments_are_valid?(arguments)
299
+ return false unless arguments.any?
300
+ verbose = arguments[1] && arguments[1..-1].include?('--verbose')
301
+ tag_provided = arguments[1] && (arguments[1..-1] - ['--verbose']).any?
302
+ nothing_special = arguments[1..-1].empty?
303
+
304
+ %w(local github).include?(arguments[0]) && (tag_provided || verbose || nothing_special)
305
+ end
306
+
307
+ def publishing_to_github?(publish_location)
308
+ config.has_option?('versions') && publish_location != 'local'
309
+ end
310
+
311
+ def subnavs_by_dir_name(sections)
312
+ sections.reduce({}) do |subnavs, section|
313
+ namespace = section.directory.gsub('/', '_')
314
+ template = section.subnav_template || 'default'
315
+
316
+ subnavs.merge(namespace => template)
317
+ end
318
+ end
319
+ end
320
+ end
321
+ end