X-Git-Url: https://sipb.mit.edu/gitweb.cgi/ikiwiki.git/blobdiff_plain/77b0454e0c69fa0a3e3855b5f25322ae26b37042..c46bcb425af0948ac59581d6ba7b477826d83ae3:/IkiWiki/Plugin/git.pm diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm index c5c83a3a7..a43b85920 100644 --- a/IkiWiki/Plugin/git.pm +++ b/IkiWiki/Plugin/git.pm @@ -25,6 +25,7 @@ sub import { hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges); hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff); 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); } @@ -51,6 +52,9 @@ sub checkconfig () { wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"), }; } + + # Avoid notes, parser does not handle and they only slow things down. + $ENV{GIT_NOTES_REF}=""; # Run receive test only if being called by the wrapper, and not # when generating same. @@ -65,6 +69,7 @@ sub getsetup () { plugin => { safe => 0, # rcs plugin rebuild => undef, + section => "rcs", }, git_wrapper => { type => "string", @@ -275,11 +280,35 @@ sub merge_past ($$$) { return $conflict; } -sub parse_diff_tree ($@) { +{ +my $prefix; +sub decode_git_file ($) { + my $file=shift; + + # git does not output utf-8 filenames, but instead + # double-quotes them with the utf-8 characters + # escaped as \nnn\nnn. + if ($file =~ m/^"(.*)"$/) { + ($file=$1) =~ s/\\([0-7]{1,3})/chr(oct($1))/eg; + } + + # strip prefix if in a subdir + if (! defined $prefix) { + ($prefix) = run_or_die('git', 'rev-parse', '--show-prefix'); + if (! defined $prefix) { + $prefix=""; + } + } + $file =~ s/^\Q$prefix\E//; + + return decode("utf8", $file); +} +} + +sub parse_diff_tree ($) { # Parse the raw diff tree chunk and return the info hash. # See git-diff-tree(1) for the syntax. - - my ($prefix, $dt_ref) = @_; + my $dt_ref = shift; # End of stream? return if !defined @{ $dt_ref } || @@ -313,8 +342,9 @@ sub parse_diff_tree ($@) { $ci{ "${who}_epoch" } = $epoch; $ci{ "${who}_tz" } = $tz; - if ($name =~ m/^[^<]+\s+<([^@>]+)/) { - $ci{"${who}_username"} = $1; + if ($name =~ m/^([^<]+)\s+<([^@>]+)/) { + $ci{"${who}_name"} = $1; + $ci{"${who}_username"} = $2; } elsif ($name =~ m/^([^<]+)\s+<>$/) { $ci{"${who}_username"} = $1; @@ -362,16 +392,9 @@ sub parse_diff_tree ($@) { my $sha1_to = shift(@tmp); my $status = shift(@tmp); - # git does not output utf-8 filenames, but instead - # double-quotes them with the utf-8 characters - # escaped as \nnn\nnn. - if ($file =~ m/^"(.*)"$/) { - ($file=$1) =~ s/\\([0-7]{1,3})/chr(oct($1))/eg; - } - $file =~ s/^\Q$prefix\E//; if (length $file) { push @{ $ci{'details'} }, { - 'file' => decode("utf8", $file), + 'file' => decode_git_file($file), 'sha1_from' => $sha1_from[0], 'sha1_to' => $sha1_to, 'mode_from' => $mode_from[0], @@ -398,10 +421,9 @@ sub git_commit_info ($;$) { my @raw_lines = run_or_die('git', 'log', @opts, '--pretty=raw', '--raw', '--abbrev=40', '--always', '-c', '-r', $sha1, '--', '.'); - my ($prefix) = run_or_die('git', 'rev-parse', '--show-prefix'); my @ci; - while (my $parsed = parse_diff_tree(($prefix or ""), \@raw_lines)) { + while (my $parsed = parse_diff_tree(\@raw_lines)) { push @ci, $parsed; } @@ -419,7 +441,10 @@ sub git_sha1 (;$) { '--', $file); if ($sha1) { ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1 is untainted now - } else { debug("Empty sha1sum for '$file'.") } + } + else { + debug("Empty sha1sum for '$file'."); + } return defined $sha1 ? $sha1 : q{}; } @@ -564,9 +589,14 @@ sub rcs_recentchanges ($) { push @messages, { line => $line }; } - my $user=$ci->{'author_username'}; + my $user=$ci->{'author_name'}; + my $usershort=$ci->{'author_username'}; my $web_commit = ($ci->{'author'} =~ /\@web>/); - + + if ($usershort =~ /:\/\//) { + $usershort=undef; # url; not really short + } + # compatability code for old web commit messages if (! $web_commit && defined $messages[0] && @@ -579,6 +609,7 @@ sub rcs_recentchanges ($) { push @rets, { rev => $sha1, user => $user, + usershort => $usershort, committype => $web_commit ? "web" : "git", when => $when, message => [@messages], @@ -608,23 +639,53 @@ sub rcs_diff ($) { } } -sub rcs_getctime ($) { +{ +my %time_cache; + +sub findtimes ($$) { my $file=shift; + my $id=shift; # 0 = mtime ; 1 = ctime + # Remove srcdir prefix $file =~ s/^\Q$config{srcdir}\E\/?//; - my @raw_lines = run_or_die('git', 'log', - '--follow', '--no-merges', - '--pretty=raw', '--raw', '--abbrev=40', '--always', '-c', - '-r', '--', $file); - my @ci; - while (my $parsed = parse_diff_tree("", \@raw_lines)) { - push @ci, $parsed; + if (! keys %time_cache) { + my $date; + foreach my $line (run_or_die('git', 'log', + '--pretty=format:%ct', + '--name-only', '--relative')) { + if (! defined $date && $line =~ /^(\d+)$/) { + $date=$line; + } + elsif (! length $line) { + $date=undef; + } + else { + my $f=decode_git_file($line); + + if (! $time_cache{$f}) { + $time_cache{$f}[0]=$date; # mtime + } + $time_cache{$f}[1]=$date; # ctime + } + } } - my $ctime = $ci[$#ci]->{'author_epoch'}; - debug("ctime for '$file': ". localtime($ctime)); - return $ctime; + return exists $time_cache{$file} ? $time_cache{$file}[$id] : 0; +} + +} + +sub rcs_getctime ($) { + my $file=shift; + + return findtimes($file, 1); +} + +sub rcs_getmtime ($) { + my $file=shift; + + return findtimes($file, 0); } sub rcs_receive () {