summaryrefslogtreecommitdiff
path: root/gitweb
diff options
context:
space:
mode:
Diffstat (limited to 'gitweb')
-rw-r--r--gitweb/README76
-rwxr-xr-xgitweb/gitweb.perl172
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 .= " &sdot; " .
+ $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 .= " &sdot; " .
+ $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">