bookwatch 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/bookwatch.gemspec +40 -0
  3. data/install_bin/bookwatch +5 -0
  4. data/lib/bookwatch/cli.rb +109 -0
  5. data/lib/bookwatch/code_example_reader.rb +95 -0
  6. data/lib/bookwatch/colorizer.rb +16 -0
  7. data/lib/bookwatch/commands/bind.rb +119 -0
  8. data/lib/bookwatch/commands/collection.rb +181 -0
  9. data/lib/bookwatch/commands/components/bind/directory_preparer.rb +33 -0
  10. data/lib/bookwatch/commands/components/bind/layout_preparer.rb +27 -0
  11. data/lib/bookwatch/commands/components/command_options.rb +45 -0
  12. data/lib/bookwatch/commands/components/imprint/directory_preparer.rb +24 -0
  13. data/lib/bookwatch/commands/generate.rb +92 -0
  14. data/lib/bookwatch/commands/imprint.rb +55 -0
  15. data/lib/bookwatch/commands/punch.rb +33 -0
  16. data/lib/bookwatch/commands/update_local_doc_repos.rb +42 -0
  17. data/lib/bookwatch/commands/watch.rb +100 -0
  18. data/lib/bookwatch/config/checkers/archive_menu_checker.rb +29 -0
  19. data/lib/bookwatch/config/checkers/ditamap_presence_checker.rb +27 -0
  20. data/lib/bookwatch/config/checkers/duplicate_section_name_checker.rb +33 -0
  21. data/lib/bookwatch/config/checkers/products_checker.rb +34 -0
  22. data/lib/bookwatch/config/checkers/repository_name_presence_checker.rb +34 -0
  23. data/lib/bookwatch/config/checkers/required_keys_checker.rb +18 -0
  24. data/lib/bookwatch/config/checkers/section_presence_checker.rb +15 -0
  25. data/lib/bookwatch/config/configuration.rb +119 -0
  26. data/lib/bookwatch/config/configuration_decorator.rb +54 -0
  27. data/lib/bookwatch/config/dita_config_generator.rb +61 -0
  28. data/lib/bookwatch/config/fetcher.rb +64 -0
  29. data/lib/bookwatch/config/imprint/configuration.rb +24 -0
  30. data/lib/bookwatch/config/product_config.rb +34 -0
  31. data/lib/bookwatch/config/section_config.rb +85 -0
  32. data/lib/bookwatch/config/validator.rb +33 -0
  33. data/lib/bookwatch/config/yaml_loader.rb +34 -0
  34. data/lib/bookwatch/css_link_checker.rb +67 -0
  35. data/lib/bookwatch/directory_helpers.rb +15 -0
  36. data/lib/bookwatch/dita_command_creator.rb +95 -0
  37. data/lib/bookwatch/dita_html_for_middleman_formatter.rb +45 -0
  38. data/lib/bookwatch/errors/programmer_mistake.rb +5 -0
  39. data/lib/bookwatch/html_document_manipulator.rb +21 -0
  40. data/lib/bookwatch/ingest/cloner_factory.rb +26 -0
  41. data/lib/bookwatch/ingest/destination_directory.rb +21 -0
  42. data/lib/bookwatch/ingest/git_accessor.rb +102 -0
  43. data/lib/bookwatch/ingest/git_cloner.rb +36 -0
  44. data/lib/bookwatch/ingest/local_filesystem_cloner.rb +66 -0
  45. data/lib/bookwatch/ingest/missing_working_copy.rb +27 -0
  46. data/lib/bookwatch/ingest/repo_identifier.rb +45 -0
  47. data/lib/bookwatch/ingest/section_repository.rb +49 -0
  48. data/lib/bookwatch/ingest/update_failure.rb +15 -0
  49. data/lib/bookwatch/ingest/update_success.rb +12 -0
  50. data/lib/bookwatch/ingest/working_copy.rb +36 -0
  51. data/lib/bookwatch/local_filesystem_accessor.rb +122 -0
  52. data/lib/bookwatch/middleman_runner.rb +48 -0
  53. data/lib/bookwatch/postprocessing/link_checker.rb +125 -0
  54. data/lib/bookwatch/postprocessing/redirection.rb +38 -0
  55. data/lib/bookwatch/preprocessing/dita_html_preprocessor.rb +91 -0
  56. data/lib/bookwatch/preprocessing/dita_pdf_preprocessor.rb +48 -0
  57. data/lib/bookwatch/preprocessing/link_to_site_gen_dir.rb +39 -0
  58. data/lib/bookwatch/preprocessing/preprocessor.rb +26 -0
  59. data/lib/bookwatch/server_director.rb +30 -0
  60. data/lib/bookwatch/sheller.rb +52 -0
  61. data/lib/bookwatch/streams/colorized_stream.rb +25 -0
  62. data/lib/bookwatch/streams/filter_stream.rb +22 -0
  63. data/lib/bookwatch/subnav/navigation_entries_from_html_toc.rb +59 -0
  64. data/lib/bookwatch/subnav/navigation_entries_from_markdown_root.rb +116 -0
  65. data/lib/bookwatch/subnav/pdf_config_creator.rb +50 -0
  66. data/lib/bookwatch/subnav/subnav_generator.rb +28 -0
  67. data/lib/bookwatch/subnav/subnav_generator_factory.rb +29 -0
  68. data/lib/bookwatch/subnav/template_creator.rb +71 -0
  69. data/lib/bookwatch/terminal.rb +19 -0
  70. data/lib/bookwatch/values/output_locations.rb +91 -0
  71. data/lib/bookwatch/values/product_info.rb +11 -0
  72. data/lib/bookwatch/values/section.rb +58 -0
  73. data/lib/bookwatch/values/subnav_template.rb +4 -0
  74. data/lib/bookwatch/values/user_message.rb +15 -0
  75. data/master_middleman/archive_drop_down_menu.rb +50 -0
  76. data/master_middleman/bookwatch_helpers.rb +259 -0
  77. data/master_middleman/compass_runner.rb +0 -0
  78. data/master_middleman/config.rb +34 -0
  79. data/master_middleman/quicklinks_renderer.rb +80 -0
  80. data/master_middleman/source/javascripts/all.js +2 -0
  81. data/master_middleman/source/javascripts/book.js +1 -0
  82. data/master_middleman/source/javascripts/bookwatch.js +103 -0
  83. data/master_middleman/source/layouts/_additional-scripts.erb +0 -0
  84. data/master_middleman/source/layouts/_book-footer.erb +0 -0
  85. data/master_middleman/source/layouts/_book-search.erb +0 -0
  86. data/master_middleman/source/layouts/_book-title.erb +3 -0
  87. data/master_middleman/source/layouts/_header.erb +34 -0
  88. data/master_middleman/source/layouts/_local-header.erb +0 -0
  89. data/master_middleman/source/layouts/_page-footer.erb +1 -0
  90. data/master_middleman/source/layouts/_title.erb +5 -0
  91. data/master_middleman/source/layouts/layout.erb +69 -0
  92. data/master_middleman/source/stylesheets/all.css.scss +3 -0
  93. data/master_middleman/source/stylesheets/base.scss +380 -0
  94. data/master_middleman/source/stylesheets/book-styles.css.scss +0 -0
  95. data/master_middleman/source/stylesheets/layout-styles.scss +0 -0
  96. data/master_middleman/source/stylesheets/partials/_book-base-values.scss +0 -0
  97. data/master_middleman/source/stylesheets/partials/_book-vars.scss +0 -0
  98. data/master_middleman/source/stylesheets/partials/_default.scss +300 -0
  99. data/master_middleman/source/stylesheets/partials/_footer.scss +64 -0
  100. data/master_middleman/source/stylesheets/partials/_header.scss +419 -0
  101. data/master_middleman/source/stylesheets/partials/_layout-vars.scss +0 -0
  102. data/master_middleman/source/stylesheets/partials/_mixins.scss +53 -0
  103. data/master_middleman/source/stylesheets/partials/_reset.scss +233 -0
  104. data/master_middleman/source/stylesheets/partials/_search.scss +78 -0
  105. data/master_middleman/source/stylesheets/partials/_sidenav.scss +191 -0
  106. data/master_middleman/source/stylesheets/partials/_syntax-highlight.scss +64 -0
  107. data/master_middleman/source/stylesheets/partials/_vars.scss +64 -0
  108. data/master_middleman/source/stylesheets/print.css.scss +58 -0
  109. data/master_middleman/source/subnavs/_default.erb +0 -0
  110. data/master_middleman/source/subnavs/_nav-links.erb +10 -0
  111. data/master_middleman/source/subnavs/_subnav_template.erb +8 -0
  112. data/master_middleman/subdirectory_aware_assets.rb +47 -0
  113. data/template_app/Gemfile +10 -0
  114. data/template_app/Gemfile.lock +43 -0
  115. data/template_app/config.ru +9 -0
  116. data/template_app/lib/rack_static_if_exists.rb +19 -0
  117. data/template_app/lib/search/handler.rb +47 -0
  118. data/template_app/lib/search/hit.rb +21 -0
  119. data/template_app/lib/search/query.rb +74 -0
  120. data/template_app/lib/search/renderer.rb +29 -0
  121. data/template_app/lib/server.rb +52 -0
  122. data/template_app/mail_sender.rb +69 -0
  123. data/template_app/rack_app.rb +110 -0
  124. data/template_app/search-results.html.erb +75 -0
  125. data/template_app/search.yml +22 -0
  126. metadata +491 -0
@@ -0,0 +1,33 @@
1
+ require_relative 'layout_preparer'
2
+
3
+ module Bookwatch
4
+ module Commands
5
+ module Components
6
+ module Bind
7
+ class DirectoryPreparer
8
+ def initialize(fs)
9
+ @fs = fs
10
+ end
11
+
12
+ def prepare_directories(config, gem_root, output_locations, cloner, ref_override: nil)
13
+ fs.remove_directory(output_locations.output_dir)
14
+ fs.empty_directory(output_locations.final_app_dir)
15
+
16
+ copy_directory_from_gem(gem_root, 'template_app', output_locations.final_app_dir)
17
+ copy_directory_from_gem(gem_root, 'master_middleman', output_locations.site_generator_home)
18
+
19
+ LayoutPreparer.new(fs).prepare(output_locations, cloner, ref_override, config)
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :fs
25
+
26
+ def copy_directory_from_gem(gem_root, dir, output_dir)
27
+ fs.copy_contents(File.join(gem_root, dir), output_dir)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ module Bookwatch
2
+ module Commands
3
+ module Components
4
+ module Bind
5
+ class LayoutPreparer
6
+ def initialize(fs)
7
+ @fs = fs
8
+ end
9
+
10
+ attr_reader :fs
11
+
12
+ def prepare(output_locations, cloner, ref_override, config)
13
+ if config.has_option?('layout_repo')
14
+
15
+ cloned_repo = cloner.call(source_repo_name: config.layout_repo,
16
+ source_ref: ref_override || config.layout_repo_ref,
17
+ destination_parent_dir: Dir.mktmpdir)
18
+
19
+ fs.copy_contents(cloned_repo.path, output_locations.site_generator_home)
20
+ end
21
+ fs.copy_contents(File.absolute_path('master_middleman'), output_locations.site_generator_home)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,45 @@
1
+ require_relative '../../sheller'
2
+ require_relative '../../colorizer'
3
+ require_relative '../../streams/colorized_stream'
4
+ require_relative '../../streams/filter_stream'
5
+
6
+ module Bookwatch
7
+ module Commands
8
+ module Components
9
+ class CommandOptions
10
+ def initialize(opts, base_streams, verbose = false)
11
+ @opts = opts
12
+ @base_streams = base_streams
13
+ @verbosity = verbose
14
+ end
15
+
16
+ def bind_source
17
+ opts.first
18
+ end
19
+
20
+ def local_repo_dir
21
+ File.expand_path('..') if bind_source == 'local'
22
+ end
23
+
24
+ def options
25
+ opts[1..-1]
26
+ end
27
+
28
+ def ref_override
29
+ 'master' if options.include?('--ignore-section-refs')
30
+ end
31
+
32
+ def streams
33
+ base_streams.merge(
34
+ out: verbosity ? base_streams[:out] :
35
+ Streams::FilterStream.new(/^(?:\s*error|Invalid CSS|Undefined mixin|\/)/i, Streams::ColorizedStream.new(Colorizer::Colors.red, base_streams[:out])),
36
+ )
37
+ end
38
+
39
+ private
40
+
41
+ attr_accessor :base_streams, :opts, :verbosity
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ module Bookwatch
2
+ module Commands
3
+ module Components
4
+ module Imprint
5
+ class DirectoryPreparer
6
+ def initialize(fs)
7
+ @fs = fs
8
+ end
9
+
10
+ def prepare_directories(output_locations)
11
+ fs.empty_directory(output_locations.output_dir)
12
+ fs.make_directory(output_locations.pdf_from_preprocessing_dir)
13
+
14
+ fs.empty_directory(output_locations.pdf_artifact_dir)
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :fs
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,92 @@
1
+ require 'bundler'
2
+
3
+ module Bookwatch
4
+ module Commands
5
+ class Generate
6
+ def initialize(fs, sheller, context_dir, streams)
7
+ @fs = fs
8
+ @sheller = sheller
9
+ @context_dir = context_dir
10
+ @streams = streams
11
+ end
12
+
13
+ def run(name, special_bookwatch_gem_args={})
14
+ path = context_dir.join(name)
15
+ streams[:out].puts "Generating book at #{path}..."
16
+ if fs.file_exist?(path)
17
+ streams[:err].puts "Cannot generate book: directory already exists"
18
+ 1
19
+ elsif install(path, special_bookwatch_gem_args).success?
20
+ streams[:success].puts "Successfully generated book at #{path}"
21
+ 0
22
+ else
23
+ 1
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :fs, :sheller, :streams
30
+
31
+ def install(path, special_bookwatch_gem_args)
32
+ make_middleman_dir(path)
33
+ init_gemfile(path, special_bookwatch_gem_args)
34
+ init_config(path)
35
+ init_index(path)
36
+ bundle_install(path)
37
+ end
38
+
39
+ def make_middleman_dir(path)
40
+ fs.make_directory(path.join('master_middleman/build'))
41
+ end
42
+
43
+ def init_gemfile(path, special_bookwatch_gem_args)
44
+ bookwatch_config = ''
45
+
46
+ unless special_bookwatch_gem_args.empty?
47
+ config = special_bookwatch_gem_args.first
48
+ bookwatch_config = ", #{config.first}: \"#{config.last}\""
49
+ end
50
+
51
+ fs.write(
52
+ text: <<-GEMFILE,
53
+ source "https://rubygems.org"
54
+
55
+ gem "bookwatch"#{bookwatch_config}
56
+ GEMFILE
57
+ to: path.join('Gemfile')
58
+ )
59
+ end
60
+
61
+ def init_config(path)
62
+ fs.write(
63
+ text: YAML.dump(
64
+ 'book_repo' => '',
65
+ 'public_host' => '',
66
+ ),
67
+ to: path.join('config.yml')
68
+ )
69
+ end
70
+
71
+ def init_index(path)
72
+ fs.write(
73
+ text: '# Empty book',
74
+ to: path.join('master_middleman/source/index.md.erb')
75
+ )
76
+ end
77
+
78
+ def bundle_install(path)
79
+ Bundler.with_clean_env do
80
+ sheller.run_command(
81
+ "bundle install --binstubs --gemfile=#{path.join('Gemfile')}",
82
+ out: streams[:out], err: streams[:err]
83
+ )
84
+ end
85
+ end
86
+
87
+ def context_dir
88
+ Pathname(@context_dir)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,55 @@
1
+ require_relative 'components/command_options'
2
+
3
+ module Bookwatch
4
+ module Commands
5
+ class Imprint
6
+ def initialize(base_streams,
7
+ output_locations: nil,
8
+ config_fetcher: nil,
9
+ preprocessor: nil,
10
+ cloner_factory: nil,
11
+ section_repository: nil,
12
+ directory_preparer: nil)
13
+
14
+ @base_streams = base_streams
15
+ @output_locations = output_locations
16
+ @config_fetcher = config_fetcher
17
+ @preprocessor = preprocessor
18
+ @cloner_factory = cloner_factory
19
+ @section_repository = section_repository
20
+ @directory_preparer = directory_preparer
21
+ end
22
+
23
+ def run(bind_type, verbose = false, dita_flags = nil)
24
+ options = Components::CommandOptions.new([bind_type], base_streams, verbose)
25
+ config = config_fetcher.fetch_config
26
+ cloner = cloner_factory.produce(options.local_repo_dir)
27
+
28
+ directory_preparer.prepare_directories(output_locations)
29
+
30
+ sections = section_repository.fetch(
31
+ configured_sections: config.sections,
32
+ destination_dir: output_locations.cloned_preprocessing_dir,
33
+ ref_override: options.ref_override,
34
+ cloner: cloner,
35
+ streams: base_streams
36
+ )
37
+
38
+ preprocessor.preprocess(
39
+ sections,
40
+ output_locations,
41
+ options: { dita_flags: dita_flags },
42
+ output_streams: options.streams,
43
+ config: config
44
+ )
45
+
46
+ options.streams[:success].puts "Bookwatch printed your pdf(s) into #{output_locations.pdf_artifact_dir}"
47
+ 0
48
+ end
49
+
50
+ private
51
+
52
+ attr_reader :preprocessor, :output_locations, :section_repository, :base_streams, :config_fetcher, :directory_preparer, :cloner_factory
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,33 @@
1
+ module Bookwatch
2
+ module Commands
3
+ class Punch
4
+ def initialize(streams, configuration_fetcher, version_control_system)
5
+ @streams = streams
6
+ @configuration_fetcher = configuration_fetcher
7
+ @version_control_system = version_control_system
8
+ end
9
+
10
+ def run((tag, *))
11
+ urls(config).each do |url|
12
+ version_control_system.remote_tag(url, tag, 'HEAD')
13
+ end
14
+
15
+ streams[:success].puts 'Success!'
16
+ streams[:out].puts "#{config.book_repo} and its sections were tagged with #{tag}"
17
+ 0
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :streams, :configuration_fetcher, :version_control_system
23
+
24
+ def urls(config)
25
+ [config.book_repo_url, config.layout_repo_url] + config.sections.map(&:repo_url).uniq
26
+ end
27
+
28
+ def config
29
+ @config ||= configuration_fetcher.fetch_config
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../ingest/destination_directory'
2
+
3
+ module Bookwatch
4
+ module Commands
5
+ class UpdateLocalDocRepos
6
+ def initialize(streams, configuration_fetcher, version_control_system)
7
+ @streams = streams
8
+ @configuration_fetcher = configuration_fetcher
9
+ @version_control_system = version_control_system
10
+ end
11
+
12
+ def run
13
+ urls = configuration_fetcher.fetch_config.sections.map(&:repo_url)
14
+ paths(urls).each do |path|
15
+ streams[:out] << "\nUpdating #{path}:"
16
+ report(version_control_system.update(path))
17
+ end
18
+ streams[:out].puts
19
+ 0
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader(:streams,
25
+ :configuration_fetcher,
26
+ :version_control_system)
27
+
28
+ def report(result)
29
+ messages = { true => "updated", false => "skipping (#{result.reason})" }
30
+ streams[stream_types[result.success?]] << " #{messages[result.success?]}"
31
+ end
32
+
33
+ def stream_types
34
+ { true => :success, false => :out }
35
+ end
36
+
37
+ def paths(urls)
38
+ urls.map {|url| File.absolute_path("../#{Ingest::DestinationDirectory.new(url)}")}
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,100 @@
1
+ module Bookwatch
2
+ module Commands
3
+ class Watch
4
+ def initialize(streams,
5
+ middleman_runner: nil,
6
+ output_locations: nil,
7
+ config_fetcher: nil,
8
+ config_decorator: nil,
9
+ file_system_accessor: nil,
10
+ preprocessor: nil,
11
+ cloner: nil,
12
+ section_repository: nil,
13
+ directory_preparer: nil,
14
+ repo_restrictions: [])
15
+ @streams = streams
16
+ @middleman_runner = middleman_runner
17
+ @output_locations = output_locations
18
+ @config_fetcher = config_fetcher
19
+ @config_decorator = config_decorator
20
+ @file_system_accessor = file_system_accessor
21
+ @preprocessor = preprocessor
22
+ @cloner = cloner
23
+ @section_repository = section_repository
24
+ @directory_preparer = directory_preparer
25
+ @repo_restrictions = repo_restrictions
26
+ end
27
+
28
+ def run
29
+ watch_config = config_fetcher.fetch_config
30
+
31
+ directory_preparer.prepare_directories(
32
+ watch_config,
33
+ File.expand_path('../../../../', __FILE__),
34
+ output_locations,
35
+ cloner
36
+ )
37
+ sections = section_repository.fetch(
38
+ configured_sections: filter_sections(watch_config.sections),
39
+ destination_dir: output_locations.cloned_preprocessing_dir,
40
+ cloner: cloner,
41
+ streams: streams
42
+ )
43
+ preprocessor.preprocess(
44
+ sections,
45
+ output_locations,
46
+ output_streams: streams,
47
+ config: watch_config
48
+ )
49
+ if file_system_accessor.file_exist?('redirects.rb')
50
+ file_system_accessor.copy('redirects.rb', output_locations.final_app_dir)
51
+ end
52
+
53
+ middleman_runner.run("server --force-polling --latency=5.0",
54
+ output_locations: output_locations,
55
+ config: config_decorator.generate(watch_config, sections),
56
+ local_repo_dir: File.expand_path('..'),
57
+ streams: streams,
58
+ subnavs: subnavs(sections),
59
+ product_info: product_infos(sections)
60
+ ).exitstatus
61
+ end
62
+
63
+ private
64
+
65
+ attr_reader(
66
+ :streams,
67
+ :middleman_runner,
68
+ :output_locations,
69
+ :config_fetcher,
70
+ :config_decorator,
71
+ :file_system_accessor,
72
+ :preprocessor,
73
+ :cloner,
74
+ :section_repository,
75
+ :directory_preparer
76
+ )
77
+
78
+ def subnavs(sections)
79
+ sections.map(&:subnav).reduce({}, :merge)
80
+ end
81
+
82
+ def product_infos(sections)
83
+ temp = Hash.new
84
+ sections.each do |section|
85
+ temp[section.namespace] = section.product_info
86
+ end
87
+ temp
88
+ end
89
+
90
+ def filter_sections(section_configs)
91
+ return section_configs if @repo_restrictions.nil? || @repo_restrictions.empty?
92
+
93
+ section_configs.select do |config|
94
+ repo_name = (config.repo_name || '').split('/').last
95
+ @repo_restrictions.include?(repo_name)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end