gitweb: bugfix: commitdiff regression
[gitweb.git] / gitweb / gitweb.perl
index 4bffbf27f37a54344985a32bbca462c2510a9e03..18ba4b0d86e8e78fef5a2c8bfa645063e90acad3 100755 (executable)
@@ -15,6 +15,7 @@
 use Encode;
 use Fcntl ':mode';
 use File::Find qw();
+use File::Basename qw(basename);
 binmode STDOUT, ':utf8';
 
 our $cgi = new CGI;
@@ -34,7 +35,7 @@
 our $git_temp = "/tmp/gitweb";
 
 # target of the home link on top of all pages
-our $home_link = $my_uri;
+our $home_link = $my_uri || "/";
 
 # string of the home link on top of all pages
 our $home_link_str = "++GITWEB_HOME_LINK_STR++";
@@ -95,8 +96,9 @@
 if (defined $project) {
        $project =~ s|^/||;
        $project =~ s|/$||;
+       $project = undef unless $project;
 }
-if (defined $project && $project) {
+if (defined $project) {
        if (!validate_input($project)) {
                die_error(undef, "Invalid project parameter");
        }
        }
 }
 
+our $file_parent = $cgi->param('fp');
+if (defined $file_parent) {
+       if (!validate_input($file_parent)) {
+               die_error(undef, "Invalid file parent parameter");
+       }
+}
+
 our $hash = $cgi->param('h');
 if (defined $hash) {
        if (!validate_input($hash)) {
        "tag" => \&git_tag,
        "tags" => \&git_tags,
        "tree" => \&git_tree,
+       "snapshot" => \&git_snapshot,
 );
 
 $action = 'summary' if (!defined($action));
@@ -192,6 +202,7 @@ (%)
                action => "a",
                project => "p",
                file_name => "f",
+               file_parent => "fp",
                hash => "h",
                hash_parent => "hp",
                hash_base => "hb",
@@ -1177,6 +1188,66 @@ sub git_print_page_path {
        }
 }
 
+sub git_print_log {
+       my $log = shift;
+
+       # remove leading empty lines
+       while (defined $log->[0] && $log->[0] eq "") {
+               shift @$log;
+       }
+
+       # print log
+       my $signoff = 0;
+       my $empty = 0;
+       foreach my $line (@$log) {
+               # print only one empty line
+               # do not print empty line after signoff
+               if ($line eq "") {
+                       next if ($empty || $signoff);
+                       $empty = 1;
+               } else {
+                       $empty = 0;
+               }
+               if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) {
+                       $signoff = 1;
+                       print "<span class=\"signoff\">" . esc_html($line) . "</span><br/>\n";
+               } else {
+                       $signoff = 0;
+                       print format_log_line_html($line) . "<br/>\n";
+               }
+       }
+}
+
+sub git_print_simplified_log {
+       my $log = shift;
+       my $remove_title = shift;
+
+       shift @$log if $remove_title;
+       # remove leading empty lines
+       while (defined $log->[0] && $log->[0] eq "") {
+               shift @$log;
+       }
+
+       # simplify and print log
+       my $empty = 0;
+       foreach my $line (@$log) {
+               # remove signoff lines
+               if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) {
+                       next;
+               }
+               # print only one empty line
+               if ($line eq "") {
+                       next if $empty;
+                       $empty = 1;
+               } else {
+                       $empty = 0;
+               }
+               print format_log_line_html($line) . "<br/>\n";
+       }
+       # end with single empty line
+       print "<br/>\n" unless $empty;
+}
+
 ## ......................................................................
 ## functions printing large fragments of HTML
 
@@ -1287,8 +1358,7 @@ sub git_difftree_body {
                              $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file)}, "blob");
                        if ($to_id ne $from_id) {
                                print " | " .
-                                     $cgi->a({-href => "$my_uri?" .
-                                             esc_param("p=$project;a=blobdiff;h=$to_id;hp=$from_id;hb=$hash;f=$to_file;fp=$from_file")}, "diff");
+                                     $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$to_file, file_parent=>$from_file)}, "diff");
                        }
                        print "</td>\n";
 
@@ -1309,8 +1379,7 @@ sub git_difftree_body {
                              $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file)}, "blob");
                        if ($to_id ne $from_id) {
                                print " | " .
-                                     $cgi->a({-href => "$my_uri?" .
-                                             esc_param("p=$project;a=blobdiff;h=$to_id;hp=$from_id;hb=$hash;f=$to_file;fp=$from_file")}, "diff");
+                                     $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$to_file, file_parent=>$from_file)}, "diff");
                        }
                        print "</td>\n";
                } # we should not encounter Unmerged (U) or Unknown (X) status
@@ -1322,6 +1391,7 @@ sub git_difftree_body {
 sub git_shortlog_body {
        # uses global variable $project
        my ($revlist, $from, $to, $refs, $extra) = @_;
+       my $have_snapshot = git_get_project_config_bool('snapshot');
        $from = 0 unless defined $from;
        $to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -1346,8 +1416,11 @@ sub git_shortlog_body {
                print "</td>\n" .
                      "<td class=\"link\">" .
                      $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
-                     $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
-                     "</td>\n" .
+                     $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
+               if ($have_snapshot) {
+                       print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
+               }
+               print "</td>\n" .
                      "</tr>\n";
        }
        if (defined $extra) {
@@ -2114,6 +2187,29 @@ sub git_tree {
        git_footer_html();
 }
 
+sub git_snapshot {
+
+       if (!defined $hash) {
+               $hash = git_get_head_hash($project);
+       }
+
+       my $filename = basename($project) . "-$hash.tar.gz";
+
+       print $cgi->header(-type => 'application/x-tar',
+                       -content-encoding => 'gzip',
+                       '-content-disposition' => "inline; filename=\"$filename\"",
+                       -status => '200 OK');
+
+       open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
+                               die_error(undef, "Execute git-tar-tree failed.");
+       binmode STDOUT, ':raw';
+       print <$fd>;
+       binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
+       close $fd;
+
+
+}
+
 sub git_log {
        my $head = git_get_head_hash($project);
        if (!defined $hash) {
@@ -2158,27 +2254,10 @@ sub git_log {
                      "<br/>\n" .
                      "</div>\n" .
                      "<i>" . esc_html($co{'author_name'}) .  " [$ad{'rfc2822'}]</i><br/>\n" .
-                     "</div>\n" .
-                     "<div class=\"log_body\">\n";
-               my $comment = $co{'comment'};
-               my $empty = 0;
-               foreach my $line (@$comment) {
-                       if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) {
-                               next;
-                       }
-                       if ($line eq "") {
-                               if ($empty) {
-                                       next;
-                               }
-                               $empty = 1;
-                       } else {
-                               $empty = 0;
-                       }
-                       print format_log_line_html($line) . "<br/>\n";
-               }
-               if (!$empty) {
-                       print "<br/>\n";
-               }
+                     "</div>\n";
+
+               print "<div class=\"log_body\">\n";
+               git_print_simplified_log($co{'comment'});
                print "</div>\n";
        }
        git_footer_html();
@@ -2208,6 +2287,7 @@ sub git_commit {
        }
        my $refs = git_get_references();
        my $ref = format_ref_marker($refs, $co{'id'});
+       my $have_snapshot = git_get_project_config_bool('snapshot');
        my $formats_nav = '';
        if (defined $file_name && defined $co{'parent'}) {
                my $parent = $co{'parent'};
@@ -2243,8 +2323,11 @@ sub git_commit {
              "<td class=\"sha1\">" .
              $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), class => "list"}, $co{'tree'}) .
              "</td>" .
-             "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree") .
-             "</td>" .
+             "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree");
+       if ($have_snapshot) {
+               print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot");
+       }
+       print "</td>" .
              "</tr>\n";
        my $parents = $co{'parents'};
        foreach my $par (@$parents) {
@@ -2259,28 +2342,9 @@ sub git_commit {
        }
        print "</table>".
              "</div>\n";
+
        print "<div class=\"page_body\">\n";
-       my $comment = $co{'comment'};
-       my $empty = 0;
-       my $signed = 0;
-       foreach my $line (@$comment) {
-               # print only one empty line
-               if ($line eq "") {
-                       if ($empty || $signed) {
-                               next;
-                       }
-                       $empty = 1;
-               } else {
-                       $empty = 0;
-               }
-               if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) {
-                       $signed = 1;
-                       print "<span class=\"signoff\">" . esc_html($line) . "</span><br/>\n";
-               } else {
-                       $signed = 0;
-                       print format_log_line_html($line) . "<br/>\n";
-               }
-       }
+       git_print_log($co{'comment'});
        print "</div>\n";
 
        git_difftree_body(\@difftree, $parent);
@@ -2304,7 +2368,7 @@ sub git_blobdiff {
        git_print_page_path($file_name, "blob");
        print "<div class=\"page_body\">\n" .
              "<div class=\"diff_info\">blob:" .
-             $cgi->a({-href => href(action=>"blob", hash=>$hash_parent, hash_base=>$hash_base, file_name=>$file_name)}, $hash_parent) .
+             $cgi->a({-href => href(action=>"blob", hash=>$hash_parent, hash_base=>$hash_base, file_name=>($file_parent || $file_name))}, $hash_parent) .
              " -> blob:" .
              $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, $hash) .
              "</div>\n";
@@ -2346,29 +2410,7 @@ sub git_commitdiff {
        git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
        git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
        print "<div class=\"page_body\">\n";
-       my $comment = $co{'comment'};
-       my $empty = 0;
-       my $signed = 0;
-       my @log = @$comment;
-       # remove first and empty lines after that
-       shift @log;
-       while (defined $log[0] && $log[0] eq "") {
-               shift @log;
-       }
-       foreach my $line (@log) {
-               if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) {
-                       next;
-               }
-               if ($line eq "") {
-                       if ($empty) {
-                               next;
-                       }
-                       $empty = 1;
-               } else {
-                       $empty = 0;
-               }
-               print format_log_line_html($line) . "<br/>\n";
-       }
+       git_print_simplified_log($co{'comment'}, 1); # skip title
        print "<br/>\n";
        foreach my $line (@difftree) {
                # ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M      ls-files.c'
@@ -2399,7 +2441,7 @@ sub git_commitdiff {
                                      $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$hash_parent, file_name=>$file)}, $from_id) .
                                      " -> " .
                                      file_type($to_mode) . ":" .
-                                     $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, $to_id) .
+                                     $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, $to_id);
                                print "</div>\n";
                                git_diff_print($from_id, "a/$file",  $to_id, "b/$file");
                        }