aboutsummaryrefslogtreecommitdiff
path: root/gitweb
diff options
context:
space:
mode:
Diffstat (limited to 'gitweb')
-rw-r--r--gitweb/INSTALL33
-rw-r--r--gitweb/Makefile60
-rw-r--r--gitweb/README14
-rwxr-xr-xgitweb/gitweb.perl579
-rw-r--r--gitweb/static/git-favicon.png (renamed from gitweb/git-favicon.png)bin115 -> 115 bytes
-rw-r--r--gitweb/static/git-logo.png (renamed from gitweb/git-logo.png)bin207 -> 207 bytes
-rw-r--r--gitweb/static/gitweb.css (renamed from gitweb/gitweb.css)18
-rw-r--r--gitweb/static/gitweb.js (renamed from gitweb/gitweb.js)0
8 files changed, 489 insertions, 215 deletions
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index cbdc13647..823053173 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -2,12 +2,13 @@ GIT web Interface (gitweb) Installation
=======================================
First you have to generate gitweb.cgi from gitweb.perl using
-"make gitweb", then copy appropriate files (gitweb.cgi, gitweb.js,
-gitweb.css, git-logo.png and git-favicon.png) to their destination.
-For example if git was (or is) installed with /usr prefix, you can do
+"make gitweb", then "make install-gitweb" appropriate files
+(gitweb.cgi, gitweb.js, gitweb.css, git-logo.png and git-favicon.png)
+to their destination. For example if git was (or is) installed with
+/usr prefix and gitwebdir is /var/www/cgi-bin, you can do
- $ make prefix=/usr gitweb ;# as yourself
- # cp gitweb/git* /var/www/cgi-bin/ ;# as root
+ $ make prefix=/usr gitweb ;# as yourself
+ # make gitwebdir=/var/www/cgi-bin install-gitweb ;# as root
Alternatively you can use autoconf generated ./configure script to
set up path to git binaries (via config.mak.autogen), so you can write
@@ -16,7 +17,8 @@ instead
$ make configure ;# as yourself
$ ./configure --prefix=/usr ;# as yourself
$ make gitweb ;# as yourself
- # cp gitweb/git* /var/www/cgi-bin/ ;# as root
+ # make gitwebdir=/var/www/cgi-bin \
+ install-gitweb ;# as root
The above example assumes that your web server is configured to run
[executable] files in /var/www/cgi-bin/ as server scripts (as CGI
@@ -74,21 +76,20 @@ file for gitweb (in gitweb/README).
Build example
~~~~~~~~~~~~~
-- To install gitweb to /var/www/cgi-bin/gitweb/ when git wrapper
- is installed at /usr/local/bin/git and the repositories (projects)
- we want to display are under /home/local/scm, you can do
+- To install gitweb to /var/www/cgi-bin/gitweb/, when git wrapper
+ is installed at /usr/local/bin/git, the repositories (projects)
+ we want to display are under /home/local/scm, and you do not use
+ minifiers, you can do
make GITWEB_PROJECTROOT="/home/local/scm" \
- GITWEB_JS="/gitweb/gitweb.js" \
- GITWEB_CSS="/gitweb/gitweb.css" \
- GITWEB_LOGO="/gitweb/git-logo.png" \
- GITWEB_FAVICON="/gitweb/git-favicon.png" \
+ GITWEB_JS="gitweb/static/gitweb.js" \
+ GITWEB_CSS="gitweb/static/gitweb.css" \
+ GITWEB_LOGO="gitweb/static/git-logo.png" \
+ GITWEB_FAVICON="gitweb/static/git-favicon.png" \
bindir=/usr/local/bin \
gitweb
- cp -fv ~/git/gitweb/gitweb.{cgi,js,css} \
- ~/git/gitweb/git-{favicon,logo}.png \
- /var/www/cgi-bin/gitweb/
+ make gitwebdir=/var/www/cgi-bin/gitweb install-gitweb
Gitweb config file
diff --git a/gitweb/Makefile b/gitweb/Makefile
index e7dd25277..2fb7c2d77 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -4,15 +4,18 @@ all::
# Define V=1 to have a more verbose compile.
#
# Define JSMIN to point to JavaScript minifier that functions as
-# a filter to have gitweb.js minified.
+# a filter to have static/gitweb.js minified.
#
# Define CSSMIN to point to a CSS minifier in order to generate a minified
-# version of gitweb.css
+# version of static/gitweb.css
#
prefix ?= $(HOME)
bindir ?= $(prefix)/bin
+gitwebdir ?= /var/www/cgi-bin
+
RM ?= rm -f
+INSTALL ?= install
# default configuration for gitweb
GITWEB_CONFIG = gitweb_config.perl
@@ -26,10 +29,10 @@ GITWEB_STRICT_EXPORT =
GITWEB_BASE_URL =
GITWEB_LIST =
GITWEB_HOMETEXT = indextext.html
-GITWEB_CSS = gitweb.css
-GITWEB_LOGO = git-logo.png
-GITWEB_FAVICON = git-favicon.png
-GITWEB_JS = gitweb.js
+GITWEB_CSS = static/gitweb.css
+GITWEB_LOGO = static/git-logo.png
+GITWEB_FAVICON = static/git-favicon.png
+GITWEB_JS = static/gitweb.js
GITWEB_SITE_HEADER =
GITWEB_SITE_FOOTER =
@@ -49,9 +52,12 @@ SHELL_PATH ?= $(SHELL)
PERL_PATH ?= /usr/bin/perl
# Shell quote;
-bindir_SQ = $(subst ','\'',$(bindir)) #'
-SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) #'
-PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) #'
+bindir_SQ = $(subst ','\'',$(bindir))#'
+gitwebdir_SQ = $(subst ','\'',$(gitwebdir))#'
+gitwebstaticdir_SQ = $(subst ','\'',$(gitwebdir)/static)#'
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))#'
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))#'
+DESTDIR_SQ = $(subst ','\'',$(DESTDIR))#'
# Quiet generation (unless V=1)
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
@@ -80,20 +86,30 @@ endif
all:: gitweb.cgi
+GITWEB_PROGRAMS = gitweb.cgi
+
ifdef JSMIN
-GITWEB_JS = gitweb.min.js
-all:: gitweb.min.js
-gitweb.min.js: gitweb.js GITWEB-BUILD-OPTIONS
+GITWEB_FILES += static/gitweb.min.js
+GITWEB_JS = static/gitweb.min.js
+all:: static/gitweb.min.js
+static/gitweb.min.js: static/gitweb.js GITWEB-BUILD-OPTIONS
$(QUIET_GEN)$(JSMIN) <$< >$@
+else
+GITWEB_FILES += static/gitweb.js
endif
ifdef CSSMIN
-GITWEB_CSS = gitweb.min.css
-all:: gitweb.min.css
-gitweb.min.css: gitweb.css GITWEB-BUILD-OPTIONS
+GITWEB_FILES += static/gitweb.min.css
+GITWEB_CSS = static/gitweb.min.css
+all:: static/gitweb.min.css
+static/gitweb.min.css: static/gitweb.css GITWEB-BUILD-OPTIONS
$(QUIET_GEN)$(CSSMIN) <$< >$@
+else
+GITWEB_FILES += static/gitweb.css
endif
+GITWEB_FILES += static/git-logo.png static/git-favicon.png
+
GITWEB_REPLACE = \
-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
-e 's|++GIT_BINDIR++|$(bindir)|g' \
@@ -127,8 +143,18 @@ gitweb.cgi: gitweb.perl GITWEB-BUILD-OPTIONS
chmod +x $@+ && \
mv $@+ $@
+### Installation rules
+
+install: all
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitwebdir_SQ)'
+ $(INSTALL) -m 755 $(GITWEB_PROGRAMS) '$(DESTDIR_SQ)$(gitwebdir_SQ)'
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)'
+ $(INSTALL) -m 644 $(GITWEB_FILES) '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)'
+
+### Cleaning rules
+
clean:
- $(RM) gitweb.cgi gitweb.min.js gitweb.min.css GITWEB-BUILD-OPTIONS
+ $(RM) gitweb.cgi static/gitweb.min.js static/gitweb.min.css GITWEB-BUILD-OPTIONS
-.PHONY: all clean .FORCE-GIT-VERSION-FILE FORCE
+.PHONY: all clean install .FORCE-GIT-VERSION-FILE FORCE
diff --git a/gitweb/README b/gitweb/README
index 71742b335..0e19be8d2 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -80,24 +80,26 @@ You can specify the following configuration variables when building GIT:
Points to the location where you put gitweb.css on your web server
(or to be more generic, the URI of gitweb stylesheet). Relative to the
base URI of gitweb. Note that you can setup multiple stylesheets from
- the gitweb config file. [Default: gitweb.css (or gitweb.min.css if the
- CSSMIN variable is defined / CSS minifier is used)]
+ the gitweb config file. [Default: static/gitweb.css (or
+ static/gitweb.min.css if the CSSMIN variable is defined / CSS minifier
+ is used)]
* GITWEB_LOGO
Points to the location where you put git-logo.png on your web server
(or to be more generic URI of logo, 72x27 size, displayed in top right
corner of each gitweb page, and used as logo for Atom feed). Relative
- to base URI of gitweb. [Default: git-logo.png]
+ to base URI of gitweb. [Default: static/git-logo.png]
* GITWEB_FAVICON
Points to the location where you put git-favicon.png on your web server
(or to be more generic URI of favicon, assumed to be image/png type;
web browsers that support favicons (website icons) may display them
in the browser's URL bar and next to site name in bookmarks). Relative
- to base URI of gitweb. [Default: git-favicon.png]
+ to base URI of gitweb. [Default: static/git-favicon.png]
* GITWEB_JS
Points to the localtion where you put gitweb.js on your web server
(or to be more generic URI of JavaScript code used by gitweb).
- Relative to base URI of gitweb. [Default: gitweb.js (or gitweb.min.js
- if JSMIN build variable is defined / JavaScript minifier is used)]
+ Relative to base URI of gitweb. [Default: static/gitweb.js (or
+ static/gitweb.min.js if JSMIN build variable is defined / JavaScript
+ minifier is used)]
* GITWEB_CONFIG
This Perl file will be loaded using 'do' and can be used to override any
of the options above as well as some other options -- see the "Runtime
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a97ce0344..cedc35731 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -11,7 +11,7 @@ use strict;
use warnings;
use CGI qw(:standard :escapeHTML -nosticky);
use CGI::Util qw(unescape);
-use CGI::Carp qw(fatalsToBrowser);
+use CGI::Carp qw(fatalsToBrowser set_message);
use Encode;
use Fcntl ':mode';
use File::Find qw();
@@ -28,34 +28,42 @@ BEGIN {
CGI->compile() if $ENV{'MOD_PERL'};
}
-our $cgi = new CGI;
our $version = "++GIT_VERSION++";
-our $my_url = $cgi->url();
-our $my_uri = $cgi->url(-absolute => 1);
-# Base URL for relative URLs in gitweb ($logo, $favicon, ...),
-# needed and used only for URLs with nonempty PATH_INFO
-our $base_url = $my_url;
+our ($my_url, $my_uri, $base_url, $path_info, $home_link);
+sub evaluate_uri {
+ our $cgi;
-# When the script is used as DirectoryIndex, the URL does not contain the name
-# of the script file itself, and $cgi->url() fails to strip PATH_INFO, so we
-# have to do it ourselves. We make $path_info global because it's also used
-# later on.
-#
-# Another issue with the script being the DirectoryIndex is that the resulting
-# $my_url data is not the full script URL: this is good, because we want
-# generated links to keep implying the script name if it wasn't explicitly
-# indicated in the URL we're handling, but it means that $my_url cannot be used
-# as base URL.
-# Therefore, if we needed to strip PATH_INFO, then we know that we have
-# to build the base URL ourselves:
-our $path_info = $ENV{"PATH_INFO"};
-if ($path_info) {
- if ($my_url =~ s,\Q$path_info\E$,, &&
- $my_uri =~ s,\Q$path_info\E$,, &&
- defined $ENV{'SCRIPT_NAME'}) {
- $base_url = $cgi->url(-base => 1) . $ENV{'SCRIPT_NAME'};
+ our $my_url = $cgi->url();
+ our $my_uri = $cgi->url(-absolute => 1);
+
+ # Base URL for relative URLs in gitweb ($logo, $favicon, ...),
+ # needed and used only for URLs with nonempty PATH_INFO
+ our $base_url = $my_url;
+
+ # When the script is used as DirectoryIndex, the URL does not contain the name
+ # of the script file itself, and $cgi->url() fails to strip PATH_INFO, so we
+ # have to do it ourselves. We make $path_info global because it's also used
+ # later on.
+ #
+ # Another issue with the script being the DirectoryIndex is that the resulting
+ # $my_url data is not the full script URL: this is good, because we want
+ # generated links to keep implying the script name if it wasn't explicitly
+ # indicated in the URL we're handling, but it means that $my_url cannot be used
+ # as base URL.
+ # Therefore, if we needed to strip PATH_INFO, then we know that we have
+ # to build the base URL ourselves:
+ our $path_info = $ENV{"PATH_INFO"};
+ if ($path_info) {
+ if ($my_url =~ s,\Q$path_info\E$,, &&
+ $my_uri =~ s,\Q$path_info\E$,, &&
+ defined $ENV{'SCRIPT_NAME'}) {
+ $base_url = $cgi->url(-base => 1) . $ENV{'SCRIPT_NAME'};
+ }
}
+
+ # target of the home link on top of all pages
+ our $home_link = $my_uri || "/";
}
# core git executable to use
@@ -70,9 +78,6 @@ our $projectroot = "++GITWEB_PROJECTROOT++";
# the number is relative to the projectroot
our $project_maxdepth = "++GITWEB_PROJECT_MAXDEPTH++";
-# 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 = "++GITWEB_HOME_LINK_STR++";
@@ -445,6 +450,19 @@ our %feature = (
'javascript-actions' => {
'override' => 0,
'default' => [0]},
+
+ # Syntax highlighting support. This is based on Daniel Svensson's
+ # and Sham Chukoury's work in gitweb-xmms2.git.
+ # It requires the 'highlight' program present in $PATH,
+ # and therefore is disabled by default.
+
+ # To enable system wide have in $GITWEB_CONFIG
+ # $feature{'highlight'}{'default'} = [1];
+
+ 'highlight' => {
+ 'sub' => sub { feature_bool('highlight', @_) },
+ 'override' => 0,
+ 'default' => [0]},
);
sub gitweb_get_feature {
@@ -553,15 +571,18 @@ sub filter_snapshot_fmts {
!$known_snapshot_formats{$_}{'disabled'}} @fmts;
}
-our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
-our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
-# die if there are errors parsing config file
-if (-e $GITWEB_CONFIG) {
- do $GITWEB_CONFIG;
- die $@ if $@;
-} elsif (-e $GITWEB_CONFIG_SYSTEM) {
- do $GITWEB_CONFIG_SYSTEM;
- die $@ if $@;
+our ($GITWEB_CONFIG, $GITWEB_CONFIG_SYSTEM);
+sub evaluate_gitweb_config {
+ our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
+ our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
+ # die if there are errors parsing config file
+ if (-e $GITWEB_CONFIG) {
+ do $GITWEB_CONFIG;
+ die $@ if $@;
+ } elsif (-e $GITWEB_CONFIG_SYSTEM) {
+ do $GITWEB_CONFIG_SYSTEM;
+ die $@ if $@;
+ }
}
# Get loadavg of system, to compare against $maxload.
@@ -587,13 +608,16 @@ sub get_loadavg {
}
# version of the core git binary
-our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
-$number_of_git_cmds++;
-
-$projects_list ||= $projectroot;
+our $git_version;
+sub evaluate_git_version {
+ our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
+ $number_of_git_cmds++;
+}
-if (defined $maxload && get_loadavg() > $maxload) {
- die_error(503, "The load average on the server is too high");
+sub check_loadavg {
+ if (defined $maxload && get_loadavg() > $maxload) {
+ die_error(503, "The load average on the server is too high");
+ }
}
# ======================================================================
@@ -680,11 +704,15 @@ our %allowed_options = (
# should be single values, but opt can be an array. We should probably
# build an array of parameters that can be multi-valued, but since for the time
# 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) ];
- } else {
- $input_params{$name} = $cgi->param($symbol);
+sub evaluate_query_params {
+ our $cgi;
+
+ while (my ($name, $symbol) = each %cgi_param_mapping) {
+ if ($symbol eq 'opt') {
+ $input_params{$name} = [ $cgi->param($symbol) ];
+ } else {
+ $input_params{$name} = $cgi->param($symbol);
+ }
}
}
@@ -831,152 +859,277 @@ sub evaluate_path_info {
}
}
}
-evaluate_path_info();
-our $action = $input_params{'action'};
-if (defined $action) {
- if (!validate_action($action)) {
- die_error(400, "Invalid action parameter");
+our ($action, $project, $file_name, $file_parent, $hash, $hash_parent, $hash_base,
+ $hash_parent_base, @extra_options, $page, $searchtype, $search_use_regexp,
+ $searchtext, $search_regexp);
+sub evaluate_and_validate_params {
+ our $action = $input_params{'action'};
+ if (defined $action) {
+ if (!validate_action($action)) {
+ die_error(400, "Invalid action parameter");
+ }
}
-}
-# parameters which are pathnames
-our $project = $input_params{'project'};
-if (defined $project) {
- if (!validate_project($project)) {
- undef $project;
- die_error(404, "No such project");
+ # parameters which are pathnames
+ our $project = $input_params{'project'};
+ if (defined $project) {
+ if (!validate_project($project)) {
+ undef $project;
+ die_error(404, "No such project");
+ }
}
-}
-our $file_name = $input_params{'file_name'};
-if (defined $file_name) {
- if (!validate_pathname($file_name)) {
- die_error(400, "Invalid file parameter");
+ our $file_name = $input_params{'file_name'};
+ if (defined $file_name) {
+ if (!validate_pathname($file_name)) {
+ die_error(400, "Invalid file parameter");
+ }
}
-}
-our $file_parent = $input_params{'file_parent'};
-if (defined $file_parent) {
- if (!validate_pathname($file_parent)) {
- die_error(400, "Invalid file parent parameter");
+ our $file_parent = $input_params{'file_parent'};
+ if (defined $file_parent) {
+ if (!validate_pathname($file_parent)) {
+ die_error(400, "Invalid file parent parameter");
+ }
}
-}
-# parameters which are refnames
-our $hash = $input_params{'hash'};
-if (defined $hash) {
- if (!validate_refname($hash)) {
- die_error(400, "Invalid hash parameter");
+ # parameters which are refnames
+ our $hash = $input_params{'hash'};
+ if (defined $hash) {
+ if (!validate_refname($hash)) {
+ die_error(400, "Invalid hash parameter");
+ }
}
-}
-our $hash_parent = $input_params{'hash_parent'};
-if (defined $hash_parent) {
- if (!validate_refname($hash_parent)) {
- die_error(400, "Invalid hash parent parameter");
+ our $hash_parent = $input_params{'hash_parent'};
+ if (defined $hash_parent) {
+ if (!validate_refname($hash_parent)) {
+ die_error(400, "Invalid hash parent parameter");
+ }
}
-}
-our $hash_base = $input_params{'hash_base'};
-if (defined $hash_base) {
- if (!validate_refname($hash_base)) {
- die_error(400, "Invalid hash base parameter");
+ our $hash_base = $input_params{'hash_base'};
+ if (defined $hash_base) {
+ if (!validate_refname($hash_base)) {
+ die_error(400, "Invalid hash base parameter");
+ }
}
-}
-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
-# is not set
-foreach my $opt (@extra_options) {
- if (not exists $allowed_options{$opt}) {
- die_error(400, "Invalid option parameter");
- }
- if (not grep(/^$action$/, @{$allowed_options{$opt}})) {
- die_error(400, "Invalid option parameter for this action");
+ 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
+ # is not set
+ foreach my $opt (@extra_options) {
+ if (not exists $allowed_options{$opt}) {
+ die_error(400, "Invalid option parameter");
+ }
+ if (not grep(/^$action$/, @{$allowed_options{$opt}})) {
+ die_error(400, "Invalid option parameter for this action");
+ }
}
-}
-our $hash_parent_base = $input_params{'hash_parent_base'};
-if (defined $hash_parent_base) {
- if (!validate_refname($hash_parent_base)) {
- die_error(400, "Invalid hash parent base parameter");
+ our $hash_parent_base = $input_params{'hash_parent_base'};
+ if (defined $hash_parent_base) {
+ if (!validate_refname($hash_parent_base)) {
+ die_error(400, "Invalid hash parent base parameter");
+ }
}
-}
-# other parameters
-our $page = $input_params{'page'};
-if (defined $page) {
- if ($page =~ m/[^0-9]/) {
- die_error(400, "Invalid page parameter");
+ # other parameters
+ our $page = $input_params{'page'};
+ if (defined $page) {
+ if ($page =~ m/[^0-9]/) {
+ die_error(400, "Invalid page parameter");
+ }
}
-}
-our $searchtype = $input_params{'searchtype'};
-if (defined $searchtype) {
- if ($searchtype =~ m/[^a-z]/) {
- die_error(400, "Invalid searchtype parameter");
+ our $searchtype = $input_params{'searchtype'};
+ if (defined $searchtype) {
+ if ($searchtype =~ m/[^a-z]/) {
+ die_error(400, "Invalid searchtype parameter");
+ }
}
-}
-our $search_use_regexp = $input_params{'search_use_regexp'};
+ our $search_use_regexp = $input_params{'search_use_regexp'};
-our $searchtext = $input_params{'searchtext'};
-our $search_regexp;
-if (defined $searchtext) {
- if (length($searchtext) < 2) {
- die_error(403, "At least two characters are required for search parameter");
+ our $searchtext = $input_params{'searchtext'};
+ our $search_regexp;
+ if (defined $searchtext) {
+ if (length($searchtext) < 2) {
+ die_error(403, "At least two characters are required for search parameter");
+ }
+ $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext;
}
- $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext;
}
# path to the current git repository
our $git_dir;
-$git_dir = "$projectroot/$project" if $project;
-
-# list of supported snapshot formats
-our @snapshot_fmts = gitweb_get_feature('snapshot');
-@snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts);
-
-# check that the avatar feature is set to a known provider name,
-# and for each provider check if the dependencies are satisfied.
-# if the provider name is invalid or the dependencies are not met,
-# reset $git_avatar to the empty string.
-our ($git_avatar) = gitweb_get_feature('avatar');
-if ($git_avatar eq 'gravatar') {
- $git_avatar = '' unless (eval { require Digest::MD5; 1; });
-} elsif ($git_avatar eq 'picon') {
- # no dependencies
-} else {
- $git_avatar = '';
+sub evaluate_git_dir {
+ our $git_dir = "$projectroot/$project" if $project;
}
-# dispatch
-if (!defined $action) {
- if (defined $hash) {
- $action = git_get_type($hash);
- } elsif (defined $hash_base && defined $file_name) {
- $action = git_get_type("$hash_base:$file_name");
- } elsif (defined $project) {
- $action = 'summary';
+our (@snapshot_fmts, $git_avatar);
+sub configure_gitweb_features {
+ # list of supported snapshot formats
+ our @snapshot_fmts = gitweb_get_feature('snapshot');
+ @snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts);
+
+ # check that the avatar feature is set to a known provider name,
+ # and for each provider check if the dependencies are satisfied.
+ # if the provider name is invalid or the dependencies are not met,
+ # reset $git_avatar to the empty string.
+ our ($git_avatar) = gitweb_get_feature('avatar');
+ if ($git_avatar eq 'gravatar') {
+ $git_avatar = '' unless (eval { require Digest::MD5; 1; });
+ } elsif ($git_avatar eq 'picon') {
+ # no dependencies
} else {
- $action = 'project_list';
+ $git_avatar = '';
+ }
+}
+
+# custom error handler: 'die <message>' is Internal Server Error
+sub handle_errors_html {
+ my $msg = shift; # it is already HTML escaped
+
+ # to avoid infinite loop where error occurs in die_error,
+ # change handler to default handler, disabling handle_errors_html
+ set_message("Error occured when inside die_error:\n$msg");
+
+ # you cannot jump out of die_error when called as error handler;
+ # the subroutine set via CGI::Carp::set_message is called _after_
+ # HTTP headers are already written, so it cannot write them itself
+ die_error(undef, undef, $msg, -error_handler => 1, -no_http_header => 1);
+}
+set_message(\&handle_errors_html);
+
+# dispatch
+sub dispatch {
+ if (!defined $action) {
+ if (defined $hash) {
+ $action = git_get_type($hash);
+ } elsif (defined $hash_base && defined $file_name) {
+ $action = git_get_type("$hash_base:$file_name");
+ } elsif (defined $project) {
+ $action = 'summary';
+ } else {
+ $action = 'project_list';
+ }
+ }
+ if (!defined($actions{$action})) {
+ die_error(400, "Unknown action");
}
+ if ($action !~ m/^(?:opml|project_list|project_index)$/ &&
+ !$project) {
+ die_error(400, "Project needed");
+ }
+ $actions{$action}->();
+}
+
+sub reset_timer {
+ our $t0 = [Time::HiRes::gettimeofday()]
+ if defined $t0;
+ our $number_of_git_cmds = 0;
+}
+
+sub run_request {
+ reset_timer();
+
+ evaluate_uri();
+ check_loadavg();
+
+ evaluate_query_params();
+ evaluate_path_info();
+ evaluate_and_validate_params();
+ evaluate_git_dir();
+
+ configure_gitweb_features();
+
+ dispatch();
+}
+
+our $is_last_request = sub { 1 };
+our ($pre_dispatch_hook, $post_dispatch_hook, $pre_listen_hook);
+our $CGI = 'CGI';
+our $cgi;
+sub configure_as_fcgi {
+ require CGI::Fast;
+ our $CGI = 'CGI::Fast';
+
+ my $request_number = 0;
+ # let each child service 100 requests
+ our $is_last_request = sub { ++$request_number > 100 };
}
-if (!defined($actions{$action})) {
- die_error(400, "Unknown action");
+sub evaluate_argv {
+ my $script_name = $ENV{'SCRIPT_NAME'} || $ENV{'SCRIPT_FILENAME'} || __FILE__;
+ configure_as_fcgi()
+ if $script_name =~ /\.fcgi$/;
+
+ return unless (@ARGV);
+
+ require Getopt::Long;
+ Getopt::Long::GetOptions(
+ 'fastcgi|fcgi|f' => \&configure_as_fcgi,
+ 'nproc|n=i' => sub {
+ my ($arg, $val) = @_;
+ return unless eval { require FCGI::ProcManager; 1; };
+ my $proc_manager = FCGI::ProcManager->new({
+ n_processes => $val,
+ });
+ our $pre_listen_hook = sub { $proc_manager->pm_manage() };
+ our $pre_dispatch_hook = sub { $proc_manager->pm_pre_dispatch() };
+ our $post_dispatch_hook = sub { $proc_manager->pm_post_dispatch() };
+ },
+ );
}
-if ($action !~ m/^(?:opml|project_list|project_index)$/ &&
- !$project) {
- die_error(400, "Project needed");
+
+sub run {
+ evaluate_argv();
+ evaluate_gitweb_config();
+ evaluate_git_version();
+
+ # $projectroot and $projects_list might be set in gitweb config file
+ $projects_list ||= $projectroot;
+
+ $pre_listen_hook->()
+ if $pre_listen_hook;
+
+ REQUEST:
+ while ($cgi = $CGI->new()) {
+ $pre_dispatch_hook->()
+ if $pre_dispatch_hook;
+
+ run_request();
+
+ $pre_dispatch_hook->()
+ if $post_dispatch_hook;
+
+ last REQUEST if ($is_last_request->());
+ }
+
+ DONE_GITWEB:
+ 1;
+}
+
+run();
+
+if (defined caller) {
+ # wrapped in a subroutine processing requests,
+ # e.g. mod_perl with ModPerl::Registry, or PSGI with Plack::App::WrapCGI
+ return;
+} else {
+ # pure CGI script, serving single request
+ exit;
}
-$actions{$action}->();
-exit;
## ======================================================================
## action links
+# possible values of extra options
+# -full => 0|1 - use absolute/full URL ($my_uri/$my_url as base)
+# -replay => 1 - start from a current view (replay with modifications)
+# -path_info => 0|1 - don't use/use path_info URL (if possible)
sub href {
my %params = @_;
# default is to use -absolute url() i.e. $my_uri
@@ -993,7 +1146,8 @@ sub href {
}
my $use_pathinfo = gitweb_check_feature('pathinfo');
- if ($use_pathinfo and defined $params{'project'}) {
+ if (defined $params{'project'} &&
+ (exists $params{-path_info} ? $params{-path_info} : $use_pathinfo)) {
# try to put as many parameters as possible in PATH_INFO:
# - project name
# - action
@@ -2419,6 +2573,9 @@ sub git_get_projects_list {
follow_skip => 2, # ignore duplicates
dangling_symlinks => 0, # ignore dangling symlinks, silently
wanted => sub {
+ # global variables
+ our $project_maxdepth;
+ our $projectroot;
# skip project-list toplevel, if we get it.
return if (m!^[/.]$!);
# only directories can be git repositories
@@ -3154,26 +3311,88 @@ sub blob_contenttype {
return $type;
}
+# guess file syntax for syntax highlighting; return undef if no highlighting
+# the name of syntax can (in the future) depend on syntax highlighter used
+sub guess_file_syntax {
+ my ($highlight, $mimetype, $file_name) = @_;
+ return undef unless ($highlight && defined $file_name);
+
+ # configuration for 'highlight' (http://www.andre-simon.de/)
+ # match by basename
+ my %highlight_basename = (
+ #'Program' => 'py',
+ #'Library' => 'py',
+ 'SConstruct' => 'py', # SCons equivalent of Makefile
+ 'Makefile' => 'make',
+ );
+ # match by extension
+ my %highlight_ext = (
+ # main extensions, defining name of syntax;
+ # see files in /usr/share/highlight/langDefs/ directory
+ map { $_ => $_ }
+ qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl),
+ # alternate extensions, see /etc/highlight/filetypes.conf
+ 'h' => 'c',
+ map { $_ => 'cpp' } qw(cxx c++ cc),
+ map { $_ => 'php' } qw(php3 php4),
+ map { $_ => 'pl' } qw(perl pm), # perhaps also 'cgi'
+ 'mak' => 'make',
+ map { $_ => 'xml' } qw(xhtml html htm),
+ );
+
+ my $basename = basename($file_name, '.in');
+ return $highlight_basename{$basename}
+ if exists $highlight_basename{$basename};
+
+ $basename =~ /\.([^.]*)$/;
+ my $ext = $1 or return undef;
+ return $highlight_ext{$ext}
+ if exists $highlight_ext{$ext};
+
+ return undef;
+}
+
+# run highlighter and return FD of its output,
+# or return original FD if no highlighting
+sub run_highlighter {
+ my ($fd, $highlight, $syntax) = @_;
+ return $fd unless ($highlight && defined $syntax);
+
+ close $fd
+ or die_error(404, "Reading blob failed");
+ open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ".
+ "highlight --xhtml --fragment --syntax $syntax |"
+ or die_error(500, "Couldn't open file or run syntax highlighter");
+ return $fd;
+}
+
## ======================================================================
## functions printing HTML: header, footer, error page
+sub get_page_title {
+ my $title = to_utf8($site_name);
+
+ return $title unless (defined $project);
+ $title .= " - " . to_utf8($project);
+
+ return $title unless (defined $action);
+ $title .= "/$action"; # $action is US-ASCII (7bit ASCII)
+
+ return $title unless (defined $file_name);
+ $title .= " - " . esc_path($file_name);
+ if ($action eq "tree" && $file_name !~ m|/$|) {
+ $title .= "/";
+ }
+
+ return $title;
+}
+
sub git_header_html {
my $status = shift || "200 OK";
my $expires = shift;
+ my %opts = @_;
- 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 $title = get_page_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'.
@@ -3187,7 +3406,8 @@ sub git_header_html {
$content_type = 'text/html';
}
print $cgi->header(-type=>$content_type, -charset => 'utf-8',
- -status=> $status, -expires => $expires);
+ -status=> $status, -expires => $expires)
+ unless ($opts{'-no_http_header'});
my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
print <<EOF;
<?xml version="1.0" encoding="utf-8"?>
@@ -3404,6 +3624,7 @@ sub die_error {
my $status = shift || 500;
my $error = esc_html(shift) || "Internal Server Error";
my $extra = shift;
+ my %opts = @_;
my %http_responses = (
400 => '400 Bad Request',
@@ -3412,7 +3633,7 @@ sub die_error {
500 => '500 Internal Server Error',
503 => '503 Service Unavailable',
);
- git_header_html($http_responses{$status});
+ git_header_html($http_responses{$status}, undef, %opts);
print <<EOF;
<div class="page_body">
<br /><br />
@@ -3426,7 +3647,8 @@ EOF
print "</div>\n";
git_footer_html();
- exit;
+ goto DONE_GITWEB
+ unless ($opts{'-error_handler'});
}
## ----------------------------------------------------------------------
@@ -5345,6 +5567,7 @@ sub git_blob {
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
or die_error(500, "Couldn't cat $file_name, $hash");
my $mimetype = blob_mimetype($fd, $file_name);
+ # use 'blob_plain' (aka 'raw') view for files that cannot be displayed
if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)! && -B $fd) {
close $fd;
return git_blob_plain($mimetype);
@@ -5352,6 +5575,11 @@ sub git_blob {
# we can have blame only for text/* mimetype
$have_blame &&= ($mimetype =~ m!^text/!);
+ my $highlight = gitweb_check_feature('highlight');
+ my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
+ $fd = run_highlighter($fd, $highlight, $syntax)
+ if $syntax;
+
git_header_html(undef, $expires);
my $formats_nav = '';
if (defined $hash_base && (my %co = parse_commit($hash_base))) {
@@ -5401,9 +5629,8 @@ sub git_blob {
chomp $line;
$nr++;
$line = untabify($line);
- printf "<div class=\"pre\"><a id=\"l%i\" href=\"" . href(-replay => 1)
- . "#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
- $nr, $nr, $nr, esc_html($line, -nbsp=>1);
+ printf qq!<div class="pre"><a id="l%i" href="%s#l%i" class="linenr">%4i</a> %s</div>\n!,
+ $nr, href(-replay => 1), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1);
}
}
close $fd
@@ -6116,8 +6343,8 @@ sub git_commitdiff {
}
push @commit_spec, '--root', $hash;
}
- open $fd, "-|", git_cmd(), "format-patch", '--encoding=utf8',
- '--stdout', @commit_spec
+ open $fd, "-|", git_cmd(), "format-patch", @diff_opts,
+ '--encoding=utf8', '--stdout', @commit_spec
or die_error(500, "Open git-format-patch failed");
} else {
die_error(400, "Unknown commitdiff format");
diff --git a/gitweb/git-favicon.png b/gitweb/static/git-favicon.png
index aae35a70e..aae35a70e 100644
--- a/gitweb/git-favicon.png
+++ b/gitweb/static/git-favicon.png
Binary files differ
diff --git a/gitweb/git-logo.png b/gitweb/static/git-logo.png
index f4ede2e94..f4ede2e94 100644
--- a/gitweb/git-logo.png
+++ b/gitweb/static/git-logo.png
Binary files differ
diff --git a/gitweb/gitweb.css b/gitweb/static/gitweb.css
index 50067f2e0..4132aabcd 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/static/gitweb.css
@@ -572,3 +572,21 @@ span.match {
div.binary {
font-style: italic;
}
+
+/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */
+
+/* Highlighting theme definition: */
+
+.num { color:#2928ff; }
+.esc { color:#ff00ff; }
+.str { color:#ff0000; }
+.dstr { color:#818100; }
+.slc { color:#838183; font-style:italic; }
+.com { color:#838183; font-style:italic; }
+.dir { color:#008200; }
+.sym { color:#000000; }
+.line { color:#555555; }
+.kwa { color:#000000; font-weight:bold; }
+.kwb { color:#830000; }
+.kwc { color:#000000; font-weight:bold; }
+.kwd { color:#010181; }
diff --git a/gitweb/gitweb.js b/gitweb/static/gitweb.js
index 9c66928c4..9c66928c4 100644
--- a/gitweb/gitweb.js
+++ b/gitweb/static/gitweb.js