@@ -282,6 +282,44 @@ BEGIN
282
282
' forks' => {
283
283
' override' => 0,
284
284
' default' => [0]},
285
+
286
+ # Insert custom links to the action bar of all project pages.
287
+ # This enables you mainly to link to third-party scripts integrating
288
+ # into gitweb; e.g. git-browser for graphical history representation
289
+ # or custom web-based repository administration interface.
290
+
291
+ # The 'default' value consists of a list of triplets in the form
292
+ # (label, link, position) where position is the label after which
293
+ # to inster the link and link is a format string where %n expands
294
+ # to the project name, %f to the project path within the filesystem,
295
+ # %h to the current hash (h gitweb parameter) and %b to the current
296
+ # hash base (hb gitweb parameter).
297
+
298
+ # To enable system wide have in $GITWEB_CONFIG e.g.
299
+ # $feature{'actions'}{'default'} = [('graphiclog',
300
+ # '/git-browser/by-commit.html?r=%n', 'summary')];
301
+ # Project specific override is not supported.
302
+ ' actions' => {
303
+ ' override' => 0,
304
+ ' default' => []},
305
+
306
+ # Allow gitweb scan project content tags described in ctags/
307
+ # of project repository, and display the popular Web 2.0-ish
308
+ # "tag cloud" near the project list. Note that this is something
309
+ # COMPLETELY different from the normal Git tags.
310
+
311
+ # gitweb by itself can show existing tags, but it does not handle
312
+ # tagging itself; you need an external application for that.
313
+ # For an example script, check Girocco's cgi/tagproj.cgi.
314
+ # You may want to install the HTML::TagCloud Perl module to get
315
+ # a pretty tag cloud instead of just a list of tags.
316
+
317
+ # To enable system wide have in $GITWEB_CONFIG
318
+ # $feature{'ctags'}{'default'} = ['path_to_tag_script'];
319
+ # Project specific override is not supported.
320
+ ' ctags' => {
321
+ ' override' => 0,
322
+ ' default' => [0]},
285
323
);
286
324
287
325
sub gitweb_check_feature {
@@ -1762,6 +1800,67 @@ sub git_get_project_description {
1762
1800
return $descr ;
1763
1801
}
1764
1802
1803
+ sub git_get_project_ctags {
1804
+ my $path = shift ;
1805
+ my $ctags = {};
1806
+
1807
+ $git_dir = " $projectroot /$path " ;
1808
+ foreach (<$git_dir /ctags/*>) {
1809
+ open CT, $_ or next ;
1810
+ my $val = <CT>;
1811
+ chomp $val ;
1812
+ close CT;
1813
+ my $ctag = $_ ; $ctag =~ s # .*/## ;
1814
+ $ctags -> {$ctag } = $val ;
1815
+ }
1816
+ $ctags ;
1817
+ }
1818
+
1819
+ sub git_populate_project_tagcloud {
1820
+ my $ctags = shift ;
1821
+
1822
+ # First, merge different-cased tags; tags vote on casing
1823
+ my %ctags_lc ;
1824
+ foreach (keys %$ctags ) {
1825
+ $ctags_lc {lc $_ }-> {count } += $ctags -> {$_ };
1826
+ if (not $ctags_lc {lc $_ }-> {topcount }
1827
+ or $ctags_lc {lc $_ }-> {topcount } < $ctags -> {$_ }) {
1828
+ $ctags_lc {lc $_ }-> {topcount } = $ctags -> {$_ };
1829
+ $ctags_lc {lc $_ }-> {topname } = $_ ;
1830
+ }
1831
+ }
1832
+
1833
+ my $cloud ;
1834
+ if (eval { require HTML::TagCloud; 1; }) {
1835
+ $cloud = HTML::TagCloud-> new;
1836
+ foreach (sort keys %ctags_lc ) {
1837
+ # Pad the title with spaces so that the cloud looks
1838
+ # less crammed.
1839
+ my $title = $ctags_lc {$_ }-> {topname };
1840
+ $title =~ s / / / g ;
1841
+ $title =~ s / ^/ / g ;
1842
+ $title =~ s / $/ / g ;
1843
+ $cloud -> add($title , $home_link ." ?by_tag=" .$_ , $ctags_lc {$_ }-> {count });
1844
+ }
1845
+ } else {
1846
+ $cloud = \%ctags_lc ;
1847
+ }
1848
+ $cloud ;
1849
+ }
1850
+
1851
+ sub git_show_project_tagcloud {
1852
+ my ($cloud , $count ) = @_ ;
1853
+ print STDERR ref ($cloud )." ..\n " ;
1854
+ if (ref $cloud eq ' HTML::TagCloud' ) {
1855
+ return $cloud -> html_and_css($count );
1856
+ } else {
1857
+ my @tags = sort { $cloud -> {$a }-> {count } <=> $cloud -> {$b }-> {count } } keys %$cloud ;
1858
+ return ' <p align="center">' . join (' , ' , map {
1859
+ " <a href=\" $home_link ?by_tag=$_ \" >$cloud ->{$_ }->{topname}</a>"
1860
+ } splice (@tags , 0, $count )) . ' </p>' ;
1861
+ }
1862
+ }
1863
+
1765
1864
sub git_get_project_url_list {
1766
1865
my $path = shift ;
1767
1866
@@ -1810,9 +1909,7 @@ sub git_get_projects_list {
1810
1909
1811
1910
my $subdir = substr ($File::Find::name , $pfxlen + 1);
1812
1911
# we check related file in $projectroot
1813
- if ($check_forks and $subdir =~ m # /.# ) {
1814
- $File::Find::prune = 1;
1815
- } elsif (check_export_ok(" $projectroot /$filter /$subdir " )) {
1912
+ if (check_export_ok(" $projectroot /$filter /$subdir " )) {
1816
1913
push @list , { path => ($filter ? " $filter /" : ' ' ) . $subdir };
1817
1914
$File::Find::prune = 1;
1818
1915
}
@@ -2764,13 +2861,26 @@ sub git_print_page_nav {
2764
2861
}
2765
2862
}
2766
2863
}
2864
+
2767
2865
$arg {' tree' }{' hash' } = $treehead if defined $treehead ;
2768
2866
$arg {' tree' }{' hash_base' } = $treebase if defined $treebase ;
2769
2867
2868
+ my @actions = gitweb_check_feature(' actions' );
2869
+ while (@actions ) {
2870
+ my ($label , $link , $pos ) = (shift (@actions ), shift (@actions ), shift (@actions ));
2871
+ @navs = map { $_ eq $pos ? ($_ , $label ) : $_ } @navs ;
2872
+ # munch munch
2873
+ $link =~ s # %n# $project # g ;
2874
+ $link =~ s # %f# $git_dir # g ;
2875
+ $treehead ? $link =~ s # %h# $treehead # g : $link =~ s # %h## g ;
2876
+ $treebase ? $link =~ s # %b# $treebase # g : $link =~ s # %b## g ;
2877
+ $arg {$label }{' _href' } = $link ;
2878
+ }
2879
+
2770
2880
print " <div class=\" page_nav\" >\n " .
2771
2881
(join " | " ,
2772
2882
map { $_ eq $current ?
2773
- $_ : $cgi -> a({-href => href(%{$arg {$_ }})}, " $_ " )
2883
+ $_ : $cgi -> a({-href => ( $arg { $_ }{ _href } ? $arg { $_ }{ _href } : href(%{$arg {$_ }}) )}, " $_ " )
2774
2884
} @navs );
2775
2885
print " <br/>\n $extra <br/>\n " .
2776
2886
" </div>\n " ;
@@ -3580,6 +3690,7 @@ sub fill_project_list_info {
3580
3690
my ($projlist , $check_forks ) = @_ ;
3581
3691
my @projects ;
3582
3692
3693
+ my $show_ctags = gitweb_check_feature(' ctags' );
3583
3694
PROJECT:
3584
3695
foreach my $pr (@$projlist ) {
3585
3696
my (@activity ) = git_get_last_activity($pr -> {' path' });
@@ -3606,25 +3717,20 @@ sub fill_project_list_info {
3606
3717
$pr -> {' forks' } = 0;
3607
3718
}
3608
3719
}
3720
+ $show_ctags and $pr -> {' ctags' } = git_get_project_ctags($pr -> {' path' });
3609
3721
push @projects , $pr ;
3610
3722
}
3611
3723
3612
3724
return @projects ;
3613
3725
}
3614
3726
3615
- # print 'sort by' <th> element, either sorting by $key if $ name eq $order
3616
- # (changing $list), or generating 'sort by $name' replay link otherwise
3727
+ # print 'sort by' <th> element, generating 'sort by $name' replay link
3728
+ # if that order is not selected
3617
3729
sub print_sort_th {
3618
- my ($str_sort , $name , $order , $key , $header , $list ) = @_ ;
3619
- $key ||= $name ;
3730
+ my ($name , $order , $header ) = @_ ;
3620
3731
$header ||= ucfirst ($name );
3621
3732
3622
3733
if ($order eq $name ) {
3623
- if ($str_sort ) {
3624
- @$list = sort {$a -> {$key } cmp $b -> {$key }} @$list ;
3625
- } else {
3626
- @$list = sort {$a -> {$key } <=> $b -> {$key }} @$list ;
3627
- }
3628
3734
print " <th>$header </th>\n " ;
3629
3735
} else {
3630
3736
print " <th>" .
@@ -3634,15 +3740,8 @@ sub print_sort_th {
3634
3740
}
3635
3741
}
3636
3742
3637
- sub print_sort_th_str {
3638
- print_sort_th(1, @_ );
3639
- }
3640
-
3641
- sub print_sort_th_num {
3642
- print_sort_th(0, @_ );
3643
- }
3644
-
3645
3743
sub git_project_list_body {
3744
+ # actually uses global variable $project
3646
3745
my ($projlist , $order , $from , $to , $extra , $no_header ) = @_ ;
3647
3746
3648
3747
my ($check_forks ) = gitweb_check_feature(' forks' );
@@ -3652,26 +3751,60 @@ sub git_project_list_body {
3652
3751
$from = 0 unless defined $from ;
3653
3752
$to = $#projects if (!defined $to || $#projects < $to );
3654
3753
3754
+ my %order_info = (
3755
+ project => { key => ' path' , type => ' str' },
3756
+ descr => { key => ' descr_long' , type => ' str' },
3757
+ owner => { key => ' owner' , type => ' str' },
3758
+ age => { key => ' age' , type => ' num' }
3759
+ );
3760
+ my $oi = $order_info {$order };
3761
+ if ($oi -> {' type' } eq ' str' ) {
3762
+ @projects = sort {$a -> {$oi -> {' key' }} cmp $b -> {$oi -> {' key' }}} @projects ;
3763
+ } else {
3764
+ @projects = sort {$a -> {$oi -> {' key' }} <=> $b -> {$oi -> {' key' }}} @projects ;
3765
+ }
3766
+
3767
+ my $show_ctags = gitweb_check_feature(' ctags' );
3768
+ if ($show_ctags ) {
3769
+ my %ctags ;
3770
+ foreach my $p (@projects ) {
3771
+ foreach my $ct (keys %{$p -> {' ctags' }}) {
3772
+ $ctags {$ct } += $p -> {' ctags' }-> {$ct };
3773
+ }
3774
+ }
3775
+ my $cloud = git_populate_project_tagcloud(\%ctags );
3776
+ print git_show_project_tagcloud($cloud , 64);
3777
+ }
3778
+
3655
3779
print " <table class=\" project_list\" >\n " ;
3656
3780
unless ($no_header ) {
3657
3781
print " <tr>\n " ;
3658
3782
if ($check_forks ) {
3659
3783
print " <th></th>\n " ;
3660
3784
}
3661
- print_sort_th_str(' project' , $order , ' path' ,
3662
- ' Project' , \@projects );
3663
- print_sort_th_str(' descr' , $order , ' descr_long' ,
3664
- ' Description' , \@projects );
3665
- print_sort_th_str(' owner' , $order , ' owner' ,
3666
- ' Owner' , \@projects );
3667
- print_sort_th_num(' age' , $order , ' age' ,
3668
- ' Last Change' , \@projects );
3785
+ print_sort_th(' project' , $order , ' Project' );
3786
+ print_sort_th(' descr' , $order , ' Description' );
3787
+ print_sort_th(' owner' , $order , ' Owner' );
3788
+ print_sort_th(' age' , $order , ' Last Change' );
3669
3789
print " <th></th>\n " . # for links
3670
3790
" </tr>\n " ;
3671
3791
}
3672
3792
my $alternate = 1;
3793
+ my $tagfilter = $cgi -> param(' by_tag' );
3673
3794
for (my $i = $from ; $i <= $to ; $i ++) {
3674
3795
my $pr = $projects [$i ];
3796
+
3797
+ next if $tagfilter and $show_ctags and not grep { lc $_ eq lc $tagfilter } keys %{$pr -> {' ctags' }};
3798
+ next if $searchtext and not $pr -> {' path' } =~ / $searchtext /
3799
+ and not $pr -> {' descr_long' } =~ / $searchtext / ;
3800
+ # Weed out forks or non-matching entries of search
3801
+ if ($check_forks ) {
3802
+ my $forkbase = $project ; $forkbase ||= ' ' ; $forkbase =~ s #\. git$# /# ;
3803
+ $forkbase =" ^$forkbase " if $forkbase ;
3804
+ next if not $searchtext and not $tagfilter and $show_ctags
3805
+ and $pr -> {' path' } =~ m #$forkbase .*/.*# ; # regexp-safe
3806
+ }
3807
+
3675
3808
if ($alternate ) {
3676
3809
print " <tr class=\" dark\" >\n " ;
3677
3810
} else {
@@ -4006,6 +4139,11 @@ sub git_project_list {
4006
4139
close $fd ;
4007
4140
print " </div>\n " ;
4008
4141
}
4142
+ print $cgi -> startform(-method => " get" ) .
4143
+ " <p class=\" projsearch\" >Search:\n " .
4144
+ $cgi -> textfield(-name => " s" , -value => $searchtext ) . " \n " .
4145
+ " </p>" .
4146
+ $cgi -> end_form() . " \n " ;
4009
4147
git_project_list_body(\@list , $order );
4010
4148
git_footer_html();
4011
4149
}
@@ -4093,6 +4231,20 @@ sub git_summary {
4093
4231
print " <tr class=\" metadata_url\" ><td>$url_tag </td><td>$git_url </td></tr>\n " ;
4094
4232
$url_tag = " " ;
4095
4233
}
4234
+
4235
+ # Tag cloud
4236
+ my $show_ctags = (gitweb_check_feature(' ctags' ))[0];
4237
+ if ($show_ctags ) {
4238
+ my $ctags = git_get_project_ctags($project );
4239
+ my $cloud = git_populate_project_tagcloud($ctags );
4240
+ print " <tr id=\" metadata_ctags\" ><td>Content tags:<br />" ;
4241
+ print " </td>\n <td>" unless %$ctags ;
4242
+ print " <form action=\" $show_ctags \" method=\" post\" ><input type=\" hidden\" name=\" p\" value=\" $project \" />Add: <input type=\" text\" name=\" t\" size=\" 8\" /></form>" ;
4243
+ print " </td>\n <td>" if %$ctags ;
4244
+ print git_show_project_tagcloud($cloud , 48);
4245
+ print " </td></tr>" ;
4246
+ }
4247
+
4096
4248
print " </table>\n " ;
4097
4249
4098
4250
if (-s " $projectroot /$project /README.html" ) {
@@ -4131,10 +4283,10 @@ sub git_summary {
4131
4283
4132
4284
if (@forklist ) {
4133
4285
git_print_header_div(' forks' );
4134
- git_project_list_body(\@forklist , undef , 0, 15,
4286
+ git_project_list_body(\@forklist , ' age ' , 0, 15,
4135
4287
$#forklist <= 15 ? undef :
4136
4288
$cgi -> a({-href => href(action => " forks" )}, " ..." ),
4137
- ' noheader ' );
4289
+ ' no_header ' );
4138
4290
}
4139
4291
4140
4292
git_footer_html();
0 commit comments