gitweb: Fix typo in git_patchset_body
[gitweb.git] / gitweb / gitweb.perl
index 0fa35f336994df9756d372c2c89169d0875091c9..7b458bcf8e454deb1136b080b0074dae81fdf2a0 100755 (executable)
@@ -31,9 +31,6 @@
 #our $projectroot = "/pub/scm";
 our $projectroot = "++GITWEB_PROJECTROOT++";
 
-# location for temporary files needed for diffs
-our $git_temp = "/tmp/gitweb";
-
 # target of the home link on top of all pages
 our $home_link = $my_uri || "/";
 
 # You define site-wide feature defaults here; override them with
 # $GITWEB_CONFIG as necessary.
 our %feature = (
-       # feature => {'sub' => feature-sub, 'override' => allow-override, 'default' => [ default options...]
-       # if feature is overridable, feature-sub will be called with default options;
-       # return value indicates if to enable specified feature
+       # feature => {
+       #       'sub' => feature-sub (subroutine),
+       #       'override' => allow-override (boolean),
+       #       'default' => [ default options...] (array reference)}
+       #
+       # if feature is overridable (it means that allow-override has true value,
+       # then feature-sub will be called with default options as parameters;
+       # return value of feature-sub indicates if to enable specified feature
+       #
+       # use gitweb_check_feature(<feature>) to check if <feature> is enabled
 
        'blame' => {
                'sub' => \&feature_blame,
@@ -98,9 +102,9 @@ sub gitweb_check_feature {
 }
 
 # To enable system wide have in $GITWEB_CONFIG
-# $feature{'blame'}{'default'} =  [1];
-# To have project specific config enable override in  $GITWEB_CONFIG
-# $feature{'blame'}{'override'} =  1;
+# $feature{'blame'}{'default'} = [1];
+# To have project specific config enable override in $GITWEB_CONFIG
+# $feature{'blame'}{'override'} = 1;
 # and in project config gitweb.blame = 0|1;
 
 sub feature_blame {
@@ -116,9 +120,9 @@ sub feature_blame {
 }
 
 # To disable system wide have in $GITWEB_CONFIG
-# $feature{'snapshot'}{'default'} =  [undef];
-# To have project specific config enable override in  $GITWEB_CONFIG
-# $feature{'blame'}{'override'} =  1;
+# $feature{'snapshot'}{'default'} = [undef];
+# To have project specific config enable override in $GITWEB_CONFIG
+# $feature{'blame'}{'override'} = 1;
 # and in project config  gitweb.snapshot = none|gzip|bzip2
 
 sub feature_snapshot {
@@ -144,9 +148,6 @@ sub feature_snapshot {
 our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
 
 $projects_list ||= $projectroot;
-if (! -d $git_temp) {
-       mkdir($git_temp, 0700) || die_error(undef, "Couldn't mkdir $git_temp");
-}
 
 # ======================================================================
 # input validation and dispatch
@@ -1555,7 +1556,7 @@ sub git_difftree_body {
                                      "blob") .
                              " | " .
                              $cgi->a({-href => href(action=>"history", hash_base=>$parent,
-                                                    file_name=>$diff{'file'})},\
+                                                    file_name=>$diff{'file'})},
                                      "history") .
                              "</td>\n";
 
@@ -1655,7 +1656,7 @@ sub git_patchset_body {
        print "<div class=\"patchset\">\n";
 
        LINE:
-       while (my $patch_line @$fd>) {
+       while (my $patch_line = <$fd>) {
                chomp $patch_line;
 
                if ($patch_line =~ m/^diff /) { # "git diff" header
@@ -1975,77 +1976,6 @@ sub git_heads_body {
        print "</table>\n";
 }
 
-## ----------------------------------------------------------------------
-## functions printing large fragments, format as one of arguments
-
-sub git_diff_print {
-       my $from = shift;
-       my $from_name = shift;
-       my $to = shift;
-       my $to_name = shift;
-       my $format = shift || "html";
-
-       my $from_tmp = "/dev/null";
-       my $to_tmp = "/dev/null";
-       my $pid = $$;
-
-       # create tmp from-file
-       if (defined $from) {
-               $from_tmp = "$git_temp/gitweb_" . $$ . "_from";
-               open my $fd2, "> $from_tmp";
-               open my $fd, "-|", $GIT, "cat-file", "blob", $from;
-               my @file = <$fd>;
-               print $fd2 @file;
-               close $fd2;
-               close $fd;
-       }
-
-       # create tmp to-file
-       if (defined $to) {
-               $to_tmp = "$git_temp/gitweb_" . $$ . "_to";
-               open my $fd2, "> $to_tmp";
-               open my $fd, "-|", $GIT, "cat-file", "blob", $to;
-               my @file = <$fd>;
-               print $fd2 @file;
-               close $fd2;
-               close $fd;
-       }
-
-       open my $fd, "-|", "/usr/bin/diff -u -p -L \'$from_name\' -L \'$to_name\' $from_tmp $to_tmp";
-       if ($format eq "plain") {
-               undef $/;
-               print <$fd>;
-               $/ = "\n";
-       } else {
-               while (my $line = <$fd>) {
-                       chomp $line;
-                       my $char = substr($line, 0, 1);
-                       my $diff_class = "";
-                       if ($char eq '+') {
-                               $diff_class = " add";
-                       } elsif ($char eq "-") {
-                               $diff_class = " rem";
-                       } elsif ($char eq "@") {
-                               $diff_class = " chunk_header";
-                       } elsif ($char eq "\\") {
-                               # skip errors
-                               next;
-                       }
-                       $line = untabify($line);
-                       print "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n";
-               }
-       }
-       close $fd;
-
-       if (defined $from) {
-               unlink($from_tmp);
-       }
-       if (defined $to) {
-               unlink($to_tmp);
-       }
-}
-
-
 ## ======================================================================
 ## ======================================================================
 ## actions
@@ -2368,7 +2298,7 @@ sub git_blame {
                chomp $line;
                $line_class_num = ($line_class_num + 1) % $line_class_len;
 
-               if ($line =~ m/^([0-9a-fA-F]{40})\t\(\s*([^\t]+)\t(\d+) \+\d\d\d\d\t(\d+)\)(.*)$/) {
+               if ($line =~ m/^([0-9a-fA-F]{40})\t\(\s*([^\t]+)\t(\d+) [+-]\d\d\d\d\t(\d+)\)(.*)$/) {
                        $long_rev = $1;
                        $author   = $2;
                        $time     = $3;
@@ -2433,6 +2363,12 @@ sub git_heads {
 }
 
 sub git_blob_plain {
+       # blobs defined by non-textual hash id's can be cached
+       my $expires;
+       if ($hash =~ m/^[0-9a-fA-F]{40}$/) {
+               $expires = "+1d";
+       }
+
        if (!defined $hash) {
                if (defined $file_name) {
                        my $base = $hash_base || git_get_head_hash($project);
@@ -2456,8 +2392,10 @@ sub git_blob_plain {
                $save_as .= '.txt';
        }
 
-       print $cgi->header(-type => "$type",
-                          -content_disposition => "inline; filename=\"$save_as\"");
+       print $cgi->header(
+               -type => "$type",
+               -expires=>$expires,
+               -content_disposition => "inline; filename=\"$save_as\"");
        undef $/;
        binmode STDOUT, ':raw';
        print <$fd>;
@@ -2467,6 +2405,12 @@ sub git_blob_plain {
 }
 
 sub git_blob {
+       # blobs defined by non-textual hash id's can be cached
+       my $expires;
+       if ($hash =~ m/^[0-9a-fA-F]{40}$/) {
+               $expires = "+1d";
+       }
+
        if (!defined $hash) {
                if (defined $file_name) {
                        my $base = $hash_base || git_get_head_hash($project);
@@ -2484,7 +2428,7 @@ sub git_blob {
                close $fd;
                return git_blob_plain($mimetype);
        }
-       git_header_html();
+       git_header_html(undef, $expires);
        my $formats_nav = '';
        if (defined $hash_base && (my %co = parse_commit($hash_base))) {
                if (defined $file_name) {
@@ -2815,9 +2759,12 @@ sub git_commit {
 }
 
 sub git_blobdiff {
+       my $format = shift || 'html';
+
        my $fd;
        my @difftree;
        my %diffinfo;
+       my $expires;
 
        # preparing $fd and %diffinfo for git_patchset_body
        # new style URI
@@ -2866,6 +2813,12 @@ sub git_blobdiff {
                $hash_parent ||= $diffinfo{'from_id'};
                $hash        ||= $diffinfo{'to_id'};
 
+               # non-textual hash id's can be cached
+               if ($hash_base =~ m/^[0-9a-fA-F]{40}$/ &&
+                   $hash_parent_base =~ m/^[0-9a-fA-F]{40}$/) {
+                       $expires = '+1d';
+               }
+
                # open patch output
                open $fd, "-|", $GIT, "diff-tree", '-r', '-p', '-M', '-C', $hash_parent_base, $hash_base,
                        "--", $file_name
@@ -2895,8 +2848,14 @@ sub git_blobdiff {
                        $diffinfo{'to_file'}   = $hash;
                }
 
-               #open $fd, "-|", $GIT, "diff", '-p', $hash_parent, $hash
-               open $fd, "-|", $GIT, "diff", '-p', $hash, $hash_parent
+               # non-textual hash id's can be cached
+               if ($hash =~ m/^[0-9a-fA-F]{40}$/ &&
+                   $hash_parent =~ m/^[0-9a-fA-F]{40}$/) {
+                       $expires = '+1d';
+               }
+
+               # open patch output
+               open $fd, "-|", $GIT, "diff", '-p', $hash_parent, $hash
                        or die_error(undef, "Open git-diff failed");
        } else  {
                die_error('404 Not Found', "Missing one of the blob diff parameters")
@@ -2904,40 +2863,67 @@ sub git_blobdiff {
        }
 
        # header
-       my $formats_nav =
-               $cgi->a({-href => href(action=>"blobdiff_plain",
-                                      hash=>$hash, hash_parent=>$hash_parent,
-                                      hash_base=>$hash_base, hash_parent_base=>$hash_parent_base,
-                                      file_name=>$file_name, file_parent=>$file_parent)},
-                       "plain");
-       git_header_html();
-       if (defined $hash_base && (my %co = parse_commit($hash_base))) {
-               git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
-               git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
-       } else {
-               print "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n";
-               print "<div class=\"title\">$hash vs $hash_parent</div>\n";
-       }
-       if (defined $file_name) {
-               git_print_page_path($file_name, "blob", $hash_base);
+       if ($format eq 'html') {
+               my $formats_nav =
+                       $cgi->a({-href => href(action=>"blobdiff_plain",
+                                              hash=>$hash, hash_parent=>$hash_parent,
+                                              hash_base=>$hash_base, hash_parent_base=>$hash_parent_base,
+                                              file_name=>$file_name, file_parent=>$file_parent)},
+                               "plain");
+               git_header_html(undef, $expires);
+               if (defined $hash_base && (my %co = parse_commit($hash_base))) {
+                       git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
+                       git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
+               } else {
+                       print "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n";
+                       print "<div class=\"title\">$hash vs $hash_parent</div>\n";
+               }
+               if (defined $file_name) {
+                       git_print_page_path($file_name, "blob", $hash_base);
+               } else {
+                       print "<div class=\"page_path\"></div>\n";
+               }
+
+       } elsif ($format eq 'plain') {
+               print $cgi->header(
+                       -type => 'text/plain',
+                       -charset => 'utf-8',
+                       -expires => $expires,
+                       -content_disposition => qq(inline; filename="${file_name}.patch"));
+
+               print "X-Git-Url: " . $cgi->self_url() . "\n\n";
+
        } else {
-               print "<div class=\"page_path\"></div>\n";
+               die_error(undef, "Unknown blobdiff format");
        }
 
        # patch
-       print "<div class=\"page_body\">\n";
+       if ($format eq 'html') {
+               print "<div class=\"page_body\">\n";
 
-       git_patchset_body($fd, [ \%diffinfo ], $hash_base, $hash_parent_base);
-       close $fd;
+               git_patchset_body($fd, [ \%diffinfo ], $hash_base, $hash_parent_base);
+               close $fd;
 
-       print "</div>\n"; # class="page_body"
-       git_footer_html();
+               print "</div>\n"; # class="page_body"
+               git_footer_html();
+
+       } else {
+               while (my $line = <$fd>) {
+                       $line =~ s!a/($hash|$hash_parent)!a/$diffinfo{'from_file'}!g;
+                       $line =~ s!b/($hash|$hash_parent)!b/$diffinfo{'to_file'}!g;
+
+                       print $line;
+
+                       last if $line =~ m!^\+\+\+!;
+               }
+               local $/ = undef;
+               print <$fd>;
+               close $fd;
+       }
 }
 
 sub git_blobdiff_plain {
-       mkdir($git_temp, 0700);
-       print $cgi->header(-type => "text/plain", -charset => 'utf-8');
-       git_diff_print($hash_parent, $file_name || $hash_parent, $hash, $file_name || $hash, "plain");
+       git_blobdiff('plain');
 }
 
 sub git_commitdiff {