Merge branch 'jn/gitweb-unborn-head'
authorJunio C Hamano <gitster@pobox.com>
Tue, 21 Feb 2012 23:25:53 +0000 (15:25 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 21 Feb 2012 23:25:53 +0000 (15:25 -0800)
* jn/gitweb-unborn-head:
gitweb: Fix "heads" view when there is no current branch

1  2 
gitweb/gitweb.perl
t/t9500-gitweb-standalone-no-errors.sh
diff --combined gitweb/gitweb.perl
index 16d376075ea8bb47271aaeffebacf56fd41e713b,a174c9d6c49ff1895c8f4e10f99bfc8c40b6d007..b63a5c67aff0fd587da31b307c1154ec033950f1
@@@ -52,7 -52,7 +52,7 @@@ sub evaluate_uri 
        # as base URL.
        # Therefore, if we needed to strip PATH_INFO, then we know that we have
        # to build the base URL ourselves:
 -      our $path_info = $ENV{"PATH_INFO"};
 +      our $path_info = decode_utf8($ENV{"PATH_INFO"});
        if ($path_info) {
                if ($my_url =~ s,\Q$path_info\E$,, &&
                    $my_uri =~ s,\Q$path_info\E$,, &&
@@@ -760,7 -760,6 +760,7 @@@ our @cgi_param_mapping = 
        search_use_regexp => "sr",
        ctag => "by_tag",
        diff_style => "ds",
 +      project_filter => "pf",
        # this must be last entry (for manipulation from JavaScript)
        javascript => "js"
  );
@@@ -817,9 -816,9 +817,9 @@@ sub evaluate_query_params 
  
        while (my ($name, $symbol) = each %cgi_param_mapping) {
                if ($symbol eq 'opt') {
 -                      $input_params{$name} = [ $cgi->param($symbol) ];
 +                      $input_params{$name} = [ map { decode_utf8($_) } $cgi->param($symbol) ];
                } else {
 -                      $input_params{$name} = $cgi->param($symbol);
 +                      $input_params{$name} = decode_utf8($cgi->param($symbol));
                }
        }
  }
@@@ -977,7 -976,7 +977,7 @@@ sub evaluate_path_info 
  
  our ($action, $project, $file_name, $file_parent, $hash, $hash_parent, $hash_base,
       $hash_parent_base, @extra_options, $page, $searchtype, $search_use_regexp,
 -     $searchtext, $search_regexp);
 +     $searchtext, $search_regexp, $project_filter);
  sub evaluate_and_validate_params {
        our $action = $input_params{'action'};
        if (defined $action) {
                }
        }
  
 +      our $project_filter = $input_params{'project_filter'};
 +      if (defined $project_filter) {
 +              if (!validate_pathname($project_filter)) {
 +                      die_error(404, "Invalid project_filter parameter");
 +              }
 +      }
 +
        our $file_name = $input_params{'file_name'};
        if (defined $file_name) {
                if (!validate_pathname($file_name)) {
@@@ -1131,10 -1123,8 +1131,10 @@@ sub dispatch 
        if (!defined $action) {
                if (defined $hash) {
                        $action = git_get_type($hash);
 +                      $action or die_error(404, "Object does not exist");
                } elsif (defined $hash_base && defined $file_name) {
                        $action = git_get_type("$hash_base:$file_name");
 +                      $action or die_error(404, "File or directory does not exist");
                } elsif (defined $project) {
                        $action = 'summary';
                } else {
@@@ -2401,7 -2391,7 +2401,7 @@@ sub get_feed_info 
        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);
 +      return if (!$action || $action =~ /^(?:tags|heads|forks|tag|search)$/x);
  
        my $branch;
        # branches refs uses 'refs/heads/' prefix (fullname) to differentiate
@@@ -2775,7 -2765,7 +2775,7 @@@ sub git_populate_project_tagcloud 
        }
  
        my $cloud;
 -      my $matched = $cgi->param('by_tag');
 +      my $matched = $input_params{'ctag'};
        if (eval { require HTML::TagCloud; 1; }) {
                $cloud = HTML::TagCloud->new;
                foreach my $ctag (sort keys %ctags_lc) {
@@@ -2837,9 -2827,10 +2837,9 @@@ sub git_get_project_url_list 
  
  sub git_get_projects_list {
        my $filter = shift || '';
 +      my $paranoid = shift;
        my @list;
  
 -      $filter =~ s/\.git$//;
 -
        if (-d $projects_list) {
                # search in directory
                my $dir = $projects_list;
                my $pfxlen = length("$dir");
                my $pfxdepth = ($dir =~ tr!/!!);
                # when filtering, search only given subdirectory
 -              if ($filter) {
 +              if ($filter && !$paranoid) {
                        $dir .= "/$filter";
                        $dir =~ s!/+$!!;
                }
                                }
  
                                my $path = substr($File::Find::name, $pfxlen + 1);
 +                              # paranoidly only filter here
 +                              if ($paranoid && $filter && $path !~ m!^\Q$filter\E/!) {
 +                                      next;
 +                              }
                                # we check related file in $projectroot
                                if (check_export_ok("$projectroot/$path")) {
                                        push @list, { path => $path };
@@@ -3742,12 -3729,7 +3742,12 @@@ sub run_highlighter 
  sub get_page_title {
        my $title = to_utf8($site_name);
  
 -      return $title unless (defined $project);
 +      unless (defined $project) {
 +              if (defined $project_filter) {
 +                      $title .= " - projects in '" . esc_path($project_filter) . "'";
 +              }
 +              return $title;
 +      }
        $title .= " - " . to_utf8($project);
  
        return $title unless (defined $action);
@@@ -3841,27 -3823,12 +3841,27 @@@ sub print_header_links 
        }
  }
  
 +sub print_nav_breadcrumbs_path {
 +      my $dirprefix = undef;
 +      while (my $part = shift) {
 +              $dirprefix .= "/" if defined $dirprefix;
 +              $dirprefix .= $part;
 +              print $cgi->a({-href => href(project => undef,
 +                                           project_filter => $dirprefix,
 +                                           action => "project_list")},
 +                            esc_html($part)) . " / ";
 +      }
 +}
 +
  sub print_nav_breadcrumbs {
        my %opts = @_;
  
        print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
        if (defined $project) {
 -              print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
 +              my @dirname = split '/', $project;
 +              my $projectbasename = pop @dirname;
 +              print_nav_breadcrumbs_path(@dirname);
 +              print $cgi->a({-href => href(action=>"summary")}, esc_html($projectbasename));
                if (defined $action) {
                        my $action_print = $action ;
                        if (defined $opts{-action_extra}) {
                        print " / $opts{-action_extra}";
                }
                print "\n";
 +      } elsif (defined $project_filter) {
 +              print_nav_breadcrumbs_path(split '/', $project_filter);
        }
  }
  
@@@ -3906,7 -3871,7 +3906,7 @@@ sub print_search_form 
                               -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
              $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
              " search:\n",
 -            $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
 +            $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" .
              "<span title=\"Extended regular expression\">" .
              $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
                             -checked => $search_use_regexp) .
@@@ -3998,11 -3963,9 +3998,11 @@@ sub git_footer_html 
                }
  
        } else {
 -              print $cgi->a({-href => href(project=>undef, action=>"opml"),
 +              print $cgi->a({-href => href(project=>undef, action=>"opml",
 +                                           project_filter => $project_filter),
                              -class => $feed_class}, "OPML") . " ";
 -              print $cgi->a({-href => href(project=>undef, action=>"project_index"),
 +              print $cgi->a({-href => href(project=>undef, action=>"project_index",
 +                                           project_filter => $project_filter),
                              -class => $feed_class}, "TXT") . "\n";
        }
        print "</div>\n"; # class="page_footer"
@@@ -5160,34 -5123,6 +5160,34 @@@ sub git_patchset_body 
  
  # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  
 +sub git_project_search_form {
 +      my ($searchtext, $search_use_regexp);
 +
 +      my $limit = '';
 +      if ($project_filter) {
 +              $limit = " in '$project_filter/'";
 +      }
 +
 +      print "<div class=\"projsearch\">\n";
 +      print $cgi->startform(-method => 'get', -action => $my_uri) .
 +            $cgi->hidden(-name => 'a', -value => 'project_list')  . "\n";
 +      print $cgi->hidden(-name => 'pf', -value => $project_filter). "\n"
 +              if (defined $project_filter);
 +      print $cgi->textfield(-name => 's', -value => $searchtext,
 +                            -title => "Search project by name and description$limit",
 +                            -size => 60) . "\n" .
 +            "<span title=\"Extended regular expression\">" .
 +            $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
 +                           -checked => $search_use_regexp) .
 +            "</span>\n" .
 +            $cgi->submit(-name => 'btnS', -value => 'Search') .
 +            $cgi->end_form() . "\n" .
 +            $cgi->a({-href => href(project => undef, searchtext => undef,
 +                                   project_filter => $project_filter)},
 +                    esc_html("List all projects$limit")) . "<br />\n";
 +      print "</div>\n";
 +}
 +
  # fills project list info (age, description, owner, category, forks)
  # for each project in the list, removing invalid projects from
  # returned list
@@@ -5345,7 -5280,7 +5345,7 @@@ sub git_project_list_body 
  
        my $check_forks = gitweb_check_feature('forks');
        my $show_ctags  = gitweb_check_feature('ctags');
 -      my $tagfilter = $show_ctags ? $cgi->param('by_tag') : undef;
 +      my $tagfilter = $show_ctags ? $input_params{'ctag'} : undef;
        $check_forks = undef
                if ($tagfilter || $searchtext);
  
@@@ -5633,7 -5568,7 +5633,7 @@@ sub git_tags_body 
  
  sub git_heads_body {
        # uses global variable $project
-       my ($headlist, $head, $from, $to, $extra) = @_;
+       my ($headlist, $head_at, $from, $to, $extra) = @_;
        $from = 0 unless defined $from;
        $to = $#{$headlist} if (!defined $to || $#{$headlist} < $to);
  
        for (my $i = $from; $i <= $to; $i++) {
                my $entry = $headlist->[$i];
                my %ref = %$entry;
-               my $curr = $ref{'id'} eq $head;
+               my $curr = defined $head_at && $ref{'id'} eq $head_at;
                if ($alternate) {
                        print "<tr class=\"dark\">\n";
                } else {
@@@ -5915,10 -5850,9 +5915,10 @@@ sub git_search_files 
        my $alternate = 1;
        my $matches = 0;
        my $lastfile = '';
 +      my $file_href;
        while (my $line = <$fd>) {
                chomp $line;
 -              my ($file, $file_href, $lno, $ltext, $binary);
 +              my ($file, $lno, $ltext, $binary);
                last if ($matches++ > 1000);
                if ($line =~ /^Binary file (.+) matches$/) {
                        $file = $1;
@@@ -6045,7 -5979,7 +6045,7 @@@ sub git_project_list 
                die_error(400, "Unknown order parameter");
        }
  
 -      my @list = git_get_projects_list();
 +      my @list = git_get_projects_list($project_filter, $strict_export);
        if (!@list) {
                die_error(404, "No projects found");
        }
                insert_file($home_text);
                print "</div>\n";
        }
 -      print $cgi->startform(-method => "get") .
 -            "<p class=\"projsearch\">Search:\n" .
 -            $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
 -            "</p>" .
 -            $cgi->end_form() . "\n";
 +
 +      git_project_search_form($searchtext, $search_use_regexp);
        git_project_list_body(\@list, $order);
        git_footer_html();
  }
@@@ -6068,9 -6005,7 +6068,9 @@@ sub git_forks 
                die_error(400, "Unknown order parameter");
        }
  
 -      my @list = git_get_projects_list($project);
 +      my $filter = $project;
 +      $filter =~ s/\.git$//;
 +      my @list = git_get_projects_list($filter);
        if (!@list) {
                die_error(404, "No forks found");
        }
  }
  
  sub git_project_index {
 -      my @projects = git_get_projects_list();
 +      my @projects = git_get_projects_list($project_filter, $strict_export);
        if (!@projects) {
                die_error(404, "No projects found");
        }
@@@ -6129,9 -6064,7 +6129,9 @@@ sub git_summary 
  
        if ($check_forks) {
                # find forks of a project
 -              @forklist = git_get_projects_list($project);
 +              my $filter = $project;
 +              $filter =~ s/\.git$//;
 +              @forklist = git_get_projects_list($filter);
                # filter out forks of forks
                @forklist = filter_forks_from_projects_list(\@forklist)
                        if (@forklist);
@@@ -6262,7 -6195,7 +6262,7 @@@ sub git_tag 
  
  sub git_blame_common {
        my $format = shift || 'porcelain';
 -      if ($format eq 'porcelain' && $cgi->param('js')) {
 +      if ($format eq 'porcelain' && $input_params{'javascript'}) {
                $format = 'incremental';
                $action = 'blame_incremental'; # for page title etc
        }
@@@ -7922,7 -7855,7 +7922,7 @@@ sub git_atom 
  }
  
  sub git_opml {
 -      my @list = git_get_projects_list();
 +      my @list = git_get_projects_list($project_filter, $strict_export);
        if (!@list) {
                die_error(404, "No projects found");
        }
                -content_disposition => 'inline; filename="opml.xml"');
  
        my $title = esc_html($site_name);
 +      my $filter = " within subdirectory ";
 +      if (defined $project_filter) {
 +              $filter .= esc_html($project_filter);
 +      } else {
 +              $filter = "";
 +      }
        print <<XML;
  <?xml version="1.0" encoding="utf-8"?>
  <opml version="1.0">
  <head>
 -  <title>$title OPML Export</title>
 +  <title>$title OPML Export$filter</title>
  </head>
  <body>
  <outline text="git RSS feeds">
index 40a1cb571e4a6ac285398054962c139a316d4306,9d3ec16769829af061e0798d7f3c92f3fca2511e..90bb6050c13ece02199b6978e43e3c67de563c84
@@@ -474,14 -474,6 +474,14 @@@ test_expect_success 
        'path_info: project/branch:dir/' \
        'gitweb_run "" "/.git/master:foo/"'
  
 +test_expect_success \
 +      'path_info: project/branch (non-existent)' \
 +      'gitweb_run "" "/.git/non-existent"'
 +
 +test_expect_success \
 +      'path_info: project/branch:filename (non-existent branch)' \
 +      'gitweb_run "" "/.git/non-existent:non-existent"'
 +
  test_expect_success \
        'path_info: project/branch:file (non-existent)' \
        'gitweb_run "" "/.git/master:non-existent"'
@@@ -637,45 -629,6 +637,45 @@@ test_expect_success 
        'config override: tree view, features enabled in repo config (2)' \
        'gitweb_run "p=.git;a=tree"'
  
 +# ----------------------------------------------------------------------
 +# searching
 +
 +cat >>gitweb_config.perl <<\EOF
 +
 +# enable search
 +$feature{'search'}{'default'} = [1];
 +$feature{'grep'}{'default'} = [1];
 +$feature{'pickaxe'}{'default'} = [1];
 +EOF
 +
 +test_expect_success \
 +      'search: preparation' \
 +      'echo "1st MATCH" >>file &&
 +       echo "2nd MATCH" >>file &&
 +       echo "MATCH" >>bar &&
 +       git add file bar &&
 +       git commit -m "Added MATCH word"'
 +
 +test_expect_success \
 +      'search: commit author' \
 +      'gitweb_run "p=.git;a=search;h=HEAD;st=author;s=A+U+Thor"'
 +
 +test_expect_success \
 +      'search: commit message' \
 +      'gitweb_run "p=.git;a=search;h=HEAD;st=commitr;s=MATCH"'
 +
 +test_expect_success \
 +      'search: grep' \
 +      'gitweb_run "p=.git;a=search;h=HEAD;st=grep;s=MATCH"'
 +
 +test_expect_success \
 +      'search: pickaxe' \
 +      'gitweb_run "p=.git;a=search;h=HEAD;st=pickaxe;s=MATCH"'
 +
 +test_expect_success \
 +      'search: projects' \
 +      'gitweb_run "a=project_list;s=.git"'
 +
  # ----------------------------------------------------------------------
  # non-ASCII in README.html
  
@@@ -778,4 -731,13 +778,13 @@@ test_expect_success 
        'echo "\$projects_list_group_categories = 1;" >>gitweb_config.perl &&
         gitweb_run'
  
+ # ----------------------------------------------------------------------
+ # unborn branches
+ test_expect_success \
+       'unborn HEAD: "summary" page (with "heads" subview)' \
+       'git checkout orphan_branch || git checkout --orphan orphan_branch &&
+        test_when_finished "git checkout master" &&
+        gitweb_run "p=.git;a=summary"'
  test_done