Merge branch 'jn/gitweb-caching-prep'
authorJunio C Hamano <gitster@pobox.com>
Fri, 21 May 2010 11:02:21 +0000 (04:02 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 21 May 2010 11:02:21 +0000 (04:02 -0700)
* jn/gitweb-caching-prep:
gitweb: Move generating page title to separate subroutine
gitweb: Add custom error handler using die_error
gitweb: Use nonlocal jump instead of 'exit' in die_error
gitweb: href(..., -path_info => 0|1)
Export more test-related variables when running external tests

1  2 
gitweb/gitweb.perl
t/test-lib.sh
diff --combined gitweb/gitweb.perl
index 4e64fc86bd29b6bf3762be6034be5662cccf18c1,7d75dc4c8c712a76765405fd4387102e4cdf7d55..934aacb61494a666ed0bdf9a9f1ef77dc6147c23
@@@ -11,7 -11,7 +11,7 @@@ use strict
  use warnings;
  use CGI qw(:standard :escapeHTML -nosticky);
  use CGI::Util qw(unescape);
- use CGI::Carp qw(fatalsToBrowser);
+ use CGI::Carp qw(fatalsToBrowser set_message);
  use Encode;
  use Fcntl ':mode';
  use File::Find qw();
@@@ -952,6 -952,21 +952,21 @@@ if ($git_avatar eq 'gravatar') 
        $git_avatar = '';
  }
  
+ # custom error handler: 'die <message>' is Internal Server Error
+ sub handle_errors_html {
+       my $msg = shift; # it is already HTML escaped
+       # to avoid infinite loop where error occurs in die_error,
+       # change handler to default handler, disabling handle_errors_html
+       set_message("Error occured when inside die_error:\n$msg");
+       # you cannot jump out of die_error when called as error handler;
+       # the subroutine set via CGI::Carp::set_message is called _after_
+       # HTTP headers are already written, so it cannot write them itself
+       die_error(undef, undef, $msg, -error_handler => 1, -no_http_header => 1);
+ }
+ set_message(\&handle_errors_html);
  # dispatch
  if (!defined $action) {
        if (defined $hash) {
@@@ -972,11 -987,16 +987,16 @@@ if ($action !~ m/^(?:opml|project_list|
        die_error(400, "Project needed");
  }
  $actions{$action}->();
- exit;
+ DONE_GITWEB:
+ 1;
  
  ## ======================================================================
  ## action links
  
+ # possible values of extra options
+ # -full => 0|1      - use absolute/full URL ($my_uri/$my_url as base)
+ # -replay => 1      - start from a current view (replay with modifications)
+ # -path_info => 0|1 - don't use/use path_info URL (if possible)
  sub href {
        my %params = @_;
        # default is to use -absolute url() i.e. $my_uri
        }
  
        my $use_pathinfo = gitweb_check_feature('pathinfo');
-       if ($use_pathinfo and defined $params{'project'}) {
+       if (defined $params{'project'} &&
+           (exists $params{-path_info} ? $params{-path_info} : $use_pathinfo)) {
                # try to put as many parameters as possible in PATH_INFO:
                #   - project name
                #   - action
@@@ -2420,9 -2441,6 +2441,9 @@@ sub git_get_projects_list 
                        follow_skip => 2, # ignore duplicates
                        dangling_symlinks => 0, # ignore dangling symlinks, silently
                        wanted => sub {
 +                              # global variables
 +                              our $project_maxdepth;
 +                              our $projectroot;
                                # skip project-list toplevel, if we get it.
                                return if (m!^[/.]$!);
                                # only directories can be git repositories
@@@ -3161,23 -3179,30 +3182,30 @@@ sub blob_contenttype 
  ## ======================================================================
  ## functions printing HTML: header, footer, error page
  
+ sub get_page_title {
+       my $title = to_utf8($site_name);
+       return $title unless (defined $project);
+       $title .= " - " . to_utf8($project);
+       return $title unless (defined $action);
+       $title .= "/$action"; # $action is US-ASCII (7bit ASCII)
+       return $title unless (defined $file_name);
+       $title .= " - " . esc_path($file_name);
+       if ($action eq "tree" && $file_name !~ m|/$|) {
+               $title .= "/";
+       }
+       return $title;
+ }
  sub git_header_html {
        my $status = shift || "200 OK";
        my $expires = shift;
+       my %opts = @_;
  
-       my $title = "$site_name";
-       if (defined $project) {
-               $title .= " - " . to_utf8($project);
-               if (defined $action) {
-                       $title .= "/$action";
-                       if (defined $file_name) {
-                               $title .= " - " . esc_path($file_name);
-                               if ($action eq "tree" && $file_name !~ m|/$|) {
-                                       $title .= "/";
-                               }
-                       }
-               }
-       }
+       my $title = get_page_title();
        my $content_type;
        # require explicit support from the UA if we are to send the page as
        # 'application/xhtml+xml', otherwise send it as plain old 'text/html'.
                $content_type = 'text/html';
        }
        print $cgi->header(-type=>$content_type, -charset => 'utf-8',
-                          -status=> $status, -expires => $expires);
+                          -status=> $status, -expires => $expires)
+               unless ($opts{'-no_http_headers'});
        my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
        print <<EOF;
  <?xml version="1.0" encoding="utf-8"?>
@@@ -3408,6 -3434,7 +3437,7 @@@ sub die_error 
        my $status = shift || 500;
        my $error = esc_html(shift) || "Internal Server Error";
        my $extra = shift;
+       my %opts = @_;
  
        my %http_responses = (
                400 => '400 Bad Request',
                500 => '500 Internal Server Error',
                503 => '503 Service Unavailable',
        );
-       git_header_html($http_responses{$status});
+       git_header_html($http_responses{$status}, undef, %opts);
        print <<EOF;
  <div class="page_body">
  <br /><br />
@@@ -3430,7 -3457,8 +3460,8 @@@ EO
        print "</div>\n";
  
        git_footer_html();
-       exit;
+       goto DONE_GITWEB
+               unless ($opts{'-error_handler'});
  }
  
  ## ----------------------------------------------------------------------
@@@ -6120,8 -6148,8 +6151,8 @@@ sub git_commitdiff 
                        }
                        push @commit_spec, '--root', $hash;
                }
 -              open $fd, "-|", git_cmd(), "format-patch", '--encoding=utf8',
 -                      '--stdout', @commit_spec
 +              open $fd, "-|", git_cmd(), "format-patch", @diff_opts,
 +                      '--encoding=utf8', '--stdout', @commit_spec
                        or die_error(500, "Open git-format-patch failed");
        } else {
                die_error(400, "Unknown commitdiff format");
diff --combined t/test-lib.sh
index 9bfa14be7f1c3935013d04318eeaecc68b4ef88c,6187328e93872ab4ef8bb65d74fce4798c9907a2..454880ac7d281d901156136900814dee9aae46c5
@@@ -2,18 -2,6 +2,18 @@@
  #
  # Copyright (c) 2005 Junio C Hamano
  #
 +# This program is free software: you can redistribute it and/or modify
 +# it under the terms of the GNU General Public License as published by
 +# the Free Software Foundation, either version 2 of the License, or
 +# (at your option) any later version.
 +#
 +# This program is distributed in the hope that it will be useful,
 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +# GNU General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program.  If not, see http://www.gnu.org/licenses/ .
  
  # if --tee was passed, write the output not only to the terminal, but
  # additionally to the file test-results/$BASENAME.out, too.
@@@ -366,10 -354,8 +366,10 @@@ test_debug () 
  }
  
  test_run_ () {
 +      test_cleanup=:
        eval >&3 2>&4 "$1"
 -      eval_ret="$?"
 +      eval_ret=$?
 +      eval >&3 2>&4 "$test_cleanup"
        return 0
  }
  
@@@ -473,6 -459,9 +473,9 @@@ test_external () 
                # Announce the script to reduce confusion about the
                # test output that follows.
                say_color "" " run $test_count: $descr ($*)"
+               # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG
+               # to be able to use them in script
+               export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG
                # Run command; redirect its stderr to &4 as in
                # test_run_, but keep its stdout on our stdout even in
                # non-verbose mode.
@@@ -530,22 -519,6 +533,22 @@@ test_must_fail () 
        test $? -gt 0 -a $? -le 129 -o $? -gt 192
  }
  
 +# Similar to test_must_fail, but tolerates success, too.  This is
 +# meant to be used in contexts like:
 +#
 +#     test_expect_success 'some command works without configuration' '
 +#             test_might_fail git config --unset all.configuration &&
 +#             do something
 +#     '
 +#
 +# Writing "git config --unset all.configuration || :" would be wrong,
 +# because we want to notice if it fails due to segv.
 +
 +test_might_fail () {
 +      "$@"
 +      test $? -ge 0 -a $? -le 129 -o $? -gt 192
 +}
 +
  # test_cmp is a helper function to compare actual and expected output.
  # You can use it like:
  #
@@@ -563,31 -536,6 +566,31 @@@ test_cmp() 
        $GIT_TEST_CMP "$@"
  }
  
 +# This function can be used to schedule some commands to be run
 +# unconditionally at the end of the test to restore sanity:
 +#
 +#     test_expect_success 'test core.capslock' '
 +#             git config core.capslock true &&
 +#             test_when_finished "git config --unset core.capslock" &&
 +#             hello world
 +#     '
 +#
 +# That would be roughly equivalent to
 +#
 +#     test_expect_success 'test core.capslock' '
 +#             git config core.capslock true &&
 +#             hello world
 +#             git config --unset core.capslock
 +#     '
 +#
 +# except that the greeting and config --unset must both succeed for
 +# the test to pass.
 +
 +test_when_finished () {
 +      test_cleanup="{ $*
 +              } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
 +}
 +
  # Most tests can use the created repository, but some may need to create more.
  # Usage: test_create_repo <directory>
  test_create_repo () {