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.
|
||||
puts "Running Jekyll..."
|
||||
Jekyll::Commands::Serve.process({
|
||||
options = {
|
||||
"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
|
||||
|
||||
desc "Generate the site"
|
||||
|
|
|
@ -13,6 +13,8 @@ require 'mercenary'
|
|||
end
|
||||
end
|
||||
|
||||
Jekyll::PluginManager.require_from_bundler
|
||||
|
||||
Jekyll::Deprecator.process(ARGV)
|
||||
|
||||
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 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
|
||||
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'"
|
||||
|
|
|
@ -146,6 +146,13 @@ When /^I run jekyll(.*)$/ do |args|
|
|||
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|
|
||||
File.open(file, 'a') do |f|
|
||||
f.write(text)
|
||||
|
|
|
@ -21,11 +21,19 @@ def jekyll_run_output
|
|||
File.read(jekyll_output_file) if File.file?(jekyll_output_file)
|
||||
end
|
||||
|
||||
def run_bundle(args)
|
||||
child = run_in_shell('bundle', *args.strip.split(' '))
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
def run_in_shell(*args)
|
||||
POSIX::Spawn::Child.new *args, :out => [JEKYLL_COMMAND_OUTPUT_FILE, "w"]
|
||||
end
|
||||
|
||||
def slug(title)
|
||||
if title
|
||||
title.downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-')
|
||||
|
|
|
@ -17,6 +17,7 @@ module Jekyll
|
|||
def conscientious_require
|
||||
require_plugin_files
|
||||
require_gems
|
||||
self.class.require_from_bundler
|
||||
end
|
||||
|
||||
# Require each of the gem plugins specified.
|
||||
|
@ -25,11 +26,26 @@ module Jekyll
|
|||
def require_gems
|
||||
site.gems.each do |gem|
|
||||
if plugin_allowed?(gem)
|
||||
Jekyll.logger.debug("PluginManager:", "Requiring #{gem}")
|
||||
require gem
|
||||
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.
|
||||
#
|
||||
# gem_name - the name of the gem
|
||||
|
|
|
@ -25,7 +25,7 @@ having to modify the Jekyll source itself.
|
|||
|
||||
## 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.
|
||||
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]
|
||||
# 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">
|
||||
<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,
|
||||
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
|
||||
|
||||
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.") }
|
||||
end
|
||||
|
||||
def with_env(key, value)
|
||||
old_value = ENV[key]
|
||||
ENV[key] = value
|
||||
yield
|
||||
ENV[key] = old_value
|
||||
end
|
||||
|
||||
def capture_stdout
|
||||
$old_stdout = $stdout
|
||||
$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