From acecbad0ff4a8c441da520522710dd5357ab31e0 Mon Sep 17 00:00:00 2001 From: Peter Gammie Date: Wed, 29 Sep 2010 15:14:19 +1000 Subject: First cut at the revert plugin. --- IkiWiki/Plugin/git.pm | 35 ++++++++++++++++++++++ IkiWiki/Plugin/recentchanges.pm | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm index fd57ce1e4..a68bd0b0e 100644 --- a/IkiWiki/Plugin/git.pm +++ b/IkiWiki/Plugin/git.pm @@ -27,6 +27,10 @@ sub import { hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime); hook(type => "rcs", id => "rcs_getmtime", call => \&rcs_getmtime); hook(type => "rcs", id => "rcs_receive", call => \&rcs_receive); + hook(type => "rcs", id => "rcs_preprevert", call => \&rcs_preprevert); + hook(type => "rcs", id => "rcs_revert", call => \&rcs_revert); + hook(type => "rcs", id => "rcs_showpatch", call => \&rcs_showpatch); + hook(type => "rcs", id => "rcs_revert", call => \&rcs_revert); } sub checkconfig () { @@ -811,4 +815,35 @@ sub rcs_receive () { return reverse @rets; } +sub rcs_preprevert ($) { + # FIXME implement +} + +sub rcs_revert (@) { + # Try to revert the given patch; returns undef on _success_. + # Same parameters as rcs_commit_staged + 'rev', the patch ID to be + # reverted. + my %params = @_; + my $rev = $params{rev}; + + if(run_or_non('git', 'revert', '--no-commit', $rev)) { + debug "Committing revert for patch '$rev'."; + rcs_commit_staged(message => "This reverts commit $rev", @_); + } else { + # No idea what is actually getting reverted, so all we can do is say we failed. + run_or_die('git', 'reset', '--hard'); + return "Failed to revert patch $rev."; + } +} + +sub rcs_showpatch ($) { + # Show the patch with the given revision id. + my ($rev) = @_; + + # FIXME check + my @r = run_or_die('git', 'show', $rev); + + return join "\n", @r; +} + 1 diff --git a/IkiWiki/Plugin/recentchanges.pm b/IkiWiki/Plugin/recentchanges.pm index 758b98348..2a78566e1 100644 --- a/IkiWiki/Plugin/recentchanges.pm +++ b/IkiWiki/Plugin/recentchanges.pm @@ -60,6 +60,72 @@ sub refresh ($) { } } +sub confirmation_form { + my ($q, $session, $rev) = @_; + + eval q{use CGI::FormBuilder}; + error($@) if $@; + my $f = CGI::FormBuilder->new( + name => "revert", + header => 0, + charset => "utf-8", + method => 'POST', + javascript => 0, + params => $q, + action => $config{cgiurl}, + stylesheet => 1, + template => { template('revert.tmpl') }, + ); + + $f->field(name => "sid", type => "hidden", value => $session->id, + force => 1); + $f->field(name => "do", type => "hidden", value => "revert", force => 1); + $f->field(name => "rev", type => "hidden", value => $rev, force => 1); + + return $f, ["Revert", "Cancel"]; +} + +sub sessioncgi ($$) { + my ($q, $session) = @_; + my $do = $q->param('do'); + my $rev = $q->param('rev'); + + return unless $do eq 'revert' && $rev; + + # FIXME rcs_preprevert ?? + IkiWiki::check_canedit('FIXME', $q, $session); + + my ($form, $buttons) = confirmation_form($q, $session); + IkiWiki::decode_form_utf8($form); + + if($form->submitted eq 'Revert' && $form->validate) { + IkiWiki::checksessionexpiry($q, $session, $q->param('sid')); + + IkiWiki::disable_commit_hook(); + my $r = IkiWiki::rcs_revert( + session => $session, + rev => $rev); + IkiWiki::enable_commit_hook(); + + if($r) { + die "FIXME revert '$rev' failed."; + } else { + IkiWiki::refresh(); + IkiWiki::saveindex(); + # FIXME indicate success. + } + } else { + $form->title(sprintf(gettext("confirm reversion of %s"), $rev)); + my $patch_contents = IkiWiki::rcs_showpatch($rev); + $form->tmpl_param(patch_contents => encode_entities($patch_contents)); + IkiWiki::showform($form, $buttons, $session, $q); + exit 0; + } + + IkiWiki::redirect($q, urlto($config{recentchangespage}, '')); + exit 0; +} + # Enable the recentchanges link. sub pagetemplate (@) { my %params=@_; -- cgit v1.2.3 From 941755e46661b65f29aeebcf38f8410f9c8cfc2e Mon Sep 17 00:00:00 2001 From: Peter Gammie Date: Wed, 29 Sep 2010 15:43:44 +1000 Subject: Get things right after moving to a branch. --- IkiWiki/Plugin/recentchanges.pm | 11 ++++++++++- templates/change.tmpl | 2 ++ templates/revert.tmpl | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/recentchanges.pm b/IkiWiki/Plugin/recentchanges.pm index 2a78566e1..79d175328 100644 --- a/IkiWiki/Plugin/recentchanges.pm +++ b/IkiWiki/Plugin/recentchanges.pm @@ -13,6 +13,7 @@ sub import { hook(type => "refresh", id => "recentchanges", call => \&refresh); hook(type => "pagetemplate", id => "recentchanges", call => \&pagetemplate); hook(type => "htmlize", id => "_change", call => \&htmlize); + hook(type => "sessioncgi", id => "recentchanges", call => \&sessioncgi); # Load goto to fix up links from recentchanges IkiWiki::loadplugin("goto"); } @@ -80,7 +81,6 @@ sub confirmation_form { $f->field(name => "sid", type => "hidden", value => $session->id, force => 1); $f->field(name => "do", type => "hidden", value => "revert", force => 1); - $f->field(name => "rev", type => "hidden", value => $rev, force => 1); return $f, ["Revert", "Cancel"]; } @@ -110,6 +110,7 @@ sub sessioncgi ($$) { if($r) { die "FIXME revert '$rev' failed."; } else { + require IkiWiki::Render; IkiWiki::refresh(); IkiWiki::saveindex(); # FIXME indicate success. @@ -118,6 +119,7 @@ sub sessioncgi ($$) { $form->title(sprintf(gettext("confirm reversion of %s"), $rev)); my $patch_contents = IkiWiki::rcs_showpatch($rev); $form->tmpl_param(patch_contents => encode_entities($patch_contents)); + $form->field(name => "rev", type => "hidden", value => $rev, force => 1); IkiWiki::showform($form, $buttons, $session, $q); exit 0; } @@ -180,6 +182,13 @@ sub store ($$$) { ]; push @{$change->{pages}}, { link => '...' } if $is_excess; + if (length $config{cgiurl}) { + $change->{reverturl} = IkiWiki::cgiurl( + do => "revert", + rev => $change->{rev} + ); + } + $change->{author}=$change->{user}; my $oiduser=eval { IkiWiki::openiduser($change->{user}) }; if (defined $oiduser) { diff --git a/templates/change.tmpl b/templates/change.tmpl index 671b9e483..148b4376e 100644 --- a/templates/change.tmpl +++ b/templates/change.tmpl @@ -28,6 +28,8 @@
Date:
+
+[[diff|wikiicons/revert.png]]
diff --git a/templates/revert.tmpl b/templates/revert.tmpl index 3cf069dca..03cd0838d 100644 --- a/templates/revert.tmpl +++ b/templates/revert.tmpl @@ -5,6 +5,7 @@
+
-- cgit v1.2.3 From 8024a2636feb60026a79715430a66bb572b9eae8 Mon Sep 17 00:00:00 2001 From: Peter Gammie Date: Fri, 1 Oct 2010 14:06:00 +1000 Subject: Complete rcs_preprevert and lightly test. --- IkiWiki.pm | 4 +- IkiWiki/Plugin/git.pm | 188 +++++++++++++++++++++++----------------- IkiWiki/Plugin/recentchanges.pm | 5 +- IkiWiki/Receive.pm | 32 +++++-- 4 files changed, 136 insertions(+), 93 deletions(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki.pm b/IkiWiki.pm index e2b2ceda3..aa4dccac3 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1941,7 +1941,7 @@ sub rcs_receive () { $hooks{rcs}{rcs_receive}{call}->(); } -sub rcs_preprevert ($) { +sub rcs_preprevert (@) { $hooks{rcs}{rcs_preprevert}{call}->(@_); } @@ -1949,7 +1949,7 @@ sub rcs_revert (@) { $hooks{rcs}{rcs_revert}{call}->(@_); } -sub rcs_showpatch ($) { +sub rcs_showpatch (@) { $hooks{rcs}{rcs_showpatch}{call}->(@_); } diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm index a68bd0b0e..46fa7d2e0 100644 --- a/IkiWiki/Plugin/git.pm +++ b/IkiWiki/Plugin/git.pm @@ -722,101 +722,130 @@ sub rcs_getmtime ($) { return findtimes($file, 0); } -sub rcs_receive () { - # The wiki may not be the only thing in the git repo. - # Determine if it is in a subdirectory by examining the srcdir, - # and its parents, looking for the .git directory. - my $subdir=""; - my $dir=$config{srcdir}; - while (! -d "$dir/.git") { - $subdir=IkiWiki::basename($dir)."/".$subdir; - $dir=IkiWiki::dirname($dir); - if (! length $dir) { - error("cannot determine root of git repo"); - } - } +{ +my $git_root; +sub git_find_root { + # The wiki may not be the only thing in the git repo. + # Determine if it is in a subdirectory by examining the srcdir, + # and its parents, looking for the .git directory. + + return $git_root if $git_root; + + my $subdir=""; + my $dir=$config{srcdir}; + while (! -d "$dir/.git") { + $subdir=IkiWiki::basename($dir)."/".$subdir; + $dir=IkiWiki::dirname($dir); + if (! length $dir) { + error("cannot determine root of git repo"); + } + } + + return $subdir; +} +} + +sub git_parse_changes { + my @changes = @_; + + my $subdir = git_find_root(); + my @rets; + foreach my $ci (@changes) { + foreach my $detail (@{ $ci->{'details'} }) { + my $file = $detail->{'file'}; + + # check that all changed files are in the + # subdir + if (length $subdir && + ! ($file =~ s/^\Q$subdir\E//)) { + error sprintf(gettext("you are not allowed to change %s"), $file); + } + + my ($action, $mode, $path); + if ($detail->{'status'} =~ /^[M]+\d*$/) { + $action="change"; + $mode=$detail->{'mode_to'}; + } + elsif ($detail->{'status'} =~ /^[AM]+\d*$/) { + $action="add"; + $mode=$detail->{'mode_to'}; + } + elsif ($detail->{'status'} =~ /^[DAM]+\d*/) { + $action="remove"; + $mode=$detail->{'mode_from'}; + } + else { + error "unknown status ".$detail->{'status'}; + } + + # test that the file mode is ok + if ($mode !~ /^100[64][64][64]$/) { + error sprintf(gettext("you cannot act on a file with mode %s"), $mode); + } + if ($action eq "change") { + if ($detail->{'mode_from'} ne $detail->{'mode_to'}) { + error gettext("you are not allowed to change file modes"); + } + } + + # extract attachment to temp file + if (($action eq 'add' || $action eq 'change') && + ! pagetype($file)) { + + eval q{use File::Temp}; + die $@ if $@; + my $fh; + ($fh, $path)=File::Temp::tempfile("XXXXXXXXXX", UNLINK => 1); + # Ensure we run this in the right place, see comments in rcs_receive. + my $cmd = ($no_chdir ? '' : "cd $config{srcdir} && ") + . "git show $detail->{sha1_to} > '$path'"; + if (system($cmd) != 0) { + error("failed writing temp file '$path'."); + } + } + + push @rets, { + file => $file, + action => $action, + path => $path, + }; + } + } + + return @rets; +} +sub rcs_receive () { my @rets; while (<>) { chomp; my ($oldrev, $newrev, $refname) = split(' ', $_, 3); - + # only allow changes to gitmaster_branch if ($refname !~ /^refs\/heads\/\Q$config{gitmaster_branch}\E$/) { error sprintf(gettext("you are not allowed to change %s"), $refname); } - + # Avoid chdir when running git here, because the changes # are in the master git repo, not the srcdir repo. - # The pre-recieve hook already puts us in the right place. + # The pre-receive hook already puts us in the right place. $no_chdir=1; - my @changes=git_commit_info($oldrev."..".$newrev); + push @rets, git_parse_changes(git_commit_info($oldrev."..".$newrev)); $no_chdir=0; - - foreach my $ci (@changes) { - foreach my $detail (@{ $ci->{'details'} }) { - my $file = $detail->{'file'}; - - # check that all changed files are in the - # subdir - if (length $subdir && - ! ($file =~ s/^\Q$subdir\E//)) { - error sprintf(gettext("you are not allowed to change %s"), $file); - } - - my ($action, $mode, $path); - if ($detail->{'status'} =~ /^[M]+\d*$/) { - $action="change"; - $mode=$detail->{'mode_to'}; - } - elsif ($detail->{'status'} =~ /^[AM]+\d*$/) { - $action="add"; - $mode=$detail->{'mode_to'}; - } - elsif ($detail->{'status'} =~ /^[DAM]+\d*/) { - $action="remove"; - $mode=$detail->{'mode_from'}; - } - else { - error "unknown status ".$detail->{'status'}; - } - - # test that the file mode is ok - if ($mode !~ /^100[64][64][64]$/) { - error sprintf(gettext("you cannot act on a file with mode %s"), $mode); - } - if ($action eq "change") { - if ($detail->{'mode_from'} ne $detail->{'mode_to'}) { - error gettext("you are not allowed to change file modes"); - } - } - - # extract attachment to temp file - if (($action eq 'add' || $action eq 'change') && - ! pagetype($file)) { - eval q{use File::Temp}; - die $@ if $@; - my $fh; - ($fh, $path)=File::Temp::tempfile("XXXXXXXXXX", UNLINK => 1); - if (system("git show ".$detail->{sha1_to}." > '$path'") != 0) { - error("failed writing temp file"); - } - } - - push @rets, { - file => $file, - action => $action, - path => $path, - }; - } - } } return reverse @rets; } -sub rcs_preprevert ($) { - # FIXME implement +sub rcs_preprevert (@) { + # Determine what the effects are of reverting the patch with the + # ID given by 'rev'. Returns the same structure as rcs_receive. + # FIXME note test_changes expects 'cgi' and 'session' parameters. + my %params = @_; + my $rev = $params{rev}; + + require IkiWiki::Receive; + IkiWiki::Receive::test_changes(%params, changes => [git_parse_changes(git_commit_info($rev, 1))]); } sub rcs_revert (@) { @@ -836,9 +865,10 @@ sub rcs_revert (@) { } } -sub rcs_showpatch ($) { +sub rcs_showpatch (@) { # Show the patch with the given revision id. - my ($rev) = @_; + my %params = @_; + my $rev = $params{rev}; # FIXME check my @r = run_or_die('git', 'show', $rev); diff --git a/IkiWiki/Plugin/recentchanges.pm b/IkiWiki/Plugin/recentchanges.pm index 79d175328..4a8d1bf80 100644 --- a/IkiWiki/Plugin/recentchanges.pm +++ b/IkiWiki/Plugin/recentchanges.pm @@ -92,8 +92,7 @@ sub sessioncgi ($$) { return unless $do eq 'revert' && $rev; - # FIXME rcs_preprevert ?? - IkiWiki::check_canedit('FIXME', $q, $session); + IkiWiki::rcs_preprevert(cgi => $q, session => $session, rev => $rev); my ($form, $buttons) = confirmation_form($q, $session); IkiWiki::decode_form_utf8($form); @@ -117,7 +116,7 @@ sub sessioncgi ($$) { } } else { $form->title(sprintf(gettext("confirm reversion of %s"), $rev)); - my $patch_contents = IkiWiki::rcs_showpatch($rev); + my $patch_contents = IkiWiki::rcs_showpatch(rev => $rev); $form->tmpl_param(patch_contents => encode_entities($patch_contents)); $form->field(name => "rev", type => "hidden", value => $rev, force => 1); IkiWiki::showform($form, $buttons, $session, $q); diff --git a/IkiWiki/Receive.pm b/IkiWiki/Receive.pm index e77c477a9..48228e5f0 100644 --- a/IkiWiki/Receive.pm +++ b/IkiWiki/Receive.pm @@ -48,10 +48,10 @@ EOF sub test () { exit 0 if trusted(); - + IkiWiki::lockwiki(); IkiWiki::loadindex(); - + # Dummy up a cgi environment to use when calling check_canedit # and friends. eval q{use CGI}; @@ -72,10 +72,22 @@ sub test () { regdate => time, }) || error("failed adding user"); } - - my %newfiles; - foreach my $change (IkiWiki::rcs_receive()) { + test_changes(cgi => $cgi, + session => $session, + changes => [IkiWiki::rcs_receive()] + ); + exit 0; +} + +sub test_changes { + my %params = @_; + my $cgi = $params{cgi}; + my $session = $params{session}; + my @changes = @{$params{changes}}; + + my %newfiles; + foreach my $change (@changes) { # This untaint is safe because we check file_pruned and # wiki_file_regexp. my ($file)=$change->{file}=~/$config{wiki_file_regexp}/; @@ -87,7 +99,7 @@ sub test () { my $type=pagetype($file); my $page=pagename($file) if defined $type; - + if ($change->{action} eq 'add') { $newfiles{$file}=1; } @@ -104,6 +116,10 @@ sub test () { IkiWiki::check_canedit($file, $cgi, $session); next; } + else { + use Data::Dumper; + die "fall through test_changes add: " . Data::Dumper::Dumper($change); + } } } elsif ($change->{action} eq 'remove') { @@ -125,11 +141,9 @@ sub test () { else { error "unknown action ".$change->{action}; } - + error sprintf(gettext("you are not allowed to change %s"), $file); } - - exit 0; } 1 -- cgit v1.2.3 From 7d1c3aa1cb42f4306535481c009367ffa42c7223 Mon Sep 17 00:00:00 2001 From: Peter Gammie Date: Fri, 1 Oct 2010 14:08:07 +1000 Subject: Minor tidy-ups. --- IkiWiki/Plugin/git.pm | 7 ++----- IkiWiki/Plugin/recentchanges.pm | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'IkiWiki/Plugin') diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm index 46fa7d2e0..457975d95 100644 --- a/IkiWiki/Plugin/git.pm +++ b/IkiWiki/Plugin/git.pm @@ -840,7 +840,7 @@ sub rcs_receive () { sub rcs_preprevert (@) { # Determine what the effects are of reverting the patch with the # ID given by 'rev'. Returns the same structure as rcs_receive. - # FIXME note test_changes expects 'cgi' and 'session' parameters. + # Note test_changes expects 'cgi' and 'session' parameters. my %params = @_; my $rev = $params{rev}; @@ -870,10 +870,7 @@ sub rcs_showpatch (@) { my %params = @_; my $rev = $params{rev}; - # FIXME check - my @r = run_or_die('git', 'show', $rev); - - return join "\n", @r; + return join "\n", run_or_die('git', 'show', $rev); } 1 diff --git a/IkiWiki/Plugin/recentchanges.pm b/IkiWiki/Plugin/recentchanges.pm index 4a8d1bf80..9a62cb243 100644 --- a/IkiWiki/Plugin/recentchanges.pm +++ b/IkiWiki/Plugin/recentchanges.pm @@ -107,12 +107,11 @@ sub sessioncgi ($$) { IkiWiki::enable_commit_hook(); if($r) { - die "FIXME revert '$rev' failed."; + die "Revert '$rev' failed."; } else { require IkiWiki::Render; IkiWiki::refresh(); IkiWiki::saveindex(); - # FIXME indicate success. } } else { $form->title(sprintf(gettext("confirm reversion of %s"), $rev)); -- cgit v1.2.3