Merge pull request #2865 from jekyll/some-kind-of-bundler-thingy
This commit is contained in:
commit
13bb7360c0
10
Rakefile
10
Rakefile
|
@ -146,10 +146,14 @@ namespace :site do
|
||||||
|
|
||||||
# Generate the site in server mode.
|
# Generate the site in server mode.
|
||||||
puts "Running Jekyll..."
|
puts "Running Jekyll..."
|
||||||
Jekyll::Commands::Serve.process({
|
options = {
|
||||||
"source" => File.expand_path("site"),
|
"source" => File.expand_path("site"),
|
||||||
"destination" => File.expand_path("site/_site")
|
"destination" => File.expand_path("site/_site"),
|
||||||
})
|
"watch" => true,
|
||||||
|
"serving" => true
|
||||||
|
}
|
||||||
|
Jekyll::Commands::Build.process(options)
|
||||||
|
Jekyll::Commands::Serve.process(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Generate the site"
|
desc "Generate the site"
|
||||||
|
|
|
@ -13,6 +13,8 @@ require 'mercenary'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Jekyll::PluginManager.require_from_bundler
|
||||||
|
|
||||||
Jekyll::Deprecator.process(ARGV)
|
Jekyll::Deprecator.process(ARGV)
|
||||||
|
|
||||||
Mercenary.program(:jekyll) do |p|
|
Mercenary.program(:jekyll) do |p|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
Feature: Configuring and using plugins
|
||||||
|
As a hacker
|
||||||
|
I want to specify my own plugins that can modify Jekyll's behaviour
|
||||||
|
|
||||||
|
Scenario: Add a gem-based plugin
|
||||||
|
Given I have an "index.html" file that contains "Whatever"
|
||||||
|
And I have a configuration file with "gems" set to "[jekyll_test_plugin]"
|
||||||
|
When I run jekyll build
|
||||||
|
Then the _site directory should exist
|
||||||
|
And I should see "Whatever" in "_site/index.html"
|
||||||
|
And I should see "this is a test" in "_site/test.txt"
|
||||||
|
|
||||||
|
Scenario: Add an empty whitelist to restrict all gems
|
||||||
|
Given I have an "index.html" file that contains "Whatever"
|
||||||
|
And I have a configuration file with:
|
||||||
|
| key | value |
|
||||||
|
| gems | [jekyll_test_plugin] |
|
||||||
|
| whitelist | [] |
|
||||||
|
When I run jekyll build --safe
|
||||||
|
Then the _site directory should exist
|
||||||
|
And I should see "Whatever" in "_site/index.html"
|
||||||
|
And the "_site/test.txt" file should not exist
|
||||||
|
|
||||||
|
Scenario: Add a whitelist to restrict some gems but allow others
|
||||||
|
Given I have an "index.html" file that contains "Whatever"
|
||||||
|
And I have a configuration file with:
|
||||||
|
| key | value |
|
||||||
|
| gems | [jekyll_test_plugin, jekyll_test_plugin_malicious] |
|
||||||
|
| whitelist | [jekyll_test_plugin] |
|
||||||
|
When I run jekyll build --safe
|
||||||
|
Then the _site directory should exist
|
||||||
|
And I should see "Whatever" in "_site/index.html"
|
||||||
|
And the "_site/test.txt" file should exist
|
||||||
|
And I should see "this is a test" in "_site/test.txt"
|
|
@ -243,37 +243,6 @@ Feature: Site configuration
|
||||||
And I should see "Post Layout: <p>content for entry1.</p>" in "_site/2007/12/31/entry1.html"
|
And I should see "Post Layout: <p>content for entry1.</p>" in "_site/2007/12/31/entry1.html"
|
||||||
And I should see "Post Layout: <p>content for entry2.</p>" in "_site/2020/01/31/entry2.html"
|
And I should see "Post Layout: <p>content for entry2.</p>" in "_site/2020/01/31/entry2.html"
|
||||||
|
|
||||||
Scenario: Add a gem-based plugin
|
|
||||||
Given I have an "index.html" file that contains "Whatever"
|
|
||||||
And I have a configuration file with "gems" set to "[jekyll_test_plugin]"
|
|
||||||
When I run jekyll build
|
|
||||||
Then the _site directory should exist
|
|
||||||
And I should see "Whatever" in "_site/index.html"
|
|
||||||
And I should see "this is a test" in "_site/test.txt"
|
|
||||||
|
|
||||||
Scenario: Add an empty whitelist to restrict all gems
|
|
||||||
Given I have an "index.html" file that contains "Whatever"
|
|
||||||
And I have a configuration file with:
|
|
||||||
| key | value |
|
|
||||||
| gems | [jekyll_test_plugin] |
|
|
||||||
| whitelist | [] |
|
|
||||||
When I run jekyll build --safe
|
|
||||||
Then the _site directory should exist
|
|
||||||
And I should see "Whatever" in "_site/index.html"
|
|
||||||
And the "_site/test.txt" file should not exist
|
|
||||||
|
|
||||||
Scenario: Add a whitelist to restrict some gems but allow others
|
|
||||||
Given I have an "index.html" file that contains "Whatever"
|
|
||||||
And I have a configuration file with:
|
|
||||||
| key | value |
|
|
||||||
| gems | [jekyll_test_plugin, jekyll_test_plugin_malicious] |
|
|
||||||
| whitelist | [jekyll_test_plugin] |
|
|
||||||
When I run jekyll build --safe
|
|
||||||
Then the _site directory should exist
|
|
||||||
And I should see "Whatever" in "_site/index.html"
|
|
||||||
And the "_site/test.txt" file should exist
|
|
||||||
And I should see "this is a test" in "_site/test.txt"
|
|
||||||
|
|
||||||
Scenario: arbitrary file reads via layouts
|
Scenario: arbitrary file reads via layouts
|
||||||
Given I have an "index.html" page with layout "page" that contains "FOO"
|
Given I have an "index.html" page with layout "page" that contains "FOO"
|
||||||
And I have a "_config.yml" file that contains "layouts: '../../../../../../../../../../../../../../usr/include'"
|
And I have a "_config.yml" file that contains "layouts: '../../../../../../../../../../../../../../usr/include'"
|
||||||
|
|
|
@ -146,6 +146,13 @@ When /^I run jekyll(.*)$/ do |args|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
When /^I run bundle(.*)$/ do |args|
|
||||||
|
status = run_bundle(args)
|
||||||
|
if args.include?("--verbose") || ENV['DEBUG']
|
||||||
|
puts jekyll_run_output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
When /^I change "(.*)" to contain "(.*)"$/ do |file, text|
|
When /^I change "(.*)" to contain "(.*)"$/ do |file, text|
|
||||||
File.open(file, 'a') do |f|
|
File.open(file, 'a') do |f|
|
||||||
f.write(text)
|
f.write(text)
|
||||||
|
|
|
@ -21,11 +21,19 @@ def jekyll_run_output
|
||||||
File.read(jekyll_output_file) if File.file?(jekyll_output_file)
|
File.read(jekyll_output_file) if File.file?(jekyll_output_file)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run_bundle(args)
|
||||||
|
child = run_in_shell('bundle', *args.strip.split(' '))
|
||||||
|
end
|
||||||
|
|
||||||
def run_jekyll(args)
|
def run_jekyll(args)
|
||||||
child = POSIX::Spawn::Child.new JEKYLL_PATH, *args.strip.split(' '), "--trace", :out => [JEKYLL_COMMAND_OUTPUT_FILE, "w"]
|
child = run_in_shell(JEKYLL_PATH, *args.strip.split(' '), "--trace")
|
||||||
child.status.exitstatus == 0
|
child.status.exitstatus == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run_in_shell(*args)
|
||||||
|
POSIX::Spawn::Child.new *args, :out => [JEKYLL_COMMAND_OUTPUT_FILE, "w"]
|
||||||
|
end
|
||||||
|
|
||||||
def slug(title)
|
def slug(title)
|
||||||
if title
|
if title
|
||||||
title.downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-')
|
title.downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-')
|
||||||
|
|
|
@ -17,6 +17,7 @@ module Jekyll
|
||||||
def conscientious_require
|
def conscientious_require
|
||||||
require_plugin_files
|
require_plugin_files
|
||||||
require_gems
|
require_gems
|
||||||
|
self.class.require_from_bundler
|
||||||
end
|
end
|
||||||
|
|
||||||
# Require each of the gem plugins specified.
|
# Require each of the gem plugins specified.
|
||||||
|
@ -25,11 +26,26 @@ module Jekyll
|
||||||
def require_gems
|
def require_gems
|
||||||
site.gems.each do |gem|
|
site.gems.each do |gem|
|
||||||
if plugin_allowed?(gem)
|
if plugin_allowed?(gem)
|
||||||
|
Jekyll.logger.debug("PluginManager:", "Requiring #{gem}")
|
||||||
require gem
|
require gem
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.require_from_bundler
|
||||||
|
if ENV["JEKYLL_NO_BUNDLER_REQUIRE"]
|
||||||
|
false
|
||||||
|
else
|
||||||
|
require "bundler"
|
||||||
|
required_gems = Bundler.require(:jekyll_plugins)
|
||||||
|
Jekyll.logger.debug("PluginManager:", "Required #{required_gems.map(&:name).join(', ')}")
|
||||||
|
ENV["JEKYLL_NO_BUNDLER_REQUIRE"] = "true"
|
||||||
|
true
|
||||||
|
end
|
||||||
|
rescue LoadError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
# Check whether a gem plugin is allowed to be used during this build.
|
# Check whether a gem plugin is allowed to be used during this build.
|
||||||
#
|
#
|
||||||
# gem_name - the name of the gem
|
# gem_name - the name of the gem
|
||||||
|
|
|
@ -25,7 +25,7 @@ having to modify the Jekyll source itself.
|
||||||
|
|
||||||
## Installing a plugin
|
## Installing a plugin
|
||||||
|
|
||||||
You have 2 options for installing plugins:
|
You have 3 options for installing plugins:
|
||||||
|
|
||||||
1. In your site source root, make a `_plugins` directory. Place your plugins here.
|
1. In your site source root, make a `_plugins` directory. Place your plugins here.
|
||||||
Any file ending in `*.rb` inside this directory will be loaded before Jekyll
|
Any file ending in `*.rb` inside this directory will be loaded before Jekyll
|
||||||
|
@ -35,6 +35,12 @@ You have 2 options for installing plugins:
|
||||||
|
|
||||||
gems: [jekyll-test-plugin, jekyll-jsonify, jekyll-assets]
|
gems: [jekyll-test-plugin, jekyll-jsonify, jekyll-assets]
|
||||||
# This will require each of these gems automatically.
|
# This will require each of these gems automatically.
|
||||||
|
3. Add the relevant plugins to a Bundler group in your `Gemfile`. An
|
||||||
|
example:
|
||||||
|
|
||||||
|
group :jekyll_plugins do
|
||||||
|
gem "my-jekyll-plugin"
|
||||||
|
end
|
||||||
|
|
||||||
<div class="note info">
|
<div class="note info">
|
||||||
<h5>
|
<h5>
|
||||||
|
@ -247,6 +253,67 @@ In our example, `UpcaseConverter#matches` checks if our filename extension is
|
||||||
simply uppercasing the entire content string. Finally, when it saves the page,
|
simply uppercasing the entire content string. Finally, when it saves the page,
|
||||||
it will do so with a `.html` extension.
|
it will do so with a `.html` extension.
|
||||||
|
|
||||||
|
## Command
|
||||||
|
|
||||||
|
As of version 2.5.0, Jekyll can be extended with plugins which provide
|
||||||
|
subcommands for the `jekyll` executable. This is possible by including the
|
||||||
|
relevant plugins in a `Gemfile` group called `:jekyll_plugins`:
|
||||||
|
|
||||||
|
{% highlight ruby %}
|
||||||
|
group :jekyll_plugins do
|
||||||
|
gem "my_fancy_jekyll_plugin"
|
||||||
|
end
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Each `Command` must be a subclass of the `Jekyll::Command` class and must
|
||||||
|
contain one class method: `init_with_program`. An example:
|
||||||
|
|
||||||
|
{% highlight ruby %}
|
||||||
|
class MyNewCommand < Jekyll::Command
|
||||||
|
class << self
|
||||||
|
def init_with_program(prog)
|
||||||
|
prog.command(:new) do |c|
|
||||||
|
c.syntax "new [options]"
|
||||||
|
c.description 'Create a new Jekyll site.'
|
||||||
|
|
||||||
|
c.option 'dest', '-d DEST, 'Where the site should go.'
|
||||||
|
|
||||||
|
c.action do |args, options|
|
||||||
|
Jekyll::Site.new_site_at(options['dest'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Commands should implement this single class method:
|
||||||
|
|
||||||
|
<div class="mobile-side-scroller">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Method</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p><code>init_with_program</code></p>
|
||||||
|
</td>
|
||||||
|
<td><p>
|
||||||
|
This method accepts one parameter, the
|
||||||
|
<code><a href="http://github.com/jekyll/mercenary#readme">Mercenary::Program</a></code>
|
||||||
|
instance, which is the Jekyll program itself. Upon the program,
|
||||||
|
commands may be created using the above syntax. For more details,
|
||||||
|
visit the Mercenary repository on GitHub.com.
|
||||||
|
</p></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
## Tags
|
## Tags
|
||||||
|
|
||||||
If you’d like to include custom liquid tags in your site, you can do so by
|
If you’d like to include custom liquid tags in your site, you can do so by
|
||||||
|
|
|
@ -58,6 +58,13 @@ class Test::Unit::TestCase
|
||||||
File.open("#{path}/index.html", "w"){ |f| f.write("I was previously generated.") }
|
File.open("#{path}/index.html", "w"){ |f| f.write("I was previously generated.") }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_env(key, value)
|
||||||
|
old_value = ENV[key]
|
||||||
|
ENV[key] = value
|
||||||
|
yield
|
||||||
|
ENV[key] = old_value
|
||||||
|
end
|
||||||
|
|
||||||
def capture_stdout
|
def capture_stdout
|
||||||
$old_stdout = $stdout
|
$old_stdout = $stdout
|
||||||
$stdout = StringIO.new
|
$stdout = StringIO.new
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
require 'helper'
|
||||||
|
|
||||||
|
class TestPluginManager < Test::Unit::TestCase
|
||||||
|
def test_requiring_from_bundler
|
||||||
|
with_env("JEKYLL_NO_BUNDLER_REQUIRE", nil) do
|
||||||
|
Jekyll::PluginManager.require_from_bundler
|
||||||
|
assert ENV["JEKYLL_NO_BUNDLER_REQUIRE"], 'Gemfile plugins were not required.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_blocking_requiring_from_bundler
|
||||||
|
with_env("JEKYLL_NO_BUNDLER_REQUIRE", "true") do
|
||||||
|
assert_equal false, Jekyll::PluginManager.require_from_bundler, "Gemfile plugins were required but shouldn't have been"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue