diff options
Diffstat (limited to 'gitweb')
-rw-r--r-- | gitweb/README | 76 | ||||
-rwxr-xr-x | gitweb/gitweb.perl | 172 |
2 files changed, 238 insertions, 10 deletions
diff --git a/gitweb/README b/gitweb/README index 825162a0b6..52ad88b34e 100644 --- a/gitweb/README +++ b/gitweb/README @@ -322,6 +322,82 @@ something like the following in your gitweb.conf (or gitweb_config.perl) file: $home_link = "/"; +PATH_INFO usage +----------------------- +If you enable PATH_INFO usage in gitweb by putting + + $feature{'pathinfo'}{'default'} = [1]; + +in your gitweb.conf, it is possible to set up your server so that it +consumes and produces URLs in the form + +http://git.example.com/project.git/shortlog/sometag + +by using a configuration such as the following, that assumes that +/var/www/gitweb is the DocumentRoot of your webserver, and that it +contains the gitweb.cgi script and complementary static files +(stylesheet, favicon): + +<VirtualHost *:80> + ServerAlias git.example.com + + DocumentRoot /var/www/gitweb + + <Directory /var/www/gitweb> + Options ExecCGI + AddHandler cgi-script cgi + + DirectoryIndex gitweb.cgi + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule ^.* /gitweb.cgi/$0 [L,PT] + </Directory> +</VirtualHost> + +The rewrite rule guarantees that existing static files will be properly +served, whereas any other URL will be passed to gitweb as PATH_INFO +parameter. + +Notice that in this case you don't need special settings for +@stylesheets, $my_uri and $home_link, but you lose "dumb client" access +to your project .git dirs. A possible workaround for the latter is the +following: in your project root dir (e.g. /pub/git) have the projects +named without a .git extension (e.g. /pub/git/project instead of +/pub/git/project.git) and configure Apache as follows: + +<VirtualHost *:80> + ServerAlias git.example.com + + DocumentRoot /var/www/gitweb + + AliasMatch ^(/.*?)(\.git)(/.*)? /pub/git$1$3 + <Directory /var/www/gitweb> + Options ExecCGI + AddHandler cgi-script cgi + + DirectoryIndex gitweb.cgi + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule ^.* /gitweb.cgi/$0 [L,PT] + </Directory> +</VirtualHost> + +The additional AliasMatch makes it so that + +http://git.example.com/project.git + +will give raw access to the project's git dir (so that the project can +be cloned), while + +http://git.example.com/project + +will provide human-friendly gitweb access. + + Originally written by: Kay Sievers <kay.sievers@vrfy.org> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0ac84d1adf..f27dbb6bf4 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -330,6 +330,21 @@ our %feature = ( 'ctags' => { 'override' => 0, 'default' => [0]}, + + # The maximum number of patches in a patchset generated in patch + # view. Set this to 0 or undef to disable patch view, or to a + # negative number to remove any limit. + + # To disable system wide have in $GITWEB_CONFIG + # $feature{'patches'}{'default'} = [0]; + # To have project specific config enable override in $GITWEB_CONFIG + # $feature{'patches'}{'override'} = 1; + # and in project config gitweb.patches = 0|n; + # where n is the maximum number of patches allowed in a patchset. + 'patches' => { + 'sub' => \&feature_patches, + 'override' => 0, + 'default' => [16]}, ); sub gitweb_get_feature { @@ -388,6 +403,16 @@ sub feature_snapshot { return @fmts; } +sub feature_patches { + my @val = (git_get_project_config('patches', '--int')); + + if (@val) { + return @val; + } + + return ($_[0]); +} + # checking HEAD file with -e is fragile if the repository was # initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed # and then pruned. @@ -481,6 +506,8 @@ our %actions = ( "heads" => \&git_heads, "history" => \&git_history, "log" => \&git_log, + "patch" => \&git_patch, + "patches" => \&git_patches, "rss" => \&git_rss, "atom" => \&git_atom, "search" => \&git_search, @@ -807,7 +834,7 @@ sub href (%) { } my $use_pathinfo = gitweb_check_feature('pathinfo'); - if ($use_pathinfo) { + if ($use_pathinfo and defined $params{'project'}) { # try to put as many parameters as possible in PATH_INFO: # - project name # - action @@ -822,7 +849,7 @@ sub href (%) { $href =~ s,/$,,; # Then add the project name, if present - $href .= "/".esc_url($params{'project'}) if defined $params{'project'}; + $href .= "/".esc_url($params{'project'}); delete $params{'project'}; # since we destructively absorb parameters, we keep this @@ -2874,9 +2901,14 @@ sub git_header_html { <meta name="robots" content="index, nofollow"/> <title>$title</title> EOF -# print out each stylesheet that exist + # the stylesheet, favicon etc urls won't work correctly with path_info + # unless we set the appropriate base URL + if ($ENV{'PATH_INFO'}) { + print '<base href="'.esc_url($my_url).'" />\n'; + } + # print out each stylesheet that exist, providing backwards capability + # for those people who defined $stylesheet in a config file if (defined $stylesheet) { -#provides backwards capability for those people who define style sheet in a config file print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n"; } else { foreach my $stylesheet (@stylesheets) { @@ -4991,6 +5023,15 @@ sub git_log { my $paging_nav = format_paging_nav('log', $hash, $head, $page, $#commitlist >= 100); + my ($patch_max) = gitweb_get_feature('patches'); + if ($patch_max) { + if ($patch_max < 0 || @commitlist <= $patch_max) { + $paging_nav .= " ⋅ " . + $cgi->a({-href => href(action=>"patches", -replay=>1)}, + "patches"); + } + } + git_header_html(); git_print_page_nav('log','', $hash,undef,undef, $paging_nav); @@ -5070,6 +5111,11 @@ sub git_commit { } @$parents ) . ')'; } + if (gitweb_check_feature('patches')) { + $formats_nav .= " | " . + $cgi->a({-href => href(action=>"patch", -replay=>1)}, + "patch"); + } if (!defined $parent) { $parent = "--root"; @@ -5346,7 +5392,14 @@ sub git_blobdiff_plain { } sub git_commitdiff { - my $format = shift || 'html'; + my %params = @_; + my $format = $params{-format} || 'html'; + + my ($patch_max) = gitweb_get_feature('patches'); + if ($format eq 'patch') { + die_error(403, "Patch view not allowed") unless $patch_max; + } + $hash ||= $hash_base || "HEAD"; my %co = parse_commit($hash) or die_error(404, "Unknown commit object"); @@ -5361,6 +5414,11 @@ sub git_commitdiff { $formats_nav = $cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)}, "raw"); + if ($patch_max) { + $formats_nav .= " | " . + $cgi->a({-href => href(action=>"patch", -replay=>1)}, + "patch"); + } if (defined $hash_parent && $hash_parent ne '-c' && $hash_parent ne '--cc') { @@ -5444,7 +5502,31 @@ sub git_commitdiff { open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, '-p', $hash_parent_param, $hash, "--" or die_error(500, "Open git-diff-tree failed"); - + } elsif ($format eq 'patch') { + # For commit ranges, we limit the output to the number of + # patches specified in the 'patches' feature. + # For single commits, we limit the output to a single patch, + # diverging from the git-format-patch default. + my @commit_spec = (); + if ($hash_parent) { + if ($patch_max > 0) { + push @commit_spec, "-$patch_max"; + } + push @commit_spec, '-n', "$hash_parent..$hash"; + } else { + if ($params{-single}) { + push @commit_spec, '-1'; + } else { + if ($patch_max > 0) { + push @commit_spec, "-$patch_max"; + } + push @commit_spec, "-n"; + } + push @commit_spec, '--root', $hash; + } + open $fd, "-|", git_cmd(), "format-patch", '--encoding=utf8', + '--stdout', @commit_spec + or die_error(500, "Open git-format-patch failed"); } else { die_error(400, "Unknown commitdiff format"); } @@ -5493,6 +5575,14 @@ sub git_commitdiff { print to_utf8($line) . "\n"; } print "---\n\n"; + } elsif ($format eq 'patch') { + my $filename = basename($project) . "-$hash.patch"; + + print $cgi->header( + -type => 'text/plain', + -charset => 'utf-8', + -expires => $expires, + -content_disposition => 'inline; filename="' . "$filename" . '"'); } # write patch @@ -5514,11 +5604,25 @@ sub git_commitdiff { print <$fd>; close $fd or print "Reading git-diff-tree failed\n"; + } elsif ($format eq 'patch') { + local $/ = undef; + print <$fd>; + close $fd + or print "Reading git-format-patch failed\n"; } } sub git_commitdiff_plain { - git_commitdiff('plain'); + git_commitdiff(-format => 'plain'); +} + +# format-patch-style patches +sub git_patch { + git_commitdiff(-format => 'patch', -single=> 1); +} + +sub git_patches { + git_commitdiff(-format => 'patch'); } sub git_history { @@ -5871,6 +5975,14 @@ sub git_shortlog { $cgi->a({-href => href(-replay=>1, page=>$page+1), -accesskey => "n", -title => "Alt-n"}, "next"); } + my $patch_max = gitweb_check_feature('patches'); + if ($patch_max) { + if ($patch_max < 0 || @commitlist <= $patch_max) { + $paging_nav .= " ⋅ " . + $cgi->a({-href => href(action=>"patches", -replay=>1)}, + "patches"); + } + } git_header_html(); git_print_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav); @@ -5908,7 +6020,25 @@ sub git_feed { } if (defined($commitlist[0])) { %latest_commit = %{$commitlist[0]}; - %latest_date = parse_date($latest_commit{'author_epoch'}); + my $latest_epoch = $latest_commit{'committer_epoch'}; + %latest_date = parse_date($latest_epoch); + my $if_modified = $cgi->http('IF_MODIFIED_SINCE'); + if (defined $if_modified) { + my $since; + if (eval { require HTTP::Date; 1; }) { + $since = HTTP::Date::str2time($if_modified); + } elsif (eval { require Time::ParseDate; 1; }) { + $since = Time::ParseDate::parsedate($if_modified, GMT => 1); + } + if (defined $since && $latest_epoch <= $since) { + print $cgi->header( + -type => $content_type, + -charset => 'utf-8', + -last_modified => $latest_date{'rfc2822'}, + -status => '304 Not Modified'); + return; + } + } print $cgi->header( -type => $content_type, -charset => 'utf-8', @@ -5967,7 +6097,24 @@ XML print "<title>$title</title>\n" . "<link>$alt_url</link>\n" . "<description>$descr</description>\n" . - "<language>en</language>\n"; + "<language>en</language>\n" . + # project owner is responsible for 'editorial' content + "<managingEditor>$owner</managingEditor>\n"; + if (defined $logo || defined $favicon) { + # prefer the logo to the favicon, since RSS + # doesn't allow both + my $img = esc_url($logo || $favicon); + print "<image>\n" . + "<url>$img</url>\n" . + "<title>$title</title>\n" . + "<link>$alt_url</link>\n" . + "</image>\n"; + } + if (%latest_date) { + print "<pubDate>$latest_date{'rfc2822'}</pubDate>\n"; + print "<lastBuildDate>$latest_date{'rfc2822'}</lastBuildDate>\n"; + } + print "<generator>gitweb v.$version/$git_version</generator>\n"; } elsif ($format eq 'atom') { print <<XML; <feed xmlns="http://www.w3.org/2005/Atom"> @@ -5994,6 +6141,7 @@ XML } else { print "<updated>$latest_date{'iso-8601'}</updated>\n"; } + print "<generator version='$version/$git_version'>gitweb</generator>\n"; } # contents @@ -6115,7 +6263,11 @@ sub git_atom { sub git_opml { my @list = git_get_projects_list(); - print $cgi->header(-type => 'text/xml', -charset => 'utf-8'); + print $cgi->header( + -type => 'text/xml', + -charset => 'utf-8', + -content_disposition => 'inline; filename="opml.xml"'); + print <<XML; <?xml version="1.0" encoding="utf-8"?> <opml version="1.0"> |