Merge branch 'jn/ctags-more'
authorJunio C Hamano <gitster@pobox.com>
Thu, 26 May 2011 17:31:53 +0000 (10:31 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 26 May 2011 17:31:53 +0000 (10:31 -0700)
* jn/ctags-more:
gitweb: Optional grouping of projects by category
gitweb: Modularized git_get_project_description to be more generic
gitweb: Split git_project_list_body in two functions

1  2 
gitweb/gitweb.perl
diff --combined gitweb/gitweb.perl
index dfac1bce848f5603ead20f8d587c7d5d3e182793,f78fdd7c5f1961c6a05ff10a91aba05f88e8104c..02d8839b9c64d65db6c3713555a317c119bac9f4
@@@ -115,6 -115,14 +115,14 @@@ our $projects_list = "++GITWEB_LIST++"
  # the width (in characters) of the projects list "Description" column
  our $projects_list_description_width = 25;
  
+ # group projects by category on the projects list
+ # (enabled if this variable evaluates to true)
+ our $projects_list_group_categories = 0;
+ # default category if none specified
+ # (leave the empty string for no category)
+ our $project_list_default_category = "";
  # default order of projects list
  # valid values are none, project, descr, owner, and age
  our $default_projects_order = "project";
@@@ -186,7 -194,7 +194,7 @@@ our %known_snapshot_formats = 
                'type' => 'application/x-gzip',
                'suffix' => '.tar.gz',
                'format' => 'tar',
 -              'compressor' => ['gzip']},
 +              'compressor' => ['gzip', '-n']},
  
        'tbz2' => {
                'display' => 'tar.bz2',
@@@ -623,30 -631,18 +631,30 @@@ sub filter_snapshot_fmts 
  # if it is true then gitweb config would be run for each request.
  our $per_request_config = 1;
  
 +# read and parse gitweb config file given by its parameter.
 +# returns true on success, false on recoverable error, allowing
 +# to chain this subroutine, using first file that exists.
 +# dies on errors during parsing config file, as it is unrecoverable.
 +sub read_config_file {
 +      my $filename = shift;
 +      return unless defined $filename;
 +      # die if there are errors parsing config file
 +      if (-e $filename) {
 +              do $filename;
 +              die $@ if $@;
 +              return 1;
 +      }
 +      return;
 +}
 +
  our ($GITWEB_CONFIG, $GITWEB_CONFIG_SYSTEM);
  sub evaluate_gitweb_config {
        our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
        our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
 -      # die if there are errors parsing config file
 -      if (-e $GITWEB_CONFIG) {
 -              do $GITWEB_CONFIG;
 -              die $@ if $@;
 -      } elsif (-e $GITWEB_CONFIG_SYSTEM) {
 -              do $GITWEB_CONFIG_SYSTEM;
 -              die $@ if $@;
 -      }
 +
 +      # use first config file that exists
 +      read_config_file($GITWEB_CONFIG) or
 +      read_config_file($GITWEB_CONFIG_SYSTEM);
  }
  
  # Get loadavg of system, to compare against $maxload.
@@@ -2574,20 -2570,34 +2582,34 @@@ sub git_get_path_by_hash 
  ## ......................................................................
  ## git utility functions, directly accessing git repository
  
- sub git_get_project_description {
-       my $path = shift;
+ # get the value of config variable either from file named as the variable
+ # itself in the repository ($GIT_DIR/$name file), or from gitweb.$name
+ # configuration variable in the repository config file.
+ sub git_get_file_or_project_config {
+       my ($path, $name) = @_;
  
        $git_dir = "$projectroot/$path";
-       open my $fd, '<', "$git_dir/description"
-               or return git_get_project_config('description');
-       my $descr = <$fd>;
+       open my $fd, '<', "$git_dir/$name"
+               or return git_get_project_config($name);
+       my $conf = <$fd>;
        close $fd;
-       if (defined $descr) {
-               chomp $descr;
+       if (defined $conf) {
+               chomp $conf;
        }
-       return $descr;
+       return $conf;
+ }
+ sub git_get_project_description {
+       my $path = shift;
+       return git_get_file_or_project_config($path, 'description');
+ }
+ sub git_get_project_category {
+       my $path = shift;
+       return git_get_file_or_project_config($path, 'category');
  }
  
  # supported formats:
  # * $GIT_DIR/ctags/<tagname> file (in 'ctags' subdirectory)
  #   - if its contents is a number, use it as tag weight,
@@@ -4881,8 -4891,9 +4903,9 @@@ sub git_patchset_body 
  
  # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  
- # fills project list info (age, description, owner, forks) for each
- # project in the list, removing invalid projects from returned list
+ # fills project list info (age, description, owner, category, forks)
+ # for each project in the list, removing invalid projects from
+ # returned list
  # NOTE: modifies $projlist, but does not remove entries from it
  sub fill_project_list_info {
        my $projlist = shift;
                if ($show_ctags) {
                        $pr->{'ctags'} = git_get_project_ctags($pr->{'path'});
                }
+               if ($projects_list_group_categories && !defined $pr->{'category'}) {
+                       my $cat = git_get_project_category($pr->{'path'}) ||
+                                                          $project_list_default_category;
+                       $pr->{'category'} = to_utf8($cat);
+               }
                push @projects, $pr;
        }
  
@@@ -4935,6 -4952,23 +4964,23 @@@ sub sort_projects_list 
        return @projects;
  }
  
+ # returns a hash of categories, containing the list of project
+ # belonging to each category
+ sub build_projlist_by_category {
+       my ($projlist, $from, $to) = @_;
+       my %categories;
+       $from = 0 unless defined $from;
+       $to = $#$projlist if (!defined $to || $#$projlist < $to);
+       for (my $i = $from; $i <= $to; $i++) {
+               my $pr = $projlist->[$i];
+               push @{$categories{ $pr->{'category'} }}, $pr;
+       }
+       return wantarray ? %categories : \%categories;
+ }
  # print 'sort by' <th> element, generating 'sort by $name' replay link
  # if that order is not selected
  sub print_sort_th {
@@@ -4958,6 -4992,55 +5004,55 @@@ sub format_sort_th 
        return $sort_th;
  }
  
+ sub git_project_list_rows {
+       my ($projlist, $from, $to, $check_forks) = @_;
+       $from = 0 unless defined $from;
+       $to = $#$projlist if (!defined $to || $#$projlist < $to);
+       my $alternate = 1;
+       for (my $i = $from; $i <= $to; $i++) {
+               my $pr = $projlist->[$i];
+               if ($alternate) {
+                       print "<tr class=\"dark\">\n";
+               } else {
+                       print "<tr class=\"light\">\n";
+               }
+               $alternate ^= 1;
+               if ($check_forks) {
+                       print "<td>";
+                       if ($pr->{'forks'}) {
+                               my $nforks = scalar @{$pr->{'forks'}};
+                               if ($nforks > 0) {
+                                       print $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks"),
+                                                      -title => "$nforks forks"}, "+");
+                               } else {
+                                       print $cgi->span({-title => "$nforks forks"}, "+");
+                               }
+                       }
+                       print "</td>\n";
+               }
+               print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
+                                       -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
+                     "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
+                                       -class => "list", -title => $pr->{'descr_long'}},
+                                       esc_html($pr->{'descr'})) . "</td>\n" .
+                     "<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n";
+               print "<td class=\"". age_class($pr->{'age'}) . "\">" .
+                     (defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</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") . " | " .
+                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " .
+                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") .
+                     ($pr->{'forks'} ? " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "forks") : '') .
+                     "</td>\n" .
+                     "</tr>\n";
+       }
+ }
  sub git_project_list_body {
        # actually uses global variable $project
        my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
                print "<th></th>\n" . # for links
                      "</tr>\n";
        }
-       my $alternate = 1;
-       for (my $i = $from; $i <= $to; $i++) {
-               my $pr = $projects[$i];
  
-               if ($alternate) {
-                       print "<tr class=\"dark\">\n";
-               } else {
-                       print "<tr class=\"light\">\n";
-               }
-               $alternate ^= 1;
-               if ($check_forks) {
-                       print "<td>";
-                       if ($pr->{'forks'}) {
-                               my $nforks = scalar @{$pr->{'forks'}};
-                               if ($nforks > 0) {
-                                       print $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks"),
-                                                      -title => "$nforks forks"}, "+");
-                               } else {
-                                       print $cgi->span({-title => "$nforks forks"}, "+");
+       if ($projects_list_group_categories) {
+               # only display categories with projects in the $from-$to window
+               @projects = sort {$a->{'category'} cmp $b->{'category'}} @projects[$from..$to];
+               my %categories = build_projlist_by_category(\@projects, $from, $to);
+               foreach my $cat (sort keys %categories) {
+                       unless ($cat eq "") {
+                               print "<tr>\n";
+                               if ($check_forks) {
+                                       print "<td></td>\n";
                                }
+                               print "<td class=\"category\" colspan=\"5\">".esc_html($cat)."</td>\n";
+                               print "</tr>\n";
                        }
-                       print "</td>\n";
+                       git_project_list_rows($categories{$cat}, undef, undef, $check_forks);
                }
-               print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
-                                       -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
-                     "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
-                                       -class => "list", -title => $pr->{'descr_long'}},
-                                       esc_html($pr->{'descr'})) . "</td>\n" .
-                     "<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n";
-               print "<td class=\"". age_class($pr->{'age'}) . "\">" .
-                     (defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</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") . " | " .
-                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " .
-                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") .
-                     ($pr->{'forks'} ? " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "forks") : '') .
-                     "</td>\n" .
-                     "</tr>\n";
+       } else {
+               git_project_list_rows(\@projects, $from, $to, $check_forks);
        }
        if (defined $extra) {
                print "<tr>\n";
                if ($check_forks) {