ngage 0.0.0

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