[RFC/PATCH 0/5] gitweb: Proof of concept of PSGI interface

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[RFC/PATCH 0/5] gitweb: Proof of concept of PSGI interface

Jakub Narębski
The major goal of this series is to make it possible for gitweb to run
as PSGI application, even if non-native (emulated).

PSGI[1][2] is an interface between Perl web applications and web servers.
It is accompanied by Plack, a Perl module and toolkit that contains PSGI
middleware (e.g. for serving static files), helpers (e.g. 'plackup'
command line launcher) and adapters to web servers (e.g. to CGI, FastCGI,
or mod_perl).  PSGI and Plack are inspired by Python's WSGI and Ruby's Rack.

[1]: http://plackperl.org
[2]: http://search.cpan.org/perldoc?PSGI
[3]: http://advent.plackperl.org


First two patches are independent improvements, and make sense even
outside this patch series.  Last patch is making use of gitweb as PSGI
in "git instaweb --httpd=plackup".


Jakub Narebski (5):
  gitweb: Jump do DONE_REQUEST not DONE_GITWEB on error
  gitweb: Prepare for splitting gitweb
  gitweb: Enable running gitweb as PSGI app, via CGI::Emulate::PSGI
  gitweb.psgi: Allow passing arguments to Plack::Runner
  git-instaweb: Use new PSGI interface mode of gitweb

 Documentation/gitweb.txt |   16 +++++++
 git-instaweb.sh          |   33 +++------------
 gitweb/INSTALL           |    3 +
 gitweb/Makefile          |   14 ++++++-
 gitweb/README            |   13 +++++-
 gitweb/gitweb.perl       |   98 +++++++++++++++++++++++++++++++++++++++++++---
 6 files changed, 141 insertions(+), 36 deletions(-)

--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[RFC/PATCH 1/5] gitweb: Jump do DONE_REQUEST not DONE_GITWEB on error

Jakub Narębski
On error (die_error()), instead of ending gitweb process by non-local
jump to DONE_GITWEB label at the end of requests loop in run()
subroutine, just end current request by jumping to DONE_REQUESt at the
end of run_request() subroutine.

This change should improve truly persistent deployment methods,
currently only FastCGI but in the future also PSGI, as an error page
would no longer require reloading whole persistent environment, just
end request.

This would allow to create new deployment mechanisms (for example
PSGI) based on run_request() and not on run().

Note that DONE_REQUEST label is removed because it is no longer used,
and it wouldn't work correctly for PSGI anyway.

Signed-off-by: Jakub Narebski <[hidden email]>
---
Without this we could not write to_psgi_app() in patch 3/5.

This patch has its value independently on PSGI support, though if it
is to be accepted standalone, the commit message would have to be
slighlty edited, so that the last two paragraphs of it read:

 "This would allow to create new deployment mechanisms based on
  run_request() and not on run().

  DONE_REQUEST label is removed because it is no longer used."

 gitweb/gitweb.perl |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e2e6a73..2cca2cd 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1195,6 +1195,10 @@ sub run_request {
  configure_gitweb_features();
 
  dispatch();
+
+
+ DONE_REQUEST:
+ 1;
 }
 
 our $is_last_request = sub { 1 };
@@ -1252,9 +1256,6 @@ sub run {
 
  last REQUEST if ($is_last_request->());
  }
-
- DONE_GITWEB:
- 1;
 }
 
 run();
@@ -4195,7 +4196,7 @@ EOF
  print "</div>\n";
 
  git_footer_html();
- goto DONE_GITWEB
+ goto DONE_REQUEST
  unless ($opts{'-error_handler'});
 }
 
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[RFC/PATCH 2/5] gitweb: Prepare for splitting gitweb

Jakub Narębski
In reply to this post by Jakub Narębski
Prepare gitweb for having been split into modules that are to be
installed alongside gitweb in 'lib/' subdirectory, by adding

  use lib __DIR__.'/lib';

to gitweb.perl (to main gitweb script), and preparing for putting
modules (relative path) in $(GITWEB_MODULES) in gitweb/Makefile.

Signed-off-by: Jakub Narebski <[hidden email]>
---
This patch is the beginning of splitting gitweb (with its 8000+
lines, and more than 240kB) into modules, and is useful independently
of being in this patch series.

Sidenote: it is needed for __DIR__ only here.

 gitweb/Makefile    |   14 +++++++++++++-
 gitweb/gitweb.perl |    8 ++++++++
 2 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/gitweb/Makefile b/gitweb/Makefile
index cd194d0..549e7dc 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -59,6 +59,7 @@ PERL_PATH  ?= /usr/bin/perl
 bindir_SQ = $(subst ','\'',$(bindir))#'
 gitwebdir_SQ = $(subst ','\'',$(gitwebdir))#'
 gitwebstaticdir_SQ = $(subst ','\'',$(gitwebdir)/static)#'
+gitweblibdir_SQ = $(subst ','\'',$(gitwebdir)/lib)#'
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))#'
 PERL_PATH_SQ  = $(subst ','\'',$(PERL_PATH))#'
 DESTDIR_SQ    = $(subst ','\'',$(DESTDIR))#'
@@ -178,12 +179,23 @@ test-installed:
 
 ### Installation rules
 
-install: all
+install: all install-modules
  $(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)'
 
+install-modules:
+ install_dirs="$(sort $(dir $(GITWEB_MODULES)))" && \
+ for dir in $$install_dirs; do \
+ test -d '$(DESTDIR_SQ)$(gitwebdir_SQ)/$$dir' || \
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitwebdir_SQ)/$$dir'; \
+ done
+ gitweb_modules="$(GITWEB_MODULES)" && \
+ for mod in $$gitweb_modules; do \
+ $(INSTALL) -m 644 $$mod '$(DESTDIR_SQ)$(gitwebdir_SQ)/$$(dirname $$mod)'; \
+ done
+
 ### Cleaning rules
 
 clean:
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 2cca2cd..22efec2 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -10,6 +10,14 @@
 use 5.008;
 use strict;
 use warnings;
+
+use File::Spec;
+# __DIR__ is taken from Dir::Self __DIR__ fragment
+sub __DIR__ () {
+ File::Spec->rel2abs(join '', (File::Spec->splitpath(__FILE__))[0, 1]);
+}
+use lib __DIR__ . '/lib';
+
 use CGI qw(:standard :escapeHTML -nosticky);
 use CGI::Util qw(unescape);
 use CGI::Carp qw(fatalsToBrowser set_message);
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[RFC/PATCH 3/5] gitweb: Enable running gitweb as PSGI app, via CGI::Emulate::PSGI

Jakub Narębski
In reply to this post by Jakub Narębski
This commit makes it possible to run gitweb as a PSGI application
(see http://plackperl.org), using any of PSGI web servers.  This
includes ability to run gitweb from command line via Plack::Runner
module; just run "./gitweb.cgi --psgi" and point web browser
to http://0:5000

Gitweb uses CGI mode by default; to trigger PSGI mode one must either
pass `--psgi` or `--plackup` option to gitweb script, or the script
must be run with *.psgi filename (either copy/rename script, or make
symlink ending with *.psgi e.g. gitweb.psgi).

Besides running gitweb itself, converting its run_request() from CGI
to PSGI via CGI::Emulate::PSGI, gitweb as PSGI app also serves static
files: scripts, stylesheets and images via Plack::Middleware::Static.
Currently it assumes that positions and URLs of those assets are left
at their default values, namely that URLs end with "/static/<file>",
and that files can be found in "static/" directory relative to the
gitweb script itself.  This assumption should be relaxed in future.

Currently "git instaweb --httpd=plackup" doesn't (yet!) use this newly
introduced feature: it is left for future commit.

Signed-off-by: Jakub Narebski <[hidden email]>
---
The major part of this series.

"./gitweb.cgi --psgi" runs web server on http://0:5000/

 Documentation/gitweb.txt |   16 +++++++++
 gitweb/INSTALL           |    3 ++
 gitweb/README            |   13 ++++++--
 gitweb/gitweb.perl       |   80 ++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 107 insertions(+), 5 deletions(-)

diff --git a/Documentation/gitweb.txt b/Documentation/gitweb.txt
index 605a085..157903b 100644
--- a/Documentation/gitweb.txt
+++ b/Documentation/gitweb.txt
@@ -473,6 +473,22 @@ With that configuration the full path to browse repositories would be:
 
   http://server/gitweb
 
+As PSGI using plackup
+~~~~~~~~~~~~~~~~~~~~~
+Gitweb can run as PSGI app (via emulation with *CGI::Emulate::PSGI*(3pm)).
+First you need to rename, copy or symlink gitweb.cgi to gitweb.psgi.
+You can run gitweb as a PSGI application from 'plackup' command line
+utility, using any *PSGI*(3) web server (see http://plackperl.org for
+a list), for example:
+
+    $ plackup --server HTTP::Server::Simple --port 8080 \
+      --host 127.0.0.1 gitweb.psgi
+
+With that configuration the full path to browse repositories would be:
+
+  http://127.0.0.1:8080/
+
+See *plackup*(1) manpage for more details.
 
 ADVANCED WEB SERVER SETUP
 -------------------------
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index 6d45406..9f55ab4 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -36,6 +36,9 @@ Requirements
 The following optional Perl modules are required for extra features
  - Digest::MD5 - for gravatar support
  - CGI::Fast and FCGI - for running gitweb as FastCGI script
+ - CGI::Emulate::PSGI, Plack::Builder, Plack::Middleware::Static
+   for running gitweb as PSGI application, and Plack::Runner to
+   make it runnable as a standalone script
  - HTML::TagCloud - for fancy tag cloud in project list view
  - HTTP::Date or Time::ParseDate - to support If-Modified-Since for feeds
 
diff --git a/gitweb/README b/gitweb/README
index 6da4778..a435f9b 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -56,9 +56,16 @@ See also gitweb.conf(5) manpage.
 Web server configuration
 ------------------------
 Gitweb can be run as CGI script, as legacy mod_perl application (using
-ModPerl::Registry), and as FastCGI script.  You can find some simple examples
-in "Example web server configuration" section in INSTALL file for gitweb (in
-gitweb/INSTALL).
+ModPerl::Registry), as FastCGI script, and as PSGI application.  You
+can find some simple examples in "Example web server configuration"
+section in INSTALL file for gitweb (in gitweb/INSTALL).
+
+Note that to run as FastCGI script gitweb must be run with *.fcgi
+extension or with `--fastcgi` / `--fcgi` parameter on command line.
+To run as PSGI application gitweb must be run with *.psgi extension,
+or with `--psgi` / `--plackup` parameter on command line, or from
+PSGI web server which sets 'PLACK_ENV' or 'PLACK_SERVER' environment
+variable.
 
 See "Webserver configuration" and "Advanced web server setup" sections in
 gitweb(1) manpage.
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 22efec2..0dbdd15 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1221,16 +1221,22 @@ sub configure_as_fcgi {
  # let each child service 100 requests
  our $is_last_request = sub { ++$request_number > 100 };
 }
+sub configure_as_psgi {
+ our $CGI = 'PSGI'; # fake
+}
 sub evaluate_argv {
  my $script_name = $ENV{'SCRIPT_NAME'} || $ENV{'SCRIPT_FILENAME'} || __FILE__;
  configure_as_fcgi()
  if $script_name =~ /\.fcgi$/;
+ configure_as_psgi()
+ if $script_name =~ /\.psgi$/;
 
  return unless (@ARGV);
 
  require Getopt::Long;
  Getopt::Long::GetOptions(
  'fastcgi|fcgi|f' => \&configure_as_fcgi,
+ 'psgi|plack'     => \&configure_as_psgi,
  'nproc|n=i' => sub {
  my ($arg, $val) = @_;
  return unless eval { require FCGI::ProcManager; 1; };
@@ -1244,8 +1250,78 @@ sub evaluate_argv {
  );
 }
 
+# it is very similar to run() subroutine, but it would be hard to
+# extract common code; note that $*_hook variables can be set only
+# for FastCGI, so they are absent here
+sub to_psgi_app {
+ require CGI::Emulate::PSGI;
+
+ our $CGI = 'CGI';
+ our $first_request = 1;
+
+ my $app = CGI::Emulate::PSGI->handler(sub {
+ CGI::initialize_globals();
+ our $cgi = CGI->new();
+
+ run_request();
+
+ $first_request = 0;
+ });
+ return $app;
+}
+
+sub build_psgi_app {
+ require Plack::Builder;
+ require Plack::Middleware::Static;
+
+ my $sigchld_mw = sub {
+ my $app = shift;
+ sub {
+ my $env = shift;
+ local $SIG{'CHLD'} = 'DEFAULT';
+ local $SIG{'CLD'}  = 'DEFAULT';
+ $app->($env);
+ };
+ };
+
+ # you're supposed to "add" middleware from outer to inner.
+ # note: Plack::Builder DSL (builder, enable_if, enable) won't work
+ # with "require Plack::Builder" outside BEGIN section.
+ my $app = to_psgi_app();
+ $app = Plack::Middleware::Static->wrap($app,
+ path => qr{(?:^|/)static/.*\.(?:js|css|png)$},
+ root => __DIR__,
+ encoding => 'utf-8', # encoding for 'text/plain' files
+ );
+ $app = $sigchld_mw->($app)
+ if (defined $SIG{'CHLD'} && $SIG{'CHLD'} eq 'IGNORE');
+
+ return $app;
+}
+
+sub run_psgi_app {
+ my $app = build_psgi_app();
+
+ # make it runnable as standalone app,
+ # like it would be run via 'plackup' utility.
+ # PLACK_ENV is set by plackup etc.
+ if ($ENV{'PLACK_ENV'} || $ENV{'PLACK_SERVER'}) {
+ return $app;
+ } else {
+ require Plack::Runner;
+
+ my $runner = Plack::Runner->new();
+ $runner->parse_options(qw(--env deployment),
+                       qw(--host 127.0.0.1));
+ $runner->run($app);
+ }
+}
+
 sub run {
  evaluate_argv();
+ if ($CGI eq 'PSGI' || $ENV{'PLACK_ENV'} || $ENV{'PLACK_SERVER'}) {
+ return run_psgi_app();
+ }
 
  $first_request = 1;
  $pre_listen_hook->()
@@ -1266,12 +1342,12 @@ sub run {
  }
 }
 
-run();
+our $app = run();
 
 if (defined caller) {
  # wrapped in a subroutine processing requests,
  # e.g. mod_perl with ModPerl::Registry, or PSGI with Plack::App::WrapCGI
- return;
+ return $app;
 } else {
  # pure CGI script, serving single request
  exit;
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[RFC/PATCH 4/5] gitweb.psgi: Allow passing arguments to Plack::Runner

Jakub Narębski
In reply to this post by Jakub Narębski
Command options after first '--' are passed literally to Plack::Runner
as arguments, in addition to default ones used.  This way you can
select PSGI server, host, port, etc.

Signed-off-by: Jakub Narebski <[hidden email]>
---
Could be squashed with 4/5, now that I realized that it is that simple.

 gitweb/gitweb.perl |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 0dbdd15..6bd7b08 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1312,7 +1312,8 @@ sub run_psgi_app {
 
  my $runner = Plack::Runner->new();
  $runner->parse_options(qw(--env deployment),
-                       qw(--host 127.0.0.1));
+                       qw(--host 127.0.0.1),
+                       @ARGV);
  $runner->run($app);
  }
 }
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[RFC/PATCH 5/5] git-instaweb: Use new PSGI interface mode of gitweb

Jakub Narębski
In reply to this post by Jakub Narębski
Now that gitweb supports PSGI interface itself, use it instead of
Plack::App::WrapCGI.

Note that gitweb as PSGI serves static files and ensures correct
handling of SIGCHLD, but the wrapper is still needed for logging,
mimetype handling (probably unnecessary), and selecting host and port.
It is now named gitweb-wrapper.psgi and not gitweb.psgi, though.

The advantage of previous version is that it uses persistent mode
(similar to FastCGI); important if $per_request_config is false or
coderef.

Signed-off-by: Jakub Narebski <[hidden email]>
---
Should make git-instaweb plackup mode better.

 git-instaweb.sh |   33 +++++++--------------------------
 1 files changed, 7 insertions(+), 26 deletions(-)

diff --git a/git-instaweb.sh b/git-instaweb.sh
index 01a1b05..58e142a 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -53,8 +53,8 @@ resolve_full_httpd () {
  fi
  ;;
  *plackup*)
- # server is started by running via generated gitweb.psgi in $fqgitdir/gitweb
- full_httpd="$fqgitdir/gitweb/gitweb.psgi"
+ # server is started by running via generated gitweb-wrapper.psgi in $fqgitdir/gitweb
+ full_httpd="$fqgitdir/gitweb/gitweb-wrapper.psgi"
  httpd_only="${httpd%% *}" # cut on first space
  return
  ;;
@@ -434,7 +434,7 @@ EOF
 plackup_conf () {
  # generate a standalone 'plackup' server script in $fqgitdir/gitweb
  # with embedded configuration; it does not use "$conf" file
- cat > "$fqgitdir/gitweb/gitweb.psgi" <<EOF
+ cat > "$fqgitdir/gitweb/gitweb-wrapper.psgi" <<EOF
 #!$PERL
 
 # gitweb - simple web interface to track changes in git repositories
@@ -445,8 +445,7 @@ use strict;
 use IO::Handle;
 use Plack::MIME;
 use Plack::Builder;
-use Plack::App::WrapCGI;
-use CGI::Emulate::PSGI 0.07; # minimum version required to work with gitweb
+use Plack::Util;
 
 # mimetype mapping (from lighttpd_conf)
 Plack::MIME->add_type(
@@ -538,25 +537,7 @@ my \$app = builder {
  \$app->(\$env);
  }
  };
- # gitweb currently doesn't work with $SIG{CHLD} set to 'IGNORE',
- # because it uses 'close $fd or die...' on piped filehandle $fh
- # (which causes the parent process to wait for child to finish).
- enable_if { \$SIG{'CHLD'} eq 'IGNORE' } sub {
- my \$app = shift;
- sub {
- my \$env = shift;
- local \$SIG{'CHLD'} = 'DEFAULT';
- local \$SIG{'CLD'}  = 'DEFAULT';
- \$app->(\$env);
- }
- };
- # serve static files, i.e. stylesheet, images, script
- enable 'Static',
- path => sub { m!\.(js|css|png)\$! && s!^/gitweb/!! },
- root => "$root/",
- encoding => 'utf-8'; # encoding for 'text/plain' files
- # convert CGI application to PSGI app
- Plack::App::WrapCGI->new(script => "$root/gitweb.cgi")->to_app;
+ Plack::Util::load_psgi("$root/gitweb.cgi");
 };
 
 # make it runnable as standalone app,
@@ -574,8 +555,8 @@ if (caller) {
 __END__
 EOF
 
- chmod a+x "$fqgitdir/gitweb/gitweb.psgi"
- # configuration is embedded in server script file, gitweb.psgi
+ chmod a+x "$fqgitdir/gitweb/gitweb-wrapper.psgi"
+ # configuration is embedded in server script file, gitweb-wrapper.psgi
  rm -f "$conf"
 }
 
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[RFC/PATCH 6/5] gitweb.psgi: Use installed static files, if they are available

Jakub Narębski
In reply to this post by Jakub Narębski
When gitweb is running as PSGI app, it must itself take care of
serving static files: stylesheets, script, images that are required
to render gitweb output.

This commit makes gitweb (in PSGI mode) use installed static files
from $(gitwebstaticdir) if such directory exists.  Before this commit
gitweb served static files from 'static/' directory relative to
position of gitweb script itself (to __DIR__).

This allows to use gitweb in PSGI mode even if static files are
installed to non-standard place.

Note that mechanism of serving is slightly different: the one with
__DIR__ uses Plack::Middleware::Static, while the installdir one uses
URLMap-ped set of Plack::App::File.

Signed-off-by: Jakub Narebski <[hidden email]>
---
This probably would have to be reworked, so that using Plack::Middleware::Static
is preferred over set of Plack::App::File (which I think is slightly slower).

 gitweb/Makefile    |    7 +++++--
 gitweb/gitweb.perl |   38 ++++++++++++++++++++++++++++++--------
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/gitweb/Makefile b/gitweb/Makefile
index 549e7dc..6f673ff 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -13,6 +13,8 @@ all::
 prefix ?= $(HOME)
 bindir ?= $(prefix)/bin
 gitwebdir ?= /var/www/cgi-bin
+gitwebstaticdir ?= $(gitwebdir)/static
+gitweblibdir ?= $(gitwebdir)/lib
 
 RM ?= rm -f
 INSTALL ?= install
@@ -58,8 +60,8 @@ PERL_PATH  ?= /usr/bin/perl
 # Shell quote;
 bindir_SQ = $(subst ','\'',$(bindir))#'
 gitwebdir_SQ = $(subst ','\'',$(gitwebdir))#'
-gitwebstaticdir_SQ = $(subst ','\'',$(gitwebdir)/static)#'
-gitweblibdir_SQ = $(subst ','\'',$(gitwebdir)/lib)#'
+gitwebstaticdir_SQ = $(subst ','\'',$(gitwebstaticdir))#'
+gitweblibdir_SQ = $(subst ','\'',$(gitweblibdir))#'
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))#'
 PERL_PATH_SQ  = $(subst ','\'',$(PERL_PATH))#'
 DESTDIR_SQ    = $(subst ','\'',$(DESTDIR))#'
@@ -130,6 +132,7 @@ GITWEB_JSLIB_FILES += static/js/blame_incremental.js
 GITWEB_REPLACE = \
  -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
  -e 's|++GIT_BINDIR++|$(bindir)|g' \
+ -e 's|++GITWEBSTATICDIR++|$(gitwebstaticdir)|g' \
  -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
  -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
  -e 's|++GITWEB_CONFIG_COMMON++|$(GITWEB_CONFIG_COMMON)|g' \
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 6bd7b08..f871090 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1271,9 +1271,10 @@ sub to_psgi_app {
 }
 
 sub build_psgi_app {
- require Plack::Builder;
- require Plack::Middleware::Static;
-
+ # gitweb currently doesn't work with $SIG{CHLD} set to 'IGNORE',
+ # because it uses 'close $fd or die...' on piped filehandle $fh
+ # (which causes the parent process to wait for child to finish).
+ # this middleware is enabled only if $SIG{CHLD} is 'IGNORE'.
  my $sigchld_mw = sub {
  my $app = shift;
  sub {
@@ -1288,14 +1289,35 @@ sub build_psgi_app {
  # note: Plack::Builder DSL (builder, enable_if, enable) won't work
  # with "require Plack::Builder" outside BEGIN section.
  my $app = to_psgi_app();
- $app = Plack::Middleware::Static->wrap($app,
- path => qr{(?:^|/)static/.*\.(?:js|css|png)$},
- root => __DIR__,
- encoding => 'utf-8', # encoding for 'text/plain' files
- );
  $app = $sigchld_mw->($app)
  if (defined $SIG{'CHLD'} && $SIG{'CHLD'} eq 'IGNORE');
 
+ if (-d "++GITWEBSTATICDIR++") {
+ require Plack::App::URLMap;
+ require Plack::App::File;
+
+ my $urlmap = Plack::App::URLMap->new();
+ $urlmap->map("/" => $app);
+ foreach my $static_url (@stylesheets, $stylesheet, $logo, $favicon, $javascript) {
+ next if (!defined $static_url || $static_url eq "");
+
+ (my $static_file = $static_url) =~ s!^.*/!!; # basename
+ $static_file = "++GITWEBSTATICDIR++/$static_file";
+ $urlmap->map($static_url => Plack::App::File->new(file => $static_file));
+ }
+ $app = $urlmap->to_app();
+
+ } else {
+ require Plack::Middleware::Static;
+
+ $app = Plack::Middleware::Static->wrap($app,
+ path => qr{(?:^|/)static/.*\.(?:js|css|png)$},
+ root => __DIR__,
+ encoding => 'utf-8', # encoding for 'text/plain' files
+ );
+
+ }
+
  return $app;
 }
 
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html