gitweb: Add a feature for adding more branch refs

Allow extra-branch-refs feature to tell gitweb to show refs from additional hierarchies in addition to branches in the list-of-branches view. Signed-off-by: Krzesimir Nowak <krzesimir@endocode.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Krzesimir Nowak committed Dec 11, 2013 at 12:54 UTC 8d646a9bac7d64c38060e0c252fd87eba6c4d5cf
2 files changed +105 -12
Documentation/gitweb.conf.txt
+37
@@ -849,6 +849,43 @@ time zones in the form of "+/-HHMM", such as "+0200".
849 +
850 Project specific override is not supported.
851
852 +extra-branch-refs::
853 + List of additional directories under "refs" which are going to
854 + be used as branch refs. For example if you have a gerrit setup
855 + where all branches under refs/heads/ are official,
856 + push-after-review ones and branches under refs/sandbox/,
857 + refs/wip and refs/other are user ones where permissions are
858 + much wider, then you might want to set this variable as
859 + follows:
860 ++
861 +--------------------------------------------------------------------------------
862 +$feature{'extra-branch-refs'}{'default'} =
863 + ['sandbox', 'wip', 'other'];
864 +--------------------------------------------------------------------------------
865 ++
866 +This feature can be configured on per-repository basis after setting
867 +$feature{'extra-branch-refs'}{'override'} to true, via repository's
868 +`gitweb.extraBranchRefs` configuration variable, which contains a
869 +space separated list of refs. An example:
870 ++
871 +--------------------------------------------------------------------------------
872 +[gitweb]
873 + extraBranchRefs = sandbox wip other
874 +--------------------------------------------------------------------------------
875 ++
876 +The gitweb.extraBranchRefs is actually a multi-valued configuration
877 +variable, so following example is also correct and the result is the
878 +same as of the snippet above:
879 ++
880 +--------------------------------------------------------------------------------
881 +[gitweb]
882 + extraBranchRefs = sandbox
883 + extraBranchRefs = wip other
884 +--------------------------------------------------------------------------------
885 ++
886 +It is an error to specify a ref that does not pass "git check-ref-format"
887 +scrutiny. Duplicated values are filtered.
888 +
889
890 EXAMPLES
891 --------
gitweb/gitweb.perl
+68 -12
@@ -548,6 +548,20 @@ our %feature = (
548 'sub' => sub { feature_bool('remote_heads', @_) },
549 'override' => 0,
550 'default' => [0]},
551 +
552 + # Enable showing branches under other refs in addition to heads
553 +
554 + # To set system wide extra branch refs have in $GITWEB_CONFIG
555 + # $feature{'extra-branch-refs'}{'default'} = ['dirs', 'of', 'choice'];
556 + # To have project specific config enable override in $GITWEB_CONFIG
557 + # $feature{'extra-branch-refs'}{'override'} = 1;
558 + # and in project config gitweb.extrabranchrefs = dirs of choice
559 + # Every directory is separated with whitespace.
560 +
561 + 'extra-branch-refs' => {
562 + 'sub' => \&feature_extra_branch_refs,
563 + 'override' => 0,
564 + 'default' => []},
565 );
566
567 sub gitweb_get_feature {
@@ -626,6 +640,21 @@ sub feature_avatar {
640 return @val ? @val : @_;
641 }
642
643 +sub feature_extra_branch_refs {
644 + my (@branch_refs) = @_;
645 + my $values = git_get_project_config('extrabranchrefs');
646 +
647 + if ($values) {
648 + $values = config_to_multi ($values);
649 + @branch_refs = ();
650 + foreach my $value (@{$values}) {
651 + push @branch_refs, split /\s+/, $value;
652 + }
653 + }
654 +
655 + return @branch_refs;
656 +}
657 +
658 # checking HEAD file with -e is fragile if the repository was
659 # initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed
660 # and then pruned.
@@ -656,6 +685,18 @@ sub filter_snapshot_fmts {
685 !$known_snapshot_formats{$_}{'disabled'}} @fmts;
686 }
687
688 +sub filter_and_validate_refs {
689 + my @refs = @_;
690 + my %unique_refs = ();
691 +
692 + foreach my $ref (@refs) {
693 + die_error(500, "Invalid ref '$ref' in 'extra-branch-refs' feature") unless (is_valid_ref_format($ref));
694 + # 'heads' are added implicitly in get_branch_refs().
695 + $unique_refs{$ref} = 1 if ($ref ne 'heads');
696 + }
697 + return sort keys %unique_refs;
698 +}
699 +
700 # If it is set to code reference, it is code that it is to be run once per
701 # request, allowing updating configurations that change with each request,
702 # while running other code in config file only once.
@@ -1113,7 +1154,7 @@ sub evaluate_git_dir {
1154 our $git_dir = "$projectroot/$project" if $project;
1155 }
1156
1116 -our (@snapshot_fmts, $git_avatar);
1157 +our (@snapshot_fmts, $git_avatar, @extra_branch_refs);
1158 sub configure_gitweb_features {
1159 # list of supported snapshot formats
1160 our @snapshot_fmts = gitweb_get_feature('snapshot');
@@ -1131,6 +1172,13 @@ sub configure_gitweb_features {
1172 } else {
1173 $git_avatar = '';
1174 }
1175 +
1176 + our @extra_branch_refs = gitweb_get_feature('extra-branch-refs');
1177 + @extra_branch_refs = filter_and_validate_refs (@extra_branch_refs);
1178 +}
1179 +
1180 +sub get_branch_refs {
1181 + return ('heads', @extra_branch_refs);
1182 }
1183
1184 # custom error handler: 'die <message>' is Internal Server Error
@@ -2527,6 +2575,7 @@ sub format_snapshot_links {
2575 sub get_feed_info {
2576 my $format = shift || 'Atom';
2577 my %res = (action => lc($format));
2578 + my $matched_ref = 0;
2579
2580 # feed links are possible only for project views
2581 return unless (defined $project);
@@ -2534,12 +2583,17 @@ sub get_feed_info {
2583 # or don't have specific feed yet (so they should use generic)
2584 return if (!$action || $action =~ /^(?:tags|heads|forks|tag|search)$/x);
2585
2537 - my $branch;
2538 - # branches refs uses 'refs/heads/' prefix (fullname) to differentiate
2539 - # from tag links; this also makes possible to detect branch links
2540 - if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) ||
2541 - (defined $hash && $hash =~ m!^refs/heads/(.*)$!)) {
2542 - $branch = $1;
2586 + my $branch = undef;
2587 + # branches refs uses 'refs/' + $get_branch_refs()[x] + '/' prefix
2588 + # (fullname) to differentiate from tag links; this also makes
2589 + # possible to detect branch links
2590 + for my $ref (get_branch_refs()) {
2591 + if ((defined $hash_base && $hash_base =~ m!^refs/\Q$ref\E/(.*)$!) ||
2592 + (defined $hash && $hash =~ m!^refs/\Q$ref\E/(.*)$!)) {
2593 + $branch = $1;
2594 + $matched_ref = $ref;
2595 + last;
2596 + }
2597 }
2598 # find log type for feed description (title)
2599 my $type = 'log';
@@ -2552,7 +2606,7 @@ sub get_feed_info {
2606 }
2607
2608 $res{-title} = $type;
2555 - $res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef);
2609 + $res{'hash'} = (defined $branch ? "refs/$matched_ref/$branch" : undef);
2610 $res{'file_name'} = $file_name;
2611
2612 return %res;
@@ -3205,7 +3259,7 @@ sub git_get_last_activity {
3259 '--format=%(committer)',
3260 '--sort=-committerdate',
3261 '--count=1',
3208 - 'refs/heads') or return;
3262 + map { "refs/$_" } get_branch_refs ()) or return;
3263 my $most_recent = <$fd>;
3264 close $fd or return;
3265 if (defined $most_recent &&
@@ -3656,7 +3710,7 @@ sub parse_from_to_diffinfo {
3710
3711 sub git_get_heads_list {
3712 my ($limit, @classes) = @_;
3659 - @classes = ('heads') unless @classes;
3713 + @classes = get_branch_refs() unless @classes;
3714 my @patterns = map { "refs/$_" } @classes;
3715 my @headslist;
3716
@@ -3674,7 +3728,8 @@ sub git_get_heads_list {
3728 my ($committer, $epoch, $tz) =
3729 ($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);
3730 $ref_item{'fullname'} = $name;
3677 - $name =~ s!^refs/(?:head|remote)s/!!;
3731 + my $strip_refs = join '|', map { quotemeta } get_branch_refs();
3732 + $name =~ s!^refs/($strip_refs|remotes)/!!;
3733
3734 $ref_item{'name'} = $name;
3735 $ref_item{'id'} = $hash;
@@ -7191,7 +7246,8 @@ sub snapshot_name {
7246 $ver = $1;
7247 } else {
7248 # branches and other need shortened SHA-1 hash
7194 - if ($hash =~ m!^refs/(?:heads|remotes)/(.*)$!) {
7249 + my $strip_refs = join '|', map { quotemeta } get_branch_refs();
7250 + if ($hash =~ m!^refs/($strip_refs|remotes)/(.*)$!) {
7251 $ver = $1;
7252 }
7253 $ver .= '-' . git_get_short_hash($project, $hash);