}
# version of the core git binary
-our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
+our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
$projects_list ||= $projectroot;
my $add_len = shift || 10;
my $where = shift || 'right'; # 'left' | 'center' | 'right'
+ # Make sure perl knows it is utf8 encoded so we don't
+ # cut in the middle of a utf8 multibyte char.
+ $str = to_utf8($str);
+
# allow only $len chars, but don't cut a word if it would fit in $add_len
# if it doesn't fit, cut it if it's still longer than the dots we would add
# remove chopped character entities entirely
return $GIT, '--git-dir='.$git_dir;
}
-# returns path to the core git executable and the --git-dir parameter as string
-sub git_cmd_str {
- return join(' ', git_cmd());
+# quote the given arguments for passing them to the shell
+# quote_command("command", "arg 1", "arg with ' and ! characters")
+# => "'command' 'arg 1' 'arg with '\'' and '\!' characters'"
+# Try to avoid using this function wherever possible.
+sub quote_command {
+ return join(' ',
+ map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ ));
}
# get HEAD ref of given project as hash
return wantarray ? @cos : \@cos;
}
-# parse ref from ref_file, given by ref_id, with given type
-sub parse_ref {
- my $ref_file = shift;
- my $ref_id = shift;
- my $type = shift || git_get_type($ref_id);
- my %ref_item;
-
- $ref_item{'type'} = $type;
- $ref_item{'id'} = $ref_id;
- $ref_item{'epoch'} = 0;
- $ref_item{'age'} = "unknown";
- if ($type eq "tag") {
- my %tag = parse_tag($ref_id);
- $ref_item{'comment'} = $tag{'comment'};
- if ($tag{'type'} eq "commit") {
- my %co = parse_commit($tag{'object'});
- $ref_item{'epoch'} = $co{'committer_epoch'};
- $ref_item{'age'} = $co{'age_string'};
- } elsif (defined($tag{'epoch'})) {
- my $age = time - $tag{'epoch'};
- $ref_item{'epoch'} = $tag{'epoch'};
- $ref_item{'age'} = age_string($age);
- }
- $ref_item{'reftype'} = $tag{'type'};
- $ref_item{'name'} = $tag{'name'};
- $ref_item{'refid'} = $tag{'object'};
- } elsif ($type eq "commit"){
- my %co = parse_commit($ref_id);
- $ref_item{'reftype'} = "commit";
- $ref_item{'name'} = $ref_file;
- $ref_item{'title'} = $co{'title'};
- $ref_item{'refid'} = $ref_id;
- $ref_item{'epoch'} = $co{'committer_epoch'};
- $ref_item{'age'} = $co{'age_string'};
- } else {
- $ref_item{'reftype'} = $type;
- $ref_item{'name'} = $ref_file;
- $ref_item{'refid'} = $ref_id;
- }
-
- return %ref_item;
-}
-
# parse line of git-diff-tree "raw" output
sub parse_difftree_raw_line {
my $line = shift;
return $default_blob_plain_mimetype unless $fd;
if (-T $fd) {
- return 'text/plain' .
- ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : '');
+ return 'text/plain';
} elsif (! $filename) {
return 'application/octet-stream';
} elsif ($filename =~ m/\.png$/i) {
}
}
+sub blob_contenttype {
+ my ($fd, $file_name, $type) = @_;
+
+ $type ||= blob_mimetype($fd, $file_name);
+ if ($type eq 'text/plain' && defined $default_text_plain_charset) {
+ $type .= "; charset=$default_text_plain_charset";
+ }
+
+ return $type;
+}
+
## ======================================================================
## functions printing HTML: header, footer, error page
print "</div>\n";
my ($have_search) = gitweb_check_feature('search');
- if ((defined $project) && ($have_search)) {
+ if (defined $project && $have_search) {
if (!defined $searchtext) {
$searchtext = "";
}
my ($use_pathinfo) = gitweb_check_feature('pathinfo');
if ($use_pathinfo) {
$action .= "/".esc_url($project);
- } else {
- $cgi->param("p", $project);
}
- $cgi->param("a", "search");
- $cgi->param("h", $search_hash);
print $cgi->startform(-method => "get", -action => $action) .
"<div class=\"search\">\n" .
- (!$use_pathinfo && $cgi->hidden(-name => "p") . "\n") .
- $cgi->hidden(-name => "a") . "\n" .
- $cgi->hidden(-name => "h") . "\n" .
+ (!$use_pathinfo &&
+ $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") .
+ $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" .
+ $cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" .
$cgi->popup_menu(-name => 'st', -default => 'commit',
-values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
$cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
}
sub format_paging_nav {
- my ($action, $hash, $head, $page, $nrevs) = @_;
+ my ($action, $hash, $head, $page, $has_next_link) = @_;
my $paging_nav;
$paging_nav .= " ⋅ prev";
}
- if ($nrevs >= (100 * ($page+1)-1)) {
+ if ($has_next_link) {
$paging_nav .= " ⋅ " .
$cgi->a({-href => href(-replay=>1, page=>$page+1),
-accesskey => "n", -title => "Alt-n"}, "next");
}
sub git_blob_plain {
+ my $type = shift;
my $expires;
if (!defined $hash) {
$expires = "+1d";
}
- my $type = shift;
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
- or die_error(undef, "Couldn't cat $file_name, $hash");
+ or die_error(undef, "Open git-cat-file blob '$hash' failed");
- $type ||= blob_mimetype($fd, $file_name);
+ # content-type (can include charset)
+ $type = blob_contenttype($fd, $file_name, $type);
- # save as filename, even when no $file_name is given
+ # "save as" filename, even when no $file_name is given
my $save_as = "$hash";
if (defined $file_name) {
$save_as = $file_name;
}
print $cgi->header(
- -type => "$type",
- -expires=>$expires,
- -content_disposition => 'inline; filename="' . "$save_as" . '"');
+ -type => $type,
+ -expires => $expires,
+ -content_disposition => 'inline; filename="' . $save_as . '"');
undef $/;
binmode STDOUT, ':raw';
print <$fd>;
$hash = git_get_head_hash($project);
}
- my $git_command = git_cmd_str();
my $name = $project;
$name =~ s,([^/])/*\.git$,$1,;
$name = basename($name);
$name =~ s/\047/\047\\\047\047/g;
my $cmd;
$filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}";
- $cmd = "$git_command archive " .
- "--format=$known_snapshot_formats{$format}{'format'} " .
- "--prefix=\'$name\'/ $hash";
+ $cmd = quote_command(
+ git_cmd(), 'archive',
+ "--format=$known_snapshot_formats{$format}{'format'}",
+ "--prefix=$name/", $hash);
if (exists $known_snapshot_formats{$format}{'compressor'}) {
- $cmd .= ' | ' . join ' ', @{$known_snapshot_formats{$format}{'compressor'}};
+ $cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}});
}
print $cgi->header(
my @commitlist = parse_commits($hash, 101, (100 * $page));
- my $paging_nav = format_paging_nav('log', $hash, $head, $page, (100 * ($page+1)));
+ my $paging_nav = format_paging_nav('log', $hash, $head, $page, $#commitlist >= 100);
git_header_html();
git_print_page_nav('log','', $hash,undef,undef, $paging_nav);
if ($hash || ($hash_base && !defined $file_name)) {
my $object_id = $hash || $hash_base;
- my $git_command = git_cmd_str();
- open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null"
+ open my $fd, "-|", quote_command(
+ git_cmd(), 'cat-file', '-t', $object_id) . ' 2> /dev/null'
or die_error('404 Not Found', "Object does not exist");
$type = <$fd>;
chomp $type;
my @commitlist = parse_commits($hash, 101, (100 * $page));
- my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, (100 * ($page+1)));
+ my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, $#commitlist >= 100);
my $next_link = '';
if ($#commitlist >= 100) {
$next_link =