ngage 0.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 (109) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/exe/ngage +55 -0
  4. data/lib/ngage.rb +3 -0
  5. data/lib/ngage/jekyll.rb +204 -0
  6. data/lib/ngage/jekyll/cleaner.rb +111 -0
  7. data/lib/ngage/jekyll/collection.rb +235 -0
  8. data/lib/ngage/jekyll/command.rb +103 -0
  9. data/lib/ngage/jekyll/commands/build.rb +93 -0
  10. data/lib/ngage/jekyll/commands/clean.rb +45 -0
  11. data/lib/ngage/jekyll/commands/doctor.rb +173 -0
  12. data/lib/ngage/jekyll/commands/help.rb +34 -0
  13. data/lib/ngage/jekyll/commands/new.rb +157 -0
  14. data/lib/ngage/jekyll/commands/new_theme.rb +42 -0
  15. data/lib/ngage/jekyll/commands/serve.rb +354 -0
  16. data/lib/ngage/jekyll/commands/serve/live_reload_reactor.rb +122 -0
  17. data/lib/ngage/jekyll/commands/serve/livereload_assets/livereload.js +1183 -0
  18. data/lib/ngage/jekyll/commands/serve/servlet.rb +203 -0
  19. data/lib/ngage/jekyll/commands/serve/websockets.rb +81 -0
  20. data/lib/ngage/jekyll/configuration.rb +391 -0
  21. data/lib/ngage/jekyll/converter.rb +54 -0
  22. data/lib/ngage/jekyll/converters/identity.rb +41 -0
  23. data/lib/ngage/jekyll/converters/markdown.rb +116 -0
  24. data/lib/ngage/jekyll/converters/markdown/kramdown_parser.rb +122 -0
  25. data/lib/ngage/jekyll/converters/smartypants.rb +70 -0
  26. data/lib/ngage/jekyll/convertible.rb +253 -0
  27. data/lib/ngage/jekyll/deprecator.rb +50 -0
  28. data/lib/ngage/jekyll/document.rb +503 -0
  29. data/lib/ngage/jekyll/drops/collection_drop.rb +20 -0
  30. data/lib/ngage/jekyll/drops/document_drop.rb +69 -0
  31. data/lib/ngage/jekyll/drops/drop.rb +209 -0
  32. data/lib/ngage/jekyll/drops/excerpt_drop.rb +15 -0
  33. data/lib/ngage/jekyll/drops/jekyll_drop.rb +32 -0
  34. data/lib/ngage/jekyll/drops/site_drop.rb +56 -0
  35. data/lib/ngage/jekyll/drops/static_file_drop.rb +14 -0
  36. data/lib/ngage/jekyll/drops/unified_payload_drop.rb +26 -0
  37. data/lib/ngage/jekyll/drops/url_drop.rb +89 -0
  38. data/lib/ngage/jekyll/entry_filter.rb +127 -0
  39. data/lib/ngage/jekyll/errors.rb +20 -0
  40. data/lib/ngage/jekyll/excerpt.rb +180 -0
  41. data/lib/ngage/jekyll/external.rb +76 -0
  42. data/lib/ngage/jekyll/filters.rb +390 -0
  43. data/lib/ngage/jekyll/filters/date_filters.rb +110 -0
  44. data/lib/ngage/jekyll/filters/grouping_filters.rb +64 -0
  45. data/lib/ngage/jekyll/filters/url_filters.rb +68 -0
  46. data/lib/ngage/jekyll/frontmatter_defaults.rb +233 -0
  47. data/lib/ngage/jekyll/generator.rb +5 -0
  48. data/lib/ngage/jekyll/hooks.rb +106 -0
  49. data/lib/ngage/jekyll/layout.rb +62 -0
  50. data/lib/ngage/jekyll/liquid_extensions.rb +22 -0
  51. data/lib/ngage/jekyll/liquid_renderer.rb +63 -0
  52. data/lib/ngage/jekyll/liquid_renderer/file.rb +56 -0
  53. data/lib/ngage/jekyll/liquid_renderer/table.rb +98 -0
  54. data/lib/ngage/jekyll/log_adapter.rb +151 -0
  55. data/lib/ngage/jekyll/mime.types +825 -0
  56. data/lib/ngage/jekyll/page.rb +185 -0
  57. data/lib/ngage/jekyll/page_without_a_file.rb +14 -0
  58. data/lib/ngage/jekyll/plugin.rb +92 -0
  59. data/lib/ngage/jekyll/plugin_manager.rb +115 -0
  60. data/lib/ngage/jekyll/publisher.rb +23 -0
  61. data/lib/ngage/jekyll/reader.rb +154 -0
  62. data/lib/ngage/jekyll/readers/collection_reader.rb +22 -0
  63. data/lib/ngage/jekyll/readers/data_reader.rb +75 -0
  64. data/lib/ngage/jekyll/readers/layout_reader.rb +70 -0
  65. data/lib/ngage/jekyll/readers/page_reader.rb +25 -0
  66. data/lib/ngage/jekyll/readers/post_reader.rb +72 -0
  67. data/lib/ngage/jekyll/readers/static_file_reader.rb +25 -0
  68. data/lib/ngage/jekyll/readers/theme_assets_reader.rb +51 -0
  69. data/lib/ngage/jekyll/regenerator.rb +195 -0
  70. data/lib/ngage/jekyll/related_posts.rb +52 -0
  71. data/lib/ngage/jekyll/renderer.rb +266 -0
  72. data/lib/ngage/jekyll/site.rb +476 -0
  73. data/lib/ngage/jekyll/static_file.rb +169 -0
  74. data/lib/ngage/jekyll/stevenson.rb +60 -0
  75. data/lib/ngage/jekyll/tags/highlight.rb +108 -0
  76. data/lib/ngage/jekyll/tags/include.rb +226 -0
  77. data/lib/ngage/jekyll/tags/link.rb +40 -0
  78. data/lib/ngage/jekyll/tags/post_url.rb +104 -0
  79. data/lib/ngage/jekyll/theme.rb +73 -0
  80. data/lib/ngage/jekyll/theme_builder.rb +121 -0
  81. data/lib/ngage/jekyll/url.rb +160 -0
  82. data/lib/ngage/jekyll/utils.rb +370 -0
  83. data/lib/ngage/jekyll/utils/ansi.rb +57 -0
  84. data/lib/ngage/jekyll/utils/exec.rb +26 -0
  85. data/lib/ngage/jekyll/utils/internet.rb +37 -0
  86. data/lib/ngage/jekyll/utils/platforms.rb +82 -0
  87. data/lib/ngage/jekyll/utils/thread_event.rb +31 -0
  88. data/lib/ngage/jekyll/utils/win_tz.rb +75 -0
  89. data/lib/ngage/site_template/.gitignore +5 -0
  90. data/lib/ngage/site_template/404.html +25 -0
  91. data/lib/ngage/site_template/_config.yml +47 -0
  92. data/lib/ngage/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -0
  93. data/lib/ngage/site_template/about.markdown +18 -0
  94. data/lib/ngage/site_template/index.markdown +6 -0
  95. data/lib/ngage/theme_template/CODE_OF_CONDUCT.md.erb +74 -0
  96. data/lib/ngage/theme_template/Gemfile +4 -0
  97. data/lib/ngage/theme_template/LICENSE.txt.erb +21 -0
  98. data/lib/ngage/theme_template/README.md.erb +52 -0
  99. data/lib/ngage/theme_template/_layouts/default.html +1 -0
  100. data/lib/ngage/theme_template/_layouts/page.html +5 -0
  101. data/lib/ngage/theme_template/_layouts/post.html +5 -0
  102. data/lib/ngage/theme_template/example/_config.yml.erb +1 -0
  103. data/lib/ngage/theme_template/example/_post.md +12 -0
  104. data/lib/ngage/theme_template/example/index.html +14 -0
  105. data/lib/ngage/theme_template/example/style.scss +7 -0
  106. data/lib/ngage/theme_template/gitignore.erb +6 -0
  107. data/lib/ngage/theme_template/theme.gemspec.erb +19 -0
  108. data/lib/ngage/version.rb +5 -0
  109. metadata +328 -0
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module Jekyll
6
+ module Commands
7
+ class New < Command
8
+ class << self
9
+ def init_with_program(prog)
10
+ prog.command(:new) do |c|
11
+ c.syntax "new PATH"
12
+ c.description "Creates a new Jekyll site scaffold in PATH"
13
+
14
+ c.option "force", "--force", "Force creation even if PATH already exists"
15
+ c.option "blank", "--blank", "Creates scaffolding but with empty files"
16
+ c.option "skip-bundle", "--skip-bundle", "Skip 'bundle install'"
17
+
18
+ c.action do |args, options|
19
+ Jekyll::Commands::New.process(args, options)
20
+ end
21
+ end
22
+ end
23
+
24
+ def process(args, options = {})
25
+ raise ArgumentError, "You must specify a path." if args.empty?
26
+
27
+ new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
28
+ FileUtils.mkdir_p new_blog_path
29
+ if preserve_source_location?(new_blog_path, options)
30
+ Jekyll.logger.error "Conflict:", "#{new_blog_path} exists and is not empty."
31
+ Jekyll.logger.abort_with "", "Ensure #{new_blog_path} is empty or else " \
32
+ "try again with `--force` to proceed and overwrite any files."
33
+ end
34
+
35
+ if options["blank"]
36
+ create_blank_site new_blog_path
37
+ else
38
+ create_site new_blog_path
39
+ end
40
+
41
+ after_install(new_blog_path, options)
42
+ end
43
+
44
+ def create_blank_site(path)
45
+ Dir.chdir(path) do
46
+ FileUtils.mkdir(%w(_layouts _posts _drafts))
47
+ FileUtils.touch("index.html")
48
+ end
49
+ end
50
+
51
+ def scaffold_post_content
52
+ ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result
53
+ end
54
+
55
+ # Internal: Gets the filename of the sample post to be created
56
+ #
57
+ # Returns the filename of the sample post, as a String
58
+ def initialized_post_name
59
+ "_posts/#{Time.now.strftime("%Y-%m-%d")}-welcome-to-jekyll.markdown"
60
+ end
61
+
62
+ private
63
+
64
+ def gemfile_contents
65
+ <<~RUBY
66
+ source "https://rubygems.org"
67
+ # Hello! This is where you manage which Jekyll version is used to run.
68
+ # When you want to use a different version, change it below, save the
69
+ # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
70
+ #
71
+ # bundle exec jekyll serve
72
+ #
73
+ # This will help ensure the proper Jekyll version is running.
74
+ # Happy Jekylling!
75
+ gem "jekyll", "~> #{Jekyll::VERSION}"
76
+ # This is the default theme for new Jekyll sites. You may change this to anything you like.
77
+ gem "minima", "~> 2.0"
78
+ # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
79
+ # uncomment the line below. To upgrade, run `bundle update github-pages`.
80
+ # gem "github-pages", group: :jekyll_plugins
81
+ # If you have any plugins, put them here!
82
+ group :jekyll_plugins do
83
+ gem "jekyll-feed", "~> 0.6"
84
+ end
85
+ # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
86
+ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
87
+ # Performance-booster for watching directories on Windows
88
+ gem "wdm", "~> 0.1.0" if Gem.win_platform?
89
+
90
+ RUBY
91
+ end
92
+
93
+ def create_site(new_blog_path)
94
+ create_sample_files new_blog_path
95
+
96
+ File.open(File.expand_path(initialized_post_name, new_blog_path), "w") do |f|
97
+ f.write(scaffold_post_content)
98
+ end
99
+
100
+ File.open(File.expand_path("Gemfile", new_blog_path), "w") do |f|
101
+ f.write(gemfile_contents)
102
+ end
103
+ end
104
+
105
+ def preserve_source_location?(path, options)
106
+ !options["force"] && !Dir["#{path}/**/*"].empty?
107
+ end
108
+
109
+ def create_sample_files(path)
110
+ FileUtils.cp_r site_template + "/.", path
111
+ FileUtils.chmod_R "u+w", path
112
+ FileUtils.rm File.expand_path(scaffold_path, path)
113
+ end
114
+
115
+ def site_template
116
+ File.expand_path("../../site_template", __dir__)
117
+ end
118
+
119
+ def scaffold_path
120
+ "_posts/0000-00-00-welcome-to-jekyll.markdown.erb"
121
+ end
122
+
123
+ # After a new blog has been created, print a success notification and
124
+ # then automatically execute bundle install from within the new blog dir
125
+ # unless the user opts to generate a blank blog or skip 'bundle install'.
126
+
127
+ def after_install(path, options = {})
128
+ unless options["blank"] || options["skip-bundle"]
129
+ begin
130
+ require "bundler"
131
+ bundle_install path
132
+ rescue LoadError
133
+ Jekyll.logger.info "Could not load Bundler. Bundle install skipped."
134
+ end
135
+ end
136
+
137
+ Jekyll.logger.info "New jekyll site installed in #{path.cyan}."
138
+ Jekyll.logger.info "Bundle install skipped." if options["skip-bundle"]
139
+ end
140
+
141
+ def bundle_install(path)
142
+ Jekyll.logger.info "Running bundle install in #{path.cyan}..."
143
+ Dir.chdir(path) do
144
+ exe = Gem.bin_path("bundler", "bundle")
145
+ process, output = Jekyll::Utils::Exec.run("ruby", exe, "install")
146
+
147
+ output.to_s.each_line do |line|
148
+ Jekyll.logger.info("Bundler:".green, line.strip) unless line.to_s.empty?
149
+ end
150
+
151
+ raise SystemExit unless process.success?
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module Jekyll
6
+ module Commands
7
+ class NewTheme < Jekyll::Command
8
+ class << self
9
+ def init_with_program(prog)
10
+ prog.command(:"new-theme") do |c|
11
+ c.syntax "new-theme NAME"
12
+ c.description "Creates a new Jekyll theme scaffold"
13
+ c.option "code_of_conduct", \
14
+ "-c", "--code-of-conduct", \
15
+ "Include a Code of Conduct. (defaults to false)"
16
+
17
+ c.action do |args, opts|
18
+ Jekyll::Commands::NewTheme.process(args, opts)
19
+ end
20
+ end
21
+ end
22
+
23
+ # rubocop:disable Metrics/AbcSize
24
+ def process(args, opts)
25
+ if !args || args.empty?
26
+ raise Jekyll::Errors::InvalidThemeName, "You must specify a theme name."
27
+ end
28
+
29
+ new_theme_name = args.join("_")
30
+ theme = Jekyll::ThemeBuilder.new(new_theme_name, opts)
31
+ Jekyll.logger.abort_with "Conflict:", "#{theme.path} already exists." if theme.path.exist?
32
+
33
+ theme.create!
34
+ Jekyll.logger.info "Your new Jekyll theme, #{theme.name.cyan}," \
35
+ " is ready for you in #{theme.path.to_s.cyan}!"
36
+ Jekyll.logger.info "For help getting started, read #{theme.path}/README.md."
37
+ end
38
+ # rubocop:enable Metrics/AbcSize
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,354 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Commands
5
+ class Serve < Command
6
+ # Similar to the pattern in Utils::ThreadEvent except we are maintaining the
7
+ # state of @running instead of just signaling an event. We have to maintain this
8
+ # state since Serve is just called via class methods instead of an instance
9
+ # being created each time.
10
+ @mutex = Mutex.new
11
+ @run_cond = ConditionVariable.new
12
+ @running = false
13
+
14
+ class << self
15
+ COMMAND_OPTIONS = {
16
+ "ssl_cert" => ["--ssl-cert [CERT]", "X.509 (SSL) certificate."],
17
+ "host" => ["host", "-H", "--host [HOST]", "Host to bind to"],
18
+ "open_url" => ["-o", "--open-url", "Launch your site in a browser"],
19
+ "detach" => ["-B", "--detach",
20
+ "Run the server in the background",],
21
+ "ssl_key" => ["--ssl-key [KEY]", "X.509 (SSL) Private Key."],
22
+ "port" => ["-P", "--port [PORT]", "Port to listen on"],
23
+ "show_dir_listing" => ["--show-dir-listing",
24
+ "Show a directory listing instead of loading" \
25
+ " your index file.",],
26
+ "skip_initial_build" => ["skip_initial_build", "--skip-initial-build",
27
+ "Skips the initial site build which occurs before" \
28
+ " the server is started.",],
29
+ "livereload" => ["-l", "--livereload",
30
+ "Use LiveReload to automatically refresh browsers",],
31
+ "livereload_ignore" => ["--livereload-ignore ignore GLOB1[,GLOB2[,...]]",
32
+ Array,
33
+ "Files for LiveReload to ignore. " \
34
+ "Remember to quote the values so your shell " \
35
+ "won't expand them",],
36
+ "livereload_min_delay" => ["--livereload-min-delay [SECONDS]",
37
+ "Minimum reload delay",],
38
+ "livereload_max_delay" => ["--livereload-max-delay [SECONDS]",
39
+ "Maximum reload delay",],
40
+ "livereload_port" => ["--livereload-port [PORT]", Integer,
41
+ "Port for LiveReload to listen on",],
42
+ }.freeze
43
+
44
+ DIRECTORY_INDEX = %w(
45
+ index.htm
46
+ index.html
47
+ index.rhtml
48
+ index.xht
49
+ index.xhtml
50
+ index.cgi
51
+ index.xml
52
+ index.json
53
+ ).freeze
54
+
55
+ LIVERELOAD_PORT = 35_729
56
+ LIVERELOAD_DIR = File.join(__dir__, "serve", "livereload_assets")
57
+
58
+ attr_reader :mutex, :run_cond, :running
59
+ alias_method :running?, :running
60
+
61
+ def init_with_program(prog)
62
+ prog.command(:serve) do |cmd|
63
+ cmd.description "Serve your site locally"
64
+ cmd.syntax "serve [options]"
65
+ cmd.alias :server
66
+ cmd.alias :s
67
+
68
+ add_build_options(cmd)
69
+ COMMAND_OPTIONS.each do |key, val|
70
+ cmd.option key, *val
71
+ end
72
+
73
+ cmd.action do |_, opts|
74
+ opts["livereload_port"] ||= LIVERELOAD_PORT
75
+ opts["serving"] = true
76
+ opts["watch"] = true unless opts.key?("watch")
77
+
78
+ # Set the reactor to nil so any old reactor will be GCed.
79
+ # We can't unregister a hook so while running tests we don't want to
80
+ # inadvertently keep using a reactor created by a previous test.
81
+ @reload_reactor = nil
82
+
83
+ config = configuration_from_options(opts)
84
+ config["url"] = default_url(config) if Jekyll.env == "development"
85
+
86
+ process_with_graceful_fail(cmd, config, Build, Serve)
87
+ end
88
+ end
89
+ end
90
+
91
+ #
92
+
93
+ def process(opts)
94
+ opts = configuration_from_options(opts)
95
+ destination = opts["destination"]
96
+ if opts["livereload"]
97
+ validate_options(opts)
98
+ register_reload_hooks(opts)
99
+ end
100
+ setup(destination)
101
+
102
+ start_up_webrick(opts, destination)
103
+ end
104
+
105
+ def shutdown
106
+ @server.shutdown if running?
107
+ end
108
+
109
+ # Perform logical validation of CLI options
110
+
111
+ private
112
+
113
+ def validate_options(opts)
114
+ if opts["livereload"]
115
+ if opts["detach"]
116
+ Jekyll.logger.warn "Warning:", "--detach and --livereload are mutually exclusive." \
117
+ " Choosing --livereload"
118
+ opts["detach"] = false
119
+ end
120
+ if opts["ssl_cert"] || opts["ssl_key"]
121
+ # This is not technically true. LiveReload works fine over SSL, but
122
+ # EventMachine's SSL support in Windows requires building the gem's
123
+ # native extensions against OpenSSL and that proved to be a process
124
+ # so tedious that expecting users to do it is a non-starter.
125
+ Jekyll.logger.abort_with "Error:", "LiveReload does not support SSL"
126
+ end
127
+ unless opts["watch"]
128
+ # Using livereload logically implies you want to watch the files
129
+ opts["watch"] = true
130
+ end
131
+ elsif %w(livereload_min_delay
132
+ livereload_max_delay
133
+ livereload_ignore
134
+ livereload_port).any? { |o| opts[o] }
135
+ Jekyll.logger.abort_with "--livereload-min-delay, "\
136
+ "--livereload-max-delay, --livereload-ignore, and "\
137
+ "--livereload-port require the --livereload option."
138
+ end
139
+ end
140
+
141
+ # rubocop:disable Metrics/AbcSize
142
+ def register_reload_hooks(opts)
143
+ require_relative "serve/live_reload_reactor"
144
+ @reload_reactor = LiveReloadReactor.new
145
+
146
+ Jekyll::Hooks.register(:site, :post_render) do |site|
147
+ regenerator = Jekyll::Regenerator.new(site)
148
+ @changed_pages = site.pages.select do |p|
149
+ regenerator.regenerate?(p)
150
+ end
151
+ end
152
+
153
+ # A note on ignoring files: LiveReload errs on the side of reloading when it
154
+ # comes to the message it gets. If, for example, a page is ignored but a CSS
155
+ # file linked in the page isn't, the page will still be reloaded if the CSS
156
+ # file is contained in the message sent to LiveReload. Additionally, the
157
+ # path matching is very loose so that a message to reload "/" will always
158
+ # lead the page to reload since every page starts with "/".
159
+ Jekyll::Hooks.register(:site, :post_write) do
160
+ if @changed_pages && @reload_reactor && @reload_reactor.running?
161
+ ignore, @changed_pages = @changed_pages.partition do |p|
162
+ Array(opts["livereload_ignore"]).any? do |filter|
163
+ File.fnmatch(filter, Jekyll.sanitized_path(p.relative_path))
164
+ end
165
+ end
166
+ Jekyll.logger.debug "LiveReload:", "Ignoring #{ignore.map(&:relative_path)}"
167
+ @reload_reactor.reload(@changed_pages)
168
+ end
169
+ @changed_pages = nil
170
+ end
171
+ end
172
+ # rubocop:enable Metrics/AbcSize
173
+
174
+ # Do a base pre-setup of WEBRick so that everything is in place
175
+ # when we get ready to party, checking for an setting up an error page
176
+ # and making sure our destination exists.
177
+
178
+ def setup(destination)
179
+ require_relative "serve/servlet"
180
+
181
+ FileUtils.mkdir_p(destination)
182
+ if File.exist?(File.join(destination, "404.html"))
183
+ WEBrick::HTTPResponse.class_eval do
184
+ def create_error_page
185
+ @header["Content-Type"] = "text/html; charset=UTF-8"
186
+ @body = IO.read(File.join(@config[:DocumentRoot], "404.html"))
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ def webrick_opts(opts)
193
+ opts = {
194
+ :JekyllOptions => opts,
195
+ :DoNotReverseLookup => true,
196
+ :MimeTypes => mime_types,
197
+ :DocumentRoot => opts["destination"],
198
+ :StartCallback => start_callback(opts["detach"]),
199
+ :StopCallback => stop_callback(opts["detach"]),
200
+ :BindAddress => opts["host"],
201
+ :Port => opts["port"],
202
+ :DirectoryIndex => DIRECTORY_INDEX,
203
+ }
204
+
205
+ opts[:DirectoryIndex] = [] if opts[:JekyllOptions]["show_dir_listing"]
206
+
207
+ enable_ssl(opts)
208
+ enable_logging(opts)
209
+ opts
210
+ end
211
+
212
+ def start_up_webrick(opts, destination)
213
+ @reload_reactor.start(opts) if opts["livereload"]
214
+
215
+ @server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") }
216
+ @server.mount(opts["baseurl"].to_s, Servlet, destination, file_handler_opts)
217
+
218
+ Jekyll.logger.info "Server address:", server_address(@server, opts)
219
+ launch_browser @server, opts if opts["open_url"]
220
+ boot_or_detach @server, opts
221
+ end
222
+
223
+ # Recreate NondisclosureName under utf-8 circumstance
224
+ def file_handler_opts
225
+ WEBrick::Config::FileHandler.merge(
226
+ :FancyIndexing => true,
227
+ :NondisclosureName => [
228
+ ".ht*", "~*",
229
+ ]
230
+ )
231
+ end
232
+
233
+ def server_address(server, options = {})
234
+ format_url(
235
+ server.config[:SSLEnable],
236
+ server.config[:BindAddress],
237
+ server.config[:Port],
238
+ options["baseurl"]
239
+ )
240
+ end
241
+
242
+ def format_url(ssl_enabled, address, port, baseurl = nil)
243
+ format("%<prefix>s://%<address>s:%<port>i%<baseurl>s",
244
+ :prefix => ssl_enabled ? "https" : "http",
245
+ :address => address,
246
+ :port => port,
247
+ :baseurl => baseurl ? "#{baseurl}/" : "")
248
+ end
249
+
250
+ def default_url(opts)
251
+ config = configuration_from_options(opts)
252
+ format_url(
253
+ config["ssl_cert"] && config["ssl_key"],
254
+ config["host"] == "127.0.0.1" ? "localhost" : config["host"],
255
+ config["port"]
256
+ )
257
+ end
258
+
259
+ def launch_browser(server, opts)
260
+ address = server_address(server, opts)
261
+ return system "start", address if Utils::Platforms.windows?
262
+ return system "xdg-open", address if Utils::Platforms.linux?
263
+ return system "open", address if Utils::Platforms.osx?
264
+
265
+ Jekyll.logger.error "Refusing to launch browser; " \
266
+ "Platform launcher unknown."
267
+ end
268
+
269
+ # Keep in our area with a thread or detach the server as requested
270
+ # by the user. This method determines what we do based on what you
271
+ # ask us to do.
272
+ def boot_or_detach(server, opts)
273
+ if opts["detach"]
274
+ pid = Process.fork do
275
+ server.start
276
+ end
277
+
278
+ Process.detach(pid)
279
+ Jekyll.logger.info "Server detached with pid '#{pid}'.", \
280
+ "Run `pkill -f jekyll' or `kill -9 #{pid}'" \
281
+ " to stop the server."
282
+ else
283
+ t = Thread.new { server.start }
284
+ trap("INT") { server.shutdown }
285
+ t.join
286
+ end
287
+ end
288
+
289
+ # Make the stack verbose if the user requests it.
290
+ def enable_logging(opts)
291
+ opts[:AccessLog] = []
292
+ level = WEBrick::Log.const_get(opts[:JekyllOptions]["verbose"] ? :DEBUG : :WARN)
293
+ opts[:Logger] = WEBrick::Log.new($stdout, level)
294
+ end
295
+
296
+ # Add SSL to the stack if the user triggers --enable-ssl and they
297
+ # provide both types of certificates commonly needed. Raise if they
298
+ # forget to add one of the certificates.
299
+ def enable_ssl(opts)
300
+ cert, key, src =
301
+ opts[:JekyllOptions].values_at("ssl_cert", "ssl_key", "source")
302
+
303
+ return if cert.nil? && key.nil?
304
+ raise "Missing --ssl_cert or --ssl_key. Both are required." unless cert && key
305
+
306
+ require "openssl"
307
+ require "webrick/https"
308
+
309
+ opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(read_file(src, cert))
310
+ opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key))
311
+ opts[:SSLEnable] = true
312
+ end
313
+
314
+ def start_callback(detached)
315
+ unless detached
316
+ proc do
317
+ mutex.synchronize do
318
+ # Block until EventMachine reactor starts
319
+ @reload_reactor&.started_event&.wait
320
+ @running = true
321
+ Jekyll.logger.info("Server running...", "press ctrl-c to stop.")
322
+ @run_cond.broadcast
323
+ end
324
+ end
325
+ end
326
+ end
327
+
328
+ def stop_callback(detached)
329
+ unless detached
330
+ proc do
331
+ mutex.synchronize do
332
+ unless @reload_reactor.nil?
333
+ @reload_reactor.stop
334
+ @reload_reactor.stopped_event.wait
335
+ end
336
+ @running = false
337
+ @run_cond.broadcast
338
+ end
339
+ end
340
+ end
341
+ end
342
+
343
+ def mime_types
344
+ file = File.expand_path("../mime.types", __dir__)
345
+ WEBrick::HTTPUtils.load_mime_types(file)
346
+ end
347
+
348
+ def read_file(source_dir, file_path)
349
+ File.read(Jekyll.sanitized_path(source_dir, file_path))
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end