close $fd or return undef;
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
- $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
+ $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/;
if (defined $type && $type ne $2) {
# type doesn't match
return undef;
return $owner;
}
+sub git_get_last_activity {
+ my ($path) = @_;
+ my $fd;
+
+ $git_dir = "$projectroot/$path";
+ open($fd, "-|", git_cmd(), 'for-each-ref',
+ '--format=%(refname) %(committer)',
+ '--sort=-committerdate',
+ 'refs/heads') or return;
+ my $most_recent = <$fd>;
+ close $fd or return;
+ if ($most_recent =~ / (\d+) [-+][01]\d\d\d$/) {
+ my $timestamp = $1;
+ my $age = time - $timestamp;
+ return ($age, age_string($age));
+ }
+}
+
sub git_get_references {
my $type = shift || "";
my %refs;
return %tag
}
-sub git_get_last_activity {
- my ($path) = @_;
- my $fd;
-
- $git_dir = "$projectroot/$path";
- open($fd, "-|", git_cmd(), 'for-each-ref',
- '--format=%(refname) %(committer)',
- '--sort=-committerdate',
- 'refs/heads') or return;
- my $most_recent = <$fd>;
- close $fd or return;
- if ($most_recent =~ / (\d+) [-+][01]\d\d\d$/) {
- my $timestamp = $1;
- my $age = time - $timestamp;
- return ($age, age_string($age));
- }
-}
-
sub parse_commit {
my $commit_id = shift;
my $commit_text = shift;
@commit_lines = @$commit_text;
} else {
local $/ = "\0";
- open my $fd, "-|", git_cmd(), "rev-list", "--header", "--parents", "--max-count=1", $commit_id
+ open my $fd, "-|", git_cmd(), "rev-list",
+ "--header", "--parents", "--max-count=1",
+ $commit_id, "--"
or return;
@commit_lines = split '\n', <$fd>;
close $fd or return;
my %res;
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
- $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
+ $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/s;
$res{'mode'} = $1;
$res{'type'} = $2;
## ......................................................................
## parse to array of hashes functions
-sub git_get_refs_list {
- my $type = shift || "";
- my %refs;
- my @reflist;
+sub git_get_heads_list {
+ my $limit = shift;
+ my @headslist;
- my @refs;
- open my $fd, "-|", $GIT, "peek-remote", "$projectroot/$project/"
+ open my $fd, '-|', git_cmd(), 'for-each-ref',
+ ($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',
+ '--format=%(objectname) %(refname) %(subject)%00%(committer)',
+ 'refs/heads'
or return;
while (my $line = <$fd>) {
- chomp $line;
- if ($line =~ m/^([0-9a-fA-F]{40})\trefs\/($type\/?([^\^]+))(\^\{\})?$/) {
- if (defined $refs{$1}) {
- push @{$refs{$1}}, $2;
- } else {
- $refs{$1} = [ $2 ];
- }
+ my %ref_item;
- if (! $4) { # unpeeled, direct reference
- push @refs, { hash => $1, name => $3 }; # without type
- } elsif ($3 eq $refs[-1]{'name'}) {
- # most likely a tag is followed by its peeled
- # (deref) one, and when that happens we know the
- # previous one was of type 'tag'.
- $refs[-1]{'type'} = "tag";
- }
+ chomp $line;
+ my ($refinfo, $committerinfo) = split(/\0/, $line);
+ my ($hash, $name, $title) = split(' ', $refinfo, 3);
+ my ($committer, $epoch, $tz) =
+ ($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);
+ $name =~ s!^refs/heads/!!;
+
+ $ref_item{'name'} = $name;
+ $ref_item{'id'} = $hash;
+ $ref_item{'title'} = $title || '(no commit message)';
+ $ref_item{'epoch'} = $epoch;
+ if ($epoch) {
+ $ref_item{'age'} = age_string(time - $ref_item{'epoch'});
+ } else {
+ $ref_item{'age'} = "unknown";
}
+
+ push @headslist, \%ref_item;
}
close $fd;
- foreach my $ref (@refs) {
- my $ref_file = $ref->{'name'};
- my $ref_id = $ref->{'hash'};
+ return wantarray ? @headslist : \@headslist;
+}
+
+sub git_get_tags_list {
+ my $limit = shift;
+ my @tagslist;
+
+ open my $fd, '-|', git_cmd(), 'for-each-ref',
+ ($limit ? '--count='.($limit+1) : ()), '--sort=-creatordate',
+ '--format=%(objectname) %(objecttype) %(refname) '.
+ '%(*objectname) %(*objecttype) %(subject)%00%(creator)',
+ 'refs/tags'
+ or return;
+ while (my $line = <$fd>) {
+ my %ref_item;
+
+ chomp $line;
+ my ($refinfo, $creatorinfo) = split(/\0/, $line);
+ my ($id, $type, $name, $refid, $reftype, $title) = split(' ', $refinfo, 6);
+ my ($creator, $epoch, $tz) =
+ ($creatorinfo =~ /^(.*) ([0-9]+) (.*)$/);
+ $name =~ s!^refs/tags/!!;
+
+ $ref_item{'type'} = $type;
+ $ref_item{'id'} = $id;
+ $ref_item{'name'} = $name;
+ if ($type eq "tag") {
+ $ref_item{'subject'} = $title;
+ $ref_item{'reftype'} = $reftype;
+ $ref_item{'refid'} = $refid;
+ } else {
+ $ref_item{'reftype'} = $type;
+ $ref_item{'refid'} = $id;
+ }
- my $type = $ref->{'type'} || git_get_type($ref_id) || next;
- my %ref_item = parse_ref($ref_file, $ref_id, $type);
+ if ($type eq "tag" || $type eq "commit") {
+ $ref_item{'epoch'} = $epoch;
+ if ($epoch) {
+ $ref_item{'age'} = age_string(time - $ref_item{'epoch'});
+ } else {
+ $ref_item{'age'} = "unknown";
+ }
+ }
- push @reflist, \%ref_item;
+ push @tagslist, \%ref_item;
}
- # sort refs by age
- @reflist = sort {$b->{'epoch'} <=> $a->{'epoch'}} @reflist;
- return (\@reflist, \%refs);
+ close $fd;
+
+ return wantarray ? @tagslist : \@tagslist;
}
## ----------------------------------------------------------------------
for (my $i = $from; $i <= $to; $i++) {
my $entry = $taglist->[$i];
my %tag = %$entry;
- my $comment_lines = $tag{'comment'};
- my $comment = shift @$comment_lines;
+ my $comment = $tag{'subject'};
my $comment_short;
if (defined $comment) {
$comment_short = chop_str($comment, 30, 5);
$cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'});
if ($tag{'reftype'} eq "commit") {
print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") .
- " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'refid'})}, "log");
+ " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log");
} elsif ($tag{'reftype'} eq "blob") {
print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
}
my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
my $entry = $headlist->[$i];
- my %tag = %$entry;
- my $curr = $tag{'id'} eq $head;
+ my %ref = %$entry;
+ my $curr = $ref{'id'} eq $head;
if ($alternate) {
print "<tr class=\"dark\">\n";
} else {
print "<tr class=\"light\">\n";
}
$alternate ^= 1;
- print "<td><i>$tag{'age'}</i></td>\n" .
- ($tag{'id'} eq $head ? "<td class=\"current_head\">" : "<td>") .
- $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'}),
- -class => "list name"},esc_html($tag{'name'})) .
+ print "<td><i>$ref{'age'}</i></td>\n" .
+ ($curr ? "<td class=\"current_head\">" : "<td>") .
+ $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'}),
+ -class => "list name"},esc_html($ref{'name'})) .
"</td>\n" .
"<td class=\"link\">" .
- $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " .
- $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . " | " .
- $cgi->a({-href => href(action=>"tree", hash=>$tag{'name'}, hash_base=>$tag{'name'})}, "tree") .
+ $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'})}, "shortlog") . " | " .
+ $cgi->a({-href => href(action=>"log", hash=>$ref{'name'})}, "log") . " | " .
+ $cgi->a({-href => href(action=>"tree", hash=>$ref{'name'}, hash_base=>$ref{'name'})}, "tree") .
"</td>\n" .
"</tr>";
}
my $owner = git_get_project_owner($project);
- my ($reflist, $refs) = git_get_refs_list();
-
- my @taglist;
- my @headlist;
- foreach my $ref (@$reflist) {
- if ($ref->{'name'} =~ s!^heads/!!) {
- push @headlist, $ref;
- } else {
- $ref->{'name'} =~ s!^tags/!!;
- push @taglist, $ref;
- }
- }
+ my $refs = git_get_references();
+ my @taglist = git_get_tags_list(15);
+ my @headlist = git_get_heads_list(15);
git_header_html();
git_print_page_nav('summary','', $head);
}
open my $fd, "-|", git_cmd(), "rev-list", "--max-count=17",
- git_get_head_hash($project)
+ git_get_head_hash($project), "--"
or die_error(undef, "Open git-rev-list failed");
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
print "<tr class=\"$rev_color[$current_color]\">\n";
if ($group_size) {
print "<td class=\"sha1\"";
- print " title=\"$author, $date\"";
+ print " title=\"". esc_html($author) . ", $date\"";
print " rowspan=\"$group_size\"" if ($group_size > 1);
print ">";
print $cgi->a({-href => href(action=>"commit",
git_print_page_nav('','', $head,undef,$head);
git_print_header_div('summary', $project);
- my ($taglist) = git_get_refs_list("tags");
- if (@$taglist) {
- git_tags_body($taglist);
+ my @tagslist = git_get_tags_list();
+ if (@tagslist) {
+ git_tags_body(\@tagslist);
}
git_footer_html();
}
git_print_page_nav('','', $head,undef,$head);
git_print_header_div('summary', $project);
- my ($headlist) = git_get_refs_list("heads");
- if (@$headlist) {
- git_heads_body($headlist, $head);
+ my @headslist = git_get_heads_list();
+ if (@headslist) {
+ git_heads_body(\@headslist, $head);
}
git_footer_html();
}
my $refs = git_get_references();
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
- open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash
+ open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash, "--"
or die_error(undef, "Open git-rev-list failed");
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
$parent = "--root";
}
open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
- @diff_opts, $parent, $hash
+ @diff_opts, $parent, $hash, "--"
or die_error(undef, "Open git-diff-tree failed");
my @difftree = map { chomp; $_ } <$fd>;
close $fd or die_error(undef, "Reading git-diff-tree failed");
if (defined $hash_base && defined $hash_parent_base) {
if (defined $file_name) {
# read raw output
- open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base,
+ open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
+ $hash_parent_base, $hash_base,
"--", $file_name
or die_error(undef, "Open git-diff-tree failed");
@difftree = map { chomp; $_ } <$fd>;
# try to find filename from $hash
# read filtered raw output
- open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base
+ open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
+ $hash_parent_base, $hash_base, "--"
or die_error(undef, "Open git-diff-tree failed");
@difftree =
# ':100644 100644 03b21826... 3b93d5e7... M ls-files.c'
}
# open patch output
- open $fd, "-|", git_cmd(), "diff", '-p', @diff_opts, $hash_parent, $hash
+ open $fd, "-|", git_cmd(), "diff", '-p', @diff_opts,
+ $hash_parent, $hash, "--"
or die_error(undef, "Open git-diff failed");
} else {
die_error('404 Not Found', "Missing one of the blob diff parameters")
if (!%co) {
die_error(undef, "Unknown commit object");
}
+
+ # we need to prepare $formats_nav before any parameter munging
+ my $formats_nav;
+ if ($format eq 'html') {
+ $formats_nav =
+ $cgi->a({-href => href(action=>"commitdiff_plain",
+ hash=>$hash, hash_parent=>$hash_parent)},
+ "raw");
+
+ if (defined $hash_parent) {
+ # commitdiff with two commits given
+ my $hash_parent_short = $hash_parent;
+ if ($hash_parent =~ m/^[0-9a-fA-F]{40}$/) {
+ $hash_parent_short = substr($hash_parent, 0, 7);
+ }
+ $formats_nav .=
+ ' (from: ' .
+ $cgi->a({-href => href(action=>"commitdiff",
+ hash=>$hash_parent)},
+ esc_html($hash_parent_short)) .
+ ')';
+ } elsif (!$co{'parent'}) {
+ # --root commitdiff
+ $formats_nav .= ' (initial)';
+ } elsif (scalar @{$co{'parents'}} == 1) {
+ # single parent commit
+ $formats_nav .=
+ ' (parent: ' .
+ $cgi->a({-href => href(action=>"commitdiff",
+ hash=>$co{'parent'})},
+ esc_html(substr($co{'parent'}, 0, 7))) .
+ ')';
+ } else {
+ # merge commit
+ $formats_nav .=
+ ' (merge: ' .
+ join(' ', map {
+ $cgi->a({-href => href(action=>"commitdiff",
+ hash=>$_)},
+ esc_html(substr($_, 0, 7)));
+ } @{$co{'parents'}} ) .
+ ')';
+ }
+ }
+
if (!defined $hash_parent) {
$hash_parent = $co{'parent'} || '--root';
}
my @difftree;
if ($format eq 'html') {
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
- "--no-commit-id",
- "--patch-with-raw", "--full-index", $hash_parent, $hash
+ "--no-commit-id", "--patch-with-raw", "--full-index",
+ $hash_parent, $hash, "--"
or die_error(undef, "Open git-diff-tree failed");
while (chomp(my $line = <$fd>)) {
} elsif ($format eq 'plain') {
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
- '-p', $hash_parent, $hash
+ '-p', $hash_parent, $hash, "--"
or die_error(undef, "Open git-diff-tree failed");
} else {
if ($format eq 'html') {
my $refs = git_get_references();
my $ref = format_ref_marker($refs, $co{'id'});
- my $formats_nav =
- $cgi->a({-href => href(action=>"commitdiff_plain",
- hash=>$hash, hash_parent=>$hash_parent)},
- "raw");
git_header_html(undef, $expires);
git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
my $alternate = 1;
if ($searchtype eq 'commit' or $searchtype eq 'author' or $searchtype eq 'committer') {
$/ = "\0";
- open my $fd, "-|", git_cmd(), "rev-list", "--header", "--parents", $hash or next;
+ open my $fd, "-|", git_cmd(), "rev-list",
+ "--header", "--parents", $hash, "--"
+ or next;
while (my $commit_text = <$fd>) {
if (!grep m/$searchtext/i, $commit_text) {
next;
my $refs = git_get_references();
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
- open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash
+ open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash, "--"
or die_error(undef, "Open git-rev-list failed");
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
sub git_rss {
# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
- open my $fd, "-|", git_cmd(), "rev-list", "--max-count=150", git_get_head_hash($project)
+ open my $fd, "-|", git_cmd(), "rev-list", "--max-count=150",
+ git_get_head_hash($project), "--"
or die_error(undef, "Open git-rev-list failed");
my @revlist = map { chomp; $_ } <$fd>;
close $fd or die_error(undef, "Reading git-rev-list failed");
}
my %cd = parse_date($co{'committer_epoch'});
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
- $co{'parent'}, $co{'id'}
+ $co{'parent'}, $co{'id'}, "--"
or next;
my @difftree = map { chomp; $_ } <$fd>;
close $fd