our @extra_options = $cgi->param('opt');
if (defined @extra_options) {
- foreach(@extra_options)
- {
- if (not grep(/^$_$/, keys %allowed_options)) {
+ foreach my $opt (@extra_options) {
+ if (not exists $allowed_options{$opt}) {
die_error(undef, "Invalid option parameter");
}
- if (not grep(/^$action$/, @{$allowed_options{$_}})) {
+ if (not grep(/^$action$/, @{$allowed_options{$opt}})) {
die_error(undef, "Invalid option parameter for this action");
}
}
our $searchtext = $cgi->param('s');
our $search_regexp;
if (defined $searchtext) {
- if ($searchtype ne 'grep' and $searchtype ne 'pickaxe' and $searchtext =~ m/[^a-zA-Z0-9_\.\/\-\+\:\@ ]/) {
- die_error(undef, "Invalid search parameter");
- }
if (length($searchtext) < 2) {
die_error(undef, "At least two characters are required for search parameter");
}
action => "a",
file_name => "f",
file_parent => "fp",
- extra_options => "opt",
hash => "h",
hash_parent => "hp",
hash_base => "hb",
searchtext => "s",
searchtype => "st",
snapshot_format => "sf",
+ extra_options => "opt",
);
my %mapping = @mapping;
for (my $i = 0; $i < @mapping; $i += 2) {
my ($name, $symbol) = ($mapping[$i], $mapping[$i+1]);
if (defined $params{$name}) {
- push @result, $symbol . "=" . esc_param($params{$name});
+ if (ref($params{$name}) eq "ARRAY") {
+ foreach my $par (@{$params{$name}}) {
+ push @result, $symbol . "=" . esc_param($par);
+ }
+ } else {
+ push @result, $symbol . "=" . esc_param($params{$name});
+ }
}
}
$href .= "?" . join(';', @result) if scalar @result;
return $age_str;
}
+use constant {
+ S_IFINVALID => 0030000,
+ S_IFGITLINK => 0160000,
+};
+
+# submodule/subproject, a commit object reference
+sub S_ISGITLINK($) {
+ my $mode = shift;
+
+ return (($mode & S_IFMT) == S_IFGITLINK)
+}
+
# convert file mode in octal to symbolic file mode string
sub mode_str {
my $mode = oct shift;
- if (S_ISDIR($mode & S_IFMT)) {
+ if (S_ISGITLINK($mode)) {
+ return 'm---------';
+ } elsif (S_ISDIR($mode & S_IFMT)) {
return 'drwxr-xr-x';
} elsif (S_ISLNK($mode)) {
return 'lrwxrwxrwx';
$mode = oct $mode;
}
- if (S_ISDIR($mode & S_IFMT)) {
+ if (S_ISGITLINK($mode)) {
+ return "submodule";
+ } elsif (S_ISDIR($mode & S_IFMT)) {
return "directory";
} elsif (S_ISLNK($mode)) {
return "symlink";
$mode = oct $mode;
}
- if (S_ISDIR($mode & S_IFMT)) {
+ if (S_ISGITLINK($mode)) {
+ return "submodule";
+ } elsif (S_ISDIR($mode & S_IFMT)) {
return "directory";
} elsif (S_ISLNK($mode)) {
return "symlink";
File::Find::find({
follow_fast => 1, # follow symbolic links
+ follow_skip => 2, # ignore duplicates
dangling_symlinks => 0, # ignore dangling symlinks, silently
wanted => sub {
# skip project-list toplevel, if we get it.
printf('<link rel="alternate" title="%s log RSS feed" '.
'href="%s" type="application/rss+xml" />'."\n",
esc_param($project), href(action=>"rss"));
+ printf('<link rel="alternate" title="%s log RSS feed (no merges)" '.
+ 'href="%s" type="application/rss+xml" />'."\n",
+ esc_param($project), href(action=>"rss",
+ extra_options=>"--no-merges"));
printf('<link rel="alternate" title="%s log Atom feed" '.
'href="%s" type="application/atom+xml" />'."\n",
esc_param($project), href(action=>"atom"));
+ printf('<link rel="alternate" title="%s log Atom feed (no merges)" '.
+ 'href="%s" type="application/atom+xml" />'."\n",
+ esc_param($project), href(action=>"atom",
+ extra_options=>"--no-merges"));
} else {
printf('<link rel="alternate" title="%s projects list" '.
'href="%s" type="text/plain; charset=utf-8"/>'."\n",
"history");
}
print "</td>\n";
+ } else {
+ # unknown object: we can only present history for it
+ # (this includes 'commit' object, i.e. submodule support)
+ print "<td class=\"list\">" .
+ esc_path($t->{'name'}) .
+ "</td>\n";
+ print "<td class=\"link\">";
+ if (defined $hash_base) {
+ print $cgi->a({-href => href(action=>"history",
+ hash_base=>$hash_base,
+ file_name=>"$basedir$t->{'name'}")},
+ "history");
+ }
+ print "</td>\n";
}
}
"diff_tree\">\n";
# header only for combined diff in 'commitdiff' view
- my $has_header = @parents > 1 && $action eq 'commitdiff';
+ my $has_header = @$difftree && @parents > 1 && $action eq 'commitdiff';
if ($has_header) {
# table header
print "<thead><tr>\n" .
}
} until (!defined $to_name || $to_name eq $diffinfo->{'to_file'} ||
$patch_idx > $#$difftree);
+
# modifies %from, %to hashes
parse_from_to_diffinfo($diffinfo, \%from, \%to, @hash_parents);
- if ($diffinfo->{'nparents'}) {
- # combined diff
- $from{'file'} = [];
- $from{'href'} = [];
- fill_from_file_info($diffinfo, @hash_parents)
- unless exists $diffinfo->{'from_file'};
- for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {
- $from{'file'}[$i] = $diffinfo->{'from_file'}[$i] || $diffinfo->{'to_file'};
- if ($diffinfo->{'status'}[$i] ne "A") { # not new (added) file
- $from{'href'}[$i] = href(action=>"blob",
- hash_base=>$hash_parents[$i],
- hash=>$diffinfo->{'from_id'}[$i],
- file_name=>$from{'file'}[$i]);
- } else {
- $from{'href'}[$i] = undef;
- }
- }
- } else {
- $from{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'};
- if ($diffinfo->{'status'} ne "A") { # not new (added) file
- $from{'href'} = href(action=>"blob", hash_base=>$hash_parent,
- hash=>$diffinfo->{'from_id'},
- file_name=>$from{'file'});
- } else {
- delete $from{'href'};
- }
- }
- $to{'file'} = $diffinfo->{'to_file'} || $diffinfo->{'file'};
- if (!is_deleted($diffinfo)) { # file exists in result
- $to{'href'} = href(action=>"blob", hash_base=>$hash,
- hash=>$diffinfo->{'to_id'},
- file_name=>$to{'file'});
- } else {
- delete $to{'href'};
- }
# this is first patch for raw difftree line with $patch_idx index
# we index @$difftree array from 0, but number patches from 1
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
"<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
-class => "list", -title => $pr->{'descr_long'}},
esc_html($pr->{'descr'})) . "</td>\n" .
- "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
+ "<td><i>" . esc_html(chop_str($pr->{'owner'}, 15)) . "</i></td>\n";
print "<td class=\"". age_class($pr->{'age'}) . "\">" .
(defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" .
"<td class=\"link\">" .
print "<div class=\"title\"> </div>\n";
print "<table cellspacing=\"0\">\n" .
"<tr><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
- "<tr><td>owner</td><td>$owner</td></tr>\n";
+ "<tr><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
if (defined $cd{'rfc2822'}) {
print "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
}
# log/feed of current (HEAD) branch, log of given branch, history of file/directory
my $head = $hash || 'HEAD';
- my @commitlist = parse_commits($head, 150);
+ my @commitlist = parse_commits($head, 150, 0, undef, $file_name);
my %latest_commit;
my %latest_date;