Merge branch 'mw/pathinfo'
authorJunio C Hamano <junkio@cox.net>
Thu, 19 Oct 2006 05:09:11 +0000 (22:09 -0700)
committerJunio C Hamano <junkio@cox.net>
Thu, 19 Oct 2006 05:09:11 +0000 (22:09 -0700)
* mw/pathinfo:
gitweb: Fix search form when PATH_INFO is enabled
gitweb: Document features better
gitweb: warn if feature cannot be overridden.
gitweb: start to generate PATH_INFO URLs.

Conflicts:

gitweb/README

1  2 
gitweb/README
gitweb/gitweb.perl
diff --combined gitweb/README
index 78e6fc05f3dbbc274f7f1523e861799a4161f379,abbaf6b8bfe8549015f777701d43fcb8a28866d4..e02e90f0429be0d2a69b76571101f20b8f75530f
@@@ -1,5 -1,4 +1,5 @@@
  GIT web Interface
 +=================
  
  The one working on:
    http://www.kernel.org/git/
@@@ -7,8 -6,7 +7,8 @@@
  From the git version 1.4.0 gitweb is bundled with git.
  
  
 -How to configure gitweb for your local system:
 +How to configure gitweb for your local system
 +---------------------------------------------
  
  You can specify the following configuration variables when building GIT:
   * GITWEB_SITENAME
   * GITWEB_LOGO
     Points to the location where you put git-logo.png on your web server.
   * GITWEB_CONFIG
-    This file will be loaded using 'require'.  If the environment
+    This file will be loaded using 'require' and can be used to override any
+    of the options above as well as some other options - see the top of
+    'gitweb.cgi' for their full list and description.  If the environment
     $GITWEB_CONFIG is set when gitweb.cgi is executed the file in the
     environment variable will be loaded instead of the file
     specified when gitweb.cgi was created.
  
 +
+ Runtime gitweb configuration
+ ----------------------------
+ You can adjust gitweb behaviour using the file specified in `GITWEB_CONFIG`
+ (defaults to 'gitweb_config.perl' in the same directory as the CGI).
+ See the top of 'gitweb.cgi' for the list of variables and some description.
+ The most notable thing that is not configurable at compile time are the
+ optional features, stored in the '%features' variable. You can find further
+ description on how to reconfigure the default features setting in your
+ `GITWEB_CONFIG` or per-project in `project.git/config` inside 'gitweb.cgi'.
 +Webserver configuration
 +-----------------------
 +
 +If you want to have one URL for both gitweb and your http://
 +repositories, you can configure apache like this:
 +
 +<VirtualHost www:80>
 +    ServerName git.domain.org
 +    DocumentRoot /pub/git
 +    RewriteEngine on
 +    RewriteRule ^/(.*\.git/(?!/?(info|objects|refs)).*)?$ /cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
 +    SetEnv    GITWEB_CONFIG   /etc/gitweb.conf
 +</VirtualHost>
 +
 +The above configuration expects your public repositories to live under
 +/pub/git and will serve them as http://git.domain.org/dir-under-pub-git,
 +both as cloneable GIT URL and as browseable gitweb interface.
 +If you then start your git-daemon with --base-path=/pub/git --export-all
 +then you can even use the git:// URL with exactly the same path.
 +
 +Setting the environment variable GITWEB_CONFIG will tell gitweb to use
 +the named file (i.e. in this example /etc/gitweb.conf) as a
 +configuration for gitweb.  Perl variables defined in here will
 +override the defaults given at the head of the gitweb.perl (or
 +gitweb.cgi).  Look at the comments in that file for information on
 +which variables and what they mean.
 +
 +
  Originally written by:
    Kay Sievers <kay.sievers@vrfy.org>
  
diff --combined gitweb/gitweb.perl
index 0ec1eeffa1b688a3b0dc90eed24ba2de61756e2b,0a7acfd4936c39d4b09a24412c800be4ca073bb1..035e85e6e9c25623783ef36e2e91964b306de3b5
@@@ -46,17 -46,11 +46,17 @@@ our $home_text = "++GITWEB_HOMETEXT++"
  
  # URI of default stylesheet
  our $stylesheet = "++GITWEB_CSS++";
 -# 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++";
  
 +# 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++";
  
@@@ -93,21 -87,66 +93,66 @@@ 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]},
  );
  
  sub gitweb_check_feature {
                $feature{$name}{'override'},
                @{$feature{$name}{'default'}});
        if (!$override) { return @defaults; }
+       if (!defined $sub) {
+               warn "feature $name is not overrideable";
+               return @defaults;
+       }
        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');
  
        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) = @_;
  
@@@ -168,12 -199,6 +205,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');
  
@@@ -381,6 -406,10 +412,10 @@@ exit
  
  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",
  
        $params{'project'} = $project unless exists $params{'project'};
  
+       my ($use_pathinfo) = gitweb_check_feature('pathinfo');
+       if ($use_pathinfo) {
+               # use PATH_INFO for project name
+               $href .= "/$params{'project'}" if defined $params{'project'};
+               delete $params{'project'};
+               # Summary just uses the project path URL
+               if (defined $params{'action'} && $params{'action'} eq 'summary') {
+                       delete $params{'action'};
+               }
+       }
+       # now encode the parameters explicitly
        my @result = ();
        for (my $i = 0; $i < @mapping; $i += 2) {
                my ($name, $symbol) = ($mapping[$i], $mapping[$i+1]);
                        push @result, $symbol . "=" . esc_param($params{$name});
                }
        }
-       return "$my_uri?" . join(';', @result);
+       $href .= "?" . join(';', @result) if scalar @result;
+       return $href;
  }
  
  
@@@ -446,12 -490,6 +496,12 @@@ sub validate_refname 
        return $input;
  }
  
 +# very thin wrapper for decode("utf8", $str, Encode::FB_DEFAULT);
 +sub to_utf8 {
 +      my $str = shift;
 +      return decode("utf8", $str, Encode::FB_DEFAULT);
 +}
 +
  # quote unsafe chars, but keep the slash, even when it's not
  # correct, but quoted slashes look too horrible in bookmarks
  sub esc_param {
@@@ -474,10 -512,9 +524,10 @@@ sub esc_url 
  # replace invalid utf8 character with SUBSTITUTION sequence
  sub esc_html {
        my $str = shift;
 -      $str = decode("utf8", $str, Encode::FB_DEFAULT);
 +      $str = to_utf8($str);
        $str = escapeHTML($str);
        $str =~ s/\014/^L/g; # escape FORM FEED (FF) character (e.g. in COPYING file)
 +      $str =~ s/\033/^[/g; # "escape" ESCAPE (\e) character (e.g. commit 20a3847d8a5032ce41f90dcc68abfb36e6fee9b1)
        return $str;
  }
  
@@@ -677,7 -714,7 +727,7 @@@ sub format_subject_html 
  
        if (length($short) < length($long)) {
                return $cgi->a({-href => $href, -class => "list subject",
 -                              -title => decode("utf8", $long, Encode::FB_DEFAULT)},
 +                              -title => to_utf8($long)},
                       esc_html($short) . $extra);
        } else {
                return $cgi->a({-href => $href, -class => "list subject"},
@@@ -854,7 -891,7 +904,7 @@@ sub git_get_projects_list 
                            -e "$projectroot/$path/$export_ok")) {
                                my $pr = {
                                        path => $path,
 -                                      owner => decode("utf8", $owner, Encode::FB_DEFAULT),
 +                                      owner => to_utf8($owner),
                                };
                                push @list, $pr
                        }
@@@ -883,7 -920,7 +933,7 @@@ sub git_get_project_owner 
                        $pr = unescape($pr);
                        $ow = unescape($ow);
                        if ($pr eq $project) {
 -                              $owner = decode("utf8", $ow, Encode::FB_DEFAULT);
 +                              $owner = to_utf8($ow);
                                last;
                        }
                }
@@@ -1074,9 -1111,6 +1124,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/^    //;
@@@ -1248,7 -1282,7 +1298,7 @@@ sub get_file_owner 
        }
        my $owner = $gcos;
        $owner =~ s/[,;].*$//;
 -      return decode("utf8", $owner, Encode::FB_DEFAULT);
 +      return to_utf8($owner);
  }
  
  ## ......................................................................
@@@ -1388,9 -1422,9 +1438,9 @@@ EO
        print "</head>\n" .
              "<body>\n" .
              "<div class=\"page_header\">\n" .
 -            "<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git documentation\">" .
 -            "<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));
                }
                $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" .
@@@ -1926,14 -1961,14 +1977,14 @@@ sub git_patchset_body 
                                print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
                                      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
                                                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
 -                                            $diffinfo->{'to_id'}) . "(new)" .
 +                                            $diffinfo->{'to_id'}) . " (new)" .
                                      "</div>\n"; # class="diff_info"
  
                        } elsif ($diffinfo->{'status'} eq "D") { # deleted
                                print "<div class=\"diff_info\">" . file_type($diffinfo->{'from_mode'}) . ":" .
                                      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
                                                             hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})},
 -                                            $diffinfo->{'from_id'}) . "(deleted)" .
 +                                            $diffinfo->{'from_id'}) . " (deleted)" .
                                      "</div>\n"; # class="diff_info"
  
                        } elsif ($diffinfo->{'status'} eq "R" || # renamed
@@@ -2037,10 -2072,8 +2088,10 @@@ sub git_shortlog_body 
                print "</td>\n" .
                      "<td class=\"link\">" .
                      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
 -                    $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . " | " .
 -                    $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
 +                    $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree");
 +              if (gitweb_have_snapshot()) {
 +                      print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
 +              }
                print "</td>\n" .
                      "</tr>\n";
        }
@@@ -2855,12 -2888,9 +2906,12 @@@ sub git_snapshot 
                -content_disposition => 'inline; filename="' . "$filename" . '"',
                -status => '200 OK');
  
 -      my $git_command = git_cmd_str();
 -      open my $fd, "-|", "$git_command tar-tree $hash \'$project\' | $command" or
 -              die_error(undef, "Execute git-tar-tree failed.");
 +      my $git = git_cmd_str();
 +      my $name = $project;
 +      $name =~ s/\047/\047\\\047\047/g;
 +      open my $fd, "-|",
 +      "$git archive --format=tar --prefix=\'$name\'/ $hash | $command"
 +              or die_error(undef, "Execute git-tar-tree failed.");
        binmode STDOUT, ':raw';
        print <$fd>;
        binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
@@@ -2957,8 -2987,13 +3008,8 @@@ sub git_commit 
                        $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)},
                                "blame");
        }
 -      if (defined $co{'parent'}) {
 -              push @views_nav,
 -                      $cgi->a({-href => href(action=>"shortlog", hash=>$hash)}, "shortlog"),
 -                      $cgi->a({-href => href(action=>"log", hash=>$hash)}, "log");
 -      }
        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));
  
@@@ -3601,7 -3636,7 +3652,7 @@@ XM
                      "<![CDATA[\n";
                my $comment = $co{'comment'};
                foreach my $line (@$comment) {
 -                      $line = decode("utf8", $line, Encode::FB_DEFAULT);
 +                      $line = to_utf8($line);
                        print "$line<br/>\n";
                }
                print "<br/>\n";
                                next;
                        }
                        my $file = esc_html(unquote($7));
 -                      $file = decode("utf8", $file, Encode::FB_DEFAULT);
 +                      $file = to_utf8($file);
                        print "$file<br/>\n";
                }
                print "]]>\n" .