use FindBin;
binmode STDOUT, ':utf8';
+use Gitalist::Util qw(to_utf8);
+
BEGIN {
- CGI->compile() if $ENV{'MOD_PERL'};
+ CGI->compile();
}
use vars qw(
$cgi $version $my_url $my_uri $base_url $path_info $GIT $projectroot
- $project_maxdepth $home_link $home_link_str $site_name $site_header
- $home_text $site_footer @stylesheets $stylesheet $logo $favicon
+ $project_maxdepth $home_link $home_link_str $site_header
+ $home_text $site_footer @stylesheets
$logo_url $logo_label $logo_url $logo_label $projects_list
$projects_list_description_width $default_projects_order
$export_ok $export_auth_hook $strict_export @git_base_url_list
# core git executable to use
# this can just be "git" if your webserver has a sensible PATH
- our $GIT = "/usr/bin/git";
+ our $GIT = `which git`;
+ chomp($GIT);
# absolute fs-path which will be prepended to the project path
- our $projectroot = "/pub/scm";
-
- # fs traversing limit for getting project list
- # the number is relative to the projectroot
- our $project_maxdepth = 2007;
+ #our $projectroot = "/pub/scm";
# target of the home link on top of all pages
our $home_link = $my_uri || "/";
# string of the home link on top of all pages
our $home_link_str = "Project Gitalist";
- # name of your site or organization to appear in page titles
- # replace this with something more descriptive for clearer bookmarks
- our $site_name = ""
- || ($ENV{'SERVER_NAME'} || "Untitled") . " Git";
-
# filename of html text to include at top of each page
our $site_header = "";
# html text to include at home page
# URI of stylesheets
our @stylesheets = ("gitweb.css");
- # URI of a single stylesheet, which can be overridden in GITWEB_CONFIG.
- our $stylesheet = undef;
- # URI of GIT logo (72x27 size)
- our $logo = "git-logo.png";
- # URI of GIT favicon, assumed to be image/png type
- our $favicon = "git-favicon.png";
# URI and label (title) of GIT logo link
our $logo_url = "http://www.kernel.org/pub/software/scm/git/docs/";
our $logo_label = "git documentation";
# source of projects list
- our $projects_list = "";
+ our $projectroot = our $projects_list = $c->config->{projectroot};
# the width (in characters) of the projects list "Description" column
our $projects_list_description_width = 25;
# version of the core git binary
our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
- $projects_list ||= $projectroot;
-
# ======================================================================
# input validation and dispatch
# being it's only this one, we just single it out
while (my ($name, $symbol) = each %cgi_param_mapping) {
if ($symbol eq 'opt') {
- $input_params{$name} = [ $cgi->param($symbol) ];
+ $input_params{$name} = [ $c->req->param($symbol) ];
} else {
- $input_params{$name} = $cgi->param($symbol);
+ $input_params{$name} = $c->req->param($symbol);
}
}
}
}
};
+
&$evaluate_path_info();
gitweb_validate_setup();
our @extra_options = @{$input_params{'extra_options'}};
# @extra_options is always defined, since it can only be (currently) set from
- # CGI, and $cgi->param() returns the empty array in array context if the param
+ # CGI, and $c->req->param() returns the empty array in array context if the param
# is not set
foreach my $opt (@extra_options) {
if (not exists $allowed_options{$opt}) {
return $input;
}
-# decode sequences of octets in utf8 into Perl's internal form,
-# which is utf-8 with utf8 flag set if needed. gitweb writes out
-# in utf-8 thanks to "binmode STDOUT, ':utf8'" at beginning
-sub to_utf8 {
- my $str = shift;
- if (utf8::valid($str)) {
- utf8::decode($str);
- return $str;
- } else {
- return decode($fallback_encoding, $str, Encode::FB_DEFAULT);
- }
-}
-
# quote unsafe chars, but keep the slash, even when it's not
# correct, but quoted slashes look too horrible in bookmarks
sub esc_param {
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 $type;
}
-## ======================================================================
-## functions printing HTML: header, footer, error page
-
-sub git_header_html {
- # XXX These aren't used, how odd.
- my $status = shift || "200 OK";
- my $expires = shift;
-
- my $title = "$site_name";
- if (defined $project) {
- $title .= " - " . to_utf8($project);
- if (defined $action) {
- $title .= "/$action";
- if (defined $file_name) {
- $title .= " - " . esc_path($file_name);
- if ($action eq "tree" && $file_name !~ m|/$|) {
- $title .= "/";
- }
- }
- }
- }
- my $content_type;
- # require explicit support from the UA if we are to send the page as
- # 'application/xhtml+xml', otherwise send it as plain old 'text/html'.
- # we have to do this because MSIE sometimes globs '*/*', pretending to
- # support xhtml+xml but choking when it gets what it asked for.
- if (defined $cgi->http('HTTP_ACCEPT') &&
- $cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ &&
- $cgi->Accept('application/xhtml+xml') != 0) {
- $content_type = 'application/xhtml+xml';
- } else {
- $content_type = 'text/html';
- }
- $c->response->content_type($content_type);
-
- my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
-
- $c->stash->{version} = $version;
- $c->stash->{git_version} = $git_version;
- $c->stash->{content_type} = $content_type;
- $c->stash->{mod_perl_version} = $mod_perl_version;
- $c->stash->{title} = $title;
-
- # the stylesheet, favicon etc urls won't work correctly with path_info
- # unless we set the appropriate base URL
- $c->stash->{baseurl} = $ENV{PATH_INFO}
- ? q[<base href="].esc_url($base_url).q[" />]
- : '';
-
- # print out each stylesheet that exist, providing backwards capability
- # for those people who defined $stylesheet in a config file
- my $ssfmt = q[<link rel="stylesheet" type="text/css" href="%s"/>];
- $c->stash->{stylesheets} = [defined $stylesheet
- ? sprintf($ssfmt, $stylesheet)
- : map(sprintf($ssfmt, $_), grep $_, @stylesheets)
- ];
-
- $c->stash->{project} = defined $project;
- if (defined $project) {
- my %href_params = get_feed_info();
- if (!exists $href_params{'-title'}) {
- $href_params{'-title'} = 'log';
- }
-
- foreach my $format qw(RSS Atom) {
- my $type = lc($format);
- my %link_attr = (
- '-rel' => 'alternate',
- '-title' => "$project - $href_params{'-title'} - $format feed",
- '-type' => "application/$type+xml"
- );
-
- $href_params{'action'} = $type;
- $link_attr{'-href'} = href(%href_params);
- $c->stash->{lc $format.'_link'} = "<link ".
- "rel=\"$link_attr{'-rel'}\" ".
- "title=\"$link_attr{'-title'}\" ".
- "href=\"$link_attr{'-href'}\" ".
- "type=\"$link_attr{'-type'}\" ".
- "/>\n";
-
- $href_params{'extra_options'} = '--no-merges';
- $link_attr{'-href'} = href(%href_params);
- $link_attr{'-title'} .= ' (no merges)';
- $c->stash->{lc $format.'_link_no_merges'} = "<link ".
- "rel=\"$link_attr{'-rel'}\" ".
- "title=\"$link_attr{'-title'}\" ".
- "href=\"$link_attr{'-href'}\" ".
- "type=\"$link_attr{'-type'}\" ".
- "/>\n";
- }
-
- } else {
- $c->stash->{projects_list} = sprintf('<link rel="alternate" title="%s projects list" '.
- 'href="%s" type="text/plain; charset=utf-8" />'."\n",
- $site_name, href(project=>undef, action=>"project_index"));
- $c->stash->{projects_feed} = sprintf('<link rel="alternate" title="%s projects feeds" '.
- 'href="%s" type="text/x-opml" />'."\n",
- $site_name, href(project=>undef, action=>"opml"));
- }
-
- $c->stash->{favicon} = defined $favicon
- ? qq(<link rel="shortcut icon" href="$favicon" type="image/png" />)
- : '';
-
- # </head><body>
-
- $c->stash->{site_header} = -f $site_header
- ? insert_file($site_header)
- : '';
-
- $c->stash->{logo}
- = $cgi->a({-href => esc_url($logo_url),
- -title => $logo_label},
- qq(<img src="$logo" width="72" height="27" alt="git" class="logo"/>));
- $c->stash->{home_link} = $cgi->a({-href => esc_url($home_link)}, $home_link_str);
-
- if(defined $project) {
- $c->stash->{summary} = $cgi->a({-href => href(action=>"summary")}, esc_html($project));
- $c->stash->{action} = $action;
- }
-
- my $have_search = $c->stash->{have_search} = gitweb_check_feature('search');
- if (defined $project && $have_search) {
- if (!defined $searchtext) {
- $searchtext = "";
- }
- my $search_hash;
- if (defined $hash_base) {
- $search_hash = $hash_base;
- } elsif (defined $hash) {
- $search_hash = $hash;
- } else {
- $search_hash = "HEAD";
- }
- my $action = $my_uri;
- my $use_pathinfo = gitweb_check_feature('pathinfo');
- if ($use_pathinfo) {
- $action .= "/".esc_url($project);
- }
- # This could be done better, but meh.
- $c->stash->{search_form} = $cgi->startform(-method => "get", -action => $action) .
- (!$use_pathinfo &&
- $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") .
- $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" .
- $cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" .
- $cgi->popup_menu(-name => 'st', -default => 'commit',
- -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
- $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
- " search:\n".
- $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
- "<span title=\"Extended regular expression\">" .
- $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
- -checked => $search_use_regexp) .
- "</span>" .
- $cgi->end_form() . "\n";
- }
-}
-
-sub git_footer_html {
- my $feed_class = 'rss_logo';
-
- if (defined $project) {
- my $descr = git_get_project_description($project);
- $c->stash->{project_description} = defined $descr
- ? esc_html($descr)
- : '';
-
- my %href_params = get_feed_info();
- if (!%href_params) {
- $feed_class .= ' generic';
- }
- $href_params{'-title'} ||= 'log';
-
- foreach my $format qw(RSS Atom) {
- $href_params{'action'} = lc($format);
- $c->stash->{lc $format.'_feed'} = $cgi->a({-href => href(%href_params),
- -title => "$href_params{'-title'} $format feed",
- -class => $feed_class}, $format);
- }
-
- } else {
- $c->stash->{opml_feed} = $cgi->a({-href => href(project=>undef, action=>"opml"),
- -class => $feed_class}, "OPML");
- $c->stash->{index_feed} = $cgi->a({-href => href(project=>undef, action=>"project_index"),
- -class => $feed_class}, "TXT");
- }
-
- $c->stash->{site_footer} = -f $site_footer
- ? insert_file($site_footer)
- : '';
-}
-
# die_error(<http_status_code>, <error_message>)
# Example: die_error(404, 'Hash not found')
# By convention, use the following status codes (as defined in RFC 2616):
<br />
</div>
EOF
- die bless {};
+ die bless { $status => $http_responses{$status}, err => $error };
}
## ----------------------------------------------------------------------
"</tr>\n";
}
my $alternate = 1;
- my $tagfilter = $cgi->param('by_tag');
+ my $tagfilter = $c->req->param('by_tag');
for (my $i = $from; $i <= $to; $i++) {
my $pr = $projects[$i];
## ......................................................................
## feeds (RSS, Atom; OPML)
+# XXX This does header stuff which may not play nice with Catalyst, so likely
+# broken in some/many ways.
sub git_feed {
my $format = shift || 'atom';
my $have_blame = gitweb_check_feature('blame');
return if ($cgi->request_method() eq 'HEAD');
# header variables
- my $title = "$site_name - $project/$action";
+ my $title = $c->config->{sitename} . " - $project/$action";
my $feed_type = 'log';
if (defined $hash) {
$title .= " - '$hash'";
"<language>en</language>\n" .
# project owner is responsible for 'editorial' content
"<managingEditor>$owner</managingEditor>\n";
- if (defined $logo || defined $favicon) {
+ if ($c->config->{logo} || $c->config->{favicon}) {
# prefer the logo to the favicon, since RSS
# doesn't allow both
- my $img = esc_url($logo || $favicon);
+ my $img = esc_url($c->config->{logo} || $c->config->{favicon});
print "<image>\n" .
"<url>$img</url>\n" .
"<title>$title</title>\n" .
"<id>" . href(-full=>1) . "</id>\n" .
# use project owner for feed author
"<author><name>$owner</name></author>\n";
- if (defined $favicon) {
- print "<icon>" . esc_url($favicon) . "</icon>\n";
+ if ($c->config->{favicon}) {
+ print "<icon>" . esc_url($c->config->{favicon}) . "</icon>\n";
}
if (defined $logo_url) {
# not twice as wide as tall: 72 x 27 pixels
- print "<logo>" . esc_url($logo) . "</logo>\n";
+ print "<logo>" . esc_url($c->config->{logo}) . "</logo>\n";
}
if (! %latest_date) {
# dummy date to keep the feed valid until commits trickle in:
-charset => 'utf-8',
-content_disposition => 'inline; filename="opml.xml"');
+ my $sitename = $c->config->{sitename};
print <<XML;
<?xml version="1.0" encoding="utf-8"?>
<opml version="1.0">
<head>
- <title>$site_name OPML Export</title>
+ <title>$sitename OPML Export</title>
</head>
<body>
<outline text="git RSS feeds">