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,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webrick"
4
+
5
+ module Jekyll
6
+ module Commands
7
+ class Serve
8
+ # This class is used to determine if the Servlet should modify a served file
9
+ # to insert the LiveReload script tags
10
+ class SkipAnalyzer
11
+ BAD_USER_AGENTS = [%r!MSIE!].freeze
12
+
13
+ def self.skip_processing?(request, response, options)
14
+ new(request, response, options).skip_processing?
15
+ end
16
+
17
+ def initialize(request, response, options)
18
+ @options = options
19
+ @request = request
20
+ @response = response
21
+ end
22
+
23
+ def skip_processing?
24
+ !html? || chunked? || inline? || bad_browser?
25
+ end
26
+
27
+ def chunked?
28
+ @response["Transfer-Encoding"] == "chunked"
29
+ end
30
+
31
+ def inline?
32
+ @response["Content-Disposition"] =~ %r!^inline!
33
+ end
34
+
35
+ def bad_browser?
36
+ BAD_USER_AGENTS.any? { |pattern| @request["User-Agent"] =~ pattern }
37
+ end
38
+
39
+ def html?
40
+ @response["Content-Type"] =~ %r!text/html!
41
+ end
42
+ end
43
+
44
+ # This class inserts the LiveReload script tags into HTML as it is served
45
+ class BodyProcessor
46
+ HEAD_TAG_REGEX = %r!<head>|<head[^(er)][^<]*>!
47
+
48
+ attr_reader :content_length, :new_body, :livereload_added
49
+
50
+ def initialize(body, options)
51
+ @body = body
52
+ @options = options
53
+ @processed = false
54
+ end
55
+
56
+ def processed?
57
+ @processed
58
+ end
59
+
60
+ # rubocop:disable Metrics/MethodLength
61
+ def process!
62
+ @new_body = []
63
+ # @body will usually be a File object but Strings occur in rare cases
64
+ if @body.respond_to?(:each)
65
+ begin
66
+ @body.each { |line| @new_body << line.to_s }
67
+ ensure
68
+ @body.close
69
+ end
70
+ else
71
+ @new_body = @body.lines
72
+ end
73
+
74
+ @content_length = 0
75
+ @livereload_added = false
76
+
77
+ @new_body.each do |line|
78
+ if !@livereload_added && line["<head"]
79
+ line.gsub!(HEAD_TAG_REGEX) do |match|
80
+ %(#{match}#{template.result(binding)})
81
+ end
82
+
83
+ @livereload_added = true
84
+ end
85
+
86
+ @content_length += line.bytesize
87
+ @processed = true
88
+ end
89
+ @new_body = @new_body.join
90
+ end
91
+ # rubocop:enable Metrics/MethodLength
92
+
93
+ def template
94
+ # Unclear what "snipver" does. Doc at
95
+ # https://github.com/livereload/livereload-js states that the recommended
96
+ # setting is 1.
97
+
98
+ # Complicated JavaScript to ensure that livereload.js is loaded from the
99
+ # same origin as the page. Mostly useful for dealing with the browser's
100
+ # distinction between 'localhost' and 127.0.0.1
101
+ template = <<-TEMPLATE
102
+ <script>
103
+ document.write(
104
+ '<script src="http://' +
105
+ (location.host || 'localhost').split(':')[0] +
106
+ ':<%=@options["livereload_port"] %>/livereload.js?snipver=1<%= livereload_args %>"' +
107
+ '></' +
108
+ 'script>');
109
+ </script>
110
+ TEMPLATE
111
+ ERB.new(Jekyll::Utils.strip_heredoc(template))
112
+ end
113
+
114
+ def livereload_args
115
+ # XHTML standard requires ampersands to be encoded as entities when in
116
+ # attributes. See http://stackoverflow.com/a/2190292
117
+ src = ""
118
+ if @options["livereload_min_delay"]
119
+ src += "&amp;mindelay=#{@options["livereload_min_delay"]}"
120
+ end
121
+ if @options["livereload_max_delay"]
122
+ src += "&amp;maxdelay=#{@options["livereload_max_delay"]}"
123
+ end
124
+ src += "&amp;port=#{@options["livereload_port"]}" if @options["livereload_port"]
125
+ src
126
+ end
127
+ end
128
+
129
+ class Servlet < WEBrick::HTTPServlet::FileHandler
130
+ DEFAULTS = {
131
+ "Cache-Control" => "private, max-age=0, proxy-revalidate, " \
132
+ "no-store, no-cache, must-revalidate",
133
+ }.freeze
134
+
135
+ def initialize(server, root, callbacks)
136
+ # So we can access them easily.
137
+ @jekyll_opts = server.config[:JekyllOptions]
138
+ set_defaults
139
+ super
140
+ end
141
+
142
+ def search_index_file(req, res)
143
+ super ||
144
+ search_file(req, res, ".html") ||
145
+ search_file(req, res, ".xhtml")
146
+ end
147
+
148
+ # Add the ability to tap file.html the same way that Nginx does on our
149
+ # Docker images (or on GitHub Pages.) The difference is that we might end
150
+ # up with a different preference on which comes first.
151
+
152
+ def search_file(req, res, basename)
153
+ # /file.* > /file/index.html > /file.html
154
+ super ||
155
+ super(req, res, "#{basename}.html") ||
156
+ super(req, res, "#{basename}.xhtml")
157
+ end
158
+
159
+ # rubocop:disable Naming/MethodName
160
+ def do_GET(req, res)
161
+ rtn = super
162
+
163
+ if @jekyll_opts["livereload"]
164
+ return rtn if SkipAnalyzer.skip_processing?(req, res, @jekyll_opts)
165
+
166
+ processor = BodyProcessor.new(res.body, @jekyll_opts)
167
+ processor.process!
168
+ res.body = processor.new_body
169
+ res.content_length = processor.content_length.to_s
170
+
171
+ if processor.livereload_added
172
+ # Add a header to indicate that the page content has been modified
173
+ res["X-Rack-LiveReload"] = "1"
174
+ end
175
+ end
176
+
177
+ validate_and_ensure_charset(req, res)
178
+ res.header.merge!(@headers)
179
+ rtn
180
+ end
181
+ # rubocop:enable Naming/MethodName
182
+
183
+ private
184
+
185
+ def validate_and_ensure_charset(_req, res)
186
+ key = res.header.keys.grep(%r!content-type!i).first
187
+ typ = res.header[key]
188
+
189
+ unless typ =~ %r!;\s*charset=!
190
+ res.header[key] = "#{typ}; charset=#{@jekyll_opts["encoding"]}"
191
+ end
192
+ end
193
+
194
+ def set_defaults
195
+ hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {})
196
+ DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash|
197
+ hash[key] = val unless hash.key?(key)
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "http/parser"
4
+
5
+ module Jekyll
6
+ module Commands
7
+ class Serve
8
+ # The LiveReload protocol requires the server to serve livereload.js over HTTP
9
+ # despite the fact that the protocol itself uses WebSockets. This custom connection
10
+ # class addresses the dual protocols that the server needs to understand.
11
+ class HttpAwareConnection < EventMachine::WebSocket::Connection
12
+ attr_reader :reload_body, :reload_size
13
+
14
+ def initialize(_opts)
15
+ # If EventMachine SSL support on Windows ever gets better, the code below will
16
+ # set up the reactor to handle SSL
17
+ #
18
+ # @ssl_enabled = opts["ssl_cert"] && opts["ssl_key"]
19
+ # if @ssl_enabled
20
+ # em_opts[:tls_options] = {
21
+ # :private_key_file => Jekyll.sanitized_path(opts["source"], opts["ssl_key"]),
22
+ # :cert_chain_file => Jekyll.sanitized_path(opts["source"], opts["ssl_cert"])
23
+ # }
24
+ # em_opts[:secure] = true
25
+ # end
26
+
27
+ # This is too noisy even for --verbose, but uncomment if you need it for
28
+ # a specific WebSockets issue. Adding ?LR-verbose=true onto the URL will
29
+ # enable logging on the client side.
30
+ # em_opts[:debug] = true
31
+
32
+ em_opts = {}
33
+ super(em_opts)
34
+
35
+ reload_file = File.join(Serve.singleton_class::LIVERELOAD_DIR, "livereload.js")
36
+
37
+ @reload_body = File.read(reload_file)
38
+ @reload_size = @reload_body.bytesize
39
+ end
40
+
41
+ # rubocop:disable Metrics/MethodLength
42
+ def dispatch(data)
43
+ parser = Http::Parser.new
44
+ parser << data
45
+
46
+ # WebSockets requests will have a Connection: Upgrade header
47
+ if parser.http_method != "GET" || parser.upgrade?
48
+ super
49
+ elsif parser.request_url =~ %r!^\/livereload.js!
50
+ headers = [
51
+ "HTTP/1.1 200 OK",
52
+ "Content-Type: application/javascript",
53
+ "Content-Length: #{reload_size}",
54
+ "",
55
+ "",
56
+ ].join("\r\n")
57
+ send_data(headers)
58
+
59
+ # stream_file_data would free us from keeping livereload.js in memory
60
+ # but JRuby blocks on that call and never returns
61
+ send_data(reload_body)
62
+ close_connection_after_writing
63
+ else
64
+ body = "This port only serves livereload.js over HTTP.\n"
65
+ headers = [
66
+ "HTTP/1.1 400 Bad Request",
67
+ "Content-Type: text/plain",
68
+ "Content-Length: #{body.bytesize}",
69
+ "",
70
+ "",
71
+ ].join("\r\n")
72
+ send_data(headers)
73
+ send_data(body)
74
+ close_connection_after_writing
75
+ end
76
+ end
77
+ # rubocop:enable Metrics/MethodLength
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,391 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class Configuration < Hash
5
+ # Default options. Overridden by values in _config.yml.
6
+ # Strings rather than symbols are used for compatibility with YAML.
7
+ DEFAULTS = Configuration[{
8
+ # Where things are
9
+ "source" => Dir.pwd,
10
+ "destination" => File.join(Dir.pwd, "_site"),
11
+ "collections_dir" => "",
12
+ "cache_dir" => ".jekyll-cache",
13
+ "plugins_dir" => "_plugins",
14
+ "layouts_dir" => "_layouts",
15
+ "data_dir" => "_data",
16
+ "includes_dir" => "_includes",
17
+ "collections" => {},
18
+
19
+ # Handling Reading
20
+ "safe" => false,
21
+ "include" => [".htaccess"],
22
+ "exclude" => %w(
23
+ Gemfile Gemfile.lock node_modules vendor/bundle/ vendor/cache/ vendor/gems/
24
+ vendor/ruby/
25
+ ),
26
+ "keep_files" => [".git", ".svn"],
27
+ "encoding" => "utf-8",
28
+ "markdown_ext" => "markdown,mkdown,mkdn,mkd,md",
29
+ "strict_front_matter" => false,
30
+
31
+ # Filtering Content
32
+ "show_drafts" => nil,
33
+ "limit_posts" => 0,
34
+ "future" => false,
35
+ "unpublished" => false,
36
+
37
+ # Plugins
38
+ "whitelist" => [],
39
+ "plugins" => [],
40
+
41
+ # Conversion
42
+ "markdown" => "kramdown",
43
+ "highlighter" => "rouge",
44
+ "lsi" => false,
45
+ "excerpt_separator" => "\n\n",
46
+ "incremental" => false,
47
+
48
+ # Serving
49
+ "detach" => false, # default to not detaching the server
50
+ "port" => "4000",
51
+ "host" => "127.0.0.1",
52
+ "baseurl" => nil, # this mounts at /, i.e. no subdirectory
53
+ "show_dir_listing" => false,
54
+
55
+ # Output Configuration
56
+ "permalink" => "date",
57
+ "paginate_path" => "/page:num",
58
+ "timezone" => nil, # use the local timezone
59
+
60
+ "quiet" => false,
61
+ "verbose" => false,
62
+ "defaults" => [],
63
+
64
+ "liquid" => {
65
+ "error_mode" => "warn",
66
+ "strict_filters" => false,
67
+ "strict_variables" => false,
68
+ },
69
+
70
+ "kramdown" => {
71
+ "auto_ids" => true,
72
+ "toc_levels" => "1..6",
73
+ "entity_output" => "as_char",
74
+ "smart_quotes" => "lsquo,rsquo,ldquo,rdquo",
75
+ "input" => "GFM",
76
+ "hard_wrap" => false,
77
+ "footnote_nr" => 1,
78
+ "show_warnings" => false,
79
+ },
80
+ }.map { |k, v| [k, v.freeze] }].freeze
81
+
82
+ class << self
83
+ # Static: Produce a Configuration ready for use in a Site.
84
+ # It takes the input, fills in the defaults where values do not
85
+ # exist, and patches common issues including migrating options for
86
+ # backwards compatiblity. Except where a key or value is being fixed,
87
+ # the user configuration will override the defaults.
88
+ #
89
+ # user_config - a Hash or Configuration of overrides.
90
+ #
91
+ # Returns a Configuration filled with defaults and fixed for common
92
+ # problems and backwards-compatibility.
93
+ def from(user_config)
94
+ Utils.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys)
95
+ .add_default_collections
96
+ end
97
+ end
98
+
99
+ # Public: Turn all keys into string
100
+ #
101
+ # Return a copy of the hash where all its keys are strings
102
+ def stringify_keys
103
+ reduce({}) { |hsh, (k, v)| hsh.merge(k.to_s => v) }
104
+ end
105
+
106
+ def get_config_value_with_override(config_key, override)
107
+ override[config_key] || self[config_key] || DEFAULTS[config_key]
108
+ end
109
+
110
+ # Public: Directory of the Jekyll source folder
111
+ #
112
+ # override - the command-line options hash
113
+ #
114
+ # Returns the path to the Jekyll source directory
115
+ def source(override)
116
+ get_config_value_with_override("source", override)
117
+ end
118
+
119
+ def quiet(override = {})
120
+ get_config_value_with_override("quiet", override)
121
+ end
122
+ alias_method :quiet?, :quiet
123
+
124
+ def verbose(override = {})
125
+ get_config_value_with_override("verbose", override)
126
+ end
127
+ alias_method :verbose?, :verbose
128
+
129
+ def safe_load_file(filename)
130
+ case File.extname(filename)
131
+ when %r!\.toml!i
132
+ Jekyll::External.require_with_graceful_fail("tomlrb") unless defined?(Tomlrb)
133
+ Tomlrb.load_file(filename)
134
+ when %r!\.ya?ml!i
135
+ SafeYAML.load_file(filename) || {}
136
+ else
137
+ raise ArgumentError, "No parser for '#{filename}' is available.
138
+ Use a .y(a)ml or .toml file instead."
139
+ end
140
+ end
141
+
142
+ # Public: Generate list of configuration files from the override
143
+ #
144
+ # override - the command-line options hash
145
+ #
146
+ # Returns an Array of config files
147
+ def config_files(override)
148
+ # Adjust verbosity quickly
149
+ Jekyll.logger.adjust_verbosity(
150
+ :quiet => quiet?(override),
151
+ :verbose => verbose?(override)
152
+ )
153
+
154
+ # Get configuration from <source>/_config.yml or <source>/<config_file>
155
+ config_files = override["config"]
156
+ if config_files.to_s.empty?
157
+ default = %w(yml yaml).find(-> { "yml" }) do |ext|
158
+ File.exist?(Jekyll.sanitized_path(source(override), "_config.#{ext}"))
159
+ end
160
+ config_files = Jekyll.sanitized_path(source(override), "_config.#{default}")
161
+ @default_config_file = true
162
+ end
163
+ Array(config_files)
164
+ end
165
+
166
+ # Public: Read configuration and return merged Hash
167
+ #
168
+ # file - the path to the YAML file to be read in
169
+ #
170
+ # Returns this configuration, overridden by the values in the file
171
+ def read_config_file(file)
172
+ next_config = safe_load_file(file)
173
+ check_config_is_hash!(next_config, file)
174
+ Jekyll.logger.info "Configuration file:", file
175
+ next_config
176
+ rescue SystemCallError
177
+ if @default_config_file ||= nil
178
+ Jekyll.logger.warn "Configuration file:", "none"
179
+ {}
180
+ else
181
+ Jekyll.logger.error "Fatal:", "The configuration file '#{file}'
182
+ could not be found."
183
+ raise LoadError, "The Configuration file '#{file}' could not be found."
184
+ end
185
+ end
186
+
187
+ # Public: Read in a list of configuration files and merge with this hash
188
+ #
189
+ # files - the list of configuration file paths
190
+ #
191
+ # Returns the full configuration, with the defaults overridden by the values in the
192
+ # configuration files
193
+ def read_config_files(files)
194
+ configuration = clone
195
+
196
+ begin
197
+ files.each do |config_file|
198
+ next if config_file.nil? || config_file.empty?
199
+
200
+ new_config = read_config_file(config_file)
201
+ configuration = Utils.deep_merge_hashes(configuration, new_config)
202
+ end
203
+ rescue ArgumentError => err
204
+ Jekyll.logger.warn "WARNING:", "Error reading configuration. " \
205
+ "Using defaults (and options)."
206
+ warn err
207
+ end
208
+
209
+ configuration.backwards_compatibilize.add_default_collections
210
+ end
211
+
212
+ # Public: Split a CSV string into an array containing its values
213
+ #
214
+ # csv - the string of comma-separated values
215
+ #
216
+ # Returns an array of the values contained in the CSV
217
+ def csv_to_array(csv)
218
+ csv.split(",").map(&:strip)
219
+ end
220
+
221
+ # Public: Ensure the proper options are set in the configuration to allow for
222
+ # backwards-compatibility with Jekyll pre-1.0
223
+ #
224
+ # Returns the backwards-compatible configuration
225
+ def backwards_compatibilize
226
+ config = clone
227
+ # Provide backwards-compatibility
228
+ check_auto(config)
229
+ check_server(config)
230
+ check_plugins(config)
231
+
232
+ renamed_key "server_port", "port", config
233
+ renamed_key "gems", "plugins", config
234
+ renamed_key "layouts", "layouts_dir", config
235
+ renamed_key "data_source", "data_dir", config
236
+
237
+ check_pygments(config)
238
+ check_include_exclude(config)
239
+ check_coderay(config)
240
+ check_maruku(config)
241
+
242
+ config
243
+ end
244
+
245
+ # DEPRECATED.
246
+ def fix_common_issues
247
+ self
248
+ end
249
+
250
+ def add_default_collections
251
+ config = clone
252
+
253
+ # It defaults to `{}`, so this is only if someone sets it to null manually.
254
+ return config if config["collections"].nil?
255
+
256
+ # Ensure we have a hash.
257
+ if config["collections"].is_a?(Array)
258
+ config["collections"] = Hash[config["collections"].map { |c| [c, {}] }]
259
+ end
260
+
261
+ config["collections"] = Utils.deep_merge_hashes(
262
+ { "posts" => {} }, config["collections"]
263
+ ).tap do |collections|
264
+ collections["posts"]["output"] = true
265
+ if config["permalink"]
266
+ collections["posts"]["permalink"] ||= style_to_permalink(config["permalink"])
267
+ end
268
+ end
269
+
270
+ config
271
+ end
272
+
273
+ def renamed_key(old, new, config, _ = nil)
274
+ if config.key?(old)
275
+ Jekyll::Deprecator.deprecation_message "The '#{old}' configuration" \
276
+ " option has been renamed to '#{new}'. Please update your config" \
277
+ " file accordingly."
278
+ config[new] = config.delete(old)
279
+ end
280
+ end
281
+
282
+ private
283
+
284
+ def style_to_permalink(permalink_style)
285
+ case permalink_style.to_sym
286
+ when :pretty
287
+ "/:categories/:year/:month/:day/:title/"
288
+ when :none
289
+ "/:categories/:title:output_ext"
290
+ when :date
291
+ "/:categories/:year/:month/:day/:title:output_ext"
292
+ when :ordinal
293
+ "/:categories/:year/:y_day/:title:output_ext"
294
+ else
295
+ permalink_style.to_s
296
+ end
297
+ end
298
+
299
+ # Private: Checks if a given config is a hash
300
+ #
301
+ # extracted_config - the value to check
302
+ # file - the file from which the config was extracted
303
+ #
304
+ # Raises an ArgumentError if given config is not a hash
305
+ def check_config_is_hash!(extracted_config, file)
306
+ unless extracted_config.is_a?(Hash)
307
+ raise ArgumentError, "Configuration file: (INVALID) #{file}".yellow
308
+ end
309
+ end
310
+
311
+ def check_auto(config)
312
+ if config.key?("auto") || config.key?("watch")
313
+ Jekyll::Deprecator.deprecation_message "Auto-regeneration can no longer" \
314
+ " be set from your configuration file(s). Use the" \
315
+ " --[no-]watch/-w command-line option instead."
316
+ config.delete("auto")
317
+ config.delete("watch")
318
+ end
319
+ end
320
+
321
+ def check_server(config)
322
+ if config.key?("server")
323
+ Jekyll::Deprecator.deprecation_message "The 'server' configuration option" \
324
+ " is no longer accepted. Use the 'jekyll serve'" \
325
+ " subcommand to serve your site with WEBrick."
326
+ config.delete("server")
327
+ end
328
+ end
329
+
330
+ def check_pygments(config)
331
+ if config.key?("pygments")
332
+ Jekyll::Deprecator.deprecation_message "The 'pygments' configuration option" \
333
+ " has been renamed to 'highlighter'. Please update your" \
334
+ " config file accordingly. The allowed values are 'rouge', " \
335
+ "'pygments' or null."
336
+
337
+ config["highlighter"] = "pygments" if config["pygments"]
338
+ config.delete("pygments")
339
+ end
340
+ end
341
+
342
+ def check_include_exclude(config)
343
+ %w(include exclude).each do |option|
344
+ if config[option].is_a?(String)
345
+ Jekyll::Deprecator.deprecation_message "The '#{option}' configuration option" \
346
+ " must now be specified as an array, but you specified" \
347
+ " a string. For now, we've treated the string you provided" \
348
+ " as a list of comma-separated values."
349
+ config[option] = csv_to_array(config[option])
350
+ end
351
+ config[option]&.map!(&:to_s)
352
+ end
353
+ end
354
+
355
+ def check_coderay(config)
356
+ if (config["kramdown"] || {}).key?("use_coderay")
357
+ Jekyll::Deprecator.deprecation_message "Please change 'use_coderay'" \
358
+ " to 'enable_coderay' in your configuration file."
359
+ config["kramdown"]["use_coderay"] = config["kramdown"].delete("enable_coderay")
360
+ end
361
+ end
362
+
363
+ def check_maruku(config)
364
+ if config.fetch("markdown", "kramdown").to_s.casecmp("maruku").zero?
365
+ Jekyll.logger.abort_with "Error:", "You're using the 'maruku' " \
366
+ "Markdown processor, which has been removed as of 3.0.0. " \
367
+ "We recommend you switch to Kramdown. To do this, replace " \
368
+ "`markdown: maruku` with `markdown: kramdown` in your " \
369
+ "`_config.yml` file."
370
+ end
371
+ end
372
+
373
+ # Private: Checks if the `plugins` config is a String
374
+ #
375
+ # config - the config hash
376
+ #
377
+ # Raises a Jekyll::Errors::InvalidConfigurationError if the config `plugins`
378
+ # is a string
379
+ def check_plugins(config)
380
+ if config.key?("plugins") && config["plugins"].is_a?(String)
381
+ Jekyll.logger.error "Configuration Error:", "You specified the" \
382
+ " `plugins` config in your configuration file as a string, please" \
383
+ " use an array instead. If you wanted to set the directory of your" \
384
+ " plugins, use the config key `plugins_dir` instead."
385
+ raise Jekyll::Errors::InvalidConfigurationError,
386
+ "'plugins' should not be a string, but was: " \
387
+ "#{config["plugins"].inspect}. Use 'plugins_dir' instead."
388
+ end
389
+ end
390
+ end
391
+ end