Incrementally regenerate missing destination file

Addresses the third point of #3591, in which the incremental regenerator doesn't notice that destination files have gone missing.
This commit is contained in:
Nicholas Burlett 2015-03-21 19:25:02 -07:00
parent e770a080a7
commit 706007ead9
3 changed files with 79 additions and 8 deletions

View File

@ -18,16 +18,21 @@ module Jekyll
def regenerate?(document) def regenerate?(document)
case document case document
when Post, Page when Post, Page
document.asset_file? || document.data['regenerate'] || return ( document.asset_file? ||
modified?(site.in_source_dir(document.relative_path)) document.data['regenerate'] ||
source_modified_or_dest_missing?(
site.in_source_dir(document.relative_path),
document.destination(@site.dest)) )
when Document when Document
!document.write? || document.data['regenerate'] || modified?(document.path) return ( !document.write? ||
document.data['regenerate'] ||
source_modified_or_dest_missing?(
document.path,
document.destination(@site.dest)) )
else else
if document.respond_to?(:path) source_path = document.respond_to?(:path) ? document.path : nil
modified?(document.path) dest_path = document.respond_to?(:destination) ? document.destination(@site.dest) : nil
else return source_modified_or_dest_missing?(source_path, dest_path)
true
end
end end
end end
@ -67,6 +72,17 @@ module Jekyll
@cache = {} @cache = {}
end end
# Checks if the source has been modified or the
# destination is missing
#
# returns a boolean
def source_modified_or_dest_missing?(source_path, dest_path)
source_modified = source_path ? modified?(source_path) : true
dest_missing = dest_path ? !File.exist?(dest_path) : false
return source_modified || dest_missing
end
# Checks if a path's (or one of its dependencies) # Checks if a path's (or one of its dependencies)
# mtime has changed # mtime has changed
# #

View File

@ -36,14 +36,50 @@ class TestRegenerator < JekyllUnitTest
@regenerator.regenerate?(@document) @regenerator.regenerate?(@document)
@regenerator.regenerate?(@asset_file) @regenerator.regenerate?(@asset_file)
# we need to create the destinations for these files,
# because regenerate? checks if the destination exists
[@page, @post, @document, @asset_file].each do |item|
if item.respond_to?(:destination)
dest = item.destination(@site.dest)
FileUtils.mkdir_p(File.dirname(dest))
FileUtils.touch(dest)
end
end
@regenerator.write_metadata @regenerator.write_metadata
@regenerator = Regenerator.new(@site) @regenerator = Regenerator.new(@site)
# these should pass, since nothing has changed, and the
# loop above made sure the desinations exist
assert !@regenerator.regenerate?(@page) assert !@regenerator.regenerate?(@page)
assert !@regenerator.regenerate?(@post) assert !@regenerator.regenerate?(@post)
assert !@regenerator.regenerate?(@document) assert !@regenerator.regenerate?(@document)
end end
should "regenerate if destination missing" do
# Process files
@regenerator.regenerate?(@page)
@regenerator.regenerate?(@post)
@regenerator.regenerate?(@document)
@regenerator.regenerate?(@asset_file)
@regenerator.write_metadata
@regenerator = Regenerator.new(@site)
# make sure the files don't actually exist
[@page, @post, @document, @asset_file].each do |item|
if item.respond_to?(:destination)
dest = item.destination(@site.dest)
File.unlink(dest) unless !File.exist?(dest)
end
end
# while nothing has changed, the output files were not
# generated, so they still need to be regenerated
assert @regenerator.regenerate?(@page)
assert @regenerator.regenerate?(@post)
assert @regenerator.regenerate?(@document)
end
should "always regenerate asset files" do should "always regenerate asset files" do
assert @regenerator.regenerate?(@asset_file) assert @regenerator.regenerate?(@asset_file)
end end

View File

@ -495,6 +495,25 @@ class TestSite < JekyllUnitTest
assert_equal mtime3, mtime4 # no modifications, so remain the same assert_equal mtime3, mtime4 # no modifications, so remain the same
end end
should "regnerate files that have had their destination deleted" do
contacts_html = @site.pages.find { |p| p.name == "contacts.html" }
@site.process
source = @site.in_source_dir(contacts_html.path)
dest = File.expand_path(contacts_html.destination(@site.dest))
mtime1 = File.stat(dest).mtime.to_i # first run must generate dest file
# simulate file modification by user
File.unlink dest
refute File.exist?(dest)
sleep 1
@site.process
assert File.exist?(dest)
mtime2 = File.stat(dest).mtime.to_i
refute_equal mtime1, mtime2 # must be regenerated
end
end end
end end