jekyllplusadmin 1.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.
- checksums.yaml +7 -0
- data/.rubocop.yml +80 -0
- data/LICENSE +21 -0
- data/README.markdown +60 -0
- data/bin/jekyll +51 -0
- data/lib/jekyll.rb +180 -0
- data/lib/jekyll/cleaner.rb +105 -0
- data/lib/jekyll/collection.rb +205 -0
- data/lib/jekyll/command.rb +65 -0
- data/lib/jekyll/commands/build.rb +77 -0
- data/lib/jekyll/commands/clean.rb +42 -0
- data/lib/jekyll/commands/doctor.rb +114 -0
- data/lib/jekyll/commands/help.rb +31 -0
- data/lib/jekyll/commands/new.rb +82 -0
- data/lib/jekyll/commands/serve.rb +235 -0
- data/lib/jekyll/commands/serve/servlet.rb +61 -0
- data/lib/jekyll/configuration.rb +323 -0
- data/lib/jekyll/converter.rb +48 -0
- data/lib/jekyll/converters/identity.rb +21 -0
- data/lib/jekyll/converters/markdown.rb +92 -0
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +117 -0
- data/lib/jekyll/converters/markdown/rdiscount_parser.rb +33 -0
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +102 -0
- data/lib/jekyll/converters/smartypants.rb +34 -0
- data/lib/jekyll/convertible.rb +297 -0
- data/lib/jekyll/deprecator.rb +46 -0
- data/lib/jekyll/document.rb +444 -0
- data/lib/jekyll/drops/collection_drop.rb +22 -0
- data/lib/jekyll/drops/document_drop.rb +27 -0
- data/lib/jekyll/drops/drop.rb +176 -0
- data/lib/jekyll/drops/jekyll_drop.rb +21 -0
- data/lib/jekyll/drops/site_drop.rb +38 -0
- data/lib/jekyll/drops/unified_payload_drop.rb +25 -0
- data/lib/jekyll/drops/url_drop.rb +83 -0
- data/lib/jekyll/entry_filter.rb +72 -0
- data/lib/jekyll/errors.rb +10 -0
- data/lib/jekyll/excerpt.rb +127 -0
- data/lib/jekyll/external.rb +59 -0
- data/lib/jekyll/filters.rb +367 -0
- data/lib/jekyll/frontmatter_defaults.rb +188 -0
- data/lib/jekyll/generator.rb +3 -0
- data/lib/jekyll/hooks.rb +101 -0
- data/lib/jekyll/layout.rb +49 -0
- data/lib/jekyll/liquid_extensions.rb +22 -0
- data/lib/jekyll/liquid_renderer.rb +39 -0
- data/lib/jekyll/liquid_renderer/file.rb +50 -0
- data/lib/jekyll/liquid_renderer/table.rb +94 -0
- data/lib/jekyll/log_adapter.rb +115 -0
- data/lib/jekyll/mime.types +800 -0
- data/lib/jekyll/page.rb +180 -0
- data/lib/jekyll/plugin.rb +96 -0
- data/lib/jekyll/plugin_manager.rb +95 -0
- data/lib/jekyll/publisher.rb +21 -0
- data/lib/jekyll/reader.rb +126 -0
- data/lib/jekyll/readers/collection_reader.rb +20 -0
- data/lib/jekyll/readers/data_reader.rb +69 -0
- data/lib/jekyll/readers/layout_reader.rb +53 -0
- data/lib/jekyll/readers/page_reader.rb +21 -0
- data/lib/jekyll/readers/post_reader.rb +62 -0
- data/lib/jekyll/readers/static_file_reader.rb +21 -0
- data/lib/jekyll/regenerator.rb +175 -0
- data/lib/jekyll/related_posts.rb +56 -0
- data/lib/jekyll/renderer.rb +191 -0
- data/lib/jekyll/site.rb +391 -0
- data/lib/jekyll/static_file.rb +141 -0
- data/lib/jekyll/stevenson.rb +58 -0
- data/lib/jekyll/tags/highlight.rb +122 -0
- data/lib/jekyll/tags/include.rb +190 -0
- data/lib/jekyll/tags/post_url.rb +88 -0
- data/lib/jekyll/url.rb +136 -0
- data/lib/jekyll/utils.rb +287 -0
- data/lib/jekyll/utils/ansi.rb +59 -0
- data/lib/jekyll/utils/platforms.rb +30 -0
- data/lib/jekyll/version.rb +3 -0
- data/lib/site_template/.gitignore +3 -0
- data/lib/site_template/_config.yml +21 -0
- data/lib/site_template/_includes/footer.html +38 -0
- data/lib/site_template/_includes/head.html +12 -0
- data/lib/site_template/_includes/header.html +27 -0
- data/lib/site_template/_includes/icon-github.html +1 -0
- data/lib/site_template/_includes/icon-github.svg +1 -0
- data/lib/site_template/_includes/icon-twitter.html +1 -0
- data/lib/site_template/_includes/icon-twitter.svg +1 -0
- data/lib/site_template/_layouts/default.html +20 -0
- data/lib/site_template/_layouts/page.html +14 -0
- data/lib/site_template/_layouts/post.html +15 -0
- data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +25 -0
- data/lib/site_template/_sass/_base.scss +206 -0
- data/lib/site_template/_sass/_layout.scss +242 -0
- data/lib/site_template/_sass/_syntax-highlighting.scss +71 -0
- data/lib/site_template/about.md +15 -0
- data/lib/site_template/css/main.scss +53 -0
- data/lib/site_template/feed.xml +30 -0
- data/lib/site_template/index.html +23 -0
- metadata +252 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Jekyll
|
|
2
|
+
module Commands
|
|
3
|
+
class Help < Command
|
|
4
|
+
class << self
|
|
5
|
+
def init_with_program(prog)
|
|
6
|
+
prog.command(:help) do |c|
|
|
7
|
+
c.syntax 'help [subcommand]'
|
|
8
|
+
c.description 'Show the help message, optionally for a given subcommand.'
|
|
9
|
+
|
|
10
|
+
c.action do |args, _|
|
|
11
|
+
cmd = (args.first || "").to_sym
|
|
12
|
+
if args.empty?
|
|
13
|
+
puts prog
|
|
14
|
+
elsif prog.has_command? cmd
|
|
15
|
+
puts prog.commands[cmd]
|
|
16
|
+
else
|
|
17
|
+
invalid_command(prog, cmd)
|
|
18
|
+
abort
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def invalid_command(prog, cmd)
|
|
25
|
+
Jekyll.logger.error "Error:", "Hmm... we don't know what the '#{cmd}' command is."
|
|
26
|
+
Jekyll.logger.info "Valid commands:", prog.commands.keys.join(", ")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'erb'
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module Commands
|
|
5
|
+
class New < Command
|
|
6
|
+
class << self
|
|
7
|
+
def init_with_program(prog)
|
|
8
|
+
prog.command(:new) do |c|
|
|
9
|
+
c.syntax 'new PATH'
|
|
10
|
+
c.description 'Creates a new Jekyll site scaffold in PATH'
|
|
11
|
+
|
|
12
|
+
c.option 'force', '--force', 'Force creation even if PATH already exists'
|
|
13
|
+
c.option 'blank', '--blank', 'Creates scaffolding but with empty files'
|
|
14
|
+
|
|
15
|
+
c.action do |args, options|
|
|
16
|
+
Jekyll::Commands::New.process(args, options)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def process(args, options = {})
|
|
22
|
+
raise ArgumentError.new('You must specify a path.') if args.empty?
|
|
23
|
+
|
|
24
|
+
new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
|
|
25
|
+
FileUtils.mkdir_p new_blog_path
|
|
26
|
+
if preserve_source_location?(new_blog_path, options)
|
|
27
|
+
Jekyll.logger.abort_with "Conflict:", "#{new_blog_path} exists and is not empty."
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if options["blank"]
|
|
31
|
+
create_blank_site new_blog_path
|
|
32
|
+
else
|
|
33
|
+
create_sample_files new_blog_path
|
|
34
|
+
|
|
35
|
+
File.open(File.expand_path(initialized_post_name, new_blog_path), "w") do |f|
|
|
36
|
+
f.write(scaffold_post_content)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Jekyll.logger.info "New jekyll site installed in #{new_blog_path}."
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_blank_site(path)
|
|
44
|
+
Dir.chdir(path) do
|
|
45
|
+
FileUtils.mkdir(%w(_layouts _posts _drafts))
|
|
46
|
+
FileUtils.touch("index.html")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def scaffold_post_content
|
|
51
|
+
ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Internal: Gets the filename of the sample post to be created
|
|
55
|
+
#
|
|
56
|
+
# Returns the filename of the sample post, as a String
|
|
57
|
+
def initialized_post_name
|
|
58
|
+
"_posts/#{Time.now.strftime('%Y-%m-%d')}-welcome-to-jekyll.markdown"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def preserve_source_location?(path, options)
|
|
64
|
+
!options["force"] && !Dir["#{path}/**/*"].empty?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def create_sample_files(path)
|
|
68
|
+
FileUtils.cp_r site_template + '/.', path
|
|
69
|
+
FileUtils.rm File.expand_path(scaffold_path, path)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def site_template
|
|
73
|
+
File.expand_path("../../site_template", File.dirname(__FILE__))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def scaffold_path
|
|
77
|
+
"_posts/0000-00-00-welcome-to-jekyll.markdown.erb"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
module Jekyll
|
|
2
|
+
module Commands
|
|
3
|
+
class Serve < Command
|
|
4
|
+
class << self
|
|
5
|
+
COMMAND_OPTIONS = {
|
|
6
|
+
"ssl_cert" => ["--ssl-cert [CERT]", "X.509 (SSL) certificate."],
|
|
7
|
+
"host" => ["host", "-H", "--host [HOST]", "Host to bind to"],
|
|
8
|
+
"open_url" => ["-o", "--open-url", "Launch your browser with your site."],
|
|
9
|
+
"detach" => ["-B", "--detach", "Run the server in the background (detach)"],
|
|
10
|
+
"ssl_key" => ["--ssl-key [KEY]", "X.509 (SSL) Private Key."],
|
|
11
|
+
"port" => ["-P", "--port [PORT]", "Port to listen on"],
|
|
12
|
+
"baseurl" => ["-b", "--baseurl [URL]", "Base URL"],
|
|
13
|
+
"skip_initial_build" => ["skip_initial_build", "--skip-initial-build",
|
|
14
|
+
"Skips the initial site build which occurs before the server is started."]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
def init_with_program(prog)
|
|
20
|
+
prog.command(:serve) do |cmd|
|
|
21
|
+
cmd.description "Serve your site locally"
|
|
22
|
+
cmd.syntax "serve [options]"
|
|
23
|
+
cmd.alias :server
|
|
24
|
+
cmd.alias :s
|
|
25
|
+
|
|
26
|
+
add_build_options(cmd)
|
|
27
|
+
COMMAND_OPTIONS.each do |key, val|
|
|
28
|
+
cmd.option key, *val
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
cmd.action do |_, opts|
|
|
32
|
+
opts["serving"] = true
|
|
33
|
+
opts["watch" ] = true unless opts.key?("watch")
|
|
34
|
+
Build.process(opts)
|
|
35
|
+
Serve.process(opts)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
#
|
|
41
|
+
|
|
42
|
+
def process(opts)
|
|
43
|
+
opts = configuration_from_options(opts)
|
|
44
|
+
destination = opts["destination"]
|
|
45
|
+
setup(destination)
|
|
46
|
+
|
|
47
|
+
server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") }
|
|
48
|
+
server.mount(opts["baseurl"], Servlet, destination, file_handler_opts)
|
|
49
|
+
server.mount('/admin', admin)
|
|
50
|
+
Jekyll.logger.info "Server address:", server_address(server, opts)
|
|
51
|
+
launch_browser server, opts if opts["open_url"]
|
|
52
|
+
boot_or_detach server, opts
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def admin
|
|
56
|
+
Class.new WEBrick::HTTPServlet::AbstractServlet do
|
|
57
|
+
def do_GET request, response
|
|
58
|
+
WEBrick::HTTPAuth.basic_auth(request, response, 'My Realm') do |user, pass|
|
|
59
|
+
credentials = SafeYAML.load_file(Jekyll::Configuration::DEFAULTS['source'] + '/admin/config.yml')
|
|
60
|
+
user == credentials['user'] && pass == credentials['password']
|
|
61
|
+
end
|
|
62
|
+
status, content_type, body = 'hello'
|
|
63
|
+
|
|
64
|
+
body_text = IO.read(File.join(Jekyll::Configuration::DEFAULTS['source'], 'admin/posts.html'))
|
|
65
|
+
body_text.gsub!('% previous_post %', IO.read(Jekyll::Configuration::DEFAULTS['source'] + '/_posts/' + Dir.entries(Jekyll::Configuration::DEFAULTS['source'] + '/_posts')[-1]))
|
|
66
|
+
|
|
67
|
+
response.status = 200
|
|
68
|
+
response['Content-Type'] = 'text/html'
|
|
69
|
+
response.body = body_text
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def do_POST request, response
|
|
73
|
+
puts request
|
|
74
|
+
File.open(Jekyll::Configuration::DEFAULTS['source'] + '/_posts/' + DateTime.now.strftime('%Y-%m-%d') + '-post' + DateTime.now.strftime('%s') + '.markdown', 'wb') do |f|
|
|
75
|
+
f.write(request.query['post'])
|
|
76
|
+
end
|
|
77
|
+
response.status = 200
|
|
78
|
+
response['Content-Type'] = 'text/html'
|
|
79
|
+
response.body = 'Your post has been added...'
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# Do a base pre-setup of WEBRick so that everything is in place
|
|
86
|
+
# when we get ready to party, checking for an setting up an error page
|
|
87
|
+
# and making sure our destination exists.
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
def setup(destination)
|
|
91
|
+
require_relative "serve/servlet"
|
|
92
|
+
|
|
93
|
+
FileUtils.mkdir_p(destination)
|
|
94
|
+
if File.exist?(File.join(destination, "404.html"))
|
|
95
|
+
WEBrick::HTTPResponse.class_eval do
|
|
96
|
+
def create_error_page
|
|
97
|
+
@header["Content-Type"] = "text/html; charset=UTF-8"
|
|
98
|
+
@body = IO.read(File.join(@config[:DocumentRoot], "404.html"))
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
#
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
def webrick_opts(opts)
|
|
108
|
+
opts = {
|
|
109
|
+
:JekyllOptions => opts,
|
|
110
|
+
:DoNotReverseLookup => true,
|
|
111
|
+
:MimeTypes => mime_types,
|
|
112
|
+
:DocumentRoot => opts["destination"],
|
|
113
|
+
:StartCallback => start_callback(opts["detach"]),
|
|
114
|
+
:BindAddress => opts["host"],
|
|
115
|
+
:Port => opts["port"],
|
|
116
|
+
:DirectoryIndex => %W(
|
|
117
|
+
index.htm
|
|
118
|
+
index.html
|
|
119
|
+
index.rhtml
|
|
120
|
+
index.cgi
|
|
121
|
+
index.xml
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
enable_ssl(opts)
|
|
126
|
+
enable_logging(opts)
|
|
127
|
+
opts
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Recreate NondisclosureName under utf-8 circumstance
|
|
131
|
+
|
|
132
|
+
private
|
|
133
|
+
def file_handler_opts
|
|
134
|
+
WEBrick::Config::FileHandler.merge({
|
|
135
|
+
:FancyIndexing => true,
|
|
136
|
+
:NondisclosureName => [
|
|
137
|
+
'.ht*', '~*'
|
|
138
|
+
]
|
|
139
|
+
})
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
#
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
def server_address(server, opts)
|
|
146
|
+
address = server.config[:BindAddress]
|
|
147
|
+
baseurl = "#{opts["baseurl"]}/" if opts["baseurl"]
|
|
148
|
+
port = server.config[:Port]
|
|
149
|
+
|
|
150
|
+
"http://#{address}:#{port}#{baseurl}"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
|
|
155
|
+
private
|
|
156
|
+
def launch_browser(server, opts)
|
|
157
|
+
command =
|
|
158
|
+
if Utils::Platforms.windows?
|
|
159
|
+
"start"
|
|
160
|
+
elsif Utils::Platforms.osx?
|
|
161
|
+
"open"
|
|
162
|
+
else
|
|
163
|
+
"xdg-open"
|
|
164
|
+
end
|
|
165
|
+
system command, server_address(server, opts)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Keep in our area with a thread or detach the server as requested
|
|
169
|
+
# by the user. This method determines what we do based on what you
|
|
170
|
+
# ask us to do.
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
def boot_or_detach(server, opts)
|
|
174
|
+
if opts["detach"]
|
|
175
|
+
pid = Process.fork do
|
|
176
|
+
server.start
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
Process.detach(pid)
|
|
180
|
+
Jekyll.logger.info "Server detached with pid '#{pid}'.", \
|
|
181
|
+
"Run `pkill -f jekyll' or `kill -9 #{pid}' to stop the server."
|
|
182
|
+
else
|
|
183
|
+
t = Thread.new { server.start }
|
|
184
|
+
trap("INT") { server.shutdown }
|
|
185
|
+
t.join
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Make the stack verbose if the user requests it.
|
|
190
|
+
|
|
191
|
+
private
|
|
192
|
+
def enable_logging(opts)
|
|
193
|
+
opts[:AccessLog] = []
|
|
194
|
+
level = WEBrick::Log.const_get(opts[:JekyllOptions]["verbose"] ? :DEBUG : :WARN)
|
|
195
|
+
opts[:Logger] = WEBrick::Log.new($stdout, level)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Add SSL to the stack if the user triggers --enable-ssl and they
|
|
199
|
+
# provide both types of certificates commonly needed. Raise if they
|
|
200
|
+
# forget to add one of the certificates.
|
|
201
|
+
|
|
202
|
+
private
|
|
203
|
+
def enable_ssl(opts)
|
|
204
|
+
return if !opts[:JekyllOptions]["ssl_cert"] && !opts[:JekyllOptions]["ssl_key"]
|
|
205
|
+
if !opts[:JekyllOptions]["ssl_cert"] || !opts[:JekyllOptions]["ssl_key"]
|
|
206
|
+
raise RuntimeError, "--ssl-cert or --ssl-key missing."
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
require "openssl"
|
|
210
|
+
require "webrick/https"
|
|
211
|
+
source_key = Jekyll.sanitized_path(opts[:JekyllOptions]["source"], opts[:JekyllOptions]["ssl_key" ])
|
|
212
|
+
source_certificate = Jekyll.sanitized_path(opts[:JekyllOptions]["source"], opts[:JekyllOptions]["ssl_cert"])
|
|
213
|
+
opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.read(source_certificate))
|
|
214
|
+
opts[:SSLPrivateKey ] = OpenSSL::PKey::RSA.new(File.read(source_key))
|
|
215
|
+
opts[:EnableSSL] = true
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
private
|
|
219
|
+
def start_callback(detached)
|
|
220
|
+
unless detached
|
|
221
|
+
proc do
|
|
222
|
+
Jekyll.logger.info("Server running...", "press ctrl-c to stop.")
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
private
|
|
228
|
+
def mime_types
|
|
229
|
+
file = File.expand_path('../mime.types', File.dirname(__FILE__))
|
|
230
|
+
WEBrick::HTTPUtils.load_mime_types(file)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require "webrick"
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module Commands
|
|
5
|
+
class Serve
|
|
6
|
+
class Servlet < WEBrick::HTTPServlet::FileHandler
|
|
7
|
+
DEFAULTS = {
|
|
8
|
+
"Cache-Control" => "private, max-age=0, proxy-revalidate, " \
|
|
9
|
+
"no-store, no-cache, must-revalidate"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
def initialize(server, root, callbacks)
|
|
13
|
+
# So we can access them easily.
|
|
14
|
+
@jekyll_opts = server.config[:JekyllOptions]
|
|
15
|
+
set_defaults
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Add the ability to tap file.html the same way that Nginx does on our
|
|
20
|
+
# Docker images (or on GitHub Pages.) The difference is that we might end
|
|
21
|
+
# up with a different preference on which comes first.
|
|
22
|
+
|
|
23
|
+
def search_file(req, res, basename)
|
|
24
|
+
# /file.* > /file/index.html > /file.html
|
|
25
|
+
super || super(req, res, "#{basename}.html")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
|
|
30
|
+
def do_GET(req, res)
|
|
31
|
+
rtn = super
|
|
32
|
+
validate_and_ensure_charset(req, res)
|
|
33
|
+
res.header.merge!(@headers)
|
|
34
|
+
rtn
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
def validate_and_ensure_charset(_req, res)
|
|
41
|
+
key = res.header.keys.grep(/content-type/i).first
|
|
42
|
+
typ = res.header[key]
|
|
43
|
+
|
|
44
|
+
unless typ =~ /;\s*charset=/
|
|
45
|
+
res.header[key] = "#{typ}; charset=#{@jekyll_opts["encoding"]}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
#
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
def set_defaults
|
|
53
|
+
hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {})
|
|
54
|
+
DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash|
|
|
55
|
+
hash[key] = val unless hash.key?(key)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
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
|
+
'plugins_dir' => '_plugins',
|
|
12
|
+
'layouts_dir' => '_layouts',
|
|
13
|
+
'data_dir' => '_data',
|
|
14
|
+
'includes_dir' => '_includes',
|
|
15
|
+
'collections' => {},
|
|
16
|
+
|
|
17
|
+
# Handling Reading
|
|
18
|
+
'safe' => false,
|
|
19
|
+
'include' => ['.htaccess'],
|
|
20
|
+
'exclude' => [],
|
|
21
|
+
'keep_files' => ['.git', '.svn'],
|
|
22
|
+
'encoding' => 'utf-8',
|
|
23
|
+
'markdown_ext' => 'markdown,mkdown,mkdn,mkd,md',
|
|
24
|
+
|
|
25
|
+
# Filtering Content
|
|
26
|
+
'show_drafts' => nil,
|
|
27
|
+
'limit_posts' => 0,
|
|
28
|
+
'future' => false,
|
|
29
|
+
'unpublished' => false,
|
|
30
|
+
|
|
31
|
+
# Plugins
|
|
32
|
+
'whitelist' => [],
|
|
33
|
+
'gems' => [],
|
|
34
|
+
|
|
35
|
+
# Conversion
|
|
36
|
+
'markdown' => 'kramdown',
|
|
37
|
+
'highlighter' => 'rouge',
|
|
38
|
+
'lsi' => false,
|
|
39
|
+
'excerpt_separator' => "\n\n",
|
|
40
|
+
'incremental' => false,
|
|
41
|
+
|
|
42
|
+
# Serving
|
|
43
|
+
'detach' => false, # default to not detaching the server
|
|
44
|
+
'port' => '4000',
|
|
45
|
+
'host' => '127.0.0.1',
|
|
46
|
+
'baseurl' => '',
|
|
47
|
+
|
|
48
|
+
# Output Configuration
|
|
49
|
+
'permalink' => 'date',
|
|
50
|
+
'paginate_path' => '/page:num',
|
|
51
|
+
'timezone' => nil, # use the local timezone
|
|
52
|
+
|
|
53
|
+
'quiet' => false,
|
|
54
|
+
'verbose' => false,
|
|
55
|
+
'defaults' => [],
|
|
56
|
+
|
|
57
|
+
'rdiscount' => {
|
|
58
|
+
'extensions' => []
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
'redcarpet' => {
|
|
62
|
+
'extensions' => []
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
'kramdown' => {
|
|
66
|
+
'auto_ids' => true,
|
|
67
|
+
'toc_levels' => '1..6',
|
|
68
|
+
'entity_output' => 'as_char',
|
|
69
|
+
'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo',
|
|
70
|
+
'input' => "GFM",
|
|
71
|
+
'hard_wrap' => false,
|
|
72
|
+
'footnote_nr' => 1
|
|
73
|
+
}
|
|
74
|
+
}]
|
|
75
|
+
|
|
76
|
+
# Public: Turn all keys into string
|
|
77
|
+
#
|
|
78
|
+
# Return a copy of the hash where all its keys are strings
|
|
79
|
+
def stringify_keys
|
|
80
|
+
reduce({}) { |hsh, (k, v)| hsh.merge(k.to_s => v) }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def get_config_value_with_override(config_key, override)
|
|
84
|
+
override[config_key] || self[config_key] || DEFAULTS[config_key]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Public: Directory of the Jekyll source folder
|
|
88
|
+
#
|
|
89
|
+
# override - the command-line options hash
|
|
90
|
+
#
|
|
91
|
+
# Returns the path to the Jekyll source directory
|
|
92
|
+
def source(override)
|
|
93
|
+
get_config_value_with_override('source', override)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def quiet(override = {})
|
|
97
|
+
get_config_value_with_override('quiet', override)
|
|
98
|
+
end
|
|
99
|
+
alias_method :quiet?, :quiet
|
|
100
|
+
|
|
101
|
+
def verbose(override = {})
|
|
102
|
+
get_config_value_with_override('verbose', override)
|
|
103
|
+
end
|
|
104
|
+
alias_method :verbose?, :verbose
|
|
105
|
+
|
|
106
|
+
def safe_load_file(filename)
|
|
107
|
+
case File.extname(filename)
|
|
108
|
+
when /\.toml/i
|
|
109
|
+
Jekyll::External.require_with_graceful_fail('toml') unless defined?(TOML)
|
|
110
|
+
TOML.load_file(filename)
|
|
111
|
+
when /\.ya?ml/i
|
|
112
|
+
SafeYAML.load_file(filename) || {}
|
|
113
|
+
else
|
|
114
|
+
raise ArgumentError, "No parser for '#{filename}' is available. Use a .toml or .y(a)ml file instead."
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Public: Generate list of configuration files from the override
|
|
119
|
+
#
|
|
120
|
+
# override - the command-line options hash
|
|
121
|
+
#
|
|
122
|
+
# Returns an Array of config files
|
|
123
|
+
def config_files(override)
|
|
124
|
+
# Adjust verbosity quickly
|
|
125
|
+
Jekyll.logger.adjust_verbosity(:quiet => quiet?(override), :verbose => verbose?(override))
|
|
126
|
+
|
|
127
|
+
# Get configuration from <source>/_config.yml or <source>/<config_file>
|
|
128
|
+
config_files = override.delete('config')
|
|
129
|
+
if config_files.to_s.empty?
|
|
130
|
+
default = %w(yml yaml).find(-> { 'yml' }) do |ext|
|
|
131
|
+
File.exist?(Jekyll.sanitized_path(source(override), "_config.#{ext}"))
|
|
132
|
+
end
|
|
133
|
+
config_files = Jekyll.sanitized_path(source(override), "_config.#{default}")
|
|
134
|
+
@default_config_file = true
|
|
135
|
+
end
|
|
136
|
+
config_files = [config_files] unless config_files.is_a? Array
|
|
137
|
+
config_files
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Public: Read configuration and return merged Hash
|
|
141
|
+
#
|
|
142
|
+
# file - the path to the YAML file to be read in
|
|
143
|
+
#
|
|
144
|
+
# Returns this configuration, overridden by the values in the file
|
|
145
|
+
def read_config_file(file)
|
|
146
|
+
next_config = safe_load_file(file)
|
|
147
|
+
check_config_is_hash!(next_config, file)
|
|
148
|
+
Jekyll.logger.info "Configuration file:", file
|
|
149
|
+
next_config
|
|
150
|
+
rescue SystemCallError
|
|
151
|
+
if @default_config_file
|
|
152
|
+
Jekyll.logger.warn "Configuration file:", "none"
|
|
153
|
+
{}
|
|
154
|
+
else
|
|
155
|
+
Jekyll.logger.error "Fatal:", "The configuration file '#{file}' could not be found."
|
|
156
|
+
raise LoadError, "The Configuration file '#{file}' could not be found."
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Public: Read in a list of configuration files and merge with this hash
|
|
161
|
+
#
|
|
162
|
+
# files - the list of configuration file paths
|
|
163
|
+
#
|
|
164
|
+
# Returns the full configuration, with the defaults overridden by the values in the
|
|
165
|
+
# configuration files
|
|
166
|
+
def read_config_files(files)
|
|
167
|
+
configuration = clone
|
|
168
|
+
|
|
169
|
+
begin
|
|
170
|
+
files.each do |config_file|
|
|
171
|
+
new_config = read_config_file(config_file)
|
|
172
|
+
configuration = Utils.deep_merge_hashes(configuration, new_config)
|
|
173
|
+
end
|
|
174
|
+
rescue ArgumentError => err
|
|
175
|
+
Jekyll.logger.warn "WARNING:", "Error reading configuration. " \
|
|
176
|
+
"Using defaults (and options)."
|
|
177
|
+
$stderr.puts "#{err}"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
configuration.fix_common_issues.backwards_compatibilize.add_default_collections
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Public: Split a CSV string into an array containing its values
|
|
184
|
+
#
|
|
185
|
+
# csv - the string of comma-separated values
|
|
186
|
+
#
|
|
187
|
+
# Returns an array of the values contained in the CSV
|
|
188
|
+
def csv_to_array(csv)
|
|
189
|
+
csv.split(",").map(&:strip)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Public: Ensure the proper options are set in the configuration to allow for
|
|
193
|
+
# backwards-compatibility with Jekyll pre-1.0
|
|
194
|
+
#
|
|
195
|
+
# Returns the backwards-compatible configuration
|
|
196
|
+
def backwards_compatibilize
|
|
197
|
+
config = clone
|
|
198
|
+
# Provide backwards-compatibility
|
|
199
|
+
if config.key?('auto') || config.key?('watch')
|
|
200
|
+
Jekyll::Deprecator.deprecation_message "Auto-regeneration can no longer" \
|
|
201
|
+
" be set from your configuration file(s). Use the"\
|
|
202
|
+
" --[no-]watch/-w command-line option instead."
|
|
203
|
+
config.delete('auto')
|
|
204
|
+
config.delete('watch')
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
if config.key? 'server'
|
|
208
|
+
Jekyll::Deprecator.deprecation_message "The 'server' configuration option" \
|
|
209
|
+
" is no longer accepted. Use the 'jekyll serve'" \
|
|
210
|
+
" subcommand to serve your site with WEBrick."
|
|
211
|
+
config.delete('server')
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
renamed_key 'server_port', 'port', config
|
|
215
|
+
renamed_key 'plugins', 'plugins_dir', config
|
|
216
|
+
renamed_key 'layouts', 'layouts_dir', config
|
|
217
|
+
renamed_key 'data_source', 'data_dir', config
|
|
218
|
+
|
|
219
|
+
if config.key? 'pygments'
|
|
220
|
+
Jekyll::Deprecator.deprecation_message "The 'pygments' configuration option" \
|
|
221
|
+
" has been renamed to 'highlighter'. Please update your" \
|
|
222
|
+
" config file accordingly. The allowed values are 'rouge', " \
|
|
223
|
+
"'pygments' or null."
|
|
224
|
+
|
|
225
|
+
config['highlighter'] = 'pygments' if config['pygments']
|
|
226
|
+
config.delete('pygments')
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
%w(include exclude).each do |option|
|
|
230
|
+
config[option] ||= []
|
|
231
|
+
if config[option].is_a?(String)
|
|
232
|
+
Jekyll::Deprecator.deprecation_message "The '#{option}' configuration option" \
|
|
233
|
+
" must now be specified as an array, but you specified" \
|
|
234
|
+
" a string. For now, we've treated the string you provided" \
|
|
235
|
+
" as a list of comma-separated values."
|
|
236
|
+
config[option] = csv_to_array(config[option])
|
|
237
|
+
end
|
|
238
|
+
config[option].map!(&:to_s)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
if (config['kramdown'] || {}).key?('use_coderay')
|
|
242
|
+
Jekyll::Deprecator.deprecation_message "Please change 'use_coderay'" \
|
|
243
|
+
" to 'enable_coderay' in your configuration file."
|
|
244
|
+
config['kramdown']['use_coderay'] = config['kramdown'].delete('enable_coderay')
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
if config.fetch('markdown', 'kramdown').to_s.downcase.eql?("maruku")
|
|
248
|
+
Jekyll.logger.abort_with "Error:", "You're using the 'maruku' " \
|
|
249
|
+
"Markdown processor, which has been removed as of 3.0.0. " \
|
|
250
|
+
"We recommend you switch to Kramdown. To do this, replace " \
|
|
251
|
+
"`markdown: maruku` with `markdown: kramdown` in your " \
|
|
252
|
+
"`_config.yml` file."
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
config
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def fix_common_issues
|
|
259
|
+
config = clone
|
|
260
|
+
|
|
261
|
+
if config.key?('paginate') && (!config['paginate'].is_a?(Integer) || config['paginate'] < 1)
|
|
262
|
+
Jekyll.logger.warn "Config Warning:", "The `paginate` key must be a" \
|
|
263
|
+
" positive integer or nil. It's currently set to '#{config['paginate'].inspect}'."
|
|
264
|
+
config['paginate'] = nil
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
config
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def add_default_collections
|
|
271
|
+
config = clone
|
|
272
|
+
|
|
273
|
+
return config if config['collections'].nil?
|
|
274
|
+
|
|
275
|
+
if config['collections'].is_a?(Array)
|
|
276
|
+
config['collections'] = Hash[config['collections'].map { |c| [c, {}] }]
|
|
277
|
+
end
|
|
278
|
+
config['collections']['posts'] ||= {}
|
|
279
|
+
config['collections']['posts']['output'] = true
|
|
280
|
+
config['collections']['posts']['permalink'] = style_to_permalink(config['permalink'])
|
|
281
|
+
|
|
282
|
+
config
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def renamed_key(old, new, config, _ = nil)
|
|
286
|
+
if config.key?(old)
|
|
287
|
+
Jekyll::Deprecator.deprecation_message "The '#{old}' configuration" \
|
|
288
|
+
"option has been renamed to '#{new}'. Please update your config " \
|
|
289
|
+
"file accordingly."
|
|
290
|
+
config[new] = config.delete(old)
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
private
|
|
295
|
+
|
|
296
|
+
def style_to_permalink(permalink_style)
|
|
297
|
+
case permalink_style.to_sym
|
|
298
|
+
when :pretty
|
|
299
|
+
"/:categories/:year/:month/:day/:title/"
|
|
300
|
+
when :none
|
|
301
|
+
"/:categories/:title:output_ext"
|
|
302
|
+
when :date
|
|
303
|
+
"/:categories/:year/:month/:day/:title:output_ext"
|
|
304
|
+
when :ordinal
|
|
305
|
+
"/:categories/:year/:y_day/:title:output_ext"
|
|
306
|
+
else
|
|
307
|
+
permalink_style.to_s
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Private: Checks if a given config is a hash
|
|
312
|
+
#
|
|
313
|
+
# extracted_config - the value to check
|
|
314
|
+
# file - the file from which the config was extracted
|
|
315
|
+
#
|
|
316
|
+
# Raises an ArgumentError if given config is not a hash
|
|
317
|
+
def check_config_is_hash!(extracted_config, file)
|
|
318
|
+
unless extracted_config.is_a?(Hash)
|
|
319
|
+
raise ArgumentError.new("Configuration file: (INVALID) #{file}".yellow)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|