X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/8024a2636feb60026a79715430a66bb572b9eae8..65e726f201d7b9919271cfe7e8a7314a6abf0fc3:/IkiWiki/Plugin/git.pm?ds=inline diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm index 46fa7d2e0..3fa29b22f 100644 --- a/IkiWiki/Plugin/git.pm +++ b/IkiWiki/Plugin/git.pm @@ -9,7 +9,7 @@ use open qw{:utf8 :std}; my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums my $dummy_commit_msg = 'dummy commit'; # message to skip in recent changes -my $no_chdir=0; +my $git_dir=undef; sub import { hook(type => "checkconfig", id => "git", call => \&checkconfig); @@ -27,9 +27,7 @@ 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_preprevert", call => \&rcs_preprevert); hook(type => "rcs", id => "rcs_revert", call => \&rcs_revert); } @@ -166,9 +164,13 @@ sub safe_git (&@) { if (!$pid) { # In child. # Git commands want to be in wc. - if (! $no_chdir) { + if (! defined $git_dir) { chdir $config{srcdir} - or error("Cannot chdir to $config{srcdir}: $!"); + or error("cannot chdir to $config{srcdir}: $!"); + } + else { + chdir $git_dir + or error("cannot chdir to $git_dir: $!"); } exec @cmdline or error("Cannot exec '@cmdline': $!"); } @@ -686,7 +688,7 @@ sub findtimes ($$) { if (! keys %time_cache) { my $date; foreach my $line (run_or_die('git', 'log', - '--pretty=format:%ct', + '--pretty=format:%at', '--name-only', '--relative')) { if (! defined $date && $line =~ /^(\d+)$/) { $date=$line; @@ -723,96 +725,95 @@ sub rcs_getmtime ($) { } { -my $git_root; +my $ret; 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; + # 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 @$ret if defined $ret; + + 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"); + } + } + + $ret=[$subdir, $dir]; + return @$ret; } + } 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; + my @changes = @_; + + my ($subdir, $rootdir) = 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); + my $cmd = "cd $git_dir && ". + "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 () { @@ -828,52 +829,53 @@ sub rcs_receive () { # Avoid chdir when running git here, because the changes # are in the master git repo, not the srcdir repo. + # (Also, if a subdir is involved, we don't want to chdir to + # it and only see changes in it.) # The pre-receive hook already puts us in the right place. - $no_chdir=1; - push @rets, git_parse_changes(git_commit_info($oldrev."..".$newrev)); - $no_chdir=0; + $git_dir="."; + push @rets, git_parse_changes(git_commit_info($oldrev."..".$newrev)); + $git_dir=undef; } return reverse @rets; } -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}; +sub rcs_preprevert ($) { + my $rev=shift; + my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint + + # Examine changes from root of git repo, not from any subdir, + # in order to see all changes. + my ($subdir, $rootdir) = git_find_root(); + $git_dir=$rootdir; + my @commits=git_commit_info($sha1, 1); + $git_dir=undef; - require IkiWiki::Receive; - IkiWiki::Receive::test_changes(%params, changes => [git_parse_changes(git_commit_info($rev, 1))]); -} + if (! @commits) { + error "unknown commit"; # just in case + } -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."; - } -} + # git revert will fail on merge commits. Add a nice message. + if (exists $commits[0]->{parents} && + @{$commits[0]->{parents}} > 1) { + error gettext("you are not allowed to revert a merge"); + } -sub rcs_showpatch (@) { - # Show the patch with the given revision id. - my %params = @_; - my $rev = $params{rev}; + return git_parse_changes(@commits); +} - # FIXME check - my @r = run_or_die('git', 'show', $rev); +sub rcs_revert ($) { + # Try to revert the given rev; returns undef on _success_. + my $rev = shift; + my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint - return join "\n", @r; + if (run_or_non('git', 'revert', '--no-commit', $sha1)) { + return undef; + } + else { + run_or_die('git', 'reset', '--hard'); + return sprintf(gettext("Failed to revert commit %s"), $sha1); + } } 1