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

Disable watch to prevent race condition between threads calling site.process #320

Merged
merged 23 commits into from
Mar 15, 2017
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fd83a67
When updating a document or page, read item by itself
parkr Mar 9, 2017
1203e14
Use ensure_* helper methods and use this more robust method as a fall…
parkr Mar 9, 2017
9e7b78d
Use accurate method names; add the || for the page server back.
parkr Mar 11, 2017
efd6ede
Merge branch 'master' into prevent-race-condition-on-change
mertkahyaoglu Mar 11, 2017
4ce5082
centralize path manipulation methods in server.rb
benbalter Mar 13, 2017
c43c34e
slightly less abstraction
benbalter Mar 13, 2017
0c170bd
DRY up removing the site source
benbalter Mar 13, 2017
82aba50
move path helper methods to its own module
benbalter Mar 13, 2017
a573bb5
correct rubocop offenses;
benbalter Mar 13, 2017
87f8e2b
centralize file manipulation methods in file helper
benbalter Mar 14, 2017
9514901
autoload ALL THE THINGS!
benbalter Mar 14, 2017
2bf85ae
add some missing tests
benbalter Mar 14, 2017
3652c41
use FileHelper and PathHelper for DataFile methods
benbalter Mar 14, 2017
f4d94ab
add entries url to collection hash
benbalter Mar 14, 2017
1d5a49b
directory_path should be private
benbalter Mar 14, 2017
5a87555
actually, actually disable watch
benbalter Mar 14, 2017
e26934f
Use @ashmaroli's approach to monkey patching the build command to dis…
benbalter Mar 15, 2017
7d086f2
stop server before starting just in case
benbalter Mar 15, 2017
c8fab6c
-f, not -9
benbalter Mar 15, 2017
e1af381
Merge branch 'master' into prevent-race-condition-on-change
benbalter Mar 15, 2017
28c4f9c
revert changes to lib/jekyll/commands/serve.rb
benbalter Mar 15, 2017
1f8c8c2
test --watch with this plugin
ashmaroli Mar 15, 2017
bce59f7
Merge pull request #324 from ashmaroli/test-watch-admin
benbalter Mar 15, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 20 additions & 22 deletions lib/jekyll-admin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,18 @@
require "sinatra/reloader"
require "sinatra/namespace"

# Jekyll-Admin stuffs
require "jekyll-admin/version"
require "jekyll-admin/server"
require "jekyll-admin/static_server"
require "jekyll-admin/server/collection.rb"
require "jekyll-admin/server/configuration.rb"
require "jekyll-admin/server/data.rb"
require "jekyll-admin/server/page.rb"
require "jekyll-admin/server/static_file.rb"
require "jekyll-admin/apiable.rb"
require "jekyll-admin/urlable.rb"
require "jekyll-admin/data_file.rb"
require "jekyll-admin/directory.rb"
require "jekyll-admin/page_without_a_file.rb"

# Monkey Patches
require_relative "./jekyll/commands/serve"
[Jekyll::Page, Jekyll::Document, Jekyll::StaticFile, Jekyll::Collection].each do |klass|
klass.include JekyllAdmin::APIable
klass.include JekyllAdmin::URLable
end

module JekyllAdmin
autoload :APIable, "jekyll-admin/apiable"
autoload :DataFile, "jekyll-admin/data_file"
autoload :Directory, "jekyll-admin/directory"
autoload :FileHelper, "jekyll-admin/file_helper"
autoload :PageWithoutAFile, "jekyll-admin/page_without_a_file"
autoload :PathHelper, "jekyll-admin/path_helper"
autoload :Server, "jekyll-admin/server"
autoload :StaticServer, "jekyll-admin/static_server"
autoload :URLable, "jekyll-admin/urlable"
autoload :Version, "jekyll-admin/version"

def self.site
@site ||= begin
site = Jekyll.sites.first
Expand All @@ -47,3 +36,12 @@ def self.site
end
end
end

# Monkey Patches
require_relative "./jekyll/commands/serve"
require_relative "./jekyll/command"

[Jekyll::Page, Jekyll::Document, Jekyll::StaticFile, Jekyll::Collection].each do |klass|
klass.include JekyllAdmin::APIable
klass.include JekyllAdmin::URLable
end
1 change: 1 addition & 0 deletions lib/jekyll-admin/apiable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def to_api(include_content: false)
# array with each rendered document, which we don't want.
if is_a?(Jekyll::Collection)
output.delete("docs")
output["entries_url"] = entries_url
end

if is_a?(Jekyll::Document)
Expand Down
25 changes: 11 additions & 14 deletions lib/jekyll-admin/data_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ class DataFile

include APIable
include URLable
include PathHelper
extend PathHelper

alias_method :path, :relative_path

# Initialize a new DataFile object
#
Expand All @@ -17,17 +21,6 @@ def exists?
@exists ||= File.exist?(absolute_path)
end

def absolute_path
@absolute_path ||= Jekyll.sanitized_path(JekyllAdmin.site.source, relative_path)
end
alias_method :file_path, :absolute_path

# Returns the relative path relative to site source
def relative_path
@relative_path = File.join(DataFile.data_dir, basename_with_extension)
end
alias_method :path, :relative_path

# Returns unparsed content as it exists on disk
def raw_content
@raw_content ||= File.open(absolute_path, "r:UTF-8", &:read)
Expand Down Expand Up @@ -65,10 +58,9 @@ def to_liquid
end

def self.all
data_dir = Jekyll.sanitized_path(JekyllAdmin.site.source, DataFile.data_dir)
data_dir = Pathname.new(data_dir)
data_dir = sanitized_path DataFile.data_dir
Dir["#{data_dir}/*.{#{EXTENSIONS.join(",")}}"].map do |path|
new(Pathname.new(path).relative_path_from(data_dir).to_s)
new path_without_site_source(path)
end
end

Expand All @@ -90,5 +82,10 @@ def basename
def basename_with_extension
[basename, extension].join
end
alias_method :filename, :basename_with_extension

def namespace
"data"
end
end
end
64 changes: 64 additions & 0 deletions lib/jekyll-admin/file_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module JekyllAdmin
module FileHelper

# The file the user requested in the URL
def requested_file
find_by_path(path)
end

# The file ultimately written to disk
# This may be the requested file, or in the case of a rename will be read
# from the new path that was actually written to disk
def written_file
find_by_path(write_path)
end

# Write a file to disk with the given content
def write_file(path, content)
Jekyll.logger.debug "WRITING:", path
path = sanitized_path(path)
FileUtils.mkdir_p File.dirname(path)
File.write(path, content)
site.process
end

# Delete the file at the given path
def delete_file(path)
Jekyll.logger.debug "DELETING:", path
FileUtils.rm_f sanitized_path(path)
site.process
end

private

def ensure_requested_file
ensure_file(requested_file)
end

def ensure_written_file
ensure_file(written_file)
end

def find_by_path(path)
files = case namespace
when "collections"
collection.docs
when "data"
DataFile.all
when "pages", "static_files"
site.public_send(namespace.to_sym)
else
[]
end
files.find { |f| sanitized_path(f.path) == path }
end

def ensure_file(file)
render_404 if file.nil?
end

def ensure_directory
render_404 unless Dir.exist?(directory_path)
end
end
end
74 changes: 74 additions & 0 deletions lib/jekyll-admin/path_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
module JekyllAdmin
module PathHelper
def sanitized_path(path)
path = path_without_site_source(path)
Jekyll.sanitized_path JekyllAdmin.site.source, path
end

# Returns the basename + extension for the requested file
def filename
params["ext"] ||= "yml" if namespace == "data"
"#{params["path"]}.#{params["ext"]}"
end

# Returns the sanitized path relative to the site source
def sanitized_relative_path(path)
path_without_site_source sanitized_path(path)
end

# Returns the sanitized absolute path to the requested object
def absolute_path
sanitized_path File.join(directory_path, filename)
end
alias_method :path, :absolute_path

# Returns the sanitized relative path to the requested object
def relative_path
sanitized_relative_path absolute_path
end

# Returns the sanitized absolute path to write the requested object
def write_path
if renamed?
sanitized_path request_payload["path"]
else
path
end
end
alias_method :request_path, :write_path

# Returns the sanitized relative path to write the requested object
def relative_write_path
sanitized_relative_path write_path
end

# Is this request renaming a file?
def renamed?
return false unless request_payload["path"]
ensure_leading_slash(request_payload["path"]) != relative_path
end

private

# Returns the path to the requested file's containing directory
def directory_path
case namespace
when "collections"
sanitized_path File.join(collection.relative_directory, params["splat"].first)
when "data"
sanitized_path File.join(DataFile.data_dir)
else
sanitized_path params["splat"].first
end
end

def ensure_leading_slash(input)
return input if input.nil? || input.empty? || input.start_with?("/")
"/#{input}"
end

def path_without_site_source(path)
path.to_s.gsub(%r!\A#{Regexp.escape(JekyllAdmin.site.source)}!, "")
end
end
end
39 changes: 22 additions & 17 deletions lib/jekyll-admin/server.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module JekyllAdmin
class Server < Sinatra::Base
ROUTES = %w(collections configuration data pages static_files).freeze
include JekyllAdmin::PathHelper
include JekyllAdmin::FileHelper

register Sinatra::Namespace

Expand Down Expand Up @@ -40,20 +42,17 @@ def render_404
end

def request_payload
@request_payload ||= begin
request.body.rewind
JSON.parse request.body.read
end
@request_payload ||= if request_body.to_s.empty?
{}
else
JSON.parse(request_body)
end
end

def base_url
"#{request.scheme}://#{request.host_with_port}"
end

def sanitized_path(questionable_path)
Jekyll.sanitized_path JekyllAdmin.site.source, questionable_path
end

def front_matter
request_payload["front_matter"]
end
Expand All @@ -69,18 +68,24 @@ def document_body
end
alias page_body document_body

def write_file(path, content)
path = sanitized_path(path)
FileUtils.mkdir_p File.dirname(path)
File.open(path, "wb") do |file|
file.write(content)
private

def request_body
@request_body ||= begin
request.body.rewind
request.body.read
end
site.process
end

def delete_file(path)
File.delete sanitized_path(path)
site.process
def namespace
namespace = request.path_info.split("/")[1].to_s.downcase
namespace if ROUTES.include?(namespace)
end
end
end

require "jekyll-admin/server/collection"
require "jekyll-admin/server/configuration"
require "jekyll-admin/server/data"
require "jekyll-admin/server/page"
require "jekyll-admin/server/static_file"
Loading