All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pavan Kumar Sunkara <pavan.sss1991@gmail.com>
To: git@vger.kernel.org, jnareb@gmail.com, chriscool@tuxfamily.org,
	pasky@ucw.cz
Cc: Pavan Kumar Sunkara <pavan.sss1991@gmail.com>
Subject: [PATCHv2 GSOC 07/11] gitweb: Create Gitweb::RepoConfig module
Date: Thu, 15 Jul 2010 12:59:07 +0530	[thread overview]
Message-ID: <1279178951-23712-8-git-send-email-pavan.sss1991@gmail.com> (raw)
In-Reply-To: <1279178951-23712-1-git-send-email-pavan.sss1991@gmail.com>

Create a Gitweb::RepoConfig module in 'gitweb/lib/Gitweb/RepoConfig.pm'
to store and handle all the configuration and subroutines
related to a single repository regarding the gitweb.perl script.

This module depend on several other modules like Git.pm,
Config.pm, Request.pm and Escape.pm.

It also include subroutines regarding project_list and
it's handling.

Subroutines moved:
	check_head_link
	check_export_ok
	hash_set_multi
	git_parse_project_config
	config_to_bool
	config_to_int
	config_to_multi
	feature_bool
	feature_snapshot
	feature_patches
	feature_avatar
	git_get_project_config
	git_get_project_description
	git_get_project_ctags
	git_populate_project_tagcloud
	git_show_project_tagcloud
	git_get_project_url_list
	git_get_projects_list
	git_get_project_list_from_file
	git_get_project_owner
	get_file_owner
	project_in_list

Update gitweb/Makefile to install Gitweb::RepoConfig module
alongside gitweb

Signed-off-by: Pavan Kumar Sunkara <pavan.sss1991@gmail.com>
---
 gitweb/Makefile                 |    1 +
 gitweb/gitweb.perl              |  441 +------------------------------------
 gitweb/lib/Gitweb/RepoConfig.pm |  466 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 468 insertions(+), 440 deletions(-)
 create mode 100644 gitweb/lib/Gitweb/RepoConfig.pm

diff --git a/gitweb/Makefile b/gitweb/Makefile
index c145ebd..726f393 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -116,6 +116,7 @@ GITWEB_MODULES += lib/Gitweb/Git.pm
 GITWEB_MODULES += lib/Gitweb/Config.pm
 GITWEB_MODULES += lib/Gitweb/Request.pm
 GITWEB_MODULES += lib/Gitweb/Escape.pm
+GITWEB_MODULES += lib/Gitweb/RepoConfig.pm
 
 GITWEB_REPLACE = \
 	-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index ed64910..16e705e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -18,7 +18,6 @@ sub __DIR__ () {
 use lib __DIR__ . '/lib';
 
 use CGI qw(:standard :escapeHTML -nosticky);
-use CGI::Util qw(unescape);
 use CGI::Carp qw(fatalsToBrowser set_message);
 use Fcntl ':mode';
 use File::Find qw();
@@ -30,6 +29,7 @@ use Gitweb::Git;
 use Gitweb::Config;
 use Gitweb::Request;
 use Gitweb::Escape;
+use Gitweb::RepoConfig;
 
 BEGIN {
 	CGI->compile() if $ENV{'MOD_PERL'};
@@ -69,64 +69,6 @@ $strict_export = "++GITWEB_STRICT_EXPORT++";
 $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
 $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
 
-sub feature_bool {
-	my $key = shift;
-	my ($val) = git_get_project_config($key, '--bool');
-
-	if (!defined $val) {
-		return ($_[0]);
-	} elsif ($val eq 'true') {
-		return (1);
-	} elsif ($val eq 'false') {
-		return (0);
-	}
-}
-
-sub feature_snapshot {
-	my (@fmts) = @_;
-
-	my ($val) = git_get_project_config('snapshot');
-
-	if ($val) {
-		@fmts = ($val eq 'none' ? () : split /\s*[,\s]\s*/, $val);
-	}
-
-	return @fmts;
-}
-
-sub feature_patches {
-	my @val = (git_get_project_config('patches', '--int'));
-
-	if (@val) {
-		return @val;
-	}
-
-	return ($_[0]);
-}
-
-sub feature_avatar {
-	my @val = (git_get_project_config('avatar'));
-
-	return @val ? @val : @_;
-}
-
-# checking HEAD file with -e is fragile if the repository was
-# initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed
-# and then pruned.
-sub check_head_link {
-	my ($dir) = @_;
-	my $headfile = "$dir/HEAD";
-	return ((-e $headfile) ||
-		(-l $headfile && readlink($headfile) =~ /^refs\/heads\//));
-}
-
-sub check_export_ok {
-	my ($dir) = @_;
-	return (check_head_link($dir) &&
-		(!$export_ok || -e "$dir/$export_ok") &&
-		(!$export_auth_hook || $export_auth_hook->($dir)));
-}
-
 # Get loadavg of system, to compare against $maxload.
 # Currently it requires '/proc/loadavg' present to get loadavg;
 # if it is not present it returns 0, which means no load checking.
@@ -781,12 +723,6 @@ sub unquote {
 	return $str;
 }
 
-sub project_in_list {
-	my $project = shift;
-	my @list = git_get_projects_list();
-	return @list && scalar(grep { $_->{'path'} eq $project } @list);
-}
-
 ## ----------------------------------------------------------------------
 ## HTML aware string manipulation
 
@@ -1595,129 +1531,6 @@ sub git_get_type {
 	return $type;
 }
 
-# repository configuration
-our $config_file = '';
-our %config;
-
-# store multiple values for single key as anonymous array reference
-# single values stored directly in the hash, not as [ <value> ]
-sub hash_set_multi {
-	my ($hash, $key, $value) = @_;
-
-	if (!exists $hash->{$key}) {
-		$hash->{$key} = $value;
-	} elsif (!ref $hash->{$key}) {
-		$hash->{$key} = [ $hash->{$key}, $value ];
-	} else {
-		push @{$hash->{$key}}, $value;
-	}
-}
-
-# return hash of git project configuration
-# optionally limited to some section, e.g. 'gitweb'
-sub git_parse_project_config {
-	my $section_regexp = shift;
-	my %config;
-
-	local $/ = "\0";
-
-	open my $fh, "-|", git_cmd(), "config", '-z', '-l',
-		or return;
-
-	while (my $keyval = <$fh>) {
-		chomp $keyval;
-		my ($key, $value) = split(/\n/, $keyval, 2);
-
-		hash_set_multi(\%config, $key, $value)
-			if (!defined $section_regexp || $key =~ /^(?:$section_regexp)\./o);
-	}
-	close $fh;
-
-	return %config;
-}
-
-# convert config value to boolean: 'true' or 'false'
-# no value, number > 0, 'true' and 'yes' values are true
-# rest of values are treated as false (never as error)
-sub config_to_bool {
-	my $val = shift;
-
-	return 1 if !defined $val;             # section.key
-
-	# strip leading and trailing whitespace
-	$val =~ s/^\s+//;
-	$val =~ s/\s+$//;
-
-	return (($val =~ /^\d+$/ && $val) ||   # section.key = 1
-	        ($val =~ /^(?:true|yes)$/i));  # section.key = true
-}
-
-# convert config value to simple decimal number
-# an optional value suffix of 'k', 'm', or 'g' will cause the value
-# to be multiplied by 1024, 1048576, or 1073741824
-sub config_to_int {
-	my $val = shift;
-
-	# strip leading and trailing whitespace
-	$val =~ s/^\s+//;
-	$val =~ s/\s+$//;
-
-	if (my ($num, $unit) = ($val =~ /^([0-9]*)([kmg])$/i)) {
-		$unit = lc($unit);
-		# unknown unit is treated as 1
-		return $num * ($unit eq 'g' ? 1073741824 :
-		               $unit eq 'm' ?    1048576 :
-		               $unit eq 'k' ?       1024 : 1);
-	}
-	return $val;
-}
-
-# convert config value to array reference, if needed
-sub config_to_multi {
-	my $val = shift;
-
-	return ref($val) ? $val : (defined($val) ? [ $val ] : []);
-}
-
-sub git_get_project_config {
-	my ($key, $type) = @_;
-
-	return unless defined $git_dir;
-
-	# key sanity check
-	return unless ($key);
-	$key =~ s/^gitweb\.//;
-	return if ($key =~ m/\W/);
-
-	# type sanity check
-	if (defined $type) {
-		$type =~ s/^--//;
-		$type = undef
-			unless ($type eq 'bool' || $type eq 'int');
-	}
-
-	# get config
-	if (!defined $config_file ||
-	    $config_file ne "$git_dir/config") {
-		%config = git_parse_project_config('gitweb');
-		$config_file = "$git_dir/config";
-	}
-
-	# check if config variable (key) exists
-	return unless exists $config{"gitweb.$key"};
-
-	# ensure given type
-	if (!defined $type) {
-		return $config{"gitweb.$key"};
-	} elsif ($type eq 'bool') {
-		# backward compatibility: 'git config --bool' returns true/false
-		return config_to_bool($config{"gitweb.$key"}) ? 'true' : 'false';
-	} elsif ($type eq 'int') {
-		return config_to_int($config{"gitweb.$key"});
-	}
-	return $config{"gitweb.$key"};
-}
-
 # get hash of given path at given ref
 sub git_get_hash_by_path {
 	my $base = shift;
@@ -1772,245 +1585,6 @@ sub git_get_path_by_hash {
 ## ......................................................................
 ## git utility functions, directly accessing git repository
 
-sub git_get_project_description {
-	my $path = shift;
-
-	$git_dir = "$projectroot/$path";
-	open my $fd, '<', "$git_dir/description"
-		or return git_get_project_config('description');
-	my $descr = <$fd>;
-	close $fd;
-	if (defined $descr) {
-		chomp $descr;
-	}
-	return $descr;
-}
-
-sub git_get_project_ctags {
-	my $path = shift;
-	my $ctags = {};
-
-	$git_dir = "$projectroot/$path";
-	opendir my $dh, "$git_dir/ctags"
-		or return $ctags;
-	foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) {
-		open my $ct, '<', $_ or next;
-		my $val = <$ct>;
-		chomp $val;
-		close $ct;
-		my $ctag = $_; $ctag =~ s#.*/##;
-		$ctags->{$ctag} = $val;
-	}
-	closedir $dh;
-	$ctags;
-}
-
-sub git_populate_project_tagcloud {
-	my $ctags = shift;
-
-	# First, merge different-cased tags; tags vote on casing
-	my %ctags_lc;
-	foreach (keys %$ctags) {
-		$ctags_lc{lc $_}->{count} += $ctags->{$_};
-		if (not $ctags_lc{lc $_}->{topcount}
-		    or $ctags_lc{lc $_}->{topcount} < $ctags->{$_}) {
-			$ctags_lc{lc $_}->{topcount} = $ctags->{$_};
-			$ctags_lc{lc $_}->{topname} = $_;
-		}
-	}
-
-	my $cloud;
-	if (eval { require HTML::TagCloud; 1; }) {
-		$cloud = HTML::TagCloud->new;
-		foreach (sort keys %ctags_lc) {
-			# Pad the title with spaces so that the cloud looks
-			# less crammed.
-			my $title = $ctags_lc{$_}->{topname};
-			$title =~ s/ /&nbsp;/g;
-			$title =~ s/^/&nbsp;/g;
-			$title =~ s/$/&nbsp;/g;
-			$cloud->add($title, $home_link."?by_tag=".$_, $ctags_lc{$_}->{count});
-		}
-	} else {
-		$cloud = \%ctags_lc;
-	}
-	$cloud;
-}
-
-sub git_show_project_tagcloud {
-	my ($cloud, $count) = @_;
-	print STDERR ref($cloud)."..\n";
-	if (ref $cloud eq 'HTML::TagCloud') {
-		return $cloud->html_and_css($count);
-	} else {
-		my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
-		return '<p align="center">' . join (', ', map {
-			"<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>"
-		} splice(@tags, 0, $count)) . '</p>';
-	}
-}
-
-sub git_get_project_url_list {
-	my $path = shift;
-
-	$git_dir = "$projectroot/$path";
-	open my $fd, '<', "$git_dir/cloneurl"
-		or return wantarray ?
-		@{ config_to_multi(git_get_project_config('url')) } :
-		   config_to_multi(git_get_project_config('url'));
-	my @git_project_url_list = map { chomp; $_ } <$fd>;
-	close $fd;
-
-	return wantarray ? @git_project_url_list : \@git_project_url_list;
-}
-
-sub git_get_projects_list {
-	my ($filter) = @_;
-	my @list;
-
-	$filter ||= '';
-	$filter =~ s/\.git$//;
-
-	my $check_forks = gitweb_check_feature('forks');
-
-	if (-d $projects_list) {
-		# search in directory
-		my $dir = $projects_list . ($filter ? "/$filter" : '');
-		# remove the trailing "/"
-		$dir =~ s!/+$!!;
-		my $pfxlen = length("$dir");
-		my $pfxdepth = ($dir =~ tr!/!!);
-
-		File::Find::find({
-			follow_fast => 1, # follow symbolic links
-			follow_skip => 2, # ignore duplicates
-			dangling_symlinks => 0, # ignore dangling symlinks, silently
-			wanted => sub {
-				# skip project-list toplevel, if we get it.
-				return if (m!^[/.]$!);
-				# only directories can be git repositories
-				return unless (-d $_);
-				# don't traverse too deep (Find is super slow on os x)
-				if (($File::Find::name =~ tr!/!!) - $pfxdepth > $project_maxdepth) {
-					$File::Find::prune = 1;
-					return;
-				}
-
-				my $subdir = substr($File::Find::name, $pfxlen + 1);
-				# we check related file in $projectroot
-				my $path = ($filter ? "$filter/" : '') . $subdir;
-				if (check_export_ok("$projectroot/$path")) {
-					push @list, { path => $path };
-					$File::Find::prune = 1;
-				}
-			},
-		}, "$dir");
-
-	} elsif (-f $projects_list) {
-		# read from file(url-encoded):
-		# 'git%2Fgit.git Linus+Torvalds'
-		# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
-		# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
-		my %paths;
-		open my $fd, '<', $projects_list or return;
-	PROJECT:
-		while (my $line = <$fd>) {
-			chomp $line;
-			my ($path, $owner) = split ' ', $line;
-			$path = unescape($path);
-			$owner = unescape($owner);
-			if (!defined $path) {
-				next;
-			}
-			if ($filter ne '') {
-				# looking for forks;
-				my $pfx = substr($path, 0, length($filter));
-				if ($pfx ne $filter) {
-					next PROJECT;
-				}
-				my $sfx = substr($path, length($filter));
-				if ($sfx !~ /^\/.*\.git$/) {
-					next PROJECT;
-				}
-			} elsif ($check_forks) {
-			PATH:
-				foreach my $filter (keys %paths) {
-					# looking for forks;
-					my $pfx = substr($path, 0, length($filter));
-					if ($pfx ne $filter) {
-						next PATH;
-					}
-					my $sfx = substr($path, length($filter));
-					if ($sfx !~ /^\/.*\.git$/) {
-						next PATH;
-					}
-					# is a fork, don't include it in
-					# the list
-					next PROJECT;
-				}
-			}
-			if (check_export_ok("$projectroot/$path")) {
-				my $pr = {
-					path => $path,
-					owner => to_utf8($owner),
-				};
-				push @list, $pr;
-				(my $forks_path = $path) =~ s/\.git$//;
-				$paths{$forks_path}++;
-			}
-		}
-		close $fd;
-	}
-	return @list;
-}
-
-our $gitweb_project_owner = undef;
-sub git_get_project_list_from_file {
-
-	return if (defined $gitweb_project_owner);
-
-	$gitweb_project_owner = {};
-	# read from file (url-encoded):
-	# 'git%2Fgit.git Linus+Torvalds'
-	# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
-	# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
-	if (-f $projects_list) {
-		open(my $fd, '<', $projects_list);
-		while (my $line = <$fd>) {
-			chomp $line;
-			my ($pr, $ow) = split ' ', $line;
-			$pr = unescape($pr);
-			$ow = unescape($ow);
-			$gitweb_project_owner->{$pr} = to_utf8($ow);
-		}
-		close $fd;
-	}
-}
-
-sub git_get_project_owner {
-	my $project = shift;
-	my $owner;
-
-	return undef unless $project;
-	$git_dir = "$projectroot/$project";
-
-	if (!defined $gitweb_project_owner) {
-		git_get_project_list_from_file();
-	}
-
-	if (exists $gitweb_project_owner->{$project}) {
-		$owner = $gitweb_project_owner->{$project};
-	}
-	if (!defined $owner){
-		$owner = git_get_project_config('owner');
-	}
-	if (!defined $owner) {
-		$owner = get_file_owner("$git_dir");
-	}
-
-	return $owner;
-}
-
 sub git_get_last_activity {
 	my ($path) = @_;
 	my $fd;
@@ -2518,19 +2092,6 @@ sub git_get_tags_list {
 ## ----------------------------------------------------------------------
 ## filesystem-related functions
 
-sub get_file_owner {
-	my $path = shift;
-
-	my ($dev, $ino, $mode, $nlink, $st_uid, $st_gid, $rdev, $size) = stat($path);
-	my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwuid($st_uid);
-	if (!defined $gcos) {
-		return undef;
-	}
-	my $owner = $gcos;
-	$owner =~ s/[,;].*$//;
-	return to_utf8($owner);
-}
-
 # assume that file exists
 sub insert_file {
 	my $filename = shift;
diff --git a/gitweb/lib/Gitweb/RepoConfig.pm b/gitweb/lib/Gitweb/RepoConfig.pm
new file mode 100644
index 0000000..c8d961d
--- /dev/null
+++ b/gitweb/lib/Gitweb/RepoConfig.pm
@@ -0,0 +1,466 @@
+#!/usr/bin/perl
+#
+# Gitweb::RepoConfig -- gitweb's per-repository configuration subs package
+#
+# This program is licensed under the GPLv2
+
+package Gitweb::RepoConfig;
+
+use strict;
+use warnings;
+use Exporter qw(import);
+
+our @EXPORT = qw($config_file %config $gitweb_project_owner git_get_project_url_list
+                 git_get_project_config git_get_project_description git_get_project_ctags
+                 git_populate_project_tagcloud git_show_project_tagcloud check_head_link
+                 check_export_ok git_get_projects_list git_get_project_list_from_file
+                 git_get_project_owner project_in_list feature_bool feature_snapshot
+                 feature_patches feature_avatar);
+
+use CGI::Util qw(unescape);
+use Gitweb::Git qw(git_cmd $git_dir);
+use Gitweb::Config qw(gitweb_check_feature $projectroot $projects_list
+                      $project_maxdepth $export_ok $export_auth_hook);
+use Gitweb::Request qw($home_link);
+use Gitweb::Escape qw(to_utf8);
+
+# repository configuration
+our $config_file = '';
+our %config;
+
+# checking HEAD file with -e is fragile if the repository was
+# initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed
+# and then pruned.
+sub check_head_link {
+	my ($dir) = @_;
+	my $headfile = "$dir/HEAD";
+	return ((-e $headfile) ||
+		(-l $headfile && readlink($headfile) =~ /^refs\/heads\//));
+}
+
+sub check_export_ok {
+	my ($dir) = @_;
+	return (check_head_link($dir) &&
+		(!$export_ok || -e "$dir/$export_ok") &&
+		(!$export_auth_hook || $export_auth_hook->($dir)));
+}
+
+# store multiple values for single key as anonymous array reference
+# single values stored directly in the hash, not as [ <value> ]
+sub hash_set_multi {
+	my ($hash, $key, $value) = @_;
+
+	if (!exists $hash->{$key}) {
+		$hash->{$key} = $value;
+	} elsif (!ref $hash->{$key}) {
+		$hash->{$key} = [ $hash->{$key}, $value ];
+	} else {
+		push @{$hash->{$key}}, $value;
+	}
+}
+
+# return hash of git project configuration
+# optionally limited to some section, e.g. 'gitweb'
+sub git_parse_project_config {
+	my $section_regexp = shift;
+	my %config;
+
+	local $/ = "\0";
+
+	open my $fh, "-|", git_cmd(), "config", '-z', '-l',
+		or return;
+
+	while (my $keyval = <$fh>) {
+		chomp $keyval;
+		my ($key, $value) = split(/\n/, $keyval, 2);
+
+		hash_set_multi(\%config, $key, $value)
+			if (!defined $section_regexp || $key =~ /^(?:$section_regexp)\./o);
+	}
+	close $fh;
+
+	return %config;
+}
+
+# convert config value to boolean: 'true' or 'false'
+# no value, number > 0, 'true' and 'yes' values are true
+# rest of values are treated as false (never as error)
+sub config_to_bool {
+	my $val = shift;
+
+	return 1 if !defined $val;             # section.key
+
+	# strip leading and trailing whitespace
+	$val =~ s/^\s+//;
+	$val =~ s/\s+$//;
+
+	return (($val =~ /^\d+$/ && $val) ||   # section.key = 1
+	        ($val =~ /^(?:true|yes)$/i));  # section.key = true
+}
+
+# convert config value to simple decimal number
+# an optional value suffix of 'k', 'm', or 'g' will cause the value
+# to be multiplied by 1024, 1048576, or 1073741824
+sub config_to_int {
+	my $val = shift;
+
+	# strip leading and trailing whitespace
+	$val =~ s/^\s+//;
+	$val =~ s/\s+$//;
+
+	if (my ($num, $unit) = ($val =~ /^([0-9]*)([kmg])$/i)) {
+		$unit = lc($unit);
+		# unknown unit is treated as 1
+		return $num * ($unit eq 'g' ? 1073741824 :
+		               $unit eq 'm' ?    1048576 :
+		               $unit eq 'k' ?       1024 : 1);
+	}
+	return $val;
+}
+
+# convert config value to array reference, if needed
+sub config_to_multi {
+	my $val = shift;
+
+	return ref($val) ? $val : (defined($val) ? [ $val ] : []);
+}
+
+sub feature_bool {
+	my $key = shift;
+	my ($val) = git_get_project_config($key, '--bool');
+
+	if (!defined $val) {
+		return ($_[0]);
+	} elsif ($val eq 'true') {
+		return (1);
+	} elsif ($val eq 'false') {
+		return (0);
+	}
+}
+
+sub feature_snapshot {
+	my (@fmts) = @_;
+
+	my ($val) = git_get_project_config('snapshot');
+
+	if ($val) {
+		@fmts = ($val eq 'none' ? () : split /\s*[,\s]\s*/, $val);
+	}
+
+	return @fmts;
+}
+
+sub feature_patches {
+	my @val = (git_get_project_config('patches', '--int'));
+
+	if (@val) {
+		return @val;
+	}
+
+	return ($_[0]);
+}
+
+sub feature_avatar {
+	my @val = (git_get_project_config('avatar'));
+
+	return @val ? @val : @_;
+}
+
+sub git_get_project_config {
+	my ($key, $type) = @_;
+
+	return unless defined $git_dir;
+
+	# key sanity check
+	return unless ($key);
+	$key =~ s/^gitweb\.//;
+	return if ($key =~ m/\W/);
+
+	# type sanity check
+	if (defined $type) {
+		$type =~ s/^--//;
+		$type = undef
+			unless ($type eq 'bool' || $type eq 'int');
+	}
+
+	# get config
+	if (!defined $config_file ||
+	    $config_file ne "$git_dir/config") {
+		%config = git_parse_project_config('gitweb');
+		$config_file = "$git_dir/config";
+	}
+
+	# check if config variable (key) exists
+	return unless exists $config{"gitweb.$key"};
+
+	# ensure given type
+	if (!defined $type) {
+		return $config{"gitweb.$key"};
+	} elsif ($type eq 'bool') {
+		# backward compatibility: 'git config --bool' returns true/false
+		return config_to_bool($config{"gitweb.$key"}) ? 'true' : 'false';
+	} elsif ($type eq 'int') {
+		return config_to_int($config{"gitweb.$key"});
+	}
+	return $config{"gitweb.$key"};
+}
+
+sub git_get_project_description {
+	my $path = shift;
+
+	$git_dir = "$projectroot/$path";
+	open my $fd, '<', "$git_dir/description"
+		or return git_get_project_config('description');
+	my $descr = <$fd>;
+	close $fd;
+	if (defined $descr) {
+		chomp $descr;
+	}
+	return $descr;
+}
+
+sub git_get_project_ctags {
+	my $path = shift;
+	my $ctags = {};
+
+	$git_dir = "$projectroot/$path";
+	opendir my $dh, "$git_dir/ctags"
+		or return $ctags;
+	foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) {
+		open my $ct, '<', $_ or next;
+		my $val = <$ct>;
+		chomp $val;
+		close $ct;
+		my $ctag = $_; $ctag =~ s#.*/##;
+		$ctags->{$ctag} = $val;
+	}
+	closedir $dh;
+	$ctags;
+}
+
+sub git_populate_project_tagcloud {
+	my $ctags = shift;
+
+	# First, merge different-cased tags; tags vote on casing
+	my %ctags_lc;
+	foreach (keys %$ctags) {
+		$ctags_lc{lc $_}->{count} += $ctags->{$_};
+		if (not $ctags_lc{lc $_}->{topcount}
+		    or $ctags_lc{lc $_}->{topcount} < $ctags->{$_}) {
+			$ctags_lc{lc $_}->{topcount} = $ctags->{$_};
+			$ctags_lc{lc $_}->{topname} = $_;
+		}
+	}
+
+	my $cloud;
+	if (eval { require HTML::TagCloud; 1; }) {
+		$cloud = HTML::TagCloud->new;
+		foreach (sort keys %ctags_lc) {
+			# Pad the title with spaces so that the cloud looks
+			# less crammed.
+			my $title = $ctags_lc{$_}->{topname};
+			$title =~ s/ /&nbsp;/g;
+			$title =~ s/^/&nbsp;/g;
+			$title =~ s/$/&nbsp;/g;
+			$cloud->add($title, $home_link."?by_tag=".$_, $ctags_lc{$_}->{count});
+		}
+	} else {
+		$cloud = \%ctags_lc;
+	}
+	$cloud;
+}
+
+sub git_show_project_tagcloud {
+	my ($cloud, $count) = @_;
+	print STDERR ref($cloud)."..\n";
+	if (ref $cloud eq 'HTML::TagCloud') {
+		return $cloud->html_and_css($count);
+	} else {
+		my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
+		return '<p align="center">' . join (', ', map {
+			"<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>"
+		} splice(@tags, 0, $count)) . '</p>';
+	}
+}
+
+sub git_get_project_url_list {
+	my $path = shift;
+
+	$git_dir = "$projectroot/$path";
+	open my $fd, '<', "$git_dir/cloneurl"
+		or return wantarray ?
+		@{ config_to_multi(git_get_project_config('url')) } :
+		   config_to_multi(git_get_project_config('url'));
+	my @git_project_url_list = map { chomp; $_ } <$fd>;
+	close $fd;
+
+	return wantarray ? @git_project_url_list : \@git_project_url_list;
+}
+
+sub git_get_projects_list {
+	my ($filter) = @_;
+	my @list;
+
+	$filter ||= '';
+	$filter =~ s/\.git$//;
+
+	my $check_forks = gitweb_check_feature('forks');
+
+	if (-d $projects_list) {
+		# search in directory
+		my $dir = $projects_list . ($filter ? "/$filter" : '');
+		# remove the trailing "/"
+		$dir =~ s!/+$!!;
+		my $pfxlen = length("$dir");
+		my $pfxdepth = ($dir =~ tr!/!!);
+
+		File::Find::find({
+			follow_fast => 1, # follow symbolic links
+			follow_skip => 2, # ignore duplicates
+			dangling_symlinks => 0, # ignore dangling symlinks, silently
+			wanted => sub {
+				# skip project-list toplevel, if we get it.
+				return if (m!^[/.]$!);
+				# only directories can be git repositories
+				return unless (-d $_);
+				# don't traverse too deep (Find is super slow on os x)
+				if (($File::Find::name =~ tr!/!!) - $pfxdepth > $project_maxdepth) {
+					$File::Find::prune = 1;
+					return;
+				}
+
+				my $subdir = substr($File::Find::name, $pfxlen + 1);
+				# we check related file in $projectroot
+				my $path = ($filter ? "$filter/" : '') . $subdir;
+				if (check_export_ok("$projectroot/$path")) {
+					push @list, { path => $path };
+					$File::Find::prune = 1;
+				}
+			},
+		}, "$dir");
+
+	} elsif (-f $projects_list) {
+		# read from file(url-encoded):
+		# 'git%2Fgit.git Linus+Torvalds'
+		# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
+		# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
+		my %paths;
+		open my $fd, '<', $projects_list or return;
+	PROJECT:
+		while (my $line = <$fd>) {
+			chomp $line;
+			my ($path, $owner) = split ' ', $line;
+			$path = unescape($path);
+			$owner = unescape($owner);
+			if (!defined $path) {
+				next;
+			}
+			if ($filter ne '') {
+				# looking for forks;
+				my $pfx = substr($path, 0, length($filter));
+				if ($pfx ne $filter) {
+					next PROJECT;
+				}
+				my $sfx = substr($path, length($filter));
+				if ($sfx !~ /^\/.*\.git$/) {
+					next PROJECT;
+				}
+			} elsif ($check_forks) {
+			PATH:
+				foreach my $filter (keys %paths) {
+					# looking for forks;
+					my $pfx = substr($path, 0, length($filter));
+					if ($pfx ne $filter) {
+						next PATH;
+					}
+					my $sfx = substr($path, length($filter));
+					if ($sfx !~ /^\/.*\.git$/) {
+						next PATH;
+					}
+					# is a fork, don't include it in
+					# the list
+					next PROJECT;
+				}
+			}
+			if (check_export_ok("$projectroot/$path")) {
+				my $pr = {
+					path => $path,
+					owner => to_utf8($owner),
+				};
+				push @list, $pr;
+				(my $forks_path = $path) =~ s/\.git$//;
+				$paths{$forks_path}++;
+			}
+		}
+		close $fd;
+	}
+	return @list;
+}
+
+our $gitweb_project_owner = undef;
+sub git_get_project_list_from_file {
+
+	return if (defined $gitweb_project_owner);
+
+	$gitweb_project_owner = {};
+	# read from file (url-encoded):
+	# 'git%2Fgit.git Linus+Torvalds'
+	# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
+	# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
+	if (-f $projects_list) {
+		open(my $fd, '<', $projects_list);
+		while (my $line = <$fd>) {
+			chomp $line;
+			my ($pr, $ow) = split ' ', $line;
+			$pr = unescape($pr);
+			$ow = unescape($ow);
+			$gitweb_project_owner->{$pr} = to_utf8($ow);
+		}
+		close $fd;
+	}
+}
+
+sub git_get_project_owner {
+	my $project = shift;
+	my $owner;
+
+	return undef unless $project;
+	$git_dir = "$projectroot/$project";
+
+	if (!defined $gitweb_project_owner) {
+		git_get_project_list_from_file();
+	}
+
+	if (exists $gitweb_project_owner->{$project}) {
+		$owner = $gitweb_project_owner->{$project};
+	}
+	if (!defined $owner){
+		$owner = git_get_project_config('owner');
+	}
+	if (!defined $owner) {
+		$owner = get_file_owner("$git_dir");
+	}
+
+	return $owner;
+}
+
+sub get_file_owner {
+	my $path = shift;
+
+	my ($dev, $ino, $mode, $nlink, $st_uid, $st_gid, $rdev, $size) = stat($path);
+	my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwuid($st_uid);
+	if (!defined $gcos) {
+		return undef;
+	}
+	my $owner = $gcos;
+	$owner =~ s/[,;].*$//;
+	return to_utf8($owner);
+}
+
+sub project_in_list {
+	my $project = shift;
+	my @list = git_get_projects_list();
+	return @list && scalar(grep { $_->{'path'} eq $project } @list);
+}
+
+1;
-- 
1.7.1.455.g8f441

  parent reply	other threads:[~2010-07-15  7:30 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-07-15  7:29 [PATCHv2 00/11] Splitting gitweb Pavan Kumar Sunkara
2010-07-15  7:29 ` [PATCHv2 GSOC 01/11] gitweb: fix esc_url Pavan Kumar Sunkara
2010-07-15 13:52   ` Jakub Narebski
2010-07-15 18:57     ` Junio C Hamano
2010-07-15 19:32       ` Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 02/11] gitweb: Prepare for splitting gitweb Pavan Kumar Sunkara
2010-07-15 18:05   ` Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 03/11] gitweb: Create Gitweb::Git module Pavan Kumar Sunkara
2010-07-15 20:13   ` Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 04/11] gitweb: Create Gitweb::Config module Pavan Kumar Sunkara
2010-07-15 21:21   ` Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 05/11] gitweb: Create Gitweb::Request module Pavan Kumar Sunkara
2010-07-16  0:11   ` Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 06/11] gitweb: Create Gitweb::Escape module Pavan Kumar Sunkara
2010-07-16  9:01   ` Jakub Narebski
2010-07-15  7:29 ` Pavan Kumar Sunkara [this message]
2010-07-16 12:11   ` [PATCHv2 GSOC 07/11] gitweb: Create Gitweb::RepoConfig module Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 08/11] gitweb: Create Gitweb::View module Pavan Kumar Sunkara
2010-07-18 15:10   ` Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 09/11] gitweb: Create Gitweb::Util module Pavan Kumar Sunkara
2010-07-18 17:45   ` Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 10/11] gitweb: Create Gitweb::Format module Pavan Kumar Sunkara
2010-07-18 20:16   ` Jakub Narebski
2010-07-15  7:29 ` [PATCHv2 GSOC 11/11] gitweb: Create Gitweb::Parse module Pavan Kumar Sunkara
2010-07-19 14:55   ` Jakub Narebski
2010-08-01 20:44 ` [PATCHv2 00/11] Splitting gitweb Sverre Rabbelier
2010-08-02 15:03   ` Jakub Narebski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1279178951-23712-8-git-send-email-pavan.sss1991@gmail.com \
    --to=pavan.sss1991@gmail.com \
    --cc=chriscool@tuxfamily.org \
    --cc=git@vger.kernel.org \
    --cc=jnareb@gmail.com \
    --cc=pasky@ucw.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.