Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor collections_dir feature for consistency #6685

Merged
merged 4 commits into from Jan 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
161 changes: 161 additions & 0 deletions features/collections_dir.feature
@@ -0,0 +1,161 @@
Feature: Collections Directory
As a hacker who likes to structure content without clutter
I want to be able to organize my collections under a single directory
And render them from there

Scenario: Custom collections_dir containing only posts
And I have a collections/_posts directory
And I have the following post within the "collections" directory:
| title | date | content |
| Gathered Post | 2009-03-27 | Random Content. |
And I have a "_config.yml" file with content:
"""
collections_dir: collections
"""
When I run jekyll build
Then I should get a zero exit status
And the _site directory should exist
And I should see "Random Content." in "_site/2009/03/27/gathered-post.html"

Scenario: Rendered collection in custom collections_dir also containing posts
Given I have a collections/_puppies directory
And I have the following document under the "puppies" collection within the "collections" directory:
| title | date | content |
| Rover | 2007-12-31 | content for Rover. |
And I have a collections/_posts directory
And I have the following post within the "collections" directory:
| title | date | content |
| Gathered Post | 2009-03-27 | Random Content. |
And I have a "_config.yml" file with content:
"""
collections:
puppies:
output: true

collections_dir: collections
"""
When I run jekyll build
Then I should get a zero exit status
And the _site directory should exist
And the "_site/puppies/rover.html" file should exist
And I should see "Random Content." in "_site/2009/03/27/gathered-post.html"

Scenario: Rendered collection in custom collections_dir with posts at the site root
Given I have a collections/_puppies directory
And I have the following document under the "puppies" collection within the "collections" directory:
| title | date | content |
| Rover | 2007-12-31 | content for Rover. |
And I have a _posts directory
And I have the following post:
| title | date | content |
| Post At Root | 2009-03-27 | Random Content. |
And I have a "_config.yml" file with content:
"""
collections:
puppies:
output: true

collections_dir: collections
"""
When I run jekyll build
Then I should get a zero exit status
And the _site directory should exist
And the "_site/puppies/rover.html" file should exist
And the "_site/2009/03/27/post-at-root.html" file should not exist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woof, this is going to screw people up. We can't enforce that the _posts directory is in the collections_dir until 4.0, if we even want to.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its not.. we just released this feature in 3.7.0 .. The sooner we ship this patch, the lesser no.of users gonna have issues..

And the _site/_posts directory should not exist

Scenario: Rendered collection in custom collections_dir also containing drafts
Given I have a collections/_puppies directory
And I have the following document under the "puppies" collection within the "collections" directory:
| title | date | content |
| Rover | 2007-12-31 | content for Rover. |
And I have a collections/_drafts directory
And I have the following draft within the "collections" directory:
| title | date | content |
| Gathered Draft | 2009-03-27 | Random Content. |
And I have a "_config.yml" file with content:
"""
collections:
puppies:
output: true

collections_dir: collections
"""
When I run jekyll build --drafts
Then I should get a zero exit status
And the _site directory should exist
And the "_site/puppies/rover.html" file should exist
And I should see "Random Content." in "_site/2009/03/27/gathered-draft.html"
And the _site/collections directory should not exist

Scenario: Rendered collection in custom collections_dir with drafts at the site root
Given I have a collections/_puppies directory
And I have the following document under the "puppies" collection within the "collections" directory:
| title | date | content |
| Rover | 2007-12-31 | content for Rover. |
And I have a _drafts directory
And I have the following draft:
| title | date | content |
| Draft At Root | 2009-03-27 | Random Content. |
And I have a "_config.yml" file with content:
"""
collections:
puppies:
output: true

collections_dir: collections
"""
When I run jekyll build --drafts
Then I should get a zero exit status
And the _site directory should exist
And the "_site/puppies/rover.html" file should exist
And the "_site/2009/03/27/draft-at-root.html" file should not exist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_drafts can't be enforced to be in collections_dir until 4.0 either.


Scenario: A complex site with collections posts and drafts at various locations
Given I have a gathering/_puppies directory
And I have a gathering/_posts directory
And I have a gathering/_drafts directory
And I have a _puppies directory
And I have a _posts directory
And I have a _drafts directory
And I have the following document under the "puppies" collection within the "gathering" directory:
| title | date | content |
| Rover in Gathering | 2007-12-31 | content for Rover. |
And I have the following document under the puppies collection:
| title | date | content |
| Rover At Root | 2007-12-31 | content for Rover. |
And I have the following post within the "gathering" directory:
| title | date | content |
| Post in Gathering | 2009-03-27 | Totally nothing. |
And I have the following post:
| title | date | content |
| Post At Root | 2009-03-27 | Totally nothing. |
And I have the following draft within the "gathering" directory:
| title | date | content |
| Draft In Gathering | 2009-03-27 | This is a draft. |
And I have the following draft:
| title | date | content |
| Draft At Root | 2009-03-27 | This is a draft. |
And I have a "_config.yml" file with content:
"""
collections:
puppies:
output: true

collections_dir: gathering
"""
And I have a "gathering/_puppies/static_file.txt" file that contains "Static content."
And I have a gathering/_puppies/nested directory
And I have a "gathering/_puppies/nested/static_file.txt" file that contains "Nested Static content."
When I run jekyll build --drafts
Then I should get a zero exit status
And the _site directory should exist
And the "_site/puppies/rover-in-gathering.html" file should exist
And the "_site/2009/03/27/post-in-gathering.html" file should exist
And the "_site/2009/03/27/draft-in-gathering.html" file should exist
And the "_site/2009/03/27/draft-at-root.html" file should not exist
And the "_site/puppies/rover-at-root.html" file should not exist
And I should see exactly "Static content." in "_site/puppies/static_file.txt"
And I should see exactly "Nested Static content." in "_site/puppies/nested/static_file.txt"
And the _site/gathering directory should not exist
And the _site/_posts directory should not exist
24 changes: 24 additions & 0 deletions features/step_definitions.rb
Expand Up @@ -95,6 +95,20 @@

#

Given(%r!^I have the following (draft|post)s? within the "(.*)" directory:$!) do |type, folder, table|
table.hashes.each do |input_hash|
title = slug(input_hash["title"])
parsed_date = Time.xmlschema(input_hash["date"]) rescue Time.parse(input_hash["date"])

filename = type == "draft" ? "#{title}.markdown" : "#{parsed_date.strftime("%Y-%m-%d")}-#{title}.markdown"

path = File.join(folder, "_#{type}s", filename)
File.write(path, file_content_from_hash(input_hash))
end
end

#

Given(%r!^I have the following documents? under the (.*) collection:$!) do |folder, table|
table.hashes.each do |input_hash|
title = slug(input_hash["title"])
Expand All @@ -108,6 +122,16 @@

#

Given(%r!^I have the following documents? under the "(.*)" collection within the "(.*)" directory:$!) do |label, dir, table|
table.hashes.each do |input_hash|
title = slug(input_hash["title"])
path = File.join(dir, "_#{label}", "#{title}.md")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why you chose .md for documents but .markdown for the post / drafts step above?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only because that's how our default site gets created from jekyll new .. and I think, an existing step also has something similar set up.. not sure..

File.write(path, file_content_from_hash(input_hash))
end
end

#

Given(%r!^I have a configuration file with "(.*)" set to "(.*)"$!) do |key, value|
config = \
if source_dir.join("_config.yml").exist?
Expand Down
17 changes: 11 additions & 6 deletions lib/jekyll/collection.rb
Expand Up @@ -95,14 +95,13 @@ def filtered_entries
end
end

# The directory for this Collection, relative to the site source.
# The directory for this Collection, relative to the site source or the directory
# containing the collection.
#
# Returns a String containing the directory name where the collection
# is stored on the filesystem.
def relative_directory
@relative_directory ||= Pathname.new(directory).relative_path_from(
Pathname.new(site.source)
).to_s
@relative_directory ||= "_#{label}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be relative to the site source, so if source is . then it should be collections_dir/_label.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Things that're going to break if @relative_directory ||= collections_dir/_label:

if draft?
categories_from_path("_drafts")
else
categories_from_path(collection.relative_directory)
end

def draft?
data["draft"] ||= relative_path.index(collection.relative_directory).nil? &&
collection.label == "posts"
end

def cleaned_relative_path
@cleaned_relative_path ||=
relative_path[0..-extname.length - 1].sub(collection.relative_directory, "")
end

end

# The full path to the directory containing the collection.
Expand All @@ -111,7 +110,7 @@ def relative_directory
# is stored on the filesystem.
def directory
@directory ||= site.in_source_dir(
File.join(site.config["collections_dir"], "_#{label}")
File.join(container, relative_directory)
)
end

Expand All @@ -125,7 +124,7 @@ def directory
# is stored on the filesystem.
def collection_dir(*files)
return directory if files.empty?
site.in_source_dir(relative_directory, *files)
site.in_source_dir(container, relative_directory, *files)
end

# Checks whether the directory "exists" for this collection.
Expand Down Expand Up @@ -204,6 +203,12 @@ def extract_metadata

private

def container
@container ||= site.config["collections_dir"]
end

private

def read_document(full_path)
doc = Jekyll::Document.new(full_path, :site => site, :collection => self)
doc.read
Expand Down
17 changes: 8 additions & 9 deletions lib/jekyll/document.rb
Expand Up @@ -78,12 +78,13 @@ def draft?
collection.label == "posts"
end

# The path to the document, relative to the site source.
# The path to the document, relative to the collections_dir.
#
# Returns a String path which represents the relative path
# from the site source to this document
# Returns a String path which represents the relative path from the collections_dir
# to this document.
def relative_path
@relative_path ||= Pathutil.new(path).relative_path_from(site.source).to_s
@relative_path ||=
Pathutil.new(path).relative_path_from(site.collections_path).to_s
end

# The output extension of the document.
Expand Down Expand Up @@ -399,11 +400,9 @@ def categories_from_path(special_dir)
def populate_categories
merge_data!({
"categories" => (
Array(data["categories"]) + Utils.pluralized_array_from_hash(
data,
"category",
"categories"
)
Array(data["categories"]) + Utils.pluralized_array_from_hash(
data, "category", "categories"
)
).map(&:to_s).flatten.uniq,
})
end
Expand Down
16 changes: 16 additions & 0 deletions lib/jekyll/reader.rb
Expand Up @@ -62,6 +62,7 @@ def read_directories(dir = "")
#
# Returns nothing.
def retrieve_posts(dir)
return if outside_configured_directory?(dir)
site.posts.docs.concat(PostReader.new(site).read_posts(dir))
site.posts.docs.concat(PostReader.new(site).read_drafts(dir)) if site.show_drafts
end
Expand Down Expand Up @@ -130,5 +131,20 @@ def get_entries(dir, subfolder)
entries = Dir.chdir(base) { filter_entries(Dir["**/*"], base) }
entries.delete_if { |e| File.directory?(site.in_source_dir(base, e)) }
end

private

# Internal
#
# Determine if the directory is supposed to contain posts and drafts.
# If the user has defined a custom collections_dir, then attempt to read
# posts and drafts only from within that directory.
#
# Returns true if a custom collections_dir has been set but current directory lies
# outside that directory.
def outside_configured_directory?(dir)
collections_dir = site.config["collections_dir"]
!collections_dir.empty? && !dir.start_with?("/#{collections_dir}")
end
end
end
9 changes: 9 additions & 0 deletions lib/jekyll/site.rb
Expand Up @@ -391,6 +391,15 @@ def in_dest_dir(*paths)
end
end

# Public: The full path to the directory that houses all the collections registered
# with the current site.
#
# Returns the source directory or the absolute path to the custom collections_dir
def collections_path
dir_str = config["collections_dir"]
@collections_path ||= dir_str.empty? ? source : in_source_dir(dir_str)
end

# Limits the current posts; removes the posts which exceed the limit_posts
#
# Returns nothing
Expand Down
7 changes: 6 additions & 1 deletion lib/jekyll/static_file.rb
Expand Up @@ -40,7 +40,12 @@ def initialize(site, base, dir, name, collection = nil)

# Returns source file path.
def path
File.join(*[@base, @dir, @name].compact)
# Static file is from a collection inside custom collections directory
if !@collection.nil? && !@site.config["collections_dir"].empty?
File.join(*[@base, @site.config["collections_dir"], @dir, @name].compact)
else
File.join(*[@base, @dir, @name].compact)
end
end

# Obtain destination path.
Expand Down