gitweb: group remote heads by remote
In remote and summary view, display a block for each remote, with the fetch and push URL(s) as well as the list of the remote heads. In summary view, if the number of remotes is higher than a prescribed limit, only display the first <limit> remotes and their fetch and push urls, without any heads information and without grouping. Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com> Acked-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Giuseppe Bilotta committed
Nov 11, 2010 at 13:26 UTC
9d0d42f3450fe34737f92b9bde31ac1cf6deeadb
2 files changed
+152
-20
gitweb/gitweb.perl
+146
-20
@@ -2772,6 +2772,44 @@ sub git_get_last_activity {
2772
return (undef, undef);
2773
}
2774
2775
+# Implementation note: when a single remote is wanted, we cannot use 'git
2776
+# remote show -n' because that command always work (assuming it's a remote URL
2777
+# if it's not defined), and we cannot use 'git remote show' because that would
2778
+# try to make a network roundtrip. So the only way to find if that particular
2779
+# remote is defined is to walk the list provided by 'git remote -v' and stop if
2780
+# and when we find what we want.
2781
+sub git_get_remotes_list {
2782
+ my $wanted = shift;
2783
+ my %remotes = ();
2784
+
2785
+ open my $fd, '-|' , git_cmd(), 'remote', '-v';
2786
+ return unless $fd;
2787
+ while (my $remote = <$fd>) {
2788
+ chomp $remote;
2789
+ $remote =~ s!\t(.*?)\s+\((\w+)\)$!!;
2790
+ next if $wanted and not $remote eq $wanted;
2791
+ my ($url, $key) = ($1, $2);
2792
+
2793
+ $remotes{$remote} ||= { 'heads' => () };
2794
+ $remotes{$remote}{$key} = $url;
2795
+ }
2796
+ close $fd or return;
2797
+ return wantarray ? %remotes : \%remotes;
2798
+}
2799
+
2800
+# Takes a hash of remotes as first parameter and fills it by adding the
2801
+# available remote heads for each of the indicated remotes.
2802
+sub fill_remote_heads {
2803
+ my $remotes = shift;
2804
+ my @heads = map { "remotes/$_" } keys %$remotes;
2805
+ my @remoteheads = git_get_heads_list(undef, @heads);
2806
+ foreach my $remote (keys %$remotes) {
2807
+ $remotes->{$remote}{'heads'} = [ grep {
2808
+ $_->{'name'} =~ s!^$remote/!!
2809
+ } @remoteheads ];
2810
+ }
2811
+}
2812
+
2813
sub git_get_references {
2814
my $type = shift || "";
2815
my %refs;
@@ -5051,6 +5089,101 @@ sub git_heads_body {
5089
print "</table>\n";
5090
}
5091
5092
+# Display a single remote block
5093
+sub git_remote_block {
5094
+ my ($remote, $rdata, $limit, $head) = @_;
5095
+
5096
+ my $heads = $rdata->{'heads'};
5097
+ my $fetch = $rdata->{'fetch'};
5098
+ my $push = $rdata->{'push'};
5099
+
5100
+ my $urls_table = "<table class=\"projects_list\">\n" ;
5101
+
5102
+ if (defined $fetch) {
5103
+ if ($fetch eq $push) {
5104
+ $urls_table .= format_repo_url("URL", $fetch);
5105
+ } else {
5106
+ $urls_table .= format_repo_url("Fetch URL", $fetch);
5107
+ $urls_table .= format_repo_url("Push URL", $push) if defined $push;
5108
+ }
5109
+ } elsif (defined $push) {
5110
+ $urls_table .= format_repo_url("Push URL", $push);
5111
+ } else {
5112
+ $urls_table .= format_repo_url("", "No remote URL");
5113
+ }
5114
+
5115
+ $urls_table .= "</table>\n";
5116
+
5117
+ my $dots;
5118
+ if (defined $limit && $limit < @$heads) {
5119
+ $dots = $cgi->a({-href => href(action=>"remotes", hash=>$remote)}, "...");
5120
+ }
5121
+
5122
+ print $urls_table;
5123
+ git_heads_body($heads, $head, 0, $limit, $dots);
5124
+}
5125
+
5126
+# Display a list of remote names with the respective fetch and push URLs
5127
+sub git_remotes_list {
5128
+ my ($remotedata, $limit) = @_;
5129
+ print "<table class=\"heads\">\n";
5130
+ my $alternate = 1;
5131
+ my @remotes = sort keys %$remotedata;
5132
+
5133
+ my $limited = $limit && $limit < @remotes;
5134
+
5135
+ $#remotes = $limit - 1 if $limited;
5136
+
5137
+ while (my $remote = shift @remotes) {
5138
+ my $rdata = $remotedata->{$remote};
5139
+ my $fetch = $rdata->{'fetch'};
5140
+ my $push = $rdata->{'push'};
5141
+ if ($alternate) {
5142
+ print "<tr class=\"dark\">\n";
5143
+ } else {
5144
+ print "<tr class=\"light\">\n";
5145
+ }
5146
+ $alternate ^= 1;
5147
+ print "<td>" .
5148
+ $cgi->a({-href=> href(action=>'remotes', hash=>$remote),
5149
+ -class=> "list name"},esc_html($remote)) .
5150
+ "</td>";
5151
+ print "<td class=\"link\">" .
5152
+ (defined $fetch ? $cgi->a({-href=> $fetch}, "fetch") : "fetch") .
5153
+ " | " .
5154
+ (defined $push ? $cgi->a({-href=> $push}, "push") : "push") .
5155
+ "</td>";
5156
+
5157
+ print "</tr>\n";
5158
+ }
5159
+
5160
+ if ($limited) {
5161
+ print "<tr>\n" .
5162
+ "<td colspan=\"3\">" .
5163
+ $cgi->a({-href => href(action=>"remotes")}, "...") .
5164
+ "</td>\n" . "</tr>\n";
5165
+ }
5166
+
5167
+ print "</table>";
5168
+}
5169
+
5170
+# Display remote heads grouped by remote, unless there are too many
5171
+# remotes, in which case we only display the remote names
5172
+sub git_remotes_body {
5173
+ my ($remotedata, $limit, $head) = @_;
5174
+ if ($limit and $limit < keys %$remotedata) {
5175
+ git_remotes_list($remotedata, $limit);
5176
+ } else {
5177
+ fill_remote_heads($remotedata);
5178
+ while (my ($remote, $rdata) = each %$remotedata) {
5179
+ git_print_section({-class=>"remote", -id=>$remote},
5180
+ ["remotes", $remote, $remote], sub {
5181
+ git_remote_block($remote, $rdata, $limit, $head);
5182
+ });
5183
+ }
5184
+ }
5185
+}
5186
+
5187
sub git_search_grep_body {
5188
my ($commitlist, $from, $to, $extra) = @_;
5189
$from = 0 unless defined $from;
@@ -5197,7 +5330,7 @@ sub git_summary {
5330
# there are more ...
5331
my @taglist = git_get_tags_list(16);
5332
my @headlist = git_get_heads_list(16);
5200
- my @remotelist = $remote_heads ? git_get_heads_list(16, 'remotes') : ();
5333
+ my %remotedata = $remote_heads ? git_get_remotes_list() : ();
5334
my @forklist;
5335
my $check_forks = gitweb_check_feature('forks');
5336
@@ -5275,11 +5408,9 @@ sub git_summary {
5408
$cgi->a({-href => href(action=>"heads")}, "..."));
5409
}
5410
5278
- if (@remotelist) {
5411
+ if (%remotedata) {
5412
git_print_header_div('remotes');
5280
- git_heads_body(\@remotelist, $head, 0, 15,
5281
- $#remotelist <= 15 ? undef :
5282
- $cgi->a({-href => href(action=>"remotes")}, "..."));
5413
+ git_remotes_body(\%remotedata, 15, $head);
5414
}
5415
5416
if (@forklist) {
@@ -5596,6 +5727,7 @@ sub git_heads {
5727
git_footer_html();
5728
}
5729
5730
+# used both for single remote view and for list of all the remotes
5731
sub git_remotes {
5732
gitweb_check_feature('remote_heads')
5733
or die_error(403, "Remote heads view is disabled");
@@ -5603,32 +5735,26 @@ sub git_remotes {
5735
my $head = git_get_head_hash($project);
5736
my $remote = $input_params{'hash'};
5737
5606
- my @remotelist;
5738
+ my $remotedata = git_get_remotes_list($remote);
5739
+ die_error(500, "Unable to get remote information") unless defined $remotedata;
5740
5608
- if (defined $remote) {
5609
- # only display the heads in a given remote, stripping the
5610
- # remote name which is already visible elsewhere
5611
- @remotelist = map {
5612
- my $ref = $_ ;
5613
- $ref->{'name'} =~ s!^$remote/!!;
5614
- $ref
5615
- } git_get_heads_list(undef, "remotes/$remote");
5616
- } else {
5617
- @remotelist = git_get_heads_list(undef, 'remotes');
5741
+ unless (%$remotedata) {
5742
+ die_error(404, defined $remote ?
5743
+ "Remote $remote not found" :
5744
+ "No remotes found");
5745
}
5746
5747
git_header_html(undef, undef, -action_extra => $remote);
5748
git_print_page_nav('', '', $head, undef, $head,
5749
format_ref_views($remote ? '' : 'remotes'));
5750
5751
+ fill_remote_heads($remotedata);
5752
if (defined $remote) {
5753
git_print_header_div('remotes', "$remote remote for $project");
5754
+ git_remote_block($remote, $remotedata->{$remote}, undef, $head);
5755
} else {
5756
git_print_header_div('summary', "$project remotes");
5628
- }
5629
-
5630
- if (@remotelist) {
5631
- git_heads_body(\@remotelist, $head);
5757
+ git_remotes_body($remotedata, undef, $head);
5758
}
5759
5760
git_footer_html();
gitweb/static/gitweb.css
+6
@@ -573,6 +573,12 @@ div.binary {
573
font-style: italic;
574
}
575
576
+div.remote {
577
+ margin: .5em;
578
+ border: 1px solid #d9d8d1;
579
+ display: inline-block;
580
+}
581
+
582
/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */
583
584
/* Highlighting theme definition: */