X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/4dbebc2534076e2c5c799c342a22c0525f935f5447f9e751f020c1362c9b20cf..62ca5cd2228519bda52b6911737014c8d0e85f6447dd318cc114569fdd9c0295:/gitweb.perl diff --git a/gitweb.perl b/gitweb.perl index 9c5dfc5..873f8d0 100755 --- a/gitweb.perl +++ b/gitweb.perl @@ -35,6 +35,10 @@ our $GIT = "++GIT_BINDIR++/git"; #our $projectroot = "/pub/scm"; our $projectroot = "++GITWEB_PROJECTROOT++"; +# fs traversing limit for getting project list +# the number is relative to the projectroot +our $project_maxdepth = "++GITWEB_PROJECT_MAXDEPTH++"; + # target of the home link on top of all pages our $home_link = $my_uri || "/"; @@ -308,10 +312,6 @@ sub feature_snapshot { if ($val) { @fmts = ($val eq 'none' ? () : split /\s*[,\s]\s*/, $val); - @fmts = grep { defined } map { - exists $known_snapshot_format_aliases{$_} ? - $known_snapshot_format_aliases{$_} : $_ } @fmts; - @fmts = grep(exists $known_snapshot_formats{$_}, @fmts); } return @fmts; @@ -357,6 +357,18 @@ sub check_export_ok { (!$export_ok || -e "$dir/$export_ok")); } +# process alternate names for backward compatibility +# filter out unsupported (unknown) snapshot formats +sub filter_snapshot_fmts { + my @fmts = @_; + + @fmts = map { + exists $known_snapshot_format_aliases{$_} ? + $known_snapshot_format_aliases{$_} : $_} @fmts; + @fmts = grep(exists $known_snapshot_formats{$_}, @fmts); + +} + our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; do $GITWEB_CONFIG if -e $GITWEB_CONFIG; @@ -429,12 +441,11 @@ my %allowed_options = ( 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"); } } @@ -465,9 +476,6 @@ if (defined $searchtype) { 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"); } @@ -591,7 +599,6 @@ sub href(%) { action => "a", file_name => "f", file_parent => "fp", - extra_options => "opt", hash => "h", hash_parent => "hp", hash_base => "hb", @@ -601,6 +608,7 @@ sub href(%) { searchtext => "s", searchtype => "st", snapshot_format => "sf", + extra_options => "opt", ); my %mapping = @mapping; @@ -623,7 +631,13 @@ sub href(%) { 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; @@ -833,6 +847,23 @@ sub chop_str { return "$body$tail"; } +# takes the same arguments as chop_str, but also wraps a around the +# result with a title attribute if it does get chopped. Additionally, the +# string is HTML-escaped. +sub chop_and_escape_str { + my $str = shift; + my $len = shift; + my $add_len = shift || 10; + + my $chopped = chop_str($str, $len, $add_len); + if ($chopped eq $str) { + return esc_html($chopped); + } else { + return qq{} . + esc_html($chopped) . qq{}; + } +} + ## ---------------------------------------------------------------------- ## functions returning short strings @@ -883,11 +914,25 @@ sub age_string { 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'; @@ -913,7 +958,9 @@ sub file_type { $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"; @@ -934,7 +981,9 @@ sub file_type_long { $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"; @@ -1300,9 +1349,11 @@ sub format_diff_line { sub format_snapshot_links { my ($hash) = @_; my @snapshot_fmts = gitweb_check_feature('snapshot'); + @snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts); my $num_fmts = @snapshot_fmts; if ($num_fmts > 1) { # A parenthesized list of links bearing format names. + # e.g. "snapshot (_tar.gz_ _zip_)" return "snapshot (" . join(' ', map $cgi->a({ -href => href( @@ -1314,8 +1365,10 @@ sub format_snapshot_links { , @snapshot_fmts) . ")"; } elsif ($num_fmts == 1) { # A single "snapshot" link whose tooltip bears the format name. + # i.e. "_snapshot_" my ($fmt) = @snapshot_fmts; - return $cgi->a({ + return + $cgi->a({ -href => href( action=>"snapshot", hash=>$hash, @@ -1478,15 +1531,22 @@ sub git_get_projects_list { # remove the trailing "/" $dir =~ s!/+$!!; my $pfxlen = length("$dir"); + my $pfxdepth = ($dir =~ tr!/!!); 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. return if (m!^[/.]$!); # only directories can be git repositories return unless (-d $_); + # don't traverse too deep (Find is super slow on os x) + if (($File::Find::name =~ tr!/!!) - $pfxdepth > $project_maxdepth) { + $File::Find::prune = 1; + return; + } my $subdir = substr($File::Find::name, $pfxlen + 1); # we check related file in $projectroot @@ -2256,9 +2316,17 @@ EOF printf(''."\n", esc_param($project), href(action=>"rss")); + printf(''."\n", + esc_param($project), href(action=>"rss", + extra_options=>"--no-merges")); printf(''."\n", esc_param($project), href(action=>"atom")); + printf(''."\n", + esc_param($project), href(action=>"atom", + extra_options=>"--no-merges")); } else { printf(''."\n", @@ -2696,6 +2764,20 @@ sub git_print_tree_entry { "history"); } print "\n"; + } else { + # unknown object: we can only present history for it + # (this includes 'commit' object, i.e. submodule support) + print "
| description | " . esc_html($descr) . " | ||
| owner | $owner | ||
| owner | " . esc_html($owner) . " | ||
| last change | $cd{'rfc2822'} | ||
| $co{'age_string_date'} | \n" . - "" . esc_html(chop_str($co{'author_name'}, 15, 5)) . " | \n" . + "" . $author . " | \n" . "" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, @@ -5301,7 +5361,7 @@ sub git_feed { # 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; |