@@ -115,6 +115,14 @@ sub evaluate_uri {
115115# the width (in characters) of the projects list "Description" column
116116our $projects_list_description_width = 25;
117117
118+ # group projects by category on the projects list
119+ # (enabled if this variable evaluates to true)
120+ our $projects_list_group_categories = 0;
121+
122+ # default category if none specified
123+ # (leave the empty string for no category)
124+ our $project_list_default_category = " " ;
125+
118126# default order of projects list
119127# valid values are none, project, descr, owner, and age
120128our $default_projects_order = " project" ;
@@ -2574,20 +2582,34 @@ sub git_get_path_by_hash {
25742582# # ......................................................................
25752583# # git utility functions, directly accessing git repository
25762584
2577- sub git_get_project_description {
2578- my $path = shift ;
2585+ # get the value of config variable either from file named as the variable
2586+ # itself in the repository ($GIT_DIR/$name file), or from gitweb.$name
2587+ # configuration variable in the repository config file.
2588+ sub git_get_file_or_project_config {
2589+ my ($path , $name ) = @_ ;
25792590
25802591 $git_dir = " $projectroot /$path " ;
2581- open my $fd , ' <' , " $git_dir /description "
2582- or return git_get_project_config(' description ' );
2583- my $descr = <$fd >;
2592+ open my $fd , ' <' , " $git_dir /$name "
2593+ or return git_get_project_config($name );
2594+ my $conf = <$fd >;
25842595 close $fd ;
2585- if (defined $descr ) {
2586- chomp $descr ;
2596+ if (defined $conf ) {
2597+ chomp $conf ;
25872598 }
2588- return $descr ;
2599+ return $conf ;
2600+ }
2601+
2602+ sub git_get_project_description {
2603+ my $path = shift ;
2604+ return git_get_file_or_project_config($path , ' description' );
25892605}
25902606
2607+ sub git_get_project_category {
2608+ my $path = shift ;
2609+ return git_get_file_or_project_config($path , ' category' );
2610+ }
2611+
2612+
25912613# supported formats:
25922614# * $GIT_DIR/ctags/<tagname> file (in 'ctags' subdirectory)
25932615# - if its contents is a number, use it as tag weight,
@@ -4881,8 +4903,9 @@ sub git_patchset_body {
48814903
48824904# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48834905
4884- # fills project list info (age, description, owner, forks) for each
4885- # project in the list, removing invalid projects from returned list
4906+ # fills project list info (age, description, owner, category, forks)
4907+ # for each project in the list, removing invalid projects from
4908+ # returned list
48864909# NOTE: modifies $projlist, but does not remove entries from it
48874910sub fill_project_list_info {
48884911 my $projlist = shift ;
@@ -4908,6 +4931,12 @@ sub fill_project_list_info {
49084931 if ($show_ctags ) {
49094932 $pr -> {' ctags' } = git_get_project_ctags($pr -> {' path' });
49104933 }
4934+ if ($projects_list_group_categories && !defined $pr -> {' category' }) {
4935+ my $cat = git_get_project_category($pr -> {' path' }) ||
4936+ $project_list_default_category ;
4937+ $pr -> {' category' } = to_utf8($cat );
4938+ }
4939+
49114940 push @projects , $pr ;
49124941 }
49134942
@@ -4935,6 +4964,23 @@ sub sort_projects_list {
49354964 return @projects ;
49364965}
49374966
4967+ # returns a hash of categories, containing the list of project
4968+ # belonging to each category
4969+ sub build_projlist_by_category {
4970+ my ($projlist , $from , $to ) = @_ ;
4971+ my %categories ;
4972+
4973+ $from = 0 unless defined $from ;
4974+ $to = $# $projlist if (!defined $to || $# $projlist < $to );
4975+
4976+ for (my $i = $from ; $i <= $to ; $i ++) {
4977+ my $pr = $projlist -> [$i ];
4978+ push @{$categories { $pr -> {' category' } }}, $pr ;
4979+ }
4980+
4981+ return wantarray ? %categories : \%categories ;
4982+ }
4983+
49384984# print 'sort by' <th> element, generating 'sort by $name' replay link
49394985# if that order is not selected
49404986sub print_sort_th {
@@ -4958,6 +5004,55 @@ sub format_sort_th {
49585004 return $sort_th ;
49595005}
49605006
5007+ sub git_project_list_rows {
5008+ my ($projlist , $from , $to , $check_forks ) = @_ ;
5009+
5010+ $from = 0 unless defined $from ;
5011+ $to = $# $projlist if (!defined $to || $# $projlist < $to );
5012+
5013+ my $alternate = 1;
5014+ for (my $i = $from ; $i <= $to ; $i ++) {
5015+ my $pr = $projlist -> [$i ];
5016+
5017+ if ($alternate ) {
5018+ print " <tr class=\" dark\" >\n " ;
5019+ } else {
5020+ print " <tr class=\" light\" >\n " ;
5021+ }
5022+ $alternate ^= 1;
5023+
5024+ if ($check_forks ) {
5025+ print " <td>" ;
5026+ if ($pr -> {' forks' }) {
5027+ my $nforks = scalar @{$pr -> {' forks' }};
5028+ if ($nforks > 0) {
5029+ print $cgi -> a({-href => href(project => $pr -> {' path' }, action => " forks" ),
5030+ -title => " $nforks forks" }, " +" );
5031+ } else {
5032+ print $cgi -> span({-title => " $nforks forks" }, " +" );
5033+ }
5034+ }
5035+ print " </td>\n " ;
5036+ }
5037+ print " <td>" . $cgi -> a({-href => href(project => $pr -> {' path' }, action => " summary" ),
5038+ -class => " list" }, esc_html($pr -> {' path' })) . " </td>\n " .
5039+ " <td>" . $cgi -> a({-href => href(project => $pr -> {' path' }, action => " summary" ),
5040+ -class => " list" , -title => $pr -> {' descr_long' }},
5041+ esc_html($pr -> {' descr' })) . " </td>\n " .
5042+ " <td><i>" . chop_and_escape_str($pr -> {' owner' }, 15) . " </i></td>\n " ;
5043+ print " <td class=\" " . age_class($pr -> {' age' }) . " \" >" .
5044+ (defined $pr -> {' age_string' } ? $pr -> {' age_string' } : " No commits" ) . " </td>\n " .
5045+ " <td class=\" link\" >" .
5046+ $cgi -> a({-href => href(project => $pr -> {' path' }, action => " summary" )}, " summary" ) . " | " .
5047+ $cgi -> a({-href => href(project => $pr -> {' path' }, action => " shortlog" )}, " shortlog" ) . " | " .
5048+ $cgi -> a({-href => href(project => $pr -> {' path' }, action => " log" )}, " log" ) . " | " .
5049+ $cgi -> a({-href => href(project => $pr -> {' path' }, action => " tree" )}, " tree" ) .
5050+ ($pr -> {' forks' } ? " | " . $cgi -> a({-href => href(project => $pr -> {' path' }, action => " forks" )}, " forks" ) : ' ' ) .
5051+ " </td>\n " .
5052+ " </tr>\n " ;
5053+ }
5054+ }
5055+
49615056sub git_project_list_body {
49625057 # actually uses global variable $project
49635058 my ($projlist , $order , $from , $to , $extra , $no_header ) = @_ ;
@@ -5013,47 +5108,27 @@ sub git_project_list_body {
50135108 print " <th></th>\n " . # for links
50145109 " </tr>\n " ;
50155110 }
5016- my $alternate = 1;
5017- for (my $i = $from ; $i <= $to ; $i ++) {
5018- my $pr = $projects [$i ];
50195111
5020- if ($alternate ) {
5021- print " <tr class=\" dark\" >\n " ;
5022- } else {
5023- print " <tr class=\" light\" >\n " ;
5024- }
5025- $alternate ^= 1;
5026-
5027- if ($check_forks ) {
5028- print " <td>" ;
5029- if ($pr -> {' forks' }) {
5030- my $nforks = scalar @{$pr -> {' forks' }};
5031- if ($nforks > 0) {
5032- print $cgi -> a({-href => href(project => $pr -> {' path' }, action => " forks" ),
5033- -title => " $nforks forks" }, " +" );
5034- } else {
5035- print $cgi -> span({-title => " $nforks forks" }, " +" );
5112+ if ($projects_list_group_categories ) {
5113+ # only display categories with projects in the $from-$to window
5114+ @projects = sort {$a -> {' category' } cmp $b -> {' category' }} @projects [$from ..$to ];
5115+ my %categories = build_projlist_by_category(\@projects , $from , $to );
5116+ foreach my $cat (sort keys %categories ) {
5117+ unless ($cat eq " " ) {
5118+ print " <tr>\n " ;
5119+ if ($check_forks ) {
5120+ print " <td></td>\n " ;
50365121 }
5122+ print " <td class=\" category\" colspan=\" 5\" >" .esc_html($cat )." </td>\n " ;
5123+ print " </tr>\n " ;
50375124 }
5038- print " </td>\n " ;
5125+
5126+ git_project_list_rows($categories {$cat }, undef , undef , $check_forks );
50395127 }
5040- print " <td>" . $cgi -> a({-href => href(project => $pr -> {' path' }, action => " summary" ),
5041- -class => " list" }, esc_html($pr -> {' path' })) . " </td>\n " .
5042- " <td>" . $cgi -> a({-href => href(project => $pr -> {' path' }, action => " summary" ),
5043- -class => " list" , -title => $pr -> {' descr_long' }},
5044- esc_html($pr -> {' descr' })) . " </td>\n " .
5045- " <td><i>" . chop_and_escape_str($pr -> {' owner' }, 15) . " </i></td>\n " ;
5046- print " <td class=\" " . age_class($pr -> {' age' }) . " \" >" .
5047- (defined $pr -> {' age_string' } ? $pr -> {' age_string' } : " No commits" ) . " </td>\n " .
5048- " <td class=\" link\" >" .
5049- $cgi -> a({-href => href(project => $pr -> {' path' }, action => " summary" )}, " summary" ) . " | " .
5050- $cgi -> a({-href => href(project => $pr -> {' path' }, action => " shortlog" )}, " shortlog" ) . " | " .
5051- $cgi -> a({-href => href(project => $pr -> {' path' }, action => " log" )}, " log" ) . " | " .
5052- $cgi -> a({-href => href(project => $pr -> {' path' }, action => " tree" )}, " tree" ) .
5053- ($pr -> {' forks' } ? " | " . $cgi -> a({-href => href(project => $pr -> {' path' }, action => " forks" )}, " forks" ) : ' ' ) .
5054- " </td>\n " .
5055- " </tr>\n " ;
5128+ } else {
5129+ git_project_list_rows(\@projects , $from , $to , $check_forks );
50565130 }
5131+
50575132 if (defined $extra ) {
50585133 print " <tr>\n " ;
50595134 if ($check_forks ) {
0 commit comments