]> Lady’s Gitweb - Gitweb/blobdiff - gitweb.perl
gitweb: Improve git_print_page_path
[Gitweb] / gitweb.perl
index 7e9b5d4ca2dc1f66d7f7e44b79e7c4d572cf7a205bb9a9e249222e38074a4784..e3c030a3025f4f4dc9e191b3dbb7ce8ee611eae22aaf0b4837c458e6bcda52ef 100755 (executable)
@@ -54,13 +54,16 @@ our $stylesheet;
 # default is not to define style sheet, but it can be overwritten later
 undef $stylesheet;
 
-# URI of GIT logo
+# URI of GIT logo (72x27 size)
 our $logo = "++GITWEB_LOGO++";
 # URI of GIT favicon, assumed to be image/png type
 our $favicon = "++GITWEB_FAVICON++";
 
-our $githelp_url = "http://git.or.cz/";
-our $githelp_label = "git homepage";
+# URI and label (title) of GIT logo link
+#our $logo_url = "http://www.kernel.org/pub/software/scm/git/docs/";
+#our $logo_label = "git documentation";
+our $logo_url = "http://git.or.cz/";
+our $logo_label = "git homepage";
 
 # source of projects list
 our $projects_list = "++GITWEB_LIST++";
@@ -98,22 +101,63 @@ our %feature = (
        #
        # use gitweb_check_feature(<feature>) to check if <feature> is enabled
 
+       # Enable the 'blame' blob view, showing the last commit that modified
+       # each line in the file. This can be very CPU-intensive.
+
+       # To enable system wide have in $GITWEB_CONFIG
+       # $feature{'blame'}{'default'} = [1];
+       # To have project specific config enable override in $GITWEB_CONFIG
+       # $feature{'blame'}{'override'} = 1;
+       # and in project config gitweb.blame = 0|1;
        'blame' => {
                'sub' => \&feature_blame,
                'override' => 0,
                'default' => [0]},
 
+       # Enable the 'snapshot' link, providing a compressed tarball of any
+       # tree. This can potentially generate high traffic if you have large
+       # project.
+
+       # To disable system wide have in $GITWEB_CONFIG
+       # $feature{'snapshot'}{'default'} = [undef];
+       # To have project specific config enable override in $GITWEB_CONFIG
+       # $feature{'blame'}{'override'} = 1;
+       # and in project config gitweb.snapshot = none|gzip|bzip2;
        'snapshot' => {
                'sub' => \&feature_snapshot,
                'override' => 0,
                #         => [content-encoding, suffix, program]
                'default' => ['x-gzip', 'gz', 'gzip']},
 
+       # Enable the pickaxe search, which will list the commits that modified
+       # a given string in a file. This can be practical and quite faster
+       # alternative to 'blame', but still potentially CPU-intensive.
+
+       # To enable system wide have in $GITWEB_CONFIG
+       # $feature{'pickaxe'}{'default'} = [1];
+       # To have project specific config enable override in $GITWEB_CONFIG
+       # $feature{'pickaxe'}{'override'} = 1;
+       # and in project config gitweb.pickaxe = 0|1;
        'pickaxe' => {
                'sub' => \&feature_pickaxe,
                'override' => 0,
                'default' => [1]},
 
+       # Make gitweb use an alternative format of the URLs which can be
+       # more readable and natural-looking: project name is embedded
+       # directly in the path and the query string contains other
+       # auxiliary information. All gitweb installations recognize
+       # URL in either format; this configures in which formats gitweb
+       # generates links.
+
+       # To enable system wide have in $GITWEB_CONFIG
+       # $feature{'pathinfo'}{'default'} = [1];
+       # Project specific override is not supported.
+
+       # Note that you will need to change the default location of CSS,
+       # favicon, logo and possibly other files to an absolute URL. Also,
+       # if gitweb.cgi serves as your indexfile, you will need to force
+       # $my_uri to contain the script name in your $GITWEB_CONFIG.
        'pathinfo' => {
                'override' => 0,
                'default' => [0]},
@@ -134,12 +178,6 @@ sub gitweb_check_feature {
        return $sub->(@defaults);
 }
 
-# To enable system wide have in $GITWEB_CONFIG
-# $feature{'blame'}{'default'} = [1];
-# To have project specific config enable override in $GITWEB_CONFIG
-# $feature{'blame'}{'override'} = 1;
-# and in project config gitweb.blame = 0|1;
-
 sub feature_blame {
        my ($val) = git_get_project_config('blame', '--bool');
 
@@ -152,12 +190,6 @@ sub feature_blame {
        return $_[0];
 }
 
-# To disable system wide have in $GITWEB_CONFIG
-# $feature{'snapshot'}{'default'} = [undef];
-# To have project specific config enable override in $GITWEB_CONFIG
-# $feature{'blame'}{'override'} = 1;
-# and in project config  gitweb.snapshot = none|gzip|bzip2
-
 sub feature_snapshot {
        my ($ctype, $suffix, $command) = @_;
 
@@ -181,12 +213,6 @@ sub gitweb_have_snapshot {
        return $have_snapshot;
 }
 
-# To enable system wide have in $GITWEB_CONFIG
-# $feature{'pickaxe'}{'default'} = [1];
-# To have project specific config enable override in $GITWEB_CONFIG
-# $feature{'pickaxe'}{'override'} = 1;
-# and in project config gitweb.pickaxe = 0|1;
-
 sub feature_pickaxe {
        my ($val) = git_get_project_config('pickaxe', '--bool');
 
@@ -412,6 +438,9 @@ sub href(%) {
        my %params = @_;
        my $href = $my_uri;
 
+       # XXX: Warning: If you touch this, check the search form for updating,
+       # too.
+
        my @mapping = (
                project => "p",
                action => "a",
@@ -1045,6 +1074,24 @@ sub parse_tag {
        return %tag
 }
 
+sub git_get_last_activity {
+       my ($path) = @_;
+       my $fd;
+
+       $git_dir = "$projectroot/$path";
+       open($fd, "-|", git_cmd(), 'for-each-ref',
+            '--format=%(refname) %(committer)',
+            '--sort=-committerdate',
+            'refs/heads') or return;
+       my $most_recent = <$fd>;
+       close $fd or return;
+       if ($most_recent =~ / (\d+) [-+][01]\d\d\d$/) {
+               my $timestamp = $1;
+               my $age = time - $timestamp;
+               return ($age, age_string($age));
+       }
+}
+
 sub parse_commit {
        my $commit_id = shift;
        my $commit_text = shift;
@@ -1120,6 +1167,9 @@ sub parse_commit {
                        last;
                }
        }
+       if ($co{'title'} eq "") {
+               $co{'title'} = $co{'title_short'} = '(no commit message)';
+       }
        # remove added spaces
        foreach my $line (@commit_lines) {
                $line =~ s/^    //;
@@ -1447,11 +1497,9 @@ EOF
        }
 
        print "<div class=\"page_header\">\n" .
-             "<a href=\"" . esc_html($githelp_url) .
-             "\" title=\"" . esc_html($githelp_label) .
-             "\">" .
-             "<img src=\"$logo\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
-             "</a>\n";
+             $cgi->a({-href => esc_url($logo_url),
+                      -title => $logo_label},
+                     qq(<img src="$logo" width="72" height="27" alt="git" class="logo"/>));
        print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
        if (defined $project) {
                print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
@@ -1472,6 +1520,7 @@ EOF
                }
                $cgi->param("a", "search");
                $cgi->param("h", $search_hash);
+               $cgi->param("p", $project);
                print $cgi->startform(-method => "get", -action => $my_uri) .
                      "<div class=\"search\">\n" .
                      $cgi->hidden(-name => "p") . "\n" .
@@ -1632,17 +1681,16 @@ sub git_print_page_path {
        my $type = shift;
        my $hb = shift;
 
-       if (!defined $name) {
-               print "<div class=\"page_path\">/</div>\n";
-       } else {
+
+       print "<div class=\"page_path\">";
+       print $cgi->a({-href => href(action=>"tree", hash_base=>$hb),
+                     -title => 'tree root'}, "[$project]");
+       print " / ";
+       if (defined $name) {
                my @dirname = split '/', $name;
                my $basename = pop @dirname;
                my $fullname = '';
 
-               print "<div class=\"page_path\">";
-               print $cgi->a({-href => href(action=>"tree", hash_base=>$hb),
-                             -title => 'tree root'}, "[$project]");
-               print " / ";
                foreach my $dir (@dirname) {
                        $fullname .= ($fullname ? '/' : '') . $dir;
                        print $cgi->a({-href => href(action=>"tree", file_name=>$fullname,
@@ -1658,11 +1706,12 @@ sub git_print_page_path {
                        print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
                                                     hash_base=>$hb),
                                      -title => $name}, esc_html($basename));
+                       print " / ";
                } else {
                        print esc_html($basename);
                }
-               print "<br/></div>\n";
        }
+       print "<br/></div>\n";
 }
 
 # sub git_print_log (\@;%) {
@@ -1739,13 +1788,13 @@ sub git_print_tree_entry {
        if ($t->{'type'} eq "blob") {
                print "<td class=\"list\">" .
                        $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
-                                              file_name=>"$basedir$t->{'name'}", %base_key),
-                                -class => "list"}, esc_html($t->{'name'})) . "</td>\n";
+                                              file_name=>"$basedir$t->{'name'}", %base_key),
+                               -class => "list"}, esc_html($t->{'name'})) . "</td>\n";
                print "<td class=\"link\">";
                if ($have_blame) {
                        print $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
-                                                    file_name=>"$basedir$t->{'name'}", %base_key)},
-                                     "blame");
+                                                          file_name=>"$basedir$t->{'name'}", %base_key)},
+                                           "blame");
                }
                if (defined $hash_base) {
                        if ($have_blame) {
@@ -1757,8 +1806,8 @@ sub git_print_tree_entry {
                }
                print " | " .
                        $cgi->a({-href => href(action=>"blob_plain", hash_base=>$hash_base,
-                                              file_name=>"$basedir$t->{'name'}")},
-                               "raw");
+                                              file_name=>"$basedir$t->{'name'}")},
+                               "raw");
                print "</td>\n";
 
        } elsif ($t->{'type'} eq "tree") {
@@ -1826,7 +1875,7 @@ sub git_difftree_body {
                        print "<td>";
                        print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
                                                     hash_base=>$hash, file_name=>$diff{'file'}),
-                                      -class => "list"}, esc_html($diff{'file'}));
+                                     -class => "list"}, esc_html($diff{'file'}));
                        print "</td>\n";
                        print "<td>$mode_chng</td>\n";
                        print "<td class=\"link\">";
@@ -1853,11 +1902,11 @@ sub git_difftree_body {
                                print " | ";
                        }
                        print $cgi->a({-href => href(action=>"blame", hash_base=>$parent,
-                                                    file_name=>$diff{'file'})},
-                                     "blame") . " | ";
+                                                    file_name=>$diff{'file'})},
+                                     "blame") . " | ";
                        print $cgi->a({-href => href(action=>"history", hash_base=>$parent,
-                                                    file_name=>$diff{'file'})},
-                                     "history");
+                                                    file_name=>$diff{'file'})},
+                                     "history");
                        print "</td>\n";
 
                } elsif ($diff{'status'} eq "M" || $diff{'status'} eq "T") { # modified, or type changed
@@ -1878,8 +1927,8 @@ sub git_difftree_body {
                        }
                        print "<td>";
                        print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
-                                                    hash_base=>$hash, file_name=>$diff{'file'}),
-                                      -class => "list"}, esc_html($diff{'file'}));
+                                                    hash_base=>$hash, file_name=>$diff{'file'}),
+                                     -class => "list"}, esc_html($diff{'file'}));
                        print "</td>\n";
                        print "<td>$mode_chnge</td>\n";
                        print "<td class=\"link\">";
@@ -1890,19 +1939,19 @@ sub git_difftree_body {
                                        print $cgi->a({-href => "#patch$patchno"}, "patch");
                                } else {
                                        print $cgi->a({-href => href(action=>"blobdiff",
-                                                                    hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
-                                                                    hash_base=>$hash, hash_parent_base=>$parent,
-                                                                    file_name=>$diff{'file'})},
-                                                     "diff");
+                                                                    hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
+                                                                    hash_base=>$hash, hash_parent_base=>$parent,
+                                                                    file_name=>$diff{'file'})},
+                                                     "diff");
                                }
                                print " | ";
                        }
                        print $cgi->a({-href => href(action=>"blame", hash_base=>$hash,
-                                                    file_name=>$diff{'file'})},
-                                     "blame") . " | ";
+                                                    file_name=>$diff{'file'})},
+                                     "blame") . " | ";
                        print $cgi->a({-href => href(action=>"history", hash_base=>$hash,
-                                                    file_name=>$diff{'file'})},
-                                     "history");
+                                                    file_name=>$diff{'file'})},
+                                     "history");
                        print "</td>\n";
 
                } elsif ($diff{'status'} eq "R" || $diff{'status'} eq "C") { # renamed or copied
@@ -1930,19 +1979,19 @@ sub git_difftree_body {
                                        print $cgi->a({-href => "#patch$patchno"}, "patch");
                                } else {
                                        print $cgi->a({-href => href(action=>"blobdiff",
-                                                                    hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
-                                                                    hash_base=>$hash, hash_parent_base=>$parent,
-                                                                    file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
-                                                     "diff");
+                                                                    hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
+                                                                    hash_base=>$hash, hash_parent_base=>$parent,
+                                                                    file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
+                                                     "diff");
                                }
                                print " | ";
                        }
                        print $cgi->a({-href => href(action=>"blame", hash_base=>$parent,
-                                                    file_name=>$diff{'from_file'})},
-                                     "blame") . " | ";
+                                                    file_name=>$diff{'from_file'})},
+                                     "blame") . " | ";
                        print $cgi->a({-href => href(action=>"history", hash_base=>$parent,
-                                                    file_name=>$diff{'from_file'})},
-                                     "history");
+                                                   file_name=>$diff{'from_file'})},
+                                     "history");
                        print "</td>\n";
 
                } # we should not encounter Unmerged (U) or Unknown (X) status
@@ -2298,16 +2347,11 @@ sub git_project_list {
                die_error(undef, "No projects found");
        }
        foreach my $pr (@list) {
-               my $head = git_get_head_hash($pr->{'path'});
-               if (!defined $head) {
+               my (@aa) = git_get_last_activity($pr->{'path'});
+               unless (@aa) {
                        next;
                }
-               $git_dir = "$projectroot/$pr->{'path'}";
-               my %co = parse_commit($head);
-               if (!%co) {
-                       next;
-               }
-               $pr->{'commit'} = \%co;
+               ($pr->{'age'}, $pr->{'age_string'}) = @aa;
                if (!defined $pr->{'descr'}) {
                        my $descr = git_get_project_description($pr->{'path'}) || "";
                        $pr->{'descr'} = chop_str($descr, 25, 5);
@@ -2357,7 +2401,7 @@ sub git_project_list {
                      "</th>\n";
        }
        if ($order eq "age") {
-               @projects = sort {$a->{'commit'}{'age'} <=> $b->{'commit'}{'age'}} @projects;
+               @projects = sort {$a->{'age'} <=> $b->{'age'}} @projects;
                print "<th>Last Change</th>\n";
        } else {
                print "<th>" .
@@ -2379,8 +2423,8 @@ sub git_project_list {
                                        -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
                      "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
                      "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
-               print "<td class=\"". age_class($pr->{'commit'}{'age'}) . "\">" .
-                     $pr->{'commit'}{'age_string'} . "</td>\n" .
+               print "<td class=\"". age_class($pr->{'age'}) . "\">" .
+                     $pr->{'age_string'} . "</td>\n" .
                      "<td class=\"link\">" .
                      $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary")   . " | " .
                      $cgi->a({-href => href(project=>$pr->{'path'}, action=>"shortlog")}, "shortlog") . " | " .
@@ -2536,7 +2580,7 @@ sub git_blame2 {
        if ($ftype !~ "blob") {
                die_error("400 Bad Request", "Object is not a blob");
        }
-       open ($fd, "-|", git_cmd(), "blame", '--porcelain', '--',
+       open ($fd, "-|", git_cmd(), "blame", '-p', '--',
              $file_name, $hash_base)
                or die_error(undef, "Open git-blame failed");
        git_header_html();
@@ -2565,7 +2609,7 @@ HTML
        while (1) {
                $_ = <$fd>;
                last unless defined $_;
-               my ($full_rev, $lineno, $orig_lineno, $group_size) =
+               my ($full_rev, $orig_lineno, $lineno, $group_size) =
                    /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/;
                if (!exists $metainfo{$full_rev}) {
                        $metainfo{$full_rev} = {};
@@ -2879,7 +2923,7 @@ sub git_tree {
        my $refs = git_get_references();
        my $ref = format_ref_marker($refs, $hash_base);
        git_header_html();
-       my $base = "";
+       my $basedir = '';
        my ($have_blame) = gitweb_check_feature('blame');
        if (defined $hash_base && (my %co = parse_commit($hash_base))) {
                my @views_nav = ();
@@ -2896,7 +2940,7 @@ sub git_tree {
                        # FIXME: Should be available when we have no hash base as well.
                        push @views_nav,
                                $cgi->a({-href => href(action=>"snapshot", hash=>$hash)},
-                                       "snapshot");
+                                       "snapshot");
                }
                git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav));
                git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
@@ -2907,7 +2951,10 @@ sub git_tree {
                print "<div class=\"title\">$hash</div>\n";
        }
        if (defined $file_name) {
-               $base = esc_html("$file_name/");
+               $basedir = $file_name;
+               if ($basedir ne '' && substr($basedir, -1) ne '/') {
+                       $basedir .= '/';
+               }
        }
        git_print_page_path($file_name, 'tree', $hash_base);
        print "<div class=\"page_body\">\n";
@@ -2923,7 +2970,7 @@ sub git_tree {
                }
                $alternate ^= 1;
 
-               git_print_tree_entry(\%t, $base, $hash_base, $have_blame);
+               git_print_tree_entry(\%t, $basedir, $hash_base, $have_blame);
 
                print "</tr>\n";
        }
@@ -3054,7 +3101,7 @@ sub git_commit {
                                "blame");
        }
        git_header_html(undef, $expires);
-       git_print_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff',
+       git_print_page_nav('commit', '',
                           $hash, $co{'tree'}, $hash,
                           join (' | ', @views_nav));
 
This page took 0.354395 seconds and 4 git commands to generate.