jekyll 3.9.3 → 4.4.1
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 +4 -4
- data/.rubocop.yml +511 -89
- data/LICENSE +1 -1
- data/README.markdown +48 -27
- data/lib/blank_template/_config.yml +3 -0
- data/lib/blank_template/_layouts/default.html +12 -0
- data/lib/blank_template/_sass/base.scss +9 -0
- data/lib/blank_template/assets/css/main.scss +4 -0
- data/lib/blank_template/index.md +8 -0
- data/lib/jekyll/cache.rb +186 -0
- data/lib/jekyll/cleaner.rb +8 -7
- data/lib/jekyll/collection.rb +84 -11
- data/lib/jekyll/command.rb +33 -6
- data/lib/jekyll/commands/build.rb +8 -28
- data/lib/jekyll/commands/clean.rb +3 -2
- data/lib/jekyll/commands/doctor.rb +46 -35
- data/lib/jekyll/commands/help.rb +1 -1
- data/lib/jekyll/commands/new.rb +44 -50
- data/lib/jekyll/commands/new_theme.rb +27 -28
- data/lib/jekyll/commands/serve/live_reload_reactor.rb +9 -16
- data/lib/jekyll/commands/serve/servlet.rb +21 -22
- data/lib/jekyll/commands/serve/websockets.rb +1 -1
- data/lib/jekyll/commands/serve.rb +75 -97
- data/lib/jekyll/configuration.rb +66 -158
- data/lib/jekyll/converters/identity.rb +18 -0
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +83 -33
- data/lib/jekyll/converters/markdown.rb +49 -40
- data/lib/jekyll/converters/smartypants.rb +34 -14
- data/lib/jekyll/convertible.rb +36 -34
- data/lib/jekyll/deprecator.rb +2 -4
- data/lib/jekyll/document.rb +107 -72
- data/lib/jekyll/drops/collection_drop.rb +3 -4
- data/lib/jekyll/drops/document_drop.rb +9 -3
- data/lib/jekyll/drops/drop.rb +115 -33
- data/lib/jekyll/drops/excerpt_drop.rb +8 -0
- data/lib/jekyll/drops/site_drop.rb +9 -8
- data/lib/jekyll/drops/static_file_drop.rb +4 -4
- data/lib/jekyll/drops/theme_drop.rb +39 -0
- data/lib/jekyll/drops/unified_payload_drop.rb +7 -2
- data/lib/jekyll/drops/url_drop.rb +55 -3
- data/lib/jekyll/entry_filter.rb +42 -51
- data/lib/jekyll/excerpt.rb +48 -38
- data/lib/jekyll/external.rb +20 -19
- data/lib/jekyll/filters/date_filters.rb +6 -3
- data/lib/jekyll/filters/grouping_filters.rb +1 -2
- data/lib/jekyll/filters/url_filters.rb +50 -15
- data/lib/jekyll/filters.rb +211 -50
- data/lib/jekyll/frontmatter_defaults.rb +45 -36
- data/lib/jekyll/hooks.rb +26 -26
- data/lib/jekyll/inclusion.rb +32 -0
- data/lib/jekyll/layout.rb +12 -19
- data/lib/jekyll/liquid_extensions.rb +0 -2
- data/lib/jekyll/liquid_renderer/file.rb +24 -3
- data/lib/jekyll/liquid_renderer/table.rb +26 -77
- data/lib/jekyll/liquid_renderer.rb +31 -16
- data/lib/jekyll/log_adapter.rb +5 -1
- data/lib/jekyll/page.rb +51 -23
- data/lib/jekyll/page_excerpt.rb +25 -0
- data/lib/jekyll/page_without_a_file.rb +0 -4
- data/lib/jekyll/path_manager.rb +74 -0
- data/lib/jekyll/plugin.rb +5 -11
- data/lib/jekyll/plugin_manager.rb +15 -5
- data/lib/jekyll/profiler.rb +51 -0
- data/lib/jekyll/reader.rb +65 -10
- data/lib/jekyll/readers/collection_reader.rb +1 -0
- data/lib/jekyll/readers/data_reader.rb +48 -10
- data/lib/jekyll/readers/layout_reader.rb +3 -12
- data/lib/jekyll/readers/page_reader.rb +5 -5
- data/lib/jekyll/readers/post_reader.rb +32 -19
- data/lib/jekyll/readers/static_file_reader.rb +4 -4
- data/lib/jekyll/readers/theme_assets_reader.rb +8 -5
- data/lib/jekyll/regenerator.rb +4 -12
- data/lib/jekyll/related_posts.rb +1 -1
- data/lib/jekyll/renderer.rb +34 -49
- data/lib/jekyll/site.rb +151 -58
- data/lib/jekyll/static_file.rb +64 -28
- data/lib/jekyll/stevenson.rb +4 -8
- data/lib/jekyll/tags/highlight.rb +44 -57
- data/lib/jekyll/tags/include.rb +114 -80
- data/lib/jekyll/tags/link.rb +12 -7
- data/lib/jekyll/tags/post_url.rb +33 -30
- data/lib/jekyll/theme.rb +20 -18
- data/lib/jekyll/theme_builder.rb +91 -89
- data/lib/jekyll/url.rb +18 -10
- data/lib/jekyll/utils/ansi.rb +2 -2
- data/lib/jekyll/utils/exec.rb +0 -1
- data/lib/jekyll/utils/internet.rb +2 -4
- data/lib/jekyll/utils/platforms.rb +37 -52
- data/lib/jekyll/utils/thread_event.rb +1 -5
- data/lib/jekyll/utils.rb +29 -28
- data/lib/jekyll/version.rb +1 -1
- data/lib/jekyll.rb +9 -14
- data/lib/site_template/.gitignore +2 -0
- data/lib/site_template/404.html +2 -1
- data/lib/site_template/_config.yml +17 -5
- data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
- data/lib/theme_template/README.md.erb +1 -3
- data/lib/theme_template/gitignore.erb +1 -0
- data/lib/theme_template/theme.gemspec.erb +1 -4
- data/rubocop/jekyll/assert_equal_literal_actual.rb +150 -0
- data/rubocop/jekyll/no_p_allowed.rb +5 -6
- data/rubocop/jekyll/no_puts_allowed.rb +5 -6
- metadata +149 -37
- data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
- data/lib/jekyll/utils/rouge.rb +0 -22
- /data/lib/site_template/{about.md → about.markdown} +0 -0
- /data/lib/site_template/{index.md → index.markdown} +0 -0
data/README.markdown
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
# [Jekyll](https://jekyllrb.com/)
|
|
2
2
|
|
|
3
3
|
[][ruby-gems]
|
|
4
|
-
[](coverage)
|
|
8
|
-
[][gemnasium]
|
|
9
|
-
[][hakiri]
|
|
4
|
+
[][ci-workflow]
|
|
5
|
+
[](#backers)
|
|
6
|
+
[](#sponsors)
|
|
10
7
|
|
|
11
8
|
[ruby-gems]: https://rubygems.org/gems/jekyll
|
|
12
|
-
[
|
|
13
|
-
[codeclimate]: https://codeclimate.com/github/jekyll/jekyll
|
|
14
|
-
[coverage]: https://codeclimate.com/github/jekyll/jekyll/coverage
|
|
15
|
-
[hakiri]: https://hakiri.io/github/jekyll/jekyll/master
|
|
16
|
-
[travis]: https://travis-ci.org/jekyll/jekyll
|
|
9
|
+
[ci-workflow]: https://github.com/jekyll/jekyll/actions?query=workflow%3A%22Continuous+Integration%22+branch%3Amaster
|
|
17
10
|
[appveyor]: https://ci.appveyor.com/project/jekyll/jekyll/branch/master
|
|
18
11
|
|
|
19
12
|
Jekyll is a simple, blog-aware, static site generator perfect for personal, project, or organization sites. Think of it like a file-based CMS, without all the complexity. Jekyll takes your content, renders Markdown and Liquid templates, and spits out a complete, static website ready to be served by Apache, Nginx or another web server. Jekyll is the engine behind [GitHub Pages](https://pages.github.com), which you can use to host sites right from your GitHub repositories.
|
|
@@ -22,39 +15,67 @@ Jekyll is a simple, blog-aware, static site generator perfect for personal, proj
|
|
|
22
15
|
|
|
23
16
|
Jekyll does what you tell it to do — no more, no less. It doesn't try to outsmart users by making bold assumptions, nor does it burden them with needless complexity and configuration. Put simply, Jekyll gets out of your way and allows you to concentrate on what truly matters: your content.
|
|
24
17
|
|
|
25
|
-
See: https://jekyllrb.com/philosophy
|
|
26
|
-
|
|
27
|
-
## Having trouble?
|
|
28
|
-
|
|
29
|
-
See: https://jekyllrb.com/docs/troubleshooting/
|
|
18
|
+
See: [https://jekyllrb.com/philosophy](https://jekyllrb.com/philosophy)
|
|
30
19
|
|
|
31
20
|
## Getting Started
|
|
32
21
|
|
|
33
22
|
* [Install](https://jekyllrb.com/docs/installation/) the gem
|
|
34
23
|
* Read up about its [Usage](https://jekyllrb.com/docs/usage/) and [Configuration](https://jekyllrb.com/docs/configuration/)
|
|
35
|
-
* Take a gander at some existing [Sites](https://
|
|
24
|
+
* Take a gander at some existing [Sites](https://github.com/jekyll/jekyll/wiki/sites)
|
|
36
25
|
* [Fork](https://github.com/jekyll/jekyll/fork) and [Contribute](https://jekyllrb.com/docs/contributing/) your own modifications
|
|
37
|
-
* Have questions? Check out our official forum community [Jekyll Talk](https://talk.jekyllrb.com/)
|
|
26
|
+
* Have questions? Check out our official forum community [Jekyll Talk](https://talk.jekyllrb.com/) and [`#jekyll` Channel on Libera IRC](https://libera.chat)
|
|
27
|
+
|
|
28
|
+
## Diving In
|
|
29
|
+
|
|
30
|
+
* [Migrate](https://import.jekyllrb.com/docs/home/) from your previous system
|
|
31
|
+
* Learn how [Front Matter](https://jekyllrb.com/docs/front-matter/) works
|
|
32
|
+
* Put information on your site with [Variables](https://jekyllrb.com/docs/variables/)
|
|
33
|
+
* Customize the [Permalinks](https://jekyllrb.com/docs/permalinks/) your posts are generated with
|
|
34
|
+
* Use the built-in [Liquid Extensions](https://jekyllrb.com/docs/templates/) to make your life easier
|
|
35
|
+
* Use custom [Plugins](https://jekyllrb.com/docs/plugins/) to generate content specific to your site
|
|
36
|
+
* Watch [video tutorials from Giraffe Academy](https://jekyllrb.com/tutorials/video-walkthroughs/)
|
|
37
|
+
|
|
38
|
+
## Need help?
|
|
39
|
+
|
|
40
|
+
If you don't find the answer to your problem in our [docs](https://jekyllrb.com/docs/), or in the [troubleshooting section](https://jekyllrb.com/docs/troubleshooting/), ask the [community](https://jekyllrb.com/docs/community/) for help.
|
|
38
41
|
|
|
39
42
|
## Code of Conduct
|
|
40
43
|
|
|
41
44
|
In order to have a more open and welcoming community, Jekyll adheres to a
|
|
42
|
-
[code of conduct](
|
|
45
|
+
[code of conduct](https://jekyllrb.com/docs/conduct/) adapted from the Ruby on Rails code of
|
|
43
46
|
conduct.
|
|
44
47
|
|
|
45
48
|
Please adhere to this code of conduct in any interactions you have in the
|
|
46
49
|
Jekyll community. It is strictly enforced on all official Jekyll
|
|
47
50
|
repositories, websites, and resources. If you encounter someone violating
|
|
48
|
-
these terms, please let one of our core team members
|
|
51
|
+
these terms, please let one of our [core team members](https://jekyllrb.com/team/#core-team) know and we will address it as soon as possible.
|
|
49
52
|
|
|
50
|
-
##
|
|
53
|
+
## Credits
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
### Sponsors
|
|
56
|
+
|
|
57
|
+
Support this project by becoming a sponsor. Your logo will show up in this README with a link to your website. [Become a sponsor!](https://opencollective.com/jekyll#sponsor)
|
|
58
|
+
[](https://opencollective.com/jekyll/sponsor/0/website)
|
|
59
|
+
[](https://opencollective.com/jekyll/sponsor/1/website)
|
|
60
|
+
[](https://opencollective.com/jekyll/sponsor/2/website)
|
|
61
|
+
[](https://opencollective.com/jekyll/sponsor/3/website)
|
|
62
|
+
[](https://opencollective.com/jekyll/sponsor/4/website)
|
|
63
|
+
[](https://opencollective.com/jekyll/sponsor/5/website)
|
|
64
|
+
[](https://opencollective.com/jekyll/sponsor/6/website)
|
|
65
|
+
[](https://opencollective.com/jekyll/sponsor/7/website)
|
|
66
|
+
[](https://opencollective.com/jekyll/sponsor/8/website)
|
|
67
|
+
[](https://opencollective.com/jekyll/sponsor/9/website)
|
|
68
|
+
|
|
69
|
+
### Contributors
|
|
70
|
+
|
|
71
|
+
This project exists thanks to all the people who contribute.
|
|
72
|
+
[](../../graphs/contributors)
|
|
73
|
+
|
|
74
|
+
### Backers
|
|
75
|
+
|
|
76
|
+
Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/jekyll#backer)
|
|
77
|
+
|
|
78
|
+
[](https://opencollective.com/jekyll#backers)
|
|
58
79
|
|
|
59
80
|
## License
|
|
60
81
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="{{ site.lang | default: "en-US" }}">
|
|
3
|
+
<head>
|
|
4
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>{{ page.title }} - {{ site.title }}</title>
|
|
7
|
+
<link rel="stylesheet" href="{{ "/assets/css/main.css" | relative_url }}">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
{{ content }}
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
$backgroundColor: #ffffff;
|
|
2
|
+
$bodyColor: #000000;
|
|
3
|
+
$bodyFont: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
|
|
4
|
+
|
|
5
|
+
body {
|
|
6
|
+
background: $backgroundColor;
|
|
7
|
+
color: $bodyColor;
|
|
8
|
+
font-family: $bodyFont;
|
|
9
|
+
}
|
data/lib/jekyll/cache.rb
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
|
|
5
|
+
module Jekyll
|
|
6
|
+
class Cache
|
|
7
|
+
# class-wide base cache
|
|
8
|
+
@base_cache = {}
|
|
9
|
+
|
|
10
|
+
# class-wide directive to write cache to disk is enabled by default
|
|
11
|
+
@disk_cache_enabled = true
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
attr_accessor :cache_dir # class-wide cache location
|
|
15
|
+
|
|
16
|
+
attr_reader :base_cache, # class-wide base cache reader
|
|
17
|
+
:disk_cache_enabled # class-wide directive to write cache to disk
|
|
18
|
+
|
|
19
|
+
# Disable Marshaling cached items to disk
|
|
20
|
+
def disable_disk_cache!
|
|
21
|
+
@disk_cache_enabled = false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Clear all caches
|
|
25
|
+
def clear
|
|
26
|
+
delete_cache_files
|
|
27
|
+
base_cache.each_value(&:clear)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Compare the current config to the cached config
|
|
31
|
+
# If they are different, clear all caches
|
|
32
|
+
#
|
|
33
|
+
# Returns nothing.
|
|
34
|
+
def clear_if_config_changed(config)
|
|
35
|
+
config = config.inspect
|
|
36
|
+
cache = Jekyll::Cache.new "Jekyll::Cache"
|
|
37
|
+
return if cache.key?("config") && cache["config"] == config
|
|
38
|
+
|
|
39
|
+
clear
|
|
40
|
+
cache = Jekyll::Cache.new "Jekyll::Cache"
|
|
41
|
+
cache["config"] = config
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# Delete all cached items from all caches
|
|
48
|
+
#
|
|
49
|
+
# Returns nothing.
|
|
50
|
+
def delete_cache_files
|
|
51
|
+
FileUtils.rm_rf(@cache_dir) if disk_cache_enabled
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
|
|
57
|
+
# Get an existing named cache, or create a new one if none exists
|
|
58
|
+
#
|
|
59
|
+
# name - name of the cache
|
|
60
|
+
#
|
|
61
|
+
# Returns nothing.
|
|
62
|
+
def initialize(name)
|
|
63
|
+
@cache = Jekyll::Cache.base_cache[name] ||= {}
|
|
64
|
+
@name = name.gsub(%r![^\w\s-]!, "-")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Clear this particular cache
|
|
68
|
+
def clear
|
|
69
|
+
delete_cache_files
|
|
70
|
+
@cache.clear
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Retrieve a cached item
|
|
74
|
+
# Raises if key does not exist in cache
|
|
75
|
+
#
|
|
76
|
+
# Returns cached value
|
|
77
|
+
def [](key)
|
|
78
|
+
return @cache[key] if @cache.key?(key)
|
|
79
|
+
|
|
80
|
+
path = path_to(hash(key))
|
|
81
|
+
if disk_cache_enabled? && File.file?(path) && File.readable?(path)
|
|
82
|
+
@cache[key] = load(path)
|
|
83
|
+
else
|
|
84
|
+
raise
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Add an item to cache
|
|
89
|
+
#
|
|
90
|
+
# Returns nothing.
|
|
91
|
+
def []=(key, value)
|
|
92
|
+
@cache[key] = value
|
|
93
|
+
return unless disk_cache_enabled?
|
|
94
|
+
|
|
95
|
+
path = path_to(hash(key))
|
|
96
|
+
value = new Hash(value) if value.is_a?(Hash) && !value.default.nil?
|
|
97
|
+
dump(path, value)
|
|
98
|
+
rescue TypeError
|
|
99
|
+
Jekyll.logger.debug "Cache:", "Cannot dump object #{key}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# If an item already exists in the cache, retrieve it.
|
|
103
|
+
# Else execute code block, and add the result to the cache, and return that result.
|
|
104
|
+
def getset(key)
|
|
105
|
+
self[key]
|
|
106
|
+
rescue StandardError
|
|
107
|
+
value = yield
|
|
108
|
+
self[key] = value
|
|
109
|
+
value
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Remove one particular item from the cache
|
|
113
|
+
#
|
|
114
|
+
# Returns nothing.
|
|
115
|
+
def delete(key)
|
|
116
|
+
@cache.delete(key)
|
|
117
|
+
File.delete(path_to(hash(key))) if disk_cache_enabled?
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Check if `key` already exists in this cache
|
|
121
|
+
#
|
|
122
|
+
# Returns true if key exists in the cache, false otherwise
|
|
123
|
+
def key?(key)
|
|
124
|
+
# First, check if item is already cached in memory
|
|
125
|
+
return true if @cache.key?(key)
|
|
126
|
+
# Otherwise, it might be cached on disk
|
|
127
|
+
# but we should not consider the disk cache if it is disabled
|
|
128
|
+
return false unless disk_cache_enabled?
|
|
129
|
+
|
|
130
|
+
path = path_to(hash(key))
|
|
131
|
+
File.file?(path) && File.readable?(path)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def disk_cache_enabled?
|
|
135
|
+
!!Jekyll::Cache.disk_cache_enabled
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
# Given a hashed key, return the path to where this item would be saved on disk.
|
|
141
|
+
def path_to(hash = nil)
|
|
142
|
+
@base_dir ||= File.join(Jekyll::Cache.cache_dir, @name)
|
|
143
|
+
return @base_dir if hash.nil?
|
|
144
|
+
|
|
145
|
+
File.join(@base_dir, hash[0..1], hash[2..-1]).freeze
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Given a key, return a SHA2 hash that can be used for caching this item to disk.
|
|
149
|
+
def hash(key)
|
|
150
|
+
Digest::SHA2.hexdigest(key).freeze
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Remove all this caches items from disk
|
|
154
|
+
#
|
|
155
|
+
# Returns nothing.
|
|
156
|
+
def delete_cache_files
|
|
157
|
+
FileUtils.rm_rf(path_to) if disk_cache_enabled?
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Load `path` from disk and return the result.
|
|
161
|
+
# This MUST NEVER be called in Safe Mode
|
|
162
|
+
# rubocop:disable Security/MarshalLoad
|
|
163
|
+
def load(path)
|
|
164
|
+
raise unless disk_cache_enabled?
|
|
165
|
+
|
|
166
|
+
cached_file = File.open(path, "rb")
|
|
167
|
+
value = Marshal.load(cached_file)
|
|
168
|
+
cached_file.close
|
|
169
|
+
value
|
|
170
|
+
end
|
|
171
|
+
# rubocop:enable Security/MarshalLoad
|
|
172
|
+
|
|
173
|
+
# Given a path and a value, save value to disk at path.
|
|
174
|
+
# This should NEVER be called in Safe Mode
|
|
175
|
+
#
|
|
176
|
+
# Returns nothing.
|
|
177
|
+
def dump(path, value)
|
|
178
|
+
return unless disk_cache_enabled?
|
|
179
|
+
|
|
180
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
181
|
+
File.open(path, "wb") do |cached_file|
|
|
182
|
+
Marshal.dump(value, cached_file)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
data/lib/jekyll/cleaner.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
# Handles the cleanup of a site's destination before it is built.
|
|
5
5
|
class Cleaner
|
|
6
|
-
HIDDEN_FILE_REGEX = %r
|
|
6
|
+
HIDDEN_FILE_REGEX = %r!/\.{1,2}$!.freeze
|
|
7
7
|
attr_reader :site
|
|
8
8
|
|
|
9
9
|
def initialize(site)
|
|
@@ -29,7 +29,7 @@ module Jekyll
|
|
|
29
29
|
|
|
30
30
|
# Private: The metadata file storing dependency tree and build history
|
|
31
31
|
#
|
|
32
|
-
# Returns an Array with the
|
|
32
|
+
# Returns an Array with the metadata file as the only item
|
|
33
33
|
def metadata_file
|
|
34
34
|
[site.regenerator.metadata_file]
|
|
35
35
|
end
|
|
@@ -44,7 +44,8 @@ module Jekyll
|
|
|
44
44
|
dirs = keep_dirs
|
|
45
45
|
|
|
46
46
|
Utils.safe_glob(site.in_dest_dir, ["**", "*"], File::FNM_DOTMATCH).each do |file|
|
|
47
|
-
next if file
|
|
47
|
+
next if HIDDEN_FILE_REGEX.match?(file) || regex.match?(file) || dirs.include?(file)
|
|
48
|
+
|
|
48
49
|
files << file
|
|
49
50
|
end
|
|
50
51
|
|
|
@@ -65,7 +66,7 @@ module Jekyll
|
|
|
65
66
|
#
|
|
66
67
|
# Returns a Set with the directory paths
|
|
67
68
|
def new_dirs
|
|
68
|
-
@new_dirs ||= new_files.
|
|
69
|
+
@new_dirs ||= new_files.flat_map { |file| parent_dirs(file) }.to_set
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
# Private: The list of parent directories of a given file
|
|
@@ -76,7 +77,7 @@ module Jekyll
|
|
|
76
77
|
if parent_dir == site.dest
|
|
77
78
|
[]
|
|
78
79
|
else
|
|
79
|
-
|
|
80
|
+
parent_dirs(parent_dir).unshift(parent_dir)
|
|
80
81
|
end
|
|
81
82
|
end
|
|
82
83
|
|
|
@@ -93,7 +94,7 @@ module Jekyll
|
|
|
93
94
|
#
|
|
94
95
|
# Returns a Set with the directory paths
|
|
95
96
|
def keep_dirs
|
|
96
|
-
site.keep_files.
|
|
97
|
+
site.keep_files.flat_map { |file| parent_dirs(site.in_dest_dir(file)) }.to_set
|
|
97
98
|
end
|
|
98
99
|
|
|
99
100
|
# Private: Creates a regular expression from the config's keep_files array
|
|
@@ -104,7 +105,7 @@ module Jekyll
|
|
|
104
105
|
#
|
|
105
106
|
# Returns the regular expression
|
|
106
107
|
def keep_file_regex
|
|
107
|
-
%r!\A#{Regexp.quote(site.dest)}
|
|
108
|
+
%r!\A#{Regexp.quote(site.dest)}/(#{Regexp.union(site.keep_files).source})!
|
|
108
109
|
end
|
|
109
110
|
end
|
|
110
111
|
end
|
data/lib/jekyll/collection.rb
CHANGED
|
@@ -35,7 +35,7 @@ module Jekyll
|
|
|
35
35
|
def method_missing(method, *args, &blck)
|
|
36
36
|
if docs.respond_to?(method.to_sym)
|
|
37
37
|
Jekyll.logger.warn "Deprecation:",
|
|
38
|
-
|
|
38
|
+
"#{label}.#{method} should be changed to #{label}.docs.#{method}."
|
|
39
39
|
Jekyll.logger.warn "", "Called by #{caller(0..0)}."
|
|
40
40
|
docs.public_send(method.to_sym, *args, &blck)
|
|
41
41
|
else
|
|
@@ -58,13 +58,15 @@ module Jekyll
|
|
|
58
58
|
filtered_entries.each do |file_path|
|
|
59
59
|
full_path = collection_dir(file_path)
|
|
60
60
|
next if File.directory?(full_path)
|
|
61
|
+
|
|
61
62
|
if Utils.has_yaml_header? full_path
|
|
62
63
|
read_document(full_path)
|
|
63
64
|
else
|
|
64
65
|
read_static_file(file_path, full_path)
|
|
65
66
|
end
|
|
66
67
|
end
|
|
67
|
-
|
|
68
|
+
site.static_files.concat(files) unless files.empty?
|
|
69
|
+
sort_docs!
|
|
68
70
|
end
|
|
69
71
|
|
|
70
72
|
# All the entries in this collection.
|
|
@@ -73,11 +75,14 @@ module Jekyll
|
|
|
73
75
|
# relative to the collection's directory
|
|
74
76
|
def entries
|
|
75
77
|
return [] unless exists?
|
|
76
|
-
|
|
78
|
+
|
|
79
|
+
@entries ||= begin
|
|
80
|
+
collection_dir_slash = "#{collection_dir}/"
|
|
77
81
|
Utils.safe_glob(collection_dir, ["**", "*"], File::FNM_DOTMATCH).map do |entry|
|
|
78
|
-
entry[
|
|
82
|
+
entry[collection_dir_slash] = ""
|
|
79
83
|
entry
|
|
80
84
|
end
|
|
85
|
+
end
|
|
81
86
|
end
|
|
82
87
|
|
|
83
88
|
# Filtered version of the entries in this collection.
|
|
@@ -86,6 +91,7 @@ module Jekyll
|
|
|
86
91
|
# Returns a list of filtered entry paths.
|
|
87
92
|
def filtered_entries
|
|
88
93
|
return [] unless exists?
|
|
94
|
+
|
|
89
95
|
@filtered_entries ||=
|
|
90
96
|
Dir.chdir(directory) do
|
|
91
97
|
entry_filter.filter(entries).reject do |f|
|
|
@@ -124,6 +130,7 @@ module Jekyll
|
|
|
124
130
|
# is stored on the filesystem.
|
|
125
131
|
def collection_dir(*files)
|
|
126
132
|
return directory if files.empty?
|
|
133
|
+
|
|
127
134
|
site.in_source_dir(container, relative_directory, *files)
|
|
128
135
|
end
|
|
129
136
|
|
|
@@ -149,7 +156,7 @@ module Jekyll
|
|
|
149
156
|
#
|
|
150
157
|
# Returns the inspect string
|
|
151
158
|
def inspect
|
|
152
|
-
"
|
|
159
|
+
"#<#{self.class} @label=#{label} docs=#{docs}>"
|
|
153
160
|
end
|
|
154
161
|
|
|
155
162
|
# Produce a sanitized label name
|
|
@@ -160,7 +167,7 @@ module Jekyll
|
|
|
160
167
|
#
|
|
161
168
|
# Returns a sanitized version of the label.
|
|
162
169
|
def sanitize_label(label)
|
|
163
|
-
label.gsub(%r![^a-z0-9_
|
|
170
|
+
label.gsub(%r![^a-z0-9_\-.]!i, "")
|
|
164
171
|
end
|
|
165
172
|
|
|
166
173
|
# Produce a representation of this Collection for use in Liquid.
|
|
@@ -207,17 +214,83 @@ module Jekyll
|
|
|
207
214
|
@container ||= site.config["collections_dir"]
|
|
208
215
|
end
|
|
209
216
|
|
|
210
|
-
private
|
|
211
|
-
|
|
212
217
|
def read_document(full_path)
|
|
213
218
|
doc = Document.new(full_path, :site => site, :collection => self)
|
|
214
219
|
doc.read
|
|
215
|
-
if site.unpublished || doc.published?
|
|
216
|
-
|
|
220
|
+
docs << doc if site.unpublished || doc.published?
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def sort_docs!
|
|
224
|
+
if metadata["order"].is_a?(Array)
|
|
225
|
+
rearrange_docs!
|
|
226
|
+
elsif metadata["sort_by"].is_a?(String)
|
|
227
|
+
sort_docs_by_key!
|
|
228
|
+
else
|
|
229
|
+
docs.sort!
|
|
217
230
|
end
|
|
218
231
|
end
|
|
219
232
|
|
|
220
|
-
|
|
233
|
+
# A custom sort function based on Schwartzian transform
|
|
234
|
+
# Refer https://byparker.com/blog/2017/schwartzian-transform-faster-sorting/ for details
|
|
235
|
+
def sort_docs_by_key!
|
|
236
|
+
meta_key = metadata["sort_by"]
|
|
237
|
+
# Modify `docs` array to cache document's property along with the Document instance
|
|
238
|
+
docs.map! { |doc| [doc.data[meta_key], doc] }.sort! do |apples, olives|
|
|
239
|
+
order = determine_sort_order(meta_key, apples, olives)
|
|
240
|
+
|
|
241
|
+
# Fall back to `Document#<=>` if the properties were equal or were non-sortable
|
|
242
|
+
# Otherwise continue with current sort-order
|
|
243
|
+
if order.nil? || order.zero?
|
|
244
|
+
apples[-1] <=> olives[-1]
|
|
245
|
+
else
|
|
246
|
+
order
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Finally restore the `docs` array with just the Document objects themselves
|
|
250
|
+
end.map!(&:last)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def determine_sort_order(sort_key, apples, olives)
|
|
254
|
+
apple_property, apple_document = apples
|
|
255
|
+
olive_property, olive_document = olives
|
|
256
|
+
|
|
257
|
+
if apple_property.nil? && !olive_property.nil?
|
|
258
|
+
order_with_warning(sort_key, apple_document, 1)
|
|
259
|
+
elsif !apple_property.nil? && olive_property.nil?
|
|
260
|
+
order_with_warning(sort_key, olive_document, -1)
|
|
261
|
+
else
|
|
262
|
+
apple_property <=> olive_property
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def order_with_warning(sort_key, document, order)
|
|
267
|
+
Jekyll.logger.warn "Sort warning:", "'#{sort_key}' not defined in #{document.relative_path}"
|
|
268
|
+
order
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Rearrange documents within the `docs` array as listed in the `metadata["order"]` array.
|
|
272
|
+
#
|
|
273
|
+
# Involves converting the two arrays into hashes based on relative_paths as keys first, then
|
|
274
|
+
# merging them to remove duplicates and finally retrieving the Document instances from the
|
|
275
|
+
# merged array.
|
|
276
|
+
def rearrange_docs!
|
|
277
|
+
docs_table = {}
|
|
278
|
+
custom_order = {}
|
|
279
|
+
|
|
280
|
+
# pre-sort to normalize default array across platforms and then proceed to create a Hash
|
|
281
|
+
# from that sorted array.
|
|
282
|
+
docs.sort.each do |doc|
|
|
283
|
+
docs_table[doc.relative_path] = doc
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
metadata["order"].each do |entry|
|
|
287
|
+
custom_order[File.join(relative_directory, entry)] = nil
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
result = Jekyll::Utils.deep_merge_hashes(custom_order, docs_table).values
|
|
291
|
+
result.compact!
|
|
292
|
+
self.docs = result
|
|
293
|
+
end
|
|
221
294
|
|
|
222
295
|
def read_static_file(file_path, full_path)
|
|
223
296
|
relative_dir = Jekyll.sanitized_path(
|
data/lib/jekyll/command.rb
CHANGED
|
@@ -40,6 +40,7 @@ module Jekyll
|
|
|
40
40
|
# Returns a full Jekyll configuration
|
|
41
41
|
def configuration_from_options(options)
|
|
42
42
|
return options if options.is_a?(Jekyll::Configuration)
|
|
43
|
+
|
|
43
44
|
Jekyll.configuration(options)
|
|
44
45
|
end
|
|
45
46
|
|
|
@@ -51,28 +52,54 @@ module Jekyll
|
|
|
51
52
|
# rubocop:disable Metrics/MethodLength
|
|
52
53
|
def add_build_options(cmd)
|
|
53
54
|
cmd.option "config", "--config CONFIG_FILE[,CONFIG_FILE2,...]",
|
|
54
|
-
|
|
55
|
+
Array, "Custom configuration file"
|
|
55
56
|
cmd.option "destination", "-d", "--destination DESTINATION",
|
|
56
|
-
|
|
57
|
+
"The current folder will be generated into DESTINATION"
|
|
57
58
|
cmd.option "source", "-s", "--source SOURCE", "Custom source directory"
|
|
58
59
|
cmd.option "future", "--future", "Publishes posts with a future date"
|
|
59
60
|
cmd.option "limit_posts", "--limit_posts MAX_POSTS", Integer,
|
|
60
|
-
|
|
61
|
+
"Limits the number of posts to parse and publish"
|
|
61
62
|
cmd.option "watch", "-w", "--[no-]watch", "Watch for changes and rebuild"
|
|
62
63
|
cmd.option "baseurl", "-b", "--baseurl URL",
|
|
63
|
-
|
|
64
|
+
"Serve the website from the given base URL"
|
|
64
65
|
cmd.option "force_polling", "--force_polling", "Force watch to use polling"
|
|
65
66
|
cmd.option "lsi", "--lsi", "Use LSI for improved related posts"
|
|
66
67
|
cmd.option "show_drafts", "-D", "--drafts", "Render posts in the _drafts folder"
|
|
67
68
|
cmd.option "unpublished", "--unpublished",
|
|
68
|
-
|
|
69
|
+
"Render posts that were marked as unpublished"
|
|
70
|
+
cmd.option "disable_disk_cache", "--disable-disk-cache",
|
|
71
|
+
"Disable caching to disk in non-safe mode"
|
|
69
72
|
cmd.option "quiet", "-q", "--quiet", "Silence output."
|
|
70
73
|
cmd.option "verbose", "-V", "--verbose", "Print verbose output."
|
|
71
74
|
cmd.option "incremental", "-I", "--incremental", "Enable incremental rebuild."
|
|
72
75
|
cmd.option "strict_front_matter", "--strict_front_matter",
|
|
73
|
-
|
|
76
|
+
"Fail if errors are present in front matter"
|
|
74
77
|
end
|
|
75
78
|
# rubocop:enable Metrics/MethodLength
|
|
79
|
+
|
|
80
|
+
# Run ::process method in a given set of Jekyll::Command subclasses and suggest
|
|
81
|
+
# re-running the associated command with --trace switch to obtain any additional
|
|
82
|
+
# information or backtrace regarding the encountered Exception.
|
|
83
|
+
#
|
|
84
|
+
# cmd - the Jekyll::Command to be handled
|
|
85
|
+
# options - configuration overrides
|
|
86
|
+
# klass - an array of Jekyll::Command subclasses associated with the command
|
|
87
|
+
#
|
|
88
|
+
# Note that all exceptions are rescued..
|
|
89
|
+
# rubocop: disable Lint/RescueException
|
|
90
|
+
def process_with_graceful_fail(cmd, options, *klass)
|
|
91
|
+
klass.each { |k| k.process(options) if k.respond_to?(:process) }
|
|
92
|
+
rescue Exception => e
|
|
93
|
+
raise e if cmd.trace
|
|
94
|
+
|
|
95
|
+
msg = " Please append `--trace` to the `#{cmd.name}` command "
|
|
96
|
+
dashes = "-" * msg.length
|
|
97
|
+
Jekyll.logger.error "", dashes
|
|
98
|
+
Jekyll.logger.error "Jekyll #{Jekyll::VERSION} ", msg
|
|
99
|
+
Jekyll.logger.error "", " for any additional information or backtrace. "
|
|
100
|
+
Jekyll.logger.abort_with "", dashes
|
|
101
|
+
end
|
|
102
|
+
# rubocop: enable Lint/RescueException
|
|
76
103
|
end
|
|
77
104
|
end
|
|
78
105
|
end
|