From: Joey Hess Date: Sun, 18 Jul 2010 21:39:28 +0000 (-0400) Subject: Merge branch 'master' of ssh://git.ikiwiki.info/srv/git/ikiwiki.info X-Git-Tag: 3.20100722~16 X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/commitdiff_plain/ad8cb6d6fafa77be4e97a983d1b209f79aaf65ac?hp=9ea48dd49bc37bca9c7efe9a35541360b67a51aa Merge branch 'master' of ssh://git.ikiwiki.info/srv/git/ikiwiki.info --- diff --git a/IkiWiki.pm b/IkiWiki.pm index 701f7137d..fa49b2c34 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -823,6 +823,17 @@ sub prep_writefile ($$) { if (-l "$destdir/$test") { error("cannot write to a symlink ($test)"); } + if (-f _ && $test ne $file) { + # Remove conflicting file. + foreach my $p (keys %renderedfiles, keys %oldrenderedfiles) { + foreach my $f (@{$renderedfiles{$p}}, @{$oldrenderedfiles{$p}}) { + if ($f eq $test) { + unlink("$destdir/$test"); + last; + } + } + } + } $test=dirname($test); } @@ -876,10 +887,36 @@ sub will_render ($$;$) { my $dest=shift; my $clear=shift; - # Important security check. + # Important security check for independently created files. if (-e "$config{destdir}/$dest" && ! $config{rebuild} && ! grep { $_ eq $dest } (@{$renderedfiles{$page}}, @{$oldrenderedfiles{$page}}, @{$wikistate{editpage}{previews}})) { - error("$config{destdir}/$dest independently created, not overwriting with version from $page"); + my $from_other_page=0; + # Expensive, but rarely runs. + foreach my $p (keys %renderedfiles, keys %oldrenderedfiles) { + if (grep { + $_ eq $dest || + dirname($_) eq $dest + } @{$renderedfiles{$p}}, @{$oldrenderedfiles{$p}}) { + $from_other_page=1; + last; + } + } + + error("$config{destdir}/$dest independently created, not overwriting with version from $page") + unless $from_other_page; + } + + # If $dest exists as a directory, remove conflicting files in it + # rendered from other pages. + if (-d _) { + foreach my $p (keys %renderedfiles, keys %oldrenderedfiles) { + foreach my $f (@{$renderedfiles{$p}}, @{$oldrenderedfiles{$p}}) { + if ($f eq dirname($dest) || dirname($f) eq $dest) { + unlink("$config{destdir}/$f"); + rmdir(dirname("$config{destdir}/$f")); + } + } + } } if (! $clear || $cleared{$page}) { diff --git a/debian/changelog b/debian/changelog index bb9a43692..21b5d01fa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -18,6 +18,8 @@ ikiwiki (3.20100705) UNRELEASED; urgency=low * po: needstranslation() pagespec can have a percent specified. * Drop Cache-Control must-revalidate (Firefox 3.5.10 does not seem to have the caching problem that was added to work around). Closes: #588623 + * Made much more robust in cases where multiple source files produce + conflicting files/directories in the destdir. -- Joey Hess Mon, 05 Jul 2010 13:59:42 -0400 diff --git a/doc/bugs/conflicts.mdwn b/doc/bugs/conflicts.mdwn new file mode 100644 index 000000000..bef0f54cd --- /dev/null +++ b/doc/bugs/conflicts.mdwn @@ -0,0 +1,32 @@ +The `conflicts` testcase has 4 failing test cases. The underlaying problem +is that there are multiple possible source files that can create the same +destination files. + +1. `foo.mdwn` is in srcdir, rendered to destdir. Then + it is removed, and `foo` is added, which will be rendered + raw to destdir. Since the `foo/` directory still exists, + it fails. +1. `foo` is added to srcdir, rendered raw to destdir. + Then it is removed from srcdir, and `foo.mdwn` is added. + The `foo` file is still present in the destdir, and mkdir + of the directory `foo/` fails. +1. `foo.mdwn` renders to `foo/index.html`. Then `foo/index.html` + is added to the srcdir, using rawhtml. It renders to the same + thing. +1. `foo/index.html` in srcdir is rendered to same thing in destdir + using rawhtml. Then `foo.mdwn` is added; renders same thing. + +Note that another case, that of page `foo.mdwn` and page `foo.txt`, that +both render to `foo/index.html`, used to cause problems, but no longer +crashes ikiwiki. It now only complains in this situation, and which +file "wins" is undefined. The fix for this relied on both pages being +named `foo`; but in the above cases, the source files have different +pagenames. + +One approach: Beef up checking in `will_render` to detect when the same +destination file is rendered by multiple pages. Or when one page renders +a file that is a parent directory of the rendered file of another page. +It could warn, rather than erroring. The last page rendered would "win"; +generating the destdir file. + +[[done]] diff --git a/t/conflicts.t b/t/conflicts.t index 7748c105f..d7e04d3ae 100755 --- a/t/conflicts.t +++ b/t/conflicts.t @@ -2,7 +2,7 @@ # Tests for bugs relating to conflicting files in the srcdir use warnings; use strict; -use Test::More 'no_plan'; +use Test::More tests => 106; # setup my $srcdir="t/tmp/src"; @@ -48,6 +48,35 @@ ok(! system("touch $srcdir/foo.mdwn")); ok(! system("touch $srcdir/foo.txt")); setupiki("conflicting page sources in setup"); +# Page and non-page file with same pagename. +newsrcdir(); +ok(! system("touch $srcdir/foo.mdwn")); +ok(! system("touch $srcdir/foo")); +setupiki("conflicting page and non-page in setup"); +newsrcdir(); +ok(! system("touch $srcdir/foo.mdwn")); +setupiki("initial setup"); +ok(! system("touch $srcdir/foo")); +refreshiki("conflicting page added (non-page already existing) in refresh"); +newsrcdir(); +ok(! system("touch $srcdir/foo")); +setupiki("initial setup"); +ok(! system("touch $srcdir/foo.mdwn")); +refreshiki("conflicting non-page added (page already existing) in refresh"); + +# Page that renders to a file that is also a subdirectory holding another +# file. +newsrcdir(); +ok(! system("touch $srcdir/foo.mdwn")); +ok(! system("mkdir -p $srcdir/foo/index.html")); +ok(! system("touch $srcdir/foo/index.html/bar.mdwn")); +setupiki("conflicting page file and subdirectory"); +newsrcdir(); +ok(! system("touch $srcdir/foo.mdwn")); +ok(! system("mkdir -p $srcdir/foo/index.html")); +ok(! system("touch $srcdir/foo/index.html/bar")); +setupiki("conflicting page file and subdirectory 2"); + # Changing a page file into a non-page could also cause ikiwiki to fail. newsrcdir(); ok(! system("touch $srcdir/foo.mdwn")); @@ -70,6 +99,27 @@ setupiki("initial setup"); ok(! system("mkdir -p $srcdir/foo")); ok(! system("touch $srcdir/foo/index.html")); refreshiki("rawhtml file rendered same as existing page in refresh"); +# Moved when refreshing +newsrcdir(); +ok(! system("touch $srcdir/foo.mdwn")); +setupiki("initial setup"); +ok(! system("mkdir -p $srcdir/foo")); +ok(! system("mv $srcdir/foo.mdwn $srcdir/foo/index.html")); +refreshiki("existing page moved to rawhtml file in refresh"); +# Inverse added when refreshing +newsrcdir(); +ok(! system("mkdir -p $srcdir/foo")); +ok(! system("touch $srcdir/foo/index.html")); +setupiki("initial setup"); +ok(! system("touch $srcdir/foo.mdwn")); +refreshiki("page rendered same as existing rawhtml file in refresh"); +# Inverse moved when refreshing +newsrcdir(); +ok(! system("mkdir -p $srcdir/foo")); +ok(! system("touch $srcdir/foo/index.html")); +setupiki("initial setup"); +ok(! system("mv $srcdir/foo/index.html $srcdir/foo.mdwn")); +refreshiki("rawhtml file moved to page in refresh"); # Present during setup newsrcdir(); ok(! system("touch $srcdir/foo.mdwn"));