jekyll 2.0.0.alpha.1 → 2.0.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of jekyll might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +15 -0
- data/.travis.yml +27 -0
- data/History.markdown +66 -1
- data/LICENSE +2 -2
- data/README.markdown +2 -2
- data/Rakefile +4 -44
- data/bin/jekyll +10 -113
- data/docs/jp/CONTRIBUTING.jp.markdown +93 -0
- data/docs/jp/README.jp.markdown +69 -0
- data/features/create_sites.feature +12 -12
- data/features/drafts.feature +23 -2
- data/features/embed_filters.feature +7 -5
- data/features/include_tag.feature +7 -7
- data/features/markdown.feature +4 -4
- data/features/pagination.feature +2 -2
- data/features/permalinks.feature +7 -7
- data/features/post_data.feature +21 -21
- data/features/post_excerpts.feature +6 -6
- data/features/site_configuration.feature +17 -17
- data/features/site_data.feature +15 -15
- data/features/step_definitions/jekyll_steps.rb +4 -4
- data/features/support/env.rb +2 -2
- data/jekyll.gemspec +17 -284
- data/lib/jekyll.rb +21 -5
- data/lib/jekyll/command.rb +72 -20
- data/lib/jekyll/commands/build.rb +82 -58
- data/lib/jekyll/commands/docs.rb +30 -0
- data/lib/jekyll/commands/doctor.rb +18 -1
- data/lib/jekyll/commands/new.rb +19 -6
- data/lib/jekyll/commands/serve.rb +80 -49
- data/lib/jekyll/configuration.rb +3 -3
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +1 -1
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +1 -0
- data/lib/jekyll/convertible.rb +19 -21
- data/lib/jekyll/draft.rb +5 -0
- data/lib/jekyll/excerpt.rb +5 -5
- data/lib/jekyll/layout.rb +2 -2
- data/lib/jekyll/layout_reader.rb +15 -2
- data/lib/jekyll/page.rb +17 -17
- data/lib/jekyll/post.rb +33 -33
- data/lib/jekyll/related_posts.rb +5 -5
- data/lib/jekyll/site.rb +84 -85
- data/lib/jekyll/static_file.rb +13 -0
- data/lib/jekyll/stevenson.rb +1 -1
- data/lib/jekyll/tags/highlight.rb +16 -6
- data/lib/jekyll/tags/include.rb +17 -17
- data/lib/jekyll/url.rb +2 -0
- data/lib/jekyll/utils.rb +79 -0
- data/lib/jekyll/version.rb +3 -0
- data/lib/site_template/_config.yml +3 -1
- data/lib/site_template/_includes/footer.html +61 -0
- data/lib/site_template/_includes/head.html +12 -0
- data/lib/site_template/_includes/header.html +27 -0
- data/lib/site_template/_layouts/default.html +9 -34
- data/lib/site_template/_layouts/page.html +14 -0
- data/lib/site_template/_layouts/post.html +11 -5
- data/lib/site_template/_posts/0000-00-00-this-post-demonstrates-post-content-styles.md +88 -0
- data/lib/site_template/about/index.md +10 -0
- data/lib/site_template/css/main.css +333 -100
- data/lib/site_template/feed.xml +21 -0
- data/lib/site_template/index.html +8 -4
- data/lib/site_template/projects/index.md +14 -0
- data/script/cibuild +0 -1
- data/script/rebund +1 -1
- data/site/_includes/analytics.html +2 -2
- data/site/_includes/css/normalize.css +1 -1
- data/site/_includes/css/style.css +28 -4
- data/site/_includes/docs_option.html +1 -1
- data/site/_includes/docs_ul.html +3 -3
- data/site/_includes/footer.html +1 -1
- data/site/_includes/header.html +2 -2
- data/site/_includes/news_item.html +1 -1
- data/site/_includes/primary-nav-items.html +4 -4
- data/site/_includes/section_nav.html +2 -2
- data/site/_includes/top.html +6 -7
- data/site/_layouts/news_item.html +1 -1
- data/site/_posts/2013-07-25-jekyll-1-0-4-released.markdown +1 -1
- data/site/_posts/2013-07-25-jekyll-1-1-2-released.markdown +1 -1
- data/site/_posts/2013-09-14-jekyll-1-2-1-released.markdown +1 -1
- data/site/_posts/2014-03-24-jekyll-1-5-0-released.markdown +19 -0
- data/site/docs/assets.md +14 -0
- data/site/docs/configuration.md +65 -56
- data/site/docs/contributing.md +7 -2
- data/site/docs/deployment-methods.md +1 -1
- data/site/docs/github-pages.md +1 -1
- data/site/docs/history.md +21 -0
- data/site/docs/index.md +7 -1
- data/site/docs/installation.md +28 -0
- data/site/docs/migrations.md +1 -1
- data/site/docs/plugins.md +6 -0
- data/site/docs/structure.md +3 -3
- data/site/docs/templates.md +44 -44
- data/site/docs/usage.md +1 -1
- data/site/docs/variables.md +15 -2
- data/site/favicon.png +0 -0
- data/site/feed.xml +0 -1
- data/site/img/article-footer.png +0 -0
- data/site/img/footer-arrow.png +0 -0
- data/site/img/footer-logo.png +0 -0
- data/site/img/logo-2x.png +0 -0
- data/site/img/octojekyll.png +0 -0
- data/site/img/tube.png +0 -0
- data/site/img/tube1x.png +0 -0
- data/site/index.html +5 -5
- data/site/js/modernizr-2.7.1.min.js +4 -0
- data/test/helper.rb +11 -0
- data/test/source/_drafts/draft-properties.text +11 -0
- data/test/source/_posts/2011-04-12-md-extension.md +1 -1
- data/test/source/_posts/2014-01-06-permalink-traversal.md +5 -0
- data/test/source/exploit.md +5 -0
- data/test/source/static_files.html +4 -0
- data/test/test_configuration.rb +2 -2
- data/test/test_draft.rb +56 -0
- data/test/test_excerpt.rb +2 -2
- data/test/test_filters.rb +1 -1
- data/test/test_generated_site.rb +10 -1
- data/test/test_kramdown.rb +1 -1
- data/test/test_layout_reader.rb +17 -0
- data/test/test_page.rb +10 -0
- data/test/test_pager.rb +4 -2
- data/test/test_path_sanitization.rb +14 -0
- data/test/test_post.rb +12 -1
- data/test/test_sass.rb +1 -64
- data/test/test_site.rb +26 -1
- data/test/test_tags.rb +39 -2
- data/test/{test_core_ext.rb → test_utils.rb} +12 -12
- metadata +200 -86
- data/lib/jekyll/converters/sass.rb +0 -58
- data/lib/jekyll/core_ext.rb +0 -55
- data/lib/site_template/css/syntax.css +0 -60
- data/site/js/modernizr-2.5.3.min.js +0 -4
data/lib/jekyll.rb
CHANGED
@@ -27,10 +27,10 @@ require 'liquid'
|
|
27
27
|
require 'maruku'
|
28
28
|
require 'colorator'
|
29
29
|
require 'toml'
|
30
|
-
require 'sass'
|
31
30
|
|
32
31
|
# internal requires
|
33
|
-
require 'jekyll/
|
32
|
+
require 'jekyll/version'
|
33
|
+
require 'jekyll/utils'
|
34
34
|
require 'jekyll/stevenson'
|
35
35
|
require 'jekyll/deprecator'
|
36
36
|
require 'jekyll/configuration'
|
@@ -64,12 +64,11 @@ require_all 'jekyll/tags'
|
|
64
64
|
|
65
65
|
# plugins
|
66
66
|
require 'jekyll-coffeescript'
|
67
|
+
require 'jekyll-sass-converter'
|
67
68
|
|
68
69
|
SafeYAML::OPTIONS[:suppress_warnings] = true
|
69
70
|
|
70
71
|
module Jekyll
|
71
|
-
VERSION = '2.0.0.alpha.1'
|
72
|
-
|
73
72
|
# Public: Generate a Jekyll configuration Hash by merging the default
|
74
73
|
# options with anything in _config.yml, and adding the given options on top.
|
75
74
|
#
|
@@ -84,7 +83,7 @@ module Jekyll
|
|
84
83
|
config = config.read_config_files(config.config_files(override))
|
85
84
|
|
86
85
|
# Merge DEFAULTS < _config.yml < override
|
87
|
-
config =
|
86
|
+
config = Utils.deep_merge_hashes(config, override).stringify_keys
|
88
87
|
set_timezone(config['timezone']) if config['timezone']
|
89
88
|
|
90
89
|
config
|
@@ -102,4 +101,21 @@ module Jekyll
|
|
102
101
|
def self.logger
|
103
102
|
@logger ||= Stevenson.new
|
104
103
|
end
|
104
|
+
|
105
|
+
# Public: File system root
|
106
|
+
#
|
107
|
+
# Returns the root of the filesystem as a Pathname
|
108
|
+
def self.fs_root
|
109
|
+
@fs_root ||= "/"
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.sanitized_path(base_directory, questionable_path)
|
113
|
+
clean_path = File.expand_path(questionable_path, fs_root)
|
114
|
+
clean_path.gsub!(/\w\:\//, '/')
|
115
|
+
unless clean_path.start_with?(base_directory)
|
116
|
+
File.join(base_directory, clean_path)
|
117
|
+
else
|
118
|
+
clean_path
|
119
|
+
end
|
120
|
+
end
|
105
121
|
end
|
data/lib/jekyll/command.rb
CHANGED
@@ -1,27 +1,79 @@
|
|
1
1
|
module Jekyll
|
2
2
|
class Command
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# A list of subclasses of Jekyll::Command
|
7
|
+
def subclasses
|
8
|
+
@subclasses ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
# Keep a list of subclasses of Jekyll::Command every time it's inherited
|
12
|
+
# Called automatically.
|
13
|
+
#
|
14
|
+
# base - the subclass
|
15
|
+
#
|
16
|
+
# Returns nothing
|
17
|
+
def inherited(base)
|
18
|
+
subclasses << base
|
19
|
+
super(base)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Listing of all directories (globbed to include subfiles and folders)
|
23
|
+
#
|
24
|
+
# source - the source path
|
25
|
+
# destination - the destination path
|
26
|
+
#
|
27
|
+
# Returns an Array of directory globs in the source, excluding the destination
|
28
|
+
def globs(source, destination)
|
29
|
+
Dir.chdir(source) do
|
30
|
+
dirs = Dir['*'].select { |x| File.directory?(x) }
|
31
|
+
dirs -= [destination, File.expand_path(destination), File.basename(destination)]
|
32
|
+
dirs = dirs.map { |x| "#{x}/**/*" }
|
33
|
+
dirs += ['*']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Run Site#process and catch errors
|
38
|
+
#
|
39
|
+
# site - the Jekyll::Site object
|
40
|
+
#
|
41
|
+
# Returns nothing
|
42
|
+
def process_site(site)
|
43
|
+
site.process
|
44
|
+
rescue Jekyll::FatalException => e
|
45
|
+
Jekyll.logger.error "ERROR:", "YOUR SITE COULD NOT BE BUILT:"
|
46
|
+
Jekyll.logger.error "", "------------------------------------"
|
47
|
+
Jekyll.logger.error "", e.message
|
48
|
+
exit(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create a full Jekyll configuration with the options passed in as overrides
|
52
|
+
#
|
53
|
+
# options - the configuration overrides
|
54
|
+
#
|
55
|
+
# Returns a full Jekyll configuration
|
56
|
+
def configuration_from_options(options)
|
57
|
+
Jekyll.configuration(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Add common options to a command for building configuration
|
61
|
+
#
|
62
|
+
# c - the Jekyll::Command to add these options to
|
63
|
+
#
|
64
|
+
# Returns nothing
|
65
|
+
def add_build_options(c)
|
66
|
+
c.option 'config', '--config CONFIG_FILE[,CONFIG_FILE2,...]', Array, 'Custom configuration file'
|
67
|
+
c.option 'future', '--future', 'Publishes posts with a future date'
|
68
|
+
c.option 'limit_posts', '--limit_posts MAX_POSTS', Integer, 'Limits the number of posts to parse and publish'
|
69
|
+
c.option 'watch', '-w', '--watch', 'Watch for changes and rebuild'
|
70
|
+
c.option 'lsi', '--lsi', 'Use LSI for improved related posts'
|
71
|
+
c.option 'show_drafts', '-D', '--drafts', 'Render posts in the _drafts folder'
|
72
|
+
c.option 'quiet', '-q', '--quiet', 'Silence output.'
|
73
|
+
c.option 'verbose', '-V', '--verbose', 'Print verbose output.'
|
9
74
|
end
|
10
|
-
end
|
11
75
|
|
12
|
-
# Static: Run Site#process and catch errors
|
13
|
-
#
|
14
|
-
# site - the Jekyll::Site object
|
15
|
-
#
|
16
|
-
# Returns nothing
|
17
|
-
def self.process_site(site)
|
18
|
-
site.process
|
19
|
-
rescue Jekyll::FatalException => e
|
20
|
-
puts
|
21
|
-
Jekyll.logger.error "ERROR:", "YOUR SITE COULD NOT BE BUILT:"
|
22
|
-
Jekyll.logger.error "", "------------------------------------"
|
23
|
-
Jekyll.logger.error "", e.message
|
24
|
-
exit(1)
|
25
76
|
end
|
77
|
+
|
26
78
|
end
|
27
79
|
end
|
@@ -1,72 +1,96 @@
|
|
1
1
|
module Jekyll
|
2
2
|
module Commands
|
3
3
|
class Build < Command
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
source = options['source']
|
21
|
-
destination = options['destination']
|
22
|
-
Jekyll.logger.info "Source:", source
|
23
|
-
Jekyll.logger.info "Destination:", destination
|
24
|
-
print Jekyll.logger.formatted_topic "Generating..."
|
25
|
-
self.process_site(site)
|
26
|
-
puts "done."
|
27
|
-
end
|
28
|
-
|
29
|
-
# Private: Watch for file changes and rebuild the site.
|
30
|
-
#
|
31
|
-
# site - A Jekyll::Site instance
|
32
|
-
# options - A Hash of options passed to the command
|
33
|
-
#
|
34
|
-
# Returns nothing.
|
35
|
-
def self.watch(site, options)
|
36
|
-
require 'listen'
|
37
|
-
|
38
|
-
source = options['source']
|
39
|
-
destination = options['destination']
|
40
|
-
|
41
|
-
begin
|
42
|
-
dest = Pathname.new(destination).relative_path_from(Pathname.new(source)).to_s
|
43
|
-
ignored = Regexp.new(Regexp.escape(dest))
|
44
|
-
rescue ArgumentError
|
45
|
-
# Destination is outside the source, no need to ignore it.
|
46
|
-
ignored = nil
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# Create the Mercenary command for the Jekyll CLI for this Command
|
8
|
+
def init_with_program(prog)
|
9
|
+
prog.command(:build) do |c|
|
10
|
+
c.syntax 'build [options]'
|
11
|
+
c.description 'Build your site'
|
12
|
+
|
13
|
+
add_build_options(c)
|
14
|
+
|
15
|
+
c.action do |args, options|
|
16
|
+
options["serving"] = false
|
17
|
+
Jekyll::Commands::Build.process(options)
|
18
|
+
end
|
19
|
+
end
|
47
20
|
end
|
48
21
|
|
49
|
-
|
22
|
+
# Build your jekyll site
|
23
|
+
# Continuously watch if `watch` is set to true in the config.
|
24
|
+
def process(options)
|
25
|
+
options = configuration_from_options(options)
|
26
|
+
site = Jekyll::Site.new(options)
|
50
27
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
28
|
+
Jekyll.logger.log_level = Jekyll::Stevenson::ERROR if options['quiet']
|
29
|
+
|
30
|
+
build(site, options)
|
31
|
+
watch(site, options) if options['watch']
|
32
|
+
end
|
33
|
+
|
34
|
+
# Build your Jekyll site.
|
35
|
+
#
|
36
|
+
# site - the Jekyll::Site instance to build
|
37
|
+
# options - the
|
38
|
+
#
|
39
|
+
# Returns nothing.
|
40
|
+
def build(site, options)
|
41
|
+
source = options['source']
|
42
|
+
destination = options['destination']
|
43
|
+
Jekyll.logger.info "Source:", source
|
44
|
+
Jekyll.logger.info "Destination:", destination
|
45
|
+
Jekyll.logger.info "Generating..."
|
46
|
+
process_site(site)
|
47
|
+
Jekyll.logger.info "", "done."
|
57
48
|
end
|
58
|
-
listener.start
|
59
49
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
50
|
+
# Private: Watch for file changes and rebuild the site.
|
51
|
+
#
|
52
|
+
# site - A Jekyll::Site instance
|
53
|
+
# options - A Hash of options passed to the command
|
54
|
+
#
|
55
|
+
# Returns nothing.
|
56
|
+
def watch(site, options)
|
57
|
+
require 'listen'
|
58
|
+
|
59
|
+
source = options['source']
|
60
|
+
destination = options['destination']
|
61
|
+
|
62
|
+
begin
|
63
|
+
dest = Pathname.new(destination).relative_path_from(Pathname.new(source)).to_s
|
64
|
+
ignored = Regexp.new(Regexp.escape(dest))
|
65
|
+
rescue ArgumentError
|
66
|
+
# Destination is outside the source, no need to ignore it.
|
67
|
+
ignored = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
Jekyll.logger.info "Auto-regeneration:", "enabled"
|
71
|
+
|
72
|
+
listener = Listen.to(source, :ignore => ignored) do |modified, added, removed|
|
73
|
+
t = Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
74
|
+
n = modified.length + added.length + removed.length
|
75
|
+
print Jekyll.logger.formatted_topic("Regenerating:") + "#{n} files at #{t} "
|
76
|
+
process_site(site)
|
77
|
+
puts "...done."
|
65
78
|
end
|
79
|
+
listener.start
|
66
80
|
|
67
|
-
|
81
|
+
unless options['serving']
|
82
|
+
trap("INT") do
|
83
|
+
listener.stop
|
84
|
+
puts " Halting auto-regeneration."
|
85
|
+
exit 0
|
86
|
+
end
|
87
|
+
|
88
|
+
loop { sleep 1000 }
|
89
|
+
end
|
68
90
|
end
|
69
|
-
|
91
|
+
|
92
|
+
end # end of class << self
|
93
|
+
|
70
94
|
end
|
71
95
|
end
|
72
96
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Commands
|
3
|
+
class Docs < Command
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def init_with_program(prog)
|
8
|
+
prog.command(:docs) do |c|
|
9
|
+
c.syntax 'docs'
|
10
|
+
c.description "Launch local server with docs for Jekyll v#{Jekyll::VERSION}"
|
11
|
+
|
12
|
+
c.option 'port', '-P', '--port [PORT]', 'Port to listen on'
|
13
|
+
c.option 'host', '-H', '--host [HOST]', 'Host to bind to'
|
14
|
+
|
15
|
+
c.action do |args, options|
|
16
|
+
options.merge!({
|
17
|
+
'source' => File.expand_path("../../../site", File.dirname(__FILE__)),
|
18
|
+
'destination' => File.expand_path("../../../site/_site", File.dirname(__FILE__))
|
19
|
+
})
|
20
|
+
Jekyll::Commands::Build.process(options)
|
21
|
+
Jekyll::Commands::Serve.process(options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -2,8 +2,23 @@ module Jekyll
|
|
2
2
|
module Commands
|
3
3
|
class Doctor < Command
|
4
4
|
class << self
|
5
|
+
|
6
|
+
def init_with_program(prog)
|
7
|
+
prog.command(:doctor) do |c|
|
8
|
+
c.syntax 'doctor'
|
9
|
+
c.description 'Search site and print specific deprecation warnings'
|
10
|
+
c.alias(:hyde)
|
11
|
+
|
12
|
+
c.option '--config CONFIG_FILE[,CONFIG_FILE2,...]', Array, 'Custom configuration file'
|
13
|
+
|
14
|
+
c.action do |args, options|
|
15
|
+
Jekyll::Commands::Doctor.process(options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
5
20
|
def process(options)
|
6
|
-
site = Jekyll::Site.new(options)
|
21
|
+
site = Jekyll::Site.new(configuration_from_options(options))
|
7
22
|
site.read
|
8
23
|
|
9
24
|
if healthy?(site)
|
@@ -61,7 +76,9 @@ module Jekyll
|
|
61
76
|
end
|
62
77
|
urls
|
63
78
|
end
|
79
|
+
|
64
80
|
end
|
81
|
+
|
65
82
|
end
|
66
83
|
end
|
67
84
|
end
|
data/lib/jekyll/commands/new.rb
CHANGED
@@ -3,23 +3,36 @@ require 'erb'
|
|
3
3
|
module Jekyll
|
4
4
|
module Commands
|
5
5
|
class New < Command
|
6
|
+
def self.init_with_program(prog)
|
7
|
+
prog.command(:new) do |c|
|
8
|
+
c.syntax 'new PATH'
|
9
|
+
c.description 'Creates a new Jekyll site scaffold in PATH'
|
10
|
+
|
11
|
+
c.option 'force', '--force', 'Force creation even if PATH already exists'
|
12
|
+
c.option 'blank', '--blank', 'Creates scaffolding but with empty files'
|
13
|
+
|
14
|
+
c.action do |args, options|
|
15
|
+
Jekyll::Commands::New.process(args, options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
6
20
|
def self.process(args, options = {})
|
7
21
|
raise ArgumentError.new('You must specify a path.') if args.empty?
|
8
22
|
|
9
23
|
new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
|
10
24
|
FileUtils.mkdir_p new_blog_path
|
11
25
|
if preserve_source_location?(new_blog_path, options)
|
12
|
-
Jekyll.logger.
|
13
|
-
exit(1)
|
26
|
+
Jekyll.logger.abort_with "Conflict:", "#{new_blog_path} exists and is not empty."
|
14
27
|
end
|
15
28
|
|
16
|
-
if options[
|
29
|
+
if options["blank"]
|
17
30
|
create_blank_site new_blog_path
|
18
31
|
else
|
19
32
|
create_sample_files new_blog_path
|
20
33
|
|
21
|
-
File.open(File.expand_path(
|
22
|
-
f.write(
|
34
|
+
File.open(File.expand_path(initialized_post_name, new_blog_path), "w") do |f|
|
35
|
+
f.write(scaffold_post_content)
|
23
36
|
end
|
24
37
|
end
|
25
38
|
|
@@ -47,7 +60,7 @@ module Jekyll
|
|
47
60
|
private
|
48
61
|
|
49
62
|
def self.preserve_source_location?(path, options)
|
50
|
-
!options[
|
63
|
+
!options["force"] && !Dir["#{path}/**/*"].empty?
|
51
64
|
end
|
52
65
|
|
53
66
|
def self.create_sample_files(path)
|
@@ -2,74 +2,105 @@
|
|
2
2
|
module Jekyll
|
3
3
|
module Commands
|
4
4
|
class Serve < Command
|
5
|
-
def self.process(options)
|
6
|
-
require 'webrick'
|
7
|
-
include WEBrick
|
8
5
|
|
9
|
-
|
6
|
+
class << self
|
10
7
|
|
11
|
-
|
8
|
+
def init_with_program(prog)
|
9
|
+
prog.command(:serve) do |c|
|
10
|
+
c.syntax 'serve [options]'
|
11
|
+
c.description 'Serve your site locally'
|
12
|
+
c.alias :server
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
add_build_options(c)
|
15
|
+
|
16
|
+
c.option 'detach', '-B', '--detach', 'Run the server in the background (detach)'
|
17
|
+
c.option 'port', '-P', '--port [PORT]', 'Port to listen on'
|
18
|
+
c.option 'host', '-H', '--host [HOST]', 'Host to bind to'
|
19
|
+
c.option 'baseurl', '-b', '--baseurl [URL]', 'Base URL'
|
20
|
+
|
21
|
+
c.action do |args, options|
|
22
|
+
options["serving"] ||= true
|
23
|
+
Jekyll::Commands::Build.process(options)
|
24
|
+
Jekyll::Commands::Serve.process(options)
|
18
25
|
end
|
19
26
|
end
|
20
27
|
end
|
21
28
|
|
22
|
-
#
|
23
|
-
|
24
|
-
|
29
|
+
# Boot up a WEBrick server which points to the compiled site's root.
|
30
|
+
def process(options)
|
31
|
+
options = configuration_from_options(options)
|
32
|
+
|
33
|
+
require 'webrick'
|
34
|
+
|
35
|
+
destination = options['destination']
|
36
|
+
|
37
|
+
FileUtils.mkdir_p(destination)
|
38
|
+
|
39
|
+
# monkey patch WEBrick using custom 404 page (/404.html)
|
40
|
+
if File.exists?(File.join(destination, '404.html'))
|
41
|
+
WEBrick::HTTPResponse.class_eval do
|
42
|
+
def create_error_page
|
43
|
+
@body = IO.read(File.join(@config[:DocumentRoot], '404.html'))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# recreate NondisclosureName under utf-8 circumstance
|
49
|
+
fh_option = WEBrick::Config::FileHandler
|
50
|
+
fh_option[:NondisclosureName] = ['.ht*','~*']
|
51
|
+
|
52
|
+
s = WEBrick::HTTPServer.new(webrick_options(options))
|
25
53
|
|
26
|
-
|
54
|
+
s.config.store(:DirectoryIndex, s.config[:DirectoryIndex] << "index.xml")
|
27
55
|
|
28
|
-
|
56
|
+
s.mount(options['baseurl'], WEBrick::HTTPServlet::FileHandler, destination, fh_option)
|
29
57
|
|
30
|
-
|
58
|
+
Jekyll.logger.info "Server address:", "http://#{s.config[:BindAddress]}:#{s.config[:Port]}"
|
31
59
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
60
|
+
if options['detach'] # detach the server
|
61
|
+
pid = Process.fork { s.start }
|
62
|
+
Process.detach(pid)
|
63
|
+
Jekyll.logger.info "Server detached with pid '#{pid}'.", "Run `kill -9 #{pid}' to stop the server."
|
64
|
+
else # create a new server thread, then join it with current terminal
|
65
|
+
t = Thread.new { s.start }
|
66
|
+
trap("INT") { s.shutdown }
|
67
|
+
t.join
|
68
|
+
end
|
40
69
|
end
|
41
|
-
end
|
42
70
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
71
|
+
def webrick_options(config)
|
72
|
+
opts = {
|
73
|
+
:DocumentRoot => config['destination'],
|
74
|
+
:Port => config['port'],
|
75
|
+
:BindAddress => config['host'],
|
76
|
+
:MimeTypes => mime_types,
|
77
|
+
:DoNotReverseLookup => true,
|
78
|
+
:StartCallback => start_callback(config['detach'])
|
79
|
+
}
|
80
|
+
|
81
|
+
if !config['verbose']
|
82
|
+
opts.merge!({
|
83
|
+
:AccessLog => [],
|
84
|
+
:Logger => WEBrick::Log.new([], WEBrick::Log::WARN)
|
85
|
+
})
|
86
|
+
end
|
87
|
+
|
88
|
+
opts
|
58
89
|
end
|
59
90
|
|
60
|
-
|
61
|
-
|
91
|
+
def start_callback(detached)
|
92
|
+
unless detached
|
93
|
+
Proc.new { Jekyll.logger.info "Server running...", "press ctrl-c to stop." }
|
94
|
+
end
|
95
|
+
end
|
62
96
|
|
63
|
-
|
64
|
-
|
65
|
-
|
97
|
+
def mime_types
|
98
|
+
mime_types_file = File.expand_path('../mime.types', File.dirname(__FILE__))
|
99
|
+
WEBrick::HTTPUtils::load_mime_types(mime_types_file)
|
66
100
|
end
|
67
|
-
end
|
68
101
|
|
69
|
-
def self.mime_types
|
70
|
-
mime_types_file = File.expand_path('../mime.types', File.dirname(__FILE__))
|
71
|
-
WEBrick::HTTPUtils::load_mime_types(mime_types_file)
|
72
102
|
end
|
103
|
+
|
73
104
|
end
|
74
105
|
end
|
75
106
|
end
|