Merge pull request #2882 from jekyll/security/centralize-path-sanitation
This commit is contained in:
commit
2ec1dc1831
|
@ -68,11 +68,12 @@ module Jekyll
|
|||
require 'jekyll/command'
|
||||
require 'jekyll/liquid_extensions'
|
||||
|
||||
class << self
|
||||
# Public: Tells you which Jekyll environment you are building in so you can skip tasks
|
||||
# if you need to. This is useful when doing expensive compression tasks on css and
|
||||
# images and allows you to skip that when working in development.
|
||||
|
||||
def self.env
|
||||
def env
|
||||
ENV["JEKYLL_ENV"] || "development"
|
||||
end
|
||||
|
||||
|
@ -84,10 +85,12 @@ module Jekyll
|
|||
# list of option names and their defaults.
|
||||
#
|
||||
# Returns the final configuration Hash.
|
||||
def self.configuration(override)
|
||||
def configuration(override = Hash.new)
|
||||
config = Configuration[Configuration::DEFAULTS]
|
||||
override = Configuration[override].stringify_keys
|
||||
unless override.delete('skip_config_files')
|
||||
config = config.read_config_files(config.config_files(override))
|
||||
end
|
||||
|
||||
# Merge DEFAULTS < _config.yml < override
|
||||
config = Utils.deep_merge_hashes(config, override).stringify_keys
|
||||
|
@ -96,32 +99,49 @@ module Jekyll
|
|||
config
|
||||
end
|
||||
|
||||
# Static: Set the TZ environment variable to use the timezone specified
|
||||
# Public: Set the TZ environment variable to use the timezone specified
|
||||
#
|
||||
# timezone - the IANA Time Zone
|
||||
#
|
||||
# Returns nothing
|
||||
def self.set_timezone(timezone)
|
||||
def set_timezone(timezone)
|
||||
ENV['TZ'] = timezone
|
||||
end
|
||||
|
||||
def self.logger
|
||||
# Public: Fetch the logger instance for this Jekyll process.
|
||||
#
|
||||
# Returns the LogAdapter instance.
|
||||
def logger
|
||||
@logger ||= LogAdapter.new(Stevenson.new)
|
||||
end
|
||||
|
||||
def self.logger=(writer)
|
||||
# Public: Set the log writer.
|
||||
# New log writer must respond to the same methods
|
||||
# as Ruby's interal Logger.
|
||||
#
|
||||
# writer - the new Logger-compatible log transport
|
||||
#
|
||||
# Returns the new logger.
|
||||
def logger=(writer)
|
||||
@logger = LogAdapter.new(writer)
|
||||
end
|
||||
|
||||
# Public: File system root
|
||||
# Public: An array of sites
|
||||
#
|
||||
# Returns the root of the filesystem as a Pathname
|
||||
def self.fs_root
|
||||
@fs_root ||= "/"
|
||||
# Returns the Jekyll sites created.
|
||||
def sites
|
||||
@sites ||= []
|
||||
end
|
||||
|
||||
def self.sanitized_path(base_directory, questionable_path)
|
||||
clean_path = File.expand_path(questionable_path, fs_root)
|
||||
# Public: Ensures the questionable path is prefixed with the base directory
|
||||
# and prepends the questionable path with the base directory if false.
|
||||
#
|
||||
# base_directory - the directory with which to prefix the questionable path
|
||||
# questionable_path - the path we're unsure about, and want prefixed
|
||||
#
|
||||
# Returns the sanitized path.
|
||||
def sanitized_path(base_directory, questionable_path)
|
||||
clean_path = File.expand_path(questionable_path, "/")
|
||||
clean_path.gsub!(/\A\w\:\//, '/')
|
||||
unless clean_path.start_with?(base_directory)
|
||||
File.join(base_directory, clean_path)
|
||||
|
@ -129,6 +149,8 @@ module Jekyll
|
|||
clean_path
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
require_all 'jekyll/commands'
|
||||
|
|
|
@ -29,7 +29,7 @@ module Jekyll
|
|||
# Returns a Set with the file paths
|
||||
def existing_files
|
||||
files = Set.new
|
||||
Dir.glob(File.join(site.dest, "**", "*"), File::FNM_DOTMATCH) do |file|
|
||||
Dir.glob(site.in_dest_dir("**", "*"), File::FNM_DOTMATCH) do |file|
|
||||
files << file unless file =~ /\/\.{1,2}$/ || file =~ keep_file_regex || keep_dirs.include?(file)
|
||||
end
|
||||
files
|
||||
|
@ -76,7 +76,7 @@ module Jekyll
|
|||
#
|
||||
# Returns a Set with the directory paths
|
||||
def keep_dirs
|
||||
site.keep_files.map { |file| parent_dirs(File.join(site.dest, file)) }.flatten.to_set
|
||||
site.keep_files.map { |file| parent_dirs(site.in_dest_dir(file)) }.flatten.to_set
|
||||
end
|
||||
|
||||
# Private: Creates a regular expression from the config's keep_files array
|
||||
|
|
|
@ -35,7 +35,8 @@ module Jekyll
|
|||
# Returns the sorted array of docs.
|
||||
def read
|
||||
filtered_entries.each do |file_path|
|
||||
full_path = Jekyll.sanitized_path(directory, file_path)
|
||||
full_path = collection_dir(file_path)
|
||||
next if File.directory?(full_path)
|
||||
if Utils.has_yaml_header? full_path
|
||||
doc = Jekyll::Document.new(full_path, { site: site, collection: self })
|
||||
doc.read
|
||||
|
@ -54,8 +55,9 @@ module Jekyll
|
|||
# relative to the collection's directory
|
||||
def entries
|
||||
return Array.new unless exists?
|
||||
Dir.glob(File.join(directory, "**", "*.*")).map do |entry|
|
||||
entry[File.join(directory, "")] = ''; entry
|
||||
@entries ||=
|
||||
Dir.glob(collection_dir("**", "*.*")).map do |entry|
|
||||
entry["#{collection_dir}/"] = ''; entry
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -65,8 +67,12 @@ module Jekyll
|
|||
# Returns a list of filtered entry paths.
|
||||
def filtered_entries
|
||||
return Array.new unless exists?
|
||||
@filtered_entries ||=
|
||||
Dir.chdir(directory) do
|
||||
entry_filter.filter(entries).reject { |f| File.directory?(f) }
|
||||
entry_filter.filter(entries).reject do |f|
|
||||
path = collection_dir(f)
|
||||
File.directory?(path) || (File.symlink?(f) && site.safe)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -78,12 +84,25 @@ module Jekyll
|
|||
@relative_directory ||= "_#{label}"
|
||||
end
|
||||
|
||||
# The full path to the directory containing the
|
||||
# The full path to the directory containing the collection.
|
||||
#
|
||||
# Returns a String containing th directory name where the collection
|
||||
# is stored on the filesystem.
|
||||
def directory
|
||||
@directory ||= Jekyll.sanitized_path(site.source, relative_directory)
|
||||
@directory ||= site.in_source_dir(relative_directory)
|
||||
end
|
||||
|
||||
# The full path to the directory containing the collection, with
|
||||
# optional subpaths.
|
||||
#
|
||||
# *files - (optional) any other path pieces relative to the
|
||||
# directory to append to the path
|
||||
#
|
||||
# Returns a String containing th directory name where the collection
|
||||
# is stored on the filesystem.
|
||||
def collection_dir(*files)
|
||||
return directory if files.empty?
|
||||
site.in_source_dir(relative_directory, *files)
|
||||
end
|
||||
|
||||
# Checks whether the directory "exists" for this collection.
|
||||
|
|
|
@ -43,7 +43,7 @@ module Jekyll
|
|||
# Returns nothing.
|
||||
def read_yaml(base, name, opts = {})
|
||||
begin
|
||||
self.content = File.read(Jekyll.sanitized_path(base, name),
|
||||
self.content = File.read(site.in_source_dir(base, name),
|
||||
merged_file_read_opts(opts))
|
||||
if content =~ /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
|
||||
self.content = $POSTMATCH
|
||||
|
|
|
@ -159,7 +159,8 @@ module Jekyll
|
|||
#
|
||||
# Returns the full path to the output file of this document.
|
||||
def destination(base_directory)
|
||||
path = Jekyll.sanitized_path(base_directory, url)
|
||||
dest = site.in_dest_dir(base_directory)
|
||||
path = site.in_dest_dir(dest, url)
|
||||
path = File.join(path, "index.html") if url =~ /\/$/
|
||||
path
|
||||
end
|
||||
|
|
|
@ -14,8 +14,8 @@ module Jekyll
|
|||
end
|
||||
|
||||
# Get the full path to the directory containing the draft files
|
||||
def containing_dir(source, dir)
|
||||
File.join(source, dir, '_drafts')
|
||||
def containing_dir(dir)
|
||||
site.in_source_dir(dir, '_drafts')
|
||||
end
|
||||
|
||||
# The path to the draft source file, relative to the site source
|
||||
|
|
|
@ -106,7 +106,7 @@ module Jekyll
|
|||
# Returns excerpt String
|
||||
def extract_excerpt(post_content)
|
||||
separator = site.config['excerpt_separator']
|
||||
head, _, tail = post_content.partition(separator)
|
||||
head, _, tail = post_content.to_s.partition(separator)
|
||||
|
||||
"" << head << "\n\n" << tail.scan(/^\[[^\]]+\]:.+$/).join("\n")
|
||||
end
|
||||
|
|
|
@ -38,12 +38,12 @@ module Jekyll
|
|||
end
|
||||
|
||||
def layout_directory_inside_source
|
||||
Jekyll.sanitized_path(site.source, site.config['layouts'])
|
||||
site.in_source_dir(site.config['layouts'])
|
||||
end
|
||||
|
||||
def layout_directory_in_cwd
|
||||
dir = Jekyll.sanitized_path(Dir.pwd, site.config['layouts'])
|
||||
if File.directory?(dir)
|
||||
if File.directory?(dir) && !site.safe
|
||||
dir
|
||||
else
|
||||
nil
|
||||
|
|
|
@ -140,7 +140,7 @@ module Jekyll
|
|||
#
|
||||
# Returns the destination file path String.
|
||||
def destination(dest)
|
||||
path = Jekyll.sanitized_path(dest, URL.unescape_path(url))
|
||||
path = site.in_dest_dir(dest, URL.unescape_path(url))
|
||||
path = File.join(path, "index.html") if url =~ /\/$/
|
||||
path
|
||||
end
|
||||
|
|
|
@ -66,7 +66,7 @@ module Jekyll
|
|||
# Returns an Array of plugin search paths
|
||||
def plugins_path
|
||||
if (site.config['plugins'] == Jekyll::Configuration::DEFAULTS['plugins'])
|
||||
[Jekyll.sanitized_path(site.source, site.config['plugins'])]
|
||||
[site.in_source_dir(site.config['plugins'])]
|
||||
else
|
||||
Array(site.config['plugins']).map { |d| File.expand_path(d) }
|
||||
end
|
||||
|
|
|
@ -49,7 +49,7 @@ module Jekyll
|
|||
def initialize(site, source, dir, name)
|
||||
@site = site
|
||||
@dir = dir
|
||||
@base = containing_dir(source, dir)
|
||||
@base = containing_dir(dir)
|
||||
@name = name
|
||||
|
||||
self.categories = dir.downcase.split('/').reject { |x| x.empty? }
|
||||
|
@ -88,8 +88,8 @@ module Jekyll
|
|||
end
|
||||
|
||||
# Get the full path to the directory containing the post files
|
||||
def containing_dir(source, dir)
|
||||
return File.join(source, dir, '_posts')
|
||||
def containing_dir(dir)
|
||||
site.in_source_dir(dir, '_posts')
|
||||
end
|
||||
|
||||
# Read the YAML frontmatter.
|
||||
|
@ -268,7 +268,7 @@ module Jekyll
|
|||
# Returns destination file path String.
|
||||
def destination(dest)
|
||||
# The url needs to be unescaped in order to preserve the correct filename
|
||||
path = Jekyll.sanitized_path(dest, URL.unescape_path(url))
|
||||
path = site.in_dest_dir(dest, URL.unescape_path(url))
|
||||
path = File.join(path, "index.html") if path[/\.html?$/].nil?
|
||||
path
|
||||
end
|
||||
|
|
|
@ -46,8 +46,7 @@ module Jekyll
|
|||
end
|
||||
|
||||
def most_recent_posts
|
||||
recent_posts = site.posts.reverse - [post]
|
||||
recent_posts.first(10)
|
||||
@most_recent_posts ||= (site.posts.reverse - [post]).first(10)
|
||||
end
|
||||
|
||||
def display(output)
|
||||
|
|
|
@ -3,11 +3,12 @@ require 'csv'
|
|||
|
||||
module Jekyll
|
||||
class Site
|
||||
attr_accessor :config, :layouts, :posts, :pages, :static_files,
|
||||
:exclude, :include, :source, :dest, :lsi, :highlighter,
|
||||
:permalink_style, :time, :future, :unpublished, :safe, :plugins, :limit_posts,
|
||||
:show_drafts, :keep_files, :baseurl, :data, :file_read_opts, :gems,
|
||||
:plugin_manager
|
||||
attr_reader :source, :dest, :config
|
||||
attr_accessor :layouts, :posts, :pages, :static_files,
|
||||
:exclude, :include, :lsi, :highlighter, :permalink_style,
|
||||
:time, :future, :unpublished, :safe, :plugins, :limit_posts,
|
||||
:show_drafts, :keep_files, :baseurl, :data, :file_read_opts,
|
||||
:gems, :plugin_manager
|
||||
|
||||
attr_accessor :converters, :generators
|
||||
|
||||
|
@ -15,16 +16,16 @@ module Jekyll
|
|||
#
|
||||
# config - A Hash containing site configuration details.
|
||||
def initialize(config)
|
||||
self.config = config.clone
|
||||
@config = config.clone
|
||||
|
||||
%w[safe lsi highlighter baseurl exclude include future unpublished
|
||||
show_drafts limit_posts keep_files gems].each do |opt|
|
||||
self.send("#{opt}=", config[opt])
|
||||
end
|
||||
|
||||
self.source = File.expand_path(config['source'])
|
||||
self.dest = File.expand_path(config['destination'])
|
||||
self.permalink_style = config['permalink'].to_sym
|
||||
# Source and destination may not be changed after the site has been created.
|
||||
@source = File.expand_path(config['source']).freeze
|
||||
@dest = File.expand_path(config['destination']).freeze
|
||||
|
||||
self.plugin_manager = Jekyll::PluginManager.new(self)
|
||||
self.plugins = plugin_manager.plugins_path
|
||||
|
@ -32,6 +33,10 @@ module Jekyll
|
|||
self.file_read_opts = {}
|
||||
self.file_read_opts[:encoding] = config['encoding'] if config['encoding']
|
||||
|
||||
self.permalink_style = config['permalink'].to_sym
|
||||
|
||||
Jekyll.sites << self
|
||||
|
||||
reset
|
||||
setup
|
||||
end
|
||||
|
@ -88,6 +93,30 @@ module Jekyll
|
|||
end
|
||||
end
|
||||
|
||||
# Public: Prefix a given path with the source directory.
|
||||
#
|
||||
# paths - (optional) path elements to a file or directory within the
|
||||
# source directory
|
||||
#
|
||||
# Returns a path which is prefixed with the source directory.
|
||||
def in_source_dir(*paths)
|
||||
paths.reduce(source) do |base, path|
|
||||
Jekyll.sanitized_path(base, path)
|
||||
end
|
||||
end
|
||||
|
||||
# Public: Prefix a given path with the destination directory.
|
||||
#
|
||||
# paths - (optional) path elements to a file or directory within the
|
||||
# destination directory
|
||||
#
|
||||
# Returns a path which is prefixed with the destination directory.
|
||||
def in_dest_dir(*paths)
|
||||
paths.reduce(dest) do |base, path|
|
||||
Jekyll.sanitized_path(base, path)
|
||||
end
|
||||
end
|
||||
|
||||
# The list of collections and their corresponding Jekyll::Collection instances.
|
||||
# If config['collections'] is set, a new instance is created for each item in the collection.
|
||||
# If config['collections'] is not set, a new hash is returned.
|
||||
|
@ -132,7 +161,7 @@ module Jekyll
|
|||
#
|
||||
# Returns nothing.
|
||||
def read_directories(dir = '')
|
||||
base = File.join(source, dir)
|
||||
base = in_source_dir(dir)
|
||||
entries = Dir.chdir(base) { filter_entries(Dir.entries('.'), base) }
|
||||
|
||||
read_posts(dir)
|
||||
|
@ -141,7 +170,7 @@ module Jekyll
|
|||
limit_posts! if limit_posts > 0 # limit the posts if :limit_posts option is set
|
||||
|
||||
entries.each do |f|
|
||||
f_abs = File.join(base, f)
|
||||
f_abs = in_source_dir(base, f)
|
||||
if File.directory?(f_abs)
|
||||
f_rel = File.join(dir, f)
|
||||
read_directories(f_rel) unless dest.sub(/\/$/, '') == f_abs
|
||||
|
@ -198,7 +227,7 @@ module Jekyll
|
|||
#
|
||||
# Returns nothing
|
||||
def read_data(dir)
|
||||
base = Jekyll.sanitized_path(source, dir)
|
||||
base = in_source_dir(dir)
|
||||
read_data_to(base, self.data)
|
||||
end
|
||||
|
||||
|
@ -217,7 +246,7 @@ module Jekyll
|
|||
end
|
||||
|
||||
entries.each do |entry|
|
||||
path = Jekyll.sanitized_path(dir, entry)
|
||||
path = in_source_dir(dir, entry)
|
||||
next if File.symlink?(path) && safe
|
||||
|
||||
key = sanitize_filename(File.basename(entry, '.*'))
|
||||
|
@ -407,10 +436,10 @@ module Jekyll
|
|||
#
|
||||
# Returns the list of entries to process
|
||||
def get_entries(dir, subfolder)
|
||||
base = File.join(source, dir, subfolder)
|
||||
base = in_source_dir(dir, subfolder)
|
||||
return [] unless File.exist?(base)
|
||||
entries = Dir.chdir(base) { filter_entries(Dir['**/*'], base) }
|
||||
entries.delete_if { |e| File.directory?(File.join(base, e)) }
|
||||
entries.delete_if { |e| File.directory?(in_source_dir(base, e)) }
|
||||
end
|
||||
|
||||
# Aggregate post information
|
||||
|
|
|
@ -37,7 +37,7 @@ module Jekyll
|
|||
#
|
||||
# Returns destination file path.
|
||||
def destination(dest)
|
||||
File.join(*[dest, destination_rel_dir, @name].compact)
|
||||
@site.in_dest_dir(*[dest, destination_rel_dir, @name].compact)
|
||||
end
|
||||
|
||||
def destination_rel_dir
|
||||
|
|
|
@ -161,7 +161,7 @@ eos
|
|||
end
|
||||
|
||||
def resolved_includes_dir(context)
|
||||
Jekyll.sanitized_path(context.registers[:site].source, page_path(context))
|
||||
context.registers[:site].in_source_dir(page_path(context))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,10 +30,10 @@ class Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def site_configuration(overrides = {})
|
||||
full_overrides = build_configs(overrides, build_configs({"destination" => dest_dir}))
|
||||
build_configs({
|
||||
"source" => source_dir,
|
||||
"destination" => dest_dir
|
||||
}, build_configs(overrides))
|
||||
}, full_overrides)
|
||||
end
|
||||
|
||||
def dest_dir(*subdirs)
|
||||
|
|
|
@ -4,15 +4,16 @@ class TestCleaner < Test::Unit::TestCase
|
|||
context "directory in keep_files" do
|
||||
setup do
|
||||
clear_dest
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(dest_dir('to_keep/child_dir'))
|
||||
FileUtils.touch(File.join(dest_dir('to_keep'), 'index.html'))
|
||||
FileUtils.touch(File.join(dest_dir('to_keep/child_dir'), 'index.html'))
|
||||
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(Jekyll.configuration({
|
||||
"skip_config_files" => true,
|
||||
"source" => source_dir,
|
||||
"destination" => dest_dir
|
||||
}))
|
||||
@site.keep_files = ['to_keep/child_dir']
|
||||
|
||||
@cleaner = Site::Cleaner.new(@site)
|
||||
|
@ -43,14 +44,15 @@ class TestCleaner < Test::Unit::TestCase
|
|||
context "directory containing no files and non-empty directories" do
|
||||
setup do
|
||||
clear_dest
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(source_dir('no_files_inside/child_dir'))
|
||||
FileUtils.touch(File.join(source_dir('no_files_inside/child_dir'), 'index.html'))
|
||||
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(Jekyll.configuration({
|
||||
"skip_config_files" => true,
|
||||
"source" => source_dir,
|
||||
"destination" => dest_dir
|
||||
}))
|
||||
@site.process
|
||||
|
||||
@cleaner = Site::Cleaner.new(@site)
|
||||
|
|
|
@ -187,6 +187,7 @@ class TestCollections < Test::Unit::TestCase
|
|||
|
||||
should "not allow symlinks" do
|
||||
assert_not_include @collection.filtered_entries, "um_hi.md"
|
||||
assert_not_include @collection.filtered_entries, "/um_hi.md"
|
||||
end
|
||||
|
||||
should "not include the symlinked file in the list of docs" do
|
||||
|
|
|
@ -4,7 +4,11 @@ require 'ostruct'
|
|||
class TestConvertible < Test::Unit::TestCase
|
||||
context "yaml front-matter" do
|
||||
setup do
|
||||
@convertible = OpenStruct.new
|
||||
@convertible = OpenStruct.new(
|
||||
"site" => Site.new(Jekyll.configuration(
|
||||
"source" => File.expand_path('../fixtures', __FILE__)
|
||||
))
|
||||
)
|
||||
@convertible.extend Jekyll::Convertible
|
||||
@base = File.expand_path('../fixtures', __FILE__)
|
||||
end
|
||||
|
|
|
@ -13,6 +13,10 @@ class TestDocument < Test::Unit::TestCase
|
|||
@document = @site.collections["methods"].docs.first
|
||||
end
|
||||
|
||||
should "exist" do
|
||||
assert !@document.nil?
|
||||
end
|
||||
|
||||
should "know its relative path" do
|
||||
assert_equal "_methods/configuration.md", @document.relative_path
|
||||
end
|
||||
|
|
|
@ -8,8 +8,7 @@ class TestDraft < Test::Unit::TestCase
|
|||
context "A Draft" do
|
||||
setup do
|
||||
clear_dest
|
||||
stub(Jekyll).configuration { Jekyll::Configuration::DEFAULTS }
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(site_configuration)
|
||||
end
|
||||
|
||||
should "ensure valid drafts are valid" do
|
||||
|
|
|
@ -3,10 +3,7 @@ require 'helper'
|
|||
class TestEntryFilter < Test::Unit::TestCase
|
||||
context "Filtering entries" do
|
||||
setup do
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
|
||||
end
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(site_configuration)
|
||||
end
|
||||
|
||||
should "filter entries" do
|
||||
|
@ -50,10 +47,7 @@ class TestEntryFilter < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should "filter symlink entries when safe mode enabled" do
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'safe' => true})
|
||||
end
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration('safe' => true))
|
||||
stub(File).symlink?('symlink.js') {true}
|
||||
files = %w[symlink.js]
|
||||
assert_equal [], site.filter_entries(files)
|
||||
|
@ -66,10 +60,7 @@ class TestEntryFilter < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should "not include symlinks in safe mode" do
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'safe' => true})
|
||||
end
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration('safe' => true))
|
||||
|
||||
site.read_directories("symlink-test")
|
||||
assert_equal [], site.pages
|
||||
|
@ -77,10 +68,7 @@ class TestEntryFilter < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should "include symlinks in unsafe mode" do
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'safe' => false})
|
||||
end
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration)
|
||||
|
||||
site.read_directories("symlink-test")
|
||||
assert_not_equal [], site.pages
|
||||
|
@ -90,10 +78,7 @@ class TestEntryFilter < Test::Unit::TestCase
|
|||
|
||||
context "#glob_include?" do
|
||||
setup do
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
|
||||
end
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(site_configuration)
|
||||
@filter = EntryFilter.new(@site)
|
||||
end
|
||||
|
||||
|
|
|
@ -13,10 +13,7 @@ class TestExcerpt < Test::Unit::TestCase
|
|||
context "With extraction disabled" do
|
||||
setup do
|
||||
clear_dest
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'excerpt_separator' => ''})
|
||||
end
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(site_configuration('excerpt_separator' => ''))
|
||||
@post = setup_post("2013-07-22-post-excerpt-with-layout.markdown")
|
||||
end
|
||||
|
||||
|
@ -29,8 +26,7 @@ class TestExcerpt < Test::Unit::TestCase
|
|||
context "An extracted excerpt" do
|
||||
setup do
|
||||
clear_dest
|
||||
stub(Jekyll).configuration { Jekyll::Configuration::DEFAULTS }
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(site_configuration)
|
||||
@post = setup_post("2013-07-22-post-excerpt-with-layout.markdown")
|
||||
@excerpt = @post.send :extract_excerpt
|
||||
end
|
||||
|
|
|
@ -15,8 +15,11 @@ class TestPage < Test::Unit::TestCase
|
|||
context "A Page" do
|
||||
setup do
|
||||
clear_dest
|
||||
stub(Jekyll).configuration { Jekyll::Configuration::DEFAULTS }
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(Jekyll.configuration({
|
||||
"source" => source_dir,
|
||||
"destination" => dest_dir,
|
||||
"skip_config_files" => true
|
||||
}))
|
||||
end
|
||||
|
||||
context "processing pages" do
|
||||
|
|
|
@ -15,8 +15,11 @@ class TestPost < Test::Unit::TestCase
|
|||
context "A Post" do
|
||||
setup do
|
||||
clear_dest
|
||||
stub(Jekyll).configuration { Jekyll::Configuration::DEFAULTS }
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(Jekyll.configuration({
|
||||
"skip_config_files" => true,
|
||||
"source" => source_dir,
|
||||
"destination" => dest_dir
|
||||
}))
|
||||
end
|
||||
|
||||
should "ensure valid posts are valid" do
|
||||
|
@ -145,7 +148,7 @@ class TestPost < Test::Unit::TestCase
|
|||
do_render(post)
|
||||
post.write(dest_dir)
|
||||
|
||||
assert !File.exist?(unexpected)
|
||||
assert !File.exist?(unexpected), "../../../baddie.html should not exist."
|
||||
assert File.exist?(File.expand_path("baddie.html", dest_dir))
|
||||
end
|
||||
|
||||
|
@ -606,7 +609,7 @@ class TestPost < Test::Unit::TestCase
|
|||
|
||||
should "include templates" do
|
||||
post = setup_post("2008-12-13-include.markdown")
|
||||
post.site.source = File.join(File.dirname(__FILE__), 'source')
|
||||
post.site.instance_variable_set(:@source, File.join(File.dirname(__FILE__), 'source'))
|
||||
do_render(post)
|
||||
|
||||
assert_equal "<<< <hr />\n<p>Tom Preston-Werner\ngithub.com/mojombo</p>\n\n<p>This <em>is</em> cool</p>\n >>>", post.output
|
||||
|
@ -685,7 +688,7 @@ class TestPost < Test::Unit::TestCase
|
|||
|
||||
context "site config with category" do
|
||||
setup do
|
||||
config = Jekyll::Configuration::DEFAULTS.merge({
|
||||
config = site_configuration({
|
||||
'defaults' => [
|
||||
'scope' => {
|
||||
'path' => ''
|
||||
|
@ -712,7 +715,7 @@ class TestPost < Test::Unit::TestCase
|
|||
|
||||
context "site config with categories" do
|
||||
setup do
|
||||
config = Jekyll::Configuration::DEFAULTS.merge({
|
||||
config = site_configuration({
|
||||
'defaults' => [
|
||||
'scope' => {
|
||||
'path' => ''
|
||||
|
|
|
@ -8,7 +8,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should "look for plugins under the site directory by default" do
|
||||
site = Site.new(Jekyll::Configuration::DEFAULTS.merge({'source' => File.expand_path(source_dir)}))
|
||||
site = Site.new(site_configuration)
|
||||
assert_equal [File.join(source_dir, '_plugins')], site.plugins
|
||||
end
|
||||
|
||||
|
@ -44,30 +44,35 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
context "creating sites" do
|
||||
setup do
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
|
||||
end
|
||||
@site = Site.new(Jekyll.configuration)
|
||||
@site = Site.new(site_configuration)
|
||||
@num_invalid_posts = 4
|
||||
end
|
||||
|
||||
teardown do
|
||||
if defined?(MyGenerator)
|
||||
self.class.send(:remove_const, :MyGenerator)
|
||||
end
|
||||
end
|
||||
|
||||
should "have an empty tag hash by default" do
|
||||
assert_equal Hash.new, @site.tags
|
||||
end
|
||||
|
||||
should "give site with parsed pages and posts to generators" do
|
||||
@site.reset
|
||||
@site.read
|
||||
class MyGenerator < Generator
|
||||
def generate(site)
|
||||
site.pages.dup.each do |page|
|
||||
raise "#{page} isn't a page" unless page.is_a?(Page)
|
||||
raise "#{page} doesn't respond to :name" unless page.respond_to?(:name)
|
||||
end
|
||||
site.file_read_opts[:secret_message] = 'hi'
|
||||
end
|
||||
end
|
||||
@site = Site.new(site_configuration)
|
||||
@site.read
|
||||
@site.generate
|
||||
assert_not_equal 0, @site.pages.size
|
||||
assert_equal 'hi', @site.file_read_opts[:secret_message]
|
||||
end
|
||||
|
||||
should "reset data before processing" do
|
||||
|
@ -221,22 +226,14 @@ class TestSite < Test::Unit::TestCase
|
|||
|
||||
context 'error handling' do
|
||||
should "raise if destination is included in source" do
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => source_dir})
|
||||
end
|
||||
|
||||
assert_raise Jekyll::Errors::FatalException do
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration('destination' => source_dir))
|
||||
end
|
||||
end
|
||||
|
||||
should "raise if destination is source" do
|
||||
stub(Jekyll).configuration do
|
||||
Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => File.join(source_dir, "..")})
|
||||
end
|
||||
|
||||
assert_raise Jekyll::Errors::FatalException do
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration('destination' => File.join(source_dir, "..")))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -281,7 +278,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should 'remove orphaned files in destination - keep_files .svn' do
|
||||
config = Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'keep_files' => ['.svn']})
|
||||
config = site_configuration('keep_files' => %w{.svn})
|
||||
@site = Site.new(config)
|
||||
@site.process
|
||||
assert !File.exist?(dest_dir('.htpasswd'))
|
||||
|
@ -308,7 +305,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
custom_processor = "CustomMarkdown"
|
||||
s = Site.new(Jekyll.configuration.merge({ 'markdown' => custom_processor }))
|
||||
s = Site.new(site_configuration('markdown' => custom_processor))
|
||||
assert_nothing_raised do
|
||||
s.process
|
||||
end
|
||||
|
@ -331,7 +328,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
bad_processor = "Custom::Markdown"
|
||||
s = Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor }))
|
||||
s = Site.new(site_configuration('markdown' => bad_processor))
|
||||
assert_raise Jekyll::Errors::FatalException do
|
||||
s.process
|
||||
end
|
||||
|
@ -345,13 +342,13 @@ class TestSite < Test::Unit::TestCase
|
|||
should 'not throw an error at initialization time' do
|
||||
bad_processor = 'not a processor name'
|
||||
assert_nothing_raised do
|
||||
Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor }))
|
||||
Site.new(site_configuration('markdown' => bad_processor))
|
||||
end
|
||||
end
|
||||
|
||||
should 'throw FatalException at process time' do
|
||||
bad_processor = 'not a processor name'
|
||||
s = Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor }))
|
||||
s = Site.new(site_configuration('markdown' => bad_processor))
|
||||
assert_raise Jekyll::Errors::FatalException do
|
||||
s.process
|
||||
end
|
||||
|
@ -360,7 +357,7 @@ class TestSite < Test::Unit::TestCase
|
|||
|
||||
context 'data directory' do
|
||||
should 'auto load yaml files' do
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration)
|
||||
site.process
|
||||
|
||||
file_content = SafeYAML.load_file(File.join(source_dir, '_data', 'members.yaml'))
|
||||
|
@ -370,7 +367,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should 'auto load yml files' do
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration)
|
||||
site.process
|
||||
|
||||
file_content = SafeYAML.load_file(File.join(source_dir, '_data', 'languages.yml'))
|
||||
|
@ -380,7 +377,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should 'auto load json files' do
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration)
|
||||
site.process
|
||||
|
||||
file_content = SafeYAML.load_file(File.join(source_dir, '_data', 'members.json'))
|
||||
|
@ -390,7 +387,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should 'auto load yaml files in subdirectory' do
|
||||
site = Site.new(Jekyll.configuration)
|
||||
site = Site.new(site_configuration)
|
||||
site.process
|
||||
|
||||
file_content = SafeYAML.load_file(File.join(source_dir, '_data', 'categories', 'dairy.yaml'))
|
||||
|
@ -400,7 +397,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should "load symlink files in unsafe mode" do
|
||||
site = Site.new(Jekyll.configuration.merge({'safe' => false}))
|
||||
site = Site.new(site_configuration('safe' => false))
|
||||
site.process
|
||||
|
||||
file_content = SafeYAML.load_file(File.join(source_dir, '_data', 'products.yml'))
|
||||
|
@ -410,7 +407,7 @@ class TestSite < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should "not load symlink files in safe mode" do
|
||||
site = Site.new(Jekyll.configuration.merge({'safe' => true}))
|
||||
site = Site.new(site_configuration('safe' => true))
|
||||
site.process
|
||||
|
||||
assert_nil site.data['products']
|
||||
|
|
Loading…
Reference in New Issue