Code

Merge branch 'mo/cvsserver'
[git.git] / gitweb / gitweb.perl
index 73d098a433f4238c43603ab03c838c1356e7ab7a..8308e2208e2a0064724367f3bcb6d33282b9e587 100755 (executable)
@@ -369,7 +369,12 @@ sub filter_snapshot_fmts {
 }
 
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
-do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
+if (-e $GITWEB_CONFIG) {
+       do $GITWEB_CONFIG;
+} else {
+       our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
+       do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM;
+}
 
 # version of the core git binary
 our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
@@ -506,7 +511,7 @@ sub evaluate_path_info {
        }
        # do not change any parameters if an action is given using the query string
        return if $action;
-       $path_info =~ s,^$project/*,,;
+       $path_info =~ s,^\Q$project\E/*,,;
        my ($refname, $pathname) = split(/:/, $path_info, 2);
        if (defined $pathname) {
                # we got "project.git/branch:filename" or "project.git/branch:dir/"
@@ -587,7 +592,7 @@ exit;
 ## ======================================================================
 ## action links
 
-sub href(%) {
+sub href (%) {
        my %params = @_;
        # default is to use -absolute url() i.e. $my_uri
        my $href = $params{-full} ? $my_url : $my_uri;
@@ -628,7 +633,7 @@ sub href(%) {
        my ($use_pathinfo) = gitweb_check_feature('pathinfo');
        if ($use_pathinfo) {
                # use PATH_INFO for project name
-               $href .= "/$params{'project'}" if defined $params{'project'};
+               $href .= "/".esc_url($params{'project'}) if defined $params{'project'};
                delete $params{'project'};
 
                # Summary just uses the project path URL
@@ -861,6 +866,10 @@ sub chop_str {
        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
@@ -1443,6 +1452,46 @@ sub format_snapshot_links {
        }
 }
 
+## ......................................................................
+## functions returning values to be passed, perhaps after some
+## transformation, to other functions; e.g. returning arguments to href()
+
+# returns hash to be passed to href to generate gitweb URL
+# in -title key it returns description of link
+sub get_feed_info {
+       my $format = shift || 'Atom';
+       my %res = (action => lc($format));
+
+       # feed links are possible only for project views
+       return unless (defined $project);
+       # some views should link to OPML, or to generic project feed,
+       # or don't have specific feed yet (so they should use generic)
+       return if ($action =~ /^(?:tags|heads|forks|tag|search)$/x);
+
+       my $branch;
+       # branches refs uses 'refs/heads/' prefix (fullname) to differentiate
+       # from tag links; this also makes possible to detect branch links
+       if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) ||
+           (defined $hash      && $hash      =~ m!^refs/heads/(.*)$!)) {
+               $branch = $1;
+       }
+       # find log type for feed description (title)
+       my $type = 'log';
+       if (defined $file_name) {
+               $type  = "history of $file_name";
+               $type .= "/" if ($action eq 'tree');
+               $type .= " on '$branch'" if (defined $branch);
+       } else {
+               $type = "log of $branch" if (defined $branch);
+       }
+
+       $res{-title} = $type;
+       $res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef);
+       $res{'file_name'} = $file_name;
+
+       return %res;
+}
+
 ## ----------------------------------------------------------------------
 ## git utility subroutines, invoking git commands
 
@@ -2505,30 +2554,49 @@ EOF
                }
        }
        if (defined $project) {
-               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"));
+               my %href_params = get_feed_info();
+               if (!exists $href_params{'-title'}) {
+                       $href_params{'-title'} = 'log';
+               }
+
+               foreach my $format qw(RSS Atom) {
+                       my $type = lc($format);
+                       my %link_attr = (
+                               '-rel' => 'alternate',
+                               '-title' => "$project - $href_params{'-title'} - $format feed",
+                               '-type' => "application/$type+xml"
+                       );
+
+                       $href_params{'action'} = $type;
+                       $link_attr{'-href'} = href(%href_params);
+                       print "<link ".
+                             "rel=\"$link_attr{'-rel'}\" ".
+                             "title=\"$link_attr{'-title'}\" ".
+                             "href=\"$link_attr{'-href'}\" ".
+                             "type=\"$link_attr{'-type'}\" ".
+                             "/>\n";
+
+                       $href_params{'extra_options'} = '--no-merges';
+                       $link_attr{'-href'} = href(%href_params);
+                       $link_attr{'-title'} .= ' (no merges)';
+                       print "<link ".
+                             "rel=\"$link_attr{'-rel'}\" ".
+                             "title=\"$link_attr{'-title'}\" ".
+                             "href=\"$link_attr{'-href'}\" ".
+                             "type=\"$link_attr{'-type'}\" ".
+                             "/>\n";
+               }
+
        } else {
                printf('<link rel="alternate" title="%s projects list" '.
-                      'href="%s" type="text/plain; charset=utf-8"/>'."\n",
+                      'href="%s" type="text/plain; charset=utf-8" />'."\n",
                       $site_name, href(project=>undef, action=>"project_index"));
                printf('<link rel="alternate" title="%s projects feeds" '.
-                      'href="%s" type="text/x-opml"/>'."\n",
+                      'href="%s" type="text/x-opml" />'."\n",
                       $site_name, href(project=>undef, action=>"opml"));
        }
        if (defined $favicon) {
-               print qq(<link rel="shortcut icon" href="$favicon" type="image/png"/>\n);
+               print qq(<link rel="shortcut icon" href="$favicon" type="image/png" />\n);
        }
 
        print "</head>\n" .
@@ -2570,7 +2638,7 @@ EOF
                my $action = $my_uri;
                my ($use_pathinfo) = gitweb_check_feature('pathinfo');
                if ($use_pathinfo) {
-                       $action .= "/$project";
+                       $action .= "/".esc_url($project);
                } else {
                        $cgi->param("p", $project);
                }
@@ -2596,23 +2664,35 @@ EOF
 }
 
 sub git_footer_html {
+       my $feed_class = 'rss_logo';
+
        print "<div class=\"page_footer\">\n";
        if (defined $project) {
                my $descr = git_get_project_description($project);
                if (defined $descr) {
                        print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
                }
-               print $cgi->a({-href => href(action=>"rss"),
-                             -class => "rss_logo"}, "RSS") . " ";
-               print $cgi->a({-href => href(action=>"atom"),
-                             -class => "rss_logo"}, "Atom") . "\n";
+
+               my %href_params = get_feed_info();
+               if (!%href_params) {
+                       $feed_class .= ' generic';
+               }
+               $href_params{'-title'} ||= 'log';
+
+               foreach my $format qw(RSS Atom) {
+                       $href_params{'action'} = lc($format);
+                       print $cgi->a({-href => href(%href_params),
+                                     -title => "$href_params{'-title'} $format feed",
+                                     -class => $feed_class}, $format)."\n";
+               }
+
        } else {
                print $cgi->a({-href => href(project=>undef, action=>"opml"),
-                             -class => "rss_logo"}, "OPML") . " ";
+                             -class => $feed_class}, "OPML") . " ";
                print $cgi->a({-href => href(project=>undef, action=>"project_index"),
-                             -class => "rss_logo"}, "TXT") . "\n";
+                             -class => $feed_class}, "TXT") . "\n";
        }
-       print "</div>\n" ;
+       print "</div>\n"; # class="page_footer"
 
        if (-f $site_footer) {
                open (my $fd, $site_footer);
@@ -5171,14 +5251,26 @@ sub git_history {
        my $refs = git_get_references();
        my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
 
+       my @commitlist = parse_commits($hash_base, 101, (100 * $page),
+                                      $file_name, "--full-history");
+       if (!@commitlist) {
+               die_error('404 Not Found', "No such file or directory on given branch");
+       }
+
        if (!defined $hash && defined $file_name) {
-               $hash = git_get_hash_by_path($hash_base, $file_name);
+               # some commits could have deleted file in question,
+               # and not have it in tree, but one of them has to have it
+               for (my $i = 0; $i <= @commitlist; $i++) {
+                       $hash = git_get_hash_by_path($commitlist[$i]{'id'}, $file_name);
+                       last if defined $hash;
+               }
        }
        if (defined $hash) {
                $ftype = git_get_type($hash);
        }
-
-       my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history");
+       if (!defined $ftype) {
+               die_error(undef, "Unknown type of object");
+       }
 
        my $paging_nav = '';
        if ($page > 0) {