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";
}
}
"<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;