@@ -2772,6 +2772,44 @@ sub git_get_last_activity {
27722772 return (undef , undef );
27732773}
27742774
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+
27752813sub git_get_references {
27762814 my $type = shift || " " ;
27772815 my %refs ;
@@ -5051,6 +5089,101 @@ sub git_heads_body {
50515089 print " </table>\n " ;
50525090}
50535091
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+
50545187sub git_search_grep_body {
50555188 my ($commitlist , $from , $to , $extra ) = @_ ;
50565189 $from = 0 unless defined $from ;
@@ -5197,7 +5330,7 @@ sub git_summary {
51975330 # there are more ...
51985331 my @taglist = git_get_tags_list(16);
51995332 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( ) : ();
52015334 my @forklist ;
52025335 my $check_forks = gitweb_check_feature(' forks' );
52035336
@@ -5275,11 +5408,9 @@ sub git_summary {
52755408 $cgi -> a({-href => href(action => " heads" )}, " ..." ));
52765409 }
52775410
5278- if (@remotelist ) {
5411+ if (%remotedata ) {
52795412 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 );
52835414 }
52845415
52855416 if (@forklist ) {
@@ -5596,39 +5727,34 @@ sub git_heads {
55965727 git_footer_html();
55975728}
55985729
5730+ # used both for single remote view and for list of all the remotes
55995731sub git_remotes {
56005732 gitweb_check_feature(' remote_heads' )
56015733 or die_error(403, " Remote heads view is disabled" );
56025734
56035735 my $head = git_get_head_hash($project );
56045736 my $remote = $input_params {' hash' };
56055737
5606- my @remotelist ;
5738+ my $remotedata = git_get_remotes_list($remote );
5739+ die_error(500, " Unable to get remote information" ) unless defined $remotedata ;
56075740
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" );
56185745 }
56195746
56205747 git_header_html(undef , undef , -action_extra => $remote );
56215748 git_print_page_nav(' ' , ' ' , $head , undef , $head ,
56225749 format_ref_views($remote ? ' ' : ' remotes' ));
56235750
5751+ fill_remote_heads($remotedata );
56245752 if (defined $remote ) {
56255753 git_print_header_div(' remotes' , " $remote remote for $project " );
5754+ git_remote_block($remote , $remotedata -> {$remote }, undef , $head );
56265755 } else {
56275756 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 );
56325758 }
56335759
56345760 git_footer_html();
0 commit comments