diff options
-rw-r--r-- | IkiWiki.pm | 4 | ||||
-rw-r--r-- | IkiWiki/Plugin/git.pm | 188 | ||||
-rw-r--r-- | IkiWiki/Plugin/recentchanges.pm | 5 | ||||
-rw-r--r-- | IkiWiki/Receive.pm | 32 |
4 files changed, 136 insertions, 93 deletions
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 |