diff --git a/IkiWiki.pm b/IkiWiki.pm index 40622a5be..c8d959edd 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -38,6 +38,7 @@ sub defaultconfig () { #{{{ wikiname => "wiki", default_pageext => "mdwn", cgi => 0, + post_commit => 0, rcs => '', notify => 0, url => '', @@ -601,7 +602,7 @@ sub lockwiki () { #{{{ } open(WIKILOCK, ">$config{wikistatedir}/lockfile") || error ("cannot write to $config{wikistatedir}/lockfile: $!"); - if (! flock(WIKILOCK, 2 | 4)) { + if (! flock(WIKILOCK, 2 | 4)) { # LOCK_EX | LOCK_NB debug("wiki seems to be locked, waiting for lock"); my $wait=600; # arbitrary, but don't hang forever to # prevent process pileup @@ -617,6 +618,29 @@ sub unlockwiki () { #{{{ close WIKILOCK; } #}}} +sub commit_hook_enabled () { #{{{ + open(COMMITLOCK, "+>$config{wikistatedir}/commitlock") || + error ("cannot write to $config{wikistatedir}/commitlock: $!"); + if (! flock(WIKILOCK, 1 | 4)) { # LOCK_SH | LOCK_NB to test + close WIKILOCK; + return 0; + } + close WIKILOCK; + return 1; +} #}}} + +sub disable_commit_hook () { #{{{ + open(COMMITLOCK, ">$config{wikistatedir}/commitlock") || + error ("cannot write to $config{wikistatedir}/commitlock: $!"); + if (! flock(COMMITLOCK, 2)) { # LOCK_EX + error("failed to get commit lock"); + } +} #}}} + +sub enable_commit_hook () { #{{{ + close COMMITLOCK; +} #}}} + sub loadindex () { #{{{ open (IN, "$config{wikistatedir}/index") || return; while () { diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index e23ef8afd..e62bcf477 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -513,6 +513,7 @@ sub cgi_editpage ($$) { #{{{ return; } + my $conflict; if ($config{rcs}) { my $message=""; if (defined $form->field('comments') && @@ -523,44 +524,44 @@ sub cgi_editpage ($$) { #{{{ if ($newfile) { rcs_add($file); } - # prevent deadlock with post-commit hook - unlockwiki(); - # presumably the commit will trigger an update - # of the wiki - my $conflict=rcs_commit($file, $message, + + # Prevent deadlock with post-commit hook by + # signaling to it that it should not try to + # do anything (except send commit mails). + disable_commit_hook(); + $conflict=rcs_commit($file, $message, $form->field("rcsinfo"), $session->param("name"), $ENV{REMOTE_ADDR}); + enable_commit_hook(); + rcs_update(); + } - if (defined $conflict) { - $form->field(name => "rcsinfo", value => rcs_prepedit($file), - force => 1); - $form->tmpl_param("page_conflict", 1); - $form->field("editcontent", value => $conflict, force => 1); - $form->field(name => "comments", value => $form->field('comments'), force => 1); - $form->field("do", "edit)"); - $form->tmpl_param("page_select", 0); - $form->field(name => "page", type => 'hidden'); - $form->field(name => "type", type => 'hidden'); - $form->title(sprintf(gettext("editing %s"), $page)); - print $form->render(submit => \@buttons); - return; - } - else { - # Make sure that the repo is up-to-date; - # locking prevents the post-commit hook - # from updating it. - rcs_update(); - } + # Refresh even if there was a conflict, since other changes + # may have been committed while the post-commit hook was + # disabled. + require IkiWiki::Render; + refresh(); + saveindex(); + + if (defined $conflict) { + $form->field(name => "rcsinfo", value => rcs_prepedit($file), + force => 1); + $form->tmpl_param("page_conflict", 1); + $form->field("editcontent", value => $conflict, force => 1); + $form->field(name => "comments", value => $form->field('comments'), force => 1); + $form->field("do", "edit)"); + $form->tmpl_param("page_select", 0); + $form->field(name => "page", type => 'hidden'); + $form->field(name => "type", type => 'hidden'); + $form->title(sprintf(gettext("editing %s"), $page)); + print $form->render(submit => \@buttons); + return; } else { - require IkiWiki::Render; - refresh(); - saveindex(); + # The trailing question mark tries to avoid broken + # caches and get the most recent version of the page. + redirect($q, "$config{url}/".htmlpage($page)."?updated"); } - - # The trailing question mark tries to avoid broken - # caches and get the most recent version of the page. - redirect($q, "$config{url}/".htmlpage($page)."?updated"); } } #}}} diff --git a/IkiWiki/Plugin/poll.pm b/IkiWiki/Plugin/poll.pm index a3321a32e..4eae6a349 100644 --- a/IkiWiki/Plugin/poll.pm +++ b/IkiWiki/Plugin/poll.pm @@ -125,17 +125,17 @@ sub cgi ($) { #{{{ IkiWiki::cgi_savesession($session); $oldchoice=$session->param($choice_param); if ($config{rcs}) { - # prevent deadlock with post-commit hook - IkiWiki::unlockwiki(); + disable_commit_hook(); IkiWiki::rcs_commit($pagesources{$page}, "poll vote ($choice)", IkiWiki::rcs_prepedit($pagesources{$page}), $session->param("name"), $ENV{REMOTE_ADDR}); + enable_commit_hook(); + rcs_update(); } - else { - require IkiWiki::Render; - IkiWiki::refresh(); - IkiWiki::saveindex(); - } + require IkiWiki::Render; + IkiWiki::refresh(); + IkiWiki::saveindex(); + # Need to set cookie in same http response that does the # redir. eval q{use CGI::Cookie}; diff --git a/IkiWiki/Setup/Standard.pm b/IkiWiki/Setup/Standard.pm index 0c4272286..f3f7bae5a 100644 --- a/IkiWiki/Setup/Standard.pm +++ b/IkiWiki/Setup/Standard.pm @@ -36,6 +36,9 @@ sub setup_standard { foreach my $wrapper (@wrappers) { %config=(%startconfig, verbose => 0, %setup, %{$wrapper}); checkconfig(); + if (! $config{cgi} && ! $config{post_commit}) { + $config{post_commit}=1; + } gen_wrapper(); } %config=(%startconfig); diff --git a/debian/changelog b/debian/changelog index 6a6dc8f82..3625d4c91 100644 --- a/debian/changelog +++ b/debian/changelog @@ -27,8 +27,14 @@ ikiwiki (1.44) UNRELEASED; urgency=low * Smarter detection of no-op changes to po files. * Elegant patch from Ethan to clean up the display of page names in the dropdown when creating a new page. + * Since the CGI had to drop the wiki lock to avoid deadlocking the + commit hook, it was possible for one CGI to race another one and "win" + the commit of both their files. This race has been fixed by adding a new + commitlock, which when locked by the CGI, disables the commit hook + (except for commit mails). The CGI then takes care of the updates the + commit hook would have done. - -- Joey Hess Tue, 20 Feb 2007 19:14:39 -0500 + -- Joey Hess Wed, 21 Feb 2007 03:35:52 -0500 ikiwiki (1.43) unstable; urgency=low diff --git a/ikiwiki.in b/ikiwiki.in index 24b02bc41..5dd1064f9 100755 --- a/ikiwiki.in +++ b/ikiwiki.in @@ -117,6 +117,12 @@ sub main () { #{{{ require IkiWiki::Render; commandline_render(); } + elsif ($config{post_commit} && ! commit_hook_enabled()) { + if ($config{notify}) { + loadindex(); + rcs_notify(); + } + } else { lockwiki(); loadindex(); diff --git a/po/ikiwiki.pot b/po/ikiwiki.pot index 76337ff7e..4399a0317 100644 --- a/po/ikiwiki.pot +++ b/po/ikiwiki.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-02-20 19:07-0500\n" +"POT-Creation-Date: 2007-02-21 03:51-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -41,16 +41,16 @@ msgstr "" msgid "creating %s" msgstr "" -#: ../IkiWiki/CGI.pm:483 ../IkiWiki/CGI.pm:511 ../IkiWiki/CGI.pm:544 +#: ../IkiWiki/CGI.pm:483 ../IkiWiki/CGI.pm:511 ../IkiWiki/CGI.pm:556 #, perl-format msgid "editing %s" msgstr "" -#: ../IkiWiki/CGI.pm:652 +#: ../IkiWiki/CGI.pm:653 msgid "You are banned." msgstr "" -#: ../IkiWiki/CGI.pm:684 +#: ../IkiWiki/CGI.pm:685 msgid "login failed, perhaps you need to turn on cookies?" msgstr "" @@ -380,15 +380,15 @@ msgstr "" msgid "generating wrappers.." msgstr "" -#: ../IkiWiki/Setup/Standard.pm:68 +#: ../IkiWiki/Setup/Standard.pm:71 msgid "rebuilding wiki.." msgstr "" -#: ../IkiWiki/Setup/Standard.pm:71 +#: ../IkiWiki/Setup/Standard.pm:74 msgid "refreshing wiki.." msgstr "" -#: ../IkiWiki/Setup/Standard.pm:80 +#: ../IkiWiki/Setup/Standard.pm:83 msgid "done" msgstr "" @@ -437,11 +437,11 @@ msgstr "" msgid "usage: ikiwiki [options] source dest" msgstr "" -#: ../IkiWiki.pm:103 +#: ../IkiWiki.pm:104 msgid "Must specify url to wiki with --url when using --cgi" msgstr "" -#: ../IkiWiki.pm:150 ../IkiWiki.pm:151 +#: ../IkiWiki.pm:151 ../IkiWiki.pm:152 msgid "Error" msgstr "" @@ -449,7 +449,7 @@ msgstr "" #. translators: preprocessor directive name, #. translators: the second a page name, the #. translators: third a number. -#: ../IkiWiki.pm:560 +#: ../IkiWiki.pm:561 #, perl-format msgid "%s preprocessing loop detected on %s at depth %i" msgstr ""