You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

git-instaweb.sh 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. #!/bin/sh
  2. #
  3. # Copyright (c) 2006 Eric Wong
  4. #
  5. PERL='@@PERL@@'
  6. OPTIONS_KEEPDASHDASH=
  7. OPTIONS_STUCKLONG=
  8. OPTIONS_SPEC="\
  9. git instaweb [options] (--start | --stop | --restart)
  10. --
  11. l,local only bind on 127.0.0.1
  12. p,port= the port to bind to
  13. d,httpd= the command to launch
  14. b,browser= the browser to launch
  15. m,module-path= the module path (only needed for apache2)
  16. Action
  17. stop stop the web server
  18. start start the web server
  19. restart restart the web server
  20. "
  21. SUBDIRECTORY_OK=Yes
  22. . git-sh-setup
  23. fqgitdir="$GIT_DIR"
  24. local="$(git config --bool --get instaweb.local)"
  25. httpd="$(git config --get instaweb.httpd)"
  26. root="$(git config --get instaweb.gitwebdir)"
  27. port=$(git config --get instaweb.port)
  28. module_path="$(git config --get instaweb.modulepath)"
  29. action="browse"
  30. conf="$GIT_DIR/gitweb/httpd.conf"
  31. # Defaults:
  32. # if installed, it doesn't need further configuration (module_path)
  33. test -z "$httpd" && httpd='lighttpd -f'
  34. # Default is @@GITWEBDIR@@
  35. test -z "$root" && root='@@GITWEBDIR@@'
  36. # any untaken local port will do...
  37. test -z "$port" && port=1234
  38. resolve_full_httpd () {
  39. case "$httpd" in
  40. *apache2*|*lighttpd*|*httpd*)
  41. # yes, *httpd* covers *lighttpd* above, but it is there for clarity
  42. # ensure that the apache2/lighttpd command ends with "-f"
  43. if ! echo "$httpd" | sane_grep -- '-f *$' >/dev/null 2>&1
  44. then
  45. httpd="$httpd -f"
  46. fi
  47. ;;
  48. *plackup*)
  49. # server is started by running via generated gitweb.psgi in $fqgitdir/gitweb
  50. full_httpd="$fqgitdir/gitweb/gitweb.psgi"
  51. httpd_only="${httpd%% *}" # cut on first space
  52. return
  53. ;;
  54. *webrick*)
  55. # server is started by running via generated webrick.rb in
  56. # $fqgitdir/gitweb
  57. full_httpd="$fqgitdir/gitweb/webrick.rb"
  58. httpd_only="${httpd%% *}" # cut on first space
  59. return
  60. ;;
  61. *python*)
  62. # server is started by running via generated gitweb.py in
  63. # $fqgitdir/gitweb
  64. full_httpd="$fqgitdir/gitweb/gitweb.py"
  65. httpd_only="${httpd%% *}" # cut on first space
  66. return
  67. ;;
  68. esac
  69. httpd_only="$(echo $httpd | cut -f1 -d' ')"
  70. if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null 2>&1;; esac
  71. then
  72. full_httpd=$httpd
  73. else
  74. # many httpds are installed in /usr/sbin or /usr/local/sbin
  75. # these days and those are not in most users $PATHs
  76. # in addition, we may have generated a server script
  77. # in $fqgitdir/gitweb.
  78. for i in /usr/local/sbin /usr/sbin "$root" "$fqgitdir/gitweb"
  79. do
  80. if test -x "$i/$httpd_only"
  81. then
  82. full_httpd=$i/$httpd
  83. return
  84. fi
  85. done
  86. echo >&2 "$httpd_only not found. Install $httpd_only or use" \
  87. "--httpd to specify another httpd daemon."
  88. exit 1
  89. fi
  90. }
  91. start_httpd () {
  92. if test -f "$fqgitdir/pid"; then
  93. say "Instance already running. Restarting..."
  94. stop_httpd
  95. fi
  96. # here $httpd should have a meaningful value
  97. resolve_full_httpd
  98. mkdir -p "$fqgitdir/gitweb/$httpd_only"
  99. conf="$fqgitdir/gitweb/$httpd_only.conf"
  100. # generate correct config file if it doesn't exist
  101. test -f "$conf" || configure_httpd
  102. test -f "$fqgitdir/gitweb/gitweb_config.perl" || gitweb_conf
  103. # don't quote $full_httpd, there can be arguments to it (-f)
  104. case "$httpd" in
  105. *mongoose*|*plackup*|*python*)
  106. #These servers don't have a daemon mode so we'll have to fork it
  107. $full_httpd "$conf" &
  108. #Save the pid before doing anything else (we'll print it later)
  109. pid=$!
  110. if test $? != 0; then
  111. echo "Could not execute http daemon $httpd."
  112. exit 1
  113. fi
  114. cat > "$fqgitdir/pid" <<EOF
  115. $pid
  116. EOF
  117. ;;
  118. *)
  119. $full_httpd "$conf"
  120. if test $? != 0; then
  121. echo "Could not execute http daemon $httpd."
  122. exit 1
  123. fi
  124. ;;
  125. esac
  126. }
  127. stop_httpd () {
  128. test -f "$fqgitdir/pid" && kill $(cat "$fqgitdir/pid")
  129. rm -f "$fqgitdir/pid"
  130. }
  131. httpd_is_ready () {
  132. "$PERL" -MIO::Socket::INET -e "
  133. local \$| = 1; # turn on autoflush
  134. exit if (IO::Socket::INET->new('127.0.0.1:$port'));
  135. print 'Waiting for \'$httpd\' to start ..';
  136. do {
  137. print '.';
  138. sleep(1);
  139. } until (IO::Socket::INET->new('127.0.0.1:$port'));
  140. print qq! (done)\n!;
  141. "
  142. }
  143. while test $# != 0
  144. do
  145. case "$1" in
  146. --stop|stop)
  147. action="stop"
  148. ;;
  149. --start|start)
  150. action="start"
  151. ;;
  152. --restart|restart)
  153. action="restart"
  154. ;;
  155. -l|--local)
  156. local=true
  157. ;;
  158. -d|--httpd)
  159. shift
  160. httpd="$1"
  161. ;;
  162. -b|--browser)
  163. shift
  164. browser="$1"
  165. ;;
  166. -p|--port)
  167. shift
  168. port="$1"
  169. ;;
  170. -m|--module-path)
  171. shift
  172. module_path="$1"
  173. ;;
  174. --)
  175. ;;
  176. *)
  177. usage
  178. ;;
  179. esac
  180. shift
  181. done
  182. mkdir -p "$GIT_DIR/gitweb/tmp"
  183. GIT_EXEC_PATH="$(git --exec-path)"
  184. GIT_DIR="$fqgitdir"
  185. GITWEB_CONFIG="$fqgitdir/gitweb/gitweb_config.perl"
  186. export GIT_EXEC_PATH GIT_DIR GITWEB_CONFIG
  187. webrick_conf () {
  188. # webrick seems to have no way of passing arbitrary environment
  189. # variables to the underlying CGI executable, so we wrap the
  190. # actual gitweb.cgi using a shell script to force it
  191. wrapper="$fqgitdir/gitweb/$httpd/wrapper.sh"
  192. cat > "$wrapper" <<EOF
  193. #!@SHELL_PATH@
  194. # we use this shell script wrapper around the real gitweb.cgi since
  195. # there appears to be no other way to pass arbitrary environment variables
  196. # into the CGI process
  197. GIT_EXEC_PATH=$GIT_EXEC_PATH GIT_DIR=$GIT_DIR GITWEB_CONFIG=$GITWEB_CONFIG
  198. export GIT_EXEC_PATH GIT_DIR GITWEB_CONFIG
  199. exec $root/gitweb.cgi
  200. EOF
  201. chmod +x "$wrapper"
  202. # This assumes _ruby_ is in the user's $PATH. that's _one_
  203. # portable way to run ruby, which could be installed anywhere, really.
  204. # generate a standalone server script in $fqgitdir/gitweb.
  205. cat >"$fqgitdir/gitweb/$httpd.rb" <<EOF
  206. #!/usr/bin/env ruby
  207. require 'webrick'
  208. require 'logger'
  209. options = {
  210. :Port => $port,
  211. :DocumentRoot => "$root",
  212. :Logger => Logger.new('$fqgitdir/gitweb/error.log'),
  213. :AccessLog => [
  214. [ Logger.new('$fqgitdir/gitweb/access.log'),
  215. WEBrick::AccessLog::COMBINED_LOG_FORMAT ]
  216. ],
  217. :DirectoryIndex => ["gitweb.cgi"],
  218. :CGIInterpreter => "$wrapper",
  219. :StartCallback => lambda do
  220. File.open("$fqgitdir/pid", "w") { |f| f.puts Process.pid }
  221. end,
  222. :ServerType => WEBrick::Daemon,
  223. }
  224. options[:BindAddress] = '127.0.0.1' if "$local" == "true"
  225. server = WEBrick::HTTPServer.new(options)
  226. ['INT', 'TERM'].each do |signal|
  227. trap(signal) {server.shutdown}
  228. end
  229. server.start
  230. EOF
  231. chmod +x "$fqgitdir/gitweb/$httpd.rb"
  232. # configuration is embedded in server script file, webrick.rb
  233. rm -f "$conf"
  234. }
  235. lighttpd_conf () {
  236. cat > "$conf" <<EOF
  237. server.document-root = "$root"
  238. server.port = $port
  239. server.modules = ( "mod_setenv", "mod_cgi" )
  240. server.indexfiles = ( "gitweb.cgi" )
  241. server.pid-file = "$fqgitdir/pid"
  242. server.errorlog = "$fqgitdir/gitweb/$httpd_only/error.log"
  243. # to enable, add "mod_access", "mod_accesslog" to server.modules
  244. # variable above and uncomment this
  245. #accesslog.filename = "$fqgitdir/gitweb/$httpd_only/access.log"
  246. setenv.add-environment = ( "PATH" => env.PATH, "GITWEB_CONFIG" => env.GITWEB_CONFIG )
  247. cgi.assign = ( ".cgi" => "" )
  248. # mimetype mapping
  249. mimetype.assign = (
  250. ".pdf" => "application/pdf",
  251. ".sig" => "application/pgp-signature",
  252. ".spl" => "application/futuresplash",
  253. ".class" => "application/octet-stream",
  254. ".ps" => "application/postscript",
  255. ".torrent" => "application/x-bittorrent",
  256. ".dvi" => "application/x-dvi",
  257. ".gz" => "application/x-gzip",
  258. ".pac" => "application/x-ns-proxy-autoconfig",
  259. ".swf" => "application/x-shockwave-flash",
  260. ".tar.gz" => "application/x-tgz",
  261. ".tgz" => "application/x-tgz",
  262. ".tar" => "application/x-tar",
  263. ".zip" => "application/zip",
  264. ".mp3" => "audio/mpeg",
  265. ".m3u" => "audio/x-mpegurl",
  266. ".wma" => "audio/x-ms-wma",
  267. ".wax" => "audio/x-ms-wax",
  268. ".ogg" => "application/ogg",
  269. ".wav" => "audio/x-wav",
  270. ".gif" => "image/gif",
  271. ".jpg" => "image/jpeg",
  272. ".jpeg" => "image/jpeg",
  273. ".png" => "image/png",
  274. ".xbm" => "image/x-xbitmap",
  275. ".xpm" => "image/x-xpixmap",
  276. ".xwd" => "image/x-xwindowdump",
  277. ".css" => "text/css",
  278. ".html" => "text/html",
  279. ".htm" => "text/html",
  280. ".js" => "text/javascript",
  281. ".asc" => "text/plain",
  282. ".c" => "text/plain",
  283. ".cpp" => "text/plain",
  284. ".log" => "text/plain",
  285. ".conf" => "text/plain",
  286. ".text" => "text/plain",
  287. ".txt" => "text/plain",
  288. ".dtd" => "text/xml",
  289. ".xml" => "text/xml",
  290. ".mpeg" => "video/mpeg",
  291. ".mpg" => "video/mpeg",
  292. ".mov" => "video/quicktime",
  293. ".qt" => "video/quicktime",
  294. ".avi" => "video/x-msvideo",
  295. ".asf" => "video/x-ms-asf",
  296. ".asx" => "video/x-ms-asf",
  297. ".wmv" => "video/x-ms-wmv",
  298. ".bz2" => "application/x-bzip",
  299. ".tbz" => "application/x-bzip-compressed-tar",
  300. ".tar.bz2" => "application/x-bzip-compressed-tar",
  301. "" => "text/plain"
  302. )
  303. EOF
  304. test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf"
  305. }
  306. apache2_conf () {
  307. for candidate in \
  308. /etc/httpd \
  309. /usr/lib/apache2 \
  310. /usr/lib/httpd ;
  311. do
  312. if test -d "$candidate/modules"
  313. then
  314. module_path="$candidate/modules"
  315. break
  316. fi
  317. done
  318. bind=
  319. test x"$local" = xtrue && bind='127.0.0.1:'
  320. echo 'text/css css' > "$fqgitdir/mime.types"
  321. cat > "$conf" <<EOF
  322. ServerName "git-instaweb"
  323. ServerRoot "$root"
  324. DocumentRoot "$root"
  325. ErrorLog "$fqgitdir/gitweb/$httpd_only/error.log"
  326. CustomLog "$fqgitdir/gitweb/$httpd_only/access.log" combined
  327. PidFile "$fqgitdir/pid"
  328. Listen $bind$port
  329. EOF
  330. for mod in mpm_event mpm_prefork mpm_worker
  331. do
  332. if test -e $module_path/mod_${mod}.so
  333. then
  334. echo "LoadModule ${mod}_module " \
  335. "$module_path/mod_${mod}.so" >> "$conf"
  336. # only one mpm module permitted
  337. break
  338. fi
  339. done
  340. for mod in mime dir env log_config authz_core unixd
  341. do
  342. if test -e $module_path/mod_${mod}.so
  343. then
  344. echo "LoadModule ${mod}_module " \
  345. "$module_path/mod_${mod}.so" >> "$conf"
  346. fi
  347. done
  348. cat >> "$conf" <<EOF
  349. TypesConfig "$fqgitdir/mime.types"
  350. DirectoryIndex gitweb.cgi
  351. EOF
  352. # check to see if Dennis Stosberg's mod_perl compatibility patch
  353. # (<20060621130708.Gcbc6e5c@leonov.stosberg.net>) has been applied
  354. if test -f "$module_path/mod_perl.so" &&
  355. sane_grep 'MOD_PERL' "$root/gitweb.cgi" >/dev/null
  356. then
  357. # favor mod_perl if available
  358. cat >> "$conf" <<EOF
  359. LoadModule perl_module $module_path/mod_perl.so
  360. PerlPassEnv GIT_DIR
  361. PerlPassEnv GIT_EXEC_PATH
  362. PerlPassEnv GITWEB_CONFIG
  363. <Location /gitweb.cgi>
  364. SetHandler perl-script
  365. PerlResponseHandler ModPerl::Registry
  366. PerlOptions +ParseHeaders
  367. Options +ExecCGI
  368. </Location>
  369. EOF
  370. else
  371. # plain-old CGI
  372. resolve_full_httpd
  373. list_mods=$(echo "$full_httpd" | sed 's/-f$/-l/')
  374. $list_mods | sane_grep 'mod_cgi\.c' >/dev/null 2>&1 || \
  375. if test -f "$module_path/mod_cgi.so"
  376. then
  377. echo "LoadModule cgi_module $module_path/mod_cgi.so" >> "$conf"
  378. else
  379. $list_mods | grep 'mod_cgid\.c' >/dev/null 2>&1 || \
  380. if test -f "$module_path/mod_cgid.so"
  381. then
  382. echo "LoadModule cgid_module $module_path/mod_cgid.so" \
  383. >> "$conf"
  384. else
  385. echo "You have no CGI support!"
  386. exit 2
  387. fi
  388. echo "ScriptSock logs/gitweb.sock" >> "$conf"
  389. fi
  390. cat >> "$conf" <<EOF
  391. PassEnv GIT_DIR
  392. PassEnv GIT_EXEC_PATH
  393. PassEnv GITWEB_CONFIG
  394. AddHandler cgi-script .cgi
  395. <Location /gitweb.cgi>
  396. Options +ExecCGI
  397. </Location>
  398. EOF
  399. fi
  400. }
  401. mongoose_conf() {
  402. cat > "$conf" <<EOF
  403. # Mongoose web server configuration file.
  404. # Lines starting with '#' and empty lines are ignored.
  405. # For detailed description of every option, visit
  406. # http://code.google.com/p/mongoose/wiki/MongooseManual
  407. root $root
  408. ports $port
  409. index_files gitweb.cgi
  410. #ssl_cert $fqgitdir/gitweb/ssl_cert.pem
  411. error_log $fqgitdir/gitweb/$httpd_only/error.log
  412. access_log $fqgitdir/gitweb/$httpd_only/access.log
  413. #cgi setup
  414. cgi_env PATH=$PATH,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH,GITWEB_CONFIG=$GITWEB_CONFIG
  415. cgi_interp $PERL
  416. cgi_ext cgi,pl
  417. # mimetype mapping
  418. mime_types .gz=application/x-gzip,.tar.gz=application/x-tgz,.tgz=application/x-tgz,.tar=application/x-tar,.zip=application/zip,.gif=image/gif,.jpg=image/jpeg,.jpeg=image/jpeg,.png=image/png,.css=text/css,.html=text/html,.htm=text/html,.js=text/javascript,.c=text/plain,.cpp=text/plain,.log=text/plain,.conf=text/plain,.text=text/plain,.txt=text/plain,.dtd=text/xml,.bz2=application/x-bzip,.tbz=application/x-bzip-compressed-tar,.tar.bz2=application/x-bzip-compressed-tar
  419. EOF
  420. }
  421. plackup_conf () {
  422. # generate a standalone 'plackup' server script in $fqgitdir/gitweb
  423. # with embedded configuration; it does not use "$conf" file
  424. cat > "$fqgitdir/gitweb/gitweb.psgi" <<EOF
  425. #!$PERL
  426. # gitweb - simple web interface to track changes in git repositories
  427. # PSGI wrapper and server starter (see http://plackperl.org)
  428. use strict;
  429. use IO::Handle;
  430. use Plack::MIME;
  431. use Plack::Builder;
  432. use Plack::App::WrapCGI;
  433. use CGI::Emulate::PSGI 0.07; # minimum version required to work with gitweb
  434. # mimetype mapping (from lighttpd_conf)
  435. Plack::MIME->add_type(
  436. ".pdf" => "application/pdf",
  437. ".sig" => "application/pgp-signature",
  438. ".spl" => "application/futuresplash",
  439. ".class" => "application/octet-stream",
  440. ".ps" => "application/postscript",
  441. ".torrent" => "application/x-bittorrent",
  442. ".dvi" => "application/x-dvi",
  443. ".gz" => "application/x-gzip",
  444. ".pac" => "application/x-ns-proxy-autoconfig",
  445. ".swf" => "application/x-shockwave-flash",
  446. ".tar.gz" => "application/x-tgz",
  447. ".tgz" => "application/x-tgz",
  448. ".tar" => "application/x-tar",
  449. ".zip" => "application/zip",
  450. ".mp3" => "audio/mpeg",
  451. ".m3u" => "audio/x-mpegurl",
  452. ".wma" => "audio/x-ms-wma",
  453. ".wax" => "audio/x-ms-wax",
  454. ".ogg" => "application/ogg",
  455. ".wav" => "audio/x-wav",
  456. ".gif" => "image/gif",
  457. ".jpg" => "image/jpeg",
  458. ".jpeg" => "image/jpeg",
  459. ".png" => "image/png",
  460. ".xbm" => "image/x-xbitmap",
  461. ".xpm" => "image/x-xpixmap",
  462. ".xwd" => "image/x-xwindowdump",
  463. ".css" => "text/css",
  464. ".html" => "text/html",
  465. ".htm" => "text/html",
  466. ".js" => "text/javascript",
  467. ".asc" => "text/plain",
  468. ".c" => "text/plain",
  469. ".cpp" => "text/plain",
  470. ".log" => "text/plain",
  471. ".conf" => "text/plain",
  472. ".text" => "text/plain",
  473. ".txt" => "text/plain",
  474. ".dtd" => "text/xml",
  475. ".xml" => "text/xml",
  476. ".mpeg" => "video/mpeg",
  477. ".mpg" => "video/mpeg",
  478. ".mov" => "video/quicktime",
  479. ".qt" => "video/quicktime",
  480. ".avi" => "video/x-msvideo",
  481. ".asf" => "video/x-ms-asf",
  482. ".asx" => "video/x-ms-asf",
  483. ".wmv" => "video/x-ms-wmv",
  484. ".bz2" => "application/x-bzip",
  485. ".tbz" => "application/x-bzip-compressed-tar",
  486. ".tar.bz2" => "application/x-bzip-compressed-tar",
  487. "" => "text/plain"
  488. );
  489. my \$app = builder {
  490. # to be able to override \$SIG{__WARN__} to log build time warnings
  491. use CGI::Carp; # it sets \$SIG{__WARN__} itself
  492. my \$logdir = "$fqgitdir/gitweb/$httpd_only";
  493. open my \$access_log_fh, '>>', "\$logdir/access.log"
  494. or die "Couldn't open access log '\$logdir/access.log': \$!";
  495. open my \$error_log_fh, '>>', "\$logdir/error.log"
  496. or die "Couldn't open error log '\$logdir/error.log': \$!";
  497. \$access_log_fh->autoflush(1);
  498. \$error_log_fh->autoflush(1);
  499. # redirect build time warnings to error.log
  500. \$SIG{'__WARN__'} = sub {
  501. my \$msg = shift;
  502. # timestamp warning like in CGI::Carp::warn
  503. my \$stamp = CGI::Carp::stamp();
  504. \$msg =~ s/^/\$stamp/gm;
  505. print \$error_log_fh \$msg;
  506. };
  507. # write errors to error.log, access to access.log
  508. enable 'AccessLog',
  509. format => "combined",
  510. logger => sub { print \$access_log_fh @_; };
  511. enable sub {
  512. my \$app = shift;
  513. sub {
  514. my \$env = shift;
  515. \$env->{'psgi.errors'} = \$error_log_fh;
  516. \$app->(\$env);
  517. }
  518. };
  519. # gitweb currently doesn't work with $SIG{CHLD} set to 'IGNORE',
  520. # because it uses 'close $fd or die...' on piped filehandle $fh
  521. # (which causes the parent process to wait for child to finish).
  522. enable_if { \$SIG{'CHLD'} eq 'IGNORE' } sub {
  523. my \$app = shift;
  524. sub {
  525. my \$env = shift;
  526. local \$SIG{'CHLD'} = 'DEFAULT';
  527. local \$SIG{'CLD'} = 'DEFAULT';
  528. \$app->(\$env);
  529. }
  530. };
  531. # serve static files, i.e. stylesheet, images, script
  532. enable 'Static',
  533. path => sub { m!\.(js|css|png)\$! && s!^/gitweb/!! },
  534. root => "$root/",
  535. encoding => 'utf-8'; # encoding for 'text/plain' files
  536. # convert CGI application to PSGI app
  537. Plack::App::WrapCGI->new(script => "$root/gitweb.cgi")->to_app;
  538. };
  539. # make it runnable as standalone app,
  540. # like it would be run via 'plackup' utility
  541. if (caller) {
  542. return \$app;
  543. } else {
  544. require Plack::Runner;
  545. my \$runner = Plack::Runner->new();
  546. \$runner->parse_options(qw(--env deployment --port $port),
  547. "$local" ? qw(--host 127.0.0.1) : ());
  548. \$runner->run(\$app);
  549. }
  550. __END__
  551. EOF
  552. chmod a+x "$fqgitdir/gitweb/gitweb.psgi"
  553. # configuration is embedded in server script file, gitweb.psgi
  554. rm -f "$conf"
  555. }
  556. python_conf() {
  557. # Python's builtin http.server and its CGI support is very limited.
  558. # CGI handler is capable of running CGI script only from inside a directory.
  559. # Trying to set cgi_directories=["/"] will add double slash to SCRIPT_NAME
  560. # and that in turn breaks gitweb's relative link generation.
  561. # create a simple web root where $fqgitdir/gitweb/$httpd_only is our root
  562. mkdir -p "$fqgitdir/gitweb/$httpd_only/cgi-bin"
  563. # Python http.server follows the symlinks
  564. ln -sf "$root/gitweb.cgi" "$fqgitdir/gitweb/$httpd_only/cgi-bin/gitweb.cgi"
  565. ln -sf "$root/static" "$fqgitdir/gitweb/$httpd_only/"
  566. # generate a standalone 'python http.server' script in $fqgitdir/gitweb
  567. # This asumes that python is in user's $PATH
  568. # This script is Python 2 and 3 compatible
  569. cat > "$fqgitdir/gitweb/gitweb.py" <<EOF
  570. #!/usr/bin/env python
  571. import os
  572. import sys
  573. # Open log file in line buffering mode
  574. accesslogfile = open("$fqgitdir/gitweb/access.log", 'a', buffering=1)
  575. errorlogfile = open("$fqgitdir/gitweb/error.log", 'a', buffering=1)
  576. # and replace our stdout and stderr with log files
  577. # also do a lowlevel duplicate of the logfile file descriptors so that
  578. # our CGI child process writes any stderr warning also to the log file
  579. _orig_stdout_fd = sys.stdout.fileno()
  580. sys.stdout.close()
  581. os.dup2(accesslogfile.fileno(), _orig_stdout_fd)
  582. sys.stdout = accesslogfile
  583. _orig_stderr_fd = sys.stderr.fileno()
  584. sys.stderr.close()
  585. os.dup2(errorlogfile.fileno(), _orig_stderr_fd)
  586. sys.stderr = errorlogfile
  587. from functools import partial
  588. if sys.version_info < (3, 0): # Python 2
  589. from CGIHTTPServer import CGIHTTPRequestHandler
  590. from BaseHTTPServer import HTTPServer as ServerClass
  591. else: # Python 3
  592. from http.server import CGIHTTPRequestHandler
  593. from http.server import HTTPServer as ServerClass
  594. # Those environment variables will be passed to the cgi script
  595. os.environ.update({
  596. "GIT_EXEC_PATH": "$GIT_EXEC_PATH",
  597. "GIT_DIR": "$GIT_DIR",
  598. "GITWEB_CONFIG": "$GITWEB_CONFIG"
  599. })
  600. class GitWebRequestHandler(CGIHTTPRequestHandler):
  601. def log_message(self, format, *args):
  602. # Write access logs to stdout
  603. sys.stdout.write("%s - - [%s] %s\n" %
  604. (self.address_string(),
  605. self.log_date_time_string(),
  606. format%args))
  607. def do_HEAD(self):
  608. self.redirect_path()
  609. CGIHTTPRequestHandler.do_HEAD(self)
  610. def do_GET(self):
  611. if self.path == "/":
  612. self.send_response(303, "See Other")
  613. self.send_header("Location", "/cgi-bin/gitweb.cgi")
  614. self.end_headers()
  615. return
  616. self.redirect_path()
  617. CGIHTTPRequestHandler.do_GET(self)
  618. def do_POST(self):
  619. self.redirect_path()
  620. CGIHTTPRequestHandler.do_POST(self)
  621. # rewrite path of every request that is not gitweb.cgi to out of cgi-bin
  622. def redirect_path(self):
  623. if not self.path.startswith("/cgi-bin/gitweb.cgi"):
  624. self.path = self.path.replace("/cgi-bin/", "/")
  625. # gitweb.cgi is the only thing that is ever going to be run here.
  626. # Ignore everything else
  627. def is_cgi(self):
  628. result = False
  629. if self.path.startswith('/cgi-bin/gitweb.cgi'):
  630. result = CGIHTTPRequestHandler.is_cgi(self)
  631. return result
  632. bind = "127.0.0.1"
  633. if "$local" == "true":
  634. bind = "0.0.0.0"
  635. # Set our http root directory
  636. # This is a work around for a missing directory argument in older Python versions
  637. # as this was added to SimpleHTTPRequestHandler in Python 3.7
  638. os.chdir("$fqgitdir/gitweb/$httpd_only/")
  639. GitWebRequestHandler.protocol_version = "HTTP/1.0"
  640. httpd = ServerClass((bind, $port), GitWebRequestHandler)
  641. sa = httpd.socket.getsockname()
  642. print("Serving HTTP on", sa[0], "port", sa[1], "...")
  643. httpd.serve_forever()
  644. EOF
  645. chmod a+x "$fqgitdir/gitweb/gitweb.py"
  646. }
  647. gitweb_conf() {
  648. cat > "$fqgitdir/gitweb/gitweb_config.perl" <<EOF
  649. #!@@PERL@@
  650. our \$projectroot = "$(dirname "$fqgitdir")";
  651. our \$git_temp = "$fqgitdir/gitweb/tmp";
  652. our \$projects_list = \$projectroot;
  653. \$feature{'remote_heads'}{'default'} = [1];
  654. EOF
  655. }
  656. configure_httpd() {
  657. case "$httpd" in
  658. *lighttpd*)
  659. lighttpd_conf
  660. ;;
  661. *apache2*|*httpd*)
  662. apache2_conf
  663. ;;
  664. webrick)
  665. webrick_conf
  666. ;;
  667. *mongoose*)
  668. mongoose_conf
  669. ;;
  670. *plackup*)
  671. plackup_conf
  672. ;;
  673. *python*)
  674. python_conf
  675. ;;
  676. *)
  677. echo "Unknown httpd specified: $httpd"
  678. exit 1
  679. ;;
  680. esac
  681. }
  682. case "$action" in
  683. stop)
  684. stop_httpd
  685. exit 0
  686. ;;
  687. start)
  688. start_httpd
  689. exit 0
  690. ;;
  691. restart)
  692. stop_httpd
  693. start_httpd
  694. exit 0
  695. ;;
  696. esac
  697. gitweb_conf
  698. resolve_full_httpd
  699. mkdir -p "$fqgitdir/gitweb/$httpd_only"
  700. conf="$fqgitdir/gitweb/$httpd_only.conf"
  701. configure_httpd
  702. start_httpd
  703. url=http://127.0.0.1:$port
  704. if test -n "$browser"; then
  705. httpd_is_ready && git web--browse -b "$browser" $url || echo $url
  706. else
  707. httpd_is_ready && git web--browse -c "instaweb.browser" $url || echo $url
  708. fi