Skip to content

Commit 229e72d

Browse files
committed
Merge branch 'jn/ctags-more'
* 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
2 parents 0a2a5d8 + d940c90 commit 229e72d

File tree

4 files changed

+152
-46
lines changed

4 files changed

+152
-46
lines changed

gitweb/README

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,15 @@ not include variables usually directly set during build):
207207
full description is available as 'title' attribute (usually shown on
208208
mouseover). By default set to 25, which might be too small if you
209209
use long project descriptions.
210+
* $projects_list_group_categories
211+
Enables the grouping of projects by category on the project list page.
212+
The category of a project is determined by the $GIT_DIR/category
213+
file or the 'gitweb.category' variable in its repository configuration.
214+
Disabled by default.
215+
* $project_list_default_category
216+
Default category for projects for which none is specified. If set
217+
to the empty string, such projects will remain uncategorized and
218+
listed at the top, above categorized projects.
210219
* @git_base_url_list
211220
List of git base URLs used for URL to where fetch project from, shown
212221
in project summary page. Full URL is "$git_base_url/$project".
@@ -314,6 +323,13 @@ You can use the following files in repository:
314323
from the template during repository creation. You can use the
315324
gitweb.description repo configuration variable, but the file takes
316325
precedence.
326+
* category (or gitweb.category)
327+
Singe line category of a project, used to group projects if
328+
$projects_list_group_categories is enabled. By default (file and
329+
configuration variable absent), uncategorized projects are put in
330+
the $project_list_default_category category. You can use the
331+
gitweb.category repo configuration variable, but the file takes
332+
precedence.
317333
* cloneurl (or multiple-valued gitweb.url)
318334
File with repository URL (used for clone and fetch), one per line.
319335
Displayed in the project summary page. You can use multiple-valued

gitweb/gitweb.perl

Lines changed: 121 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,14 @@ sub evaluate_uri {
115115
# the width (in characters) of the projects list "Description" column
116116
our $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
120128
our $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
48874910
sub 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
49404986
sub 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+
49615056
sub 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) {

gitweb/static/gitweb.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,13 @@ td.current_head {
295295
text-decoration: underline;
296296
}
297297

298+
td.category {
299+
background-color: #d9d8d1;
300+
border-top: 1px solid #000000;
301+
border-left: 1px solid #000000;
302+
font-weight: bold;
303+
}
304+
298305
table.diff_tree span.file_status.new {
299306
color: #008000;
300307
}

t/t9500-gitweb-standalone-no-errors.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,4 +644,12 @@ test_expect_success \
644644
'ctags: search projects by non existent tag' \
645645
'gitweb_run "by_tag=non-existent"'
646646

647+
# ----------------------------------------------------------------------
648+
# categories
649+
650+
test_expect_success \
651+
'categories: projects list, only default category' \
652+
'echo "\$projects_list_group_categories = 1;" >>gitweb_config.perl &&
653+
gitweb_run'
654+
647655
test_done

0 commit comments

Comments
 (0)