From 756d2f064b2419fcdf9cd9c851f352e2a4f75103 Mon Sep 17 00:00:00 2001 From: Martin Waitz Date: Thu, 17 Aug 2006 00:28:36 +0200 Subject: [PATCH 01/46] gitweb: continue consolidation of URL generation. Further use href() instead of URL generation by string concatenation. Almost all functions are converted now. Signed-off-by: Martin Waitz Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 68 ++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 04282fa5e3..4bffbf27f3 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -204,7 +204,9 @@ (%) my $href = "$my_uri?"; $href .= esc_param( join(";", - map { "$mapping{$_}=$params{$_}" } keys %params + map { + "$mapping{$_}=$params{$_}" if defined $params{$_} + } keys %params ) ); return $href; @@ -1058,7 +1060,7 @@ sub git_footer_html { } print $cgi->a({-href => href(action=>"rss"), -class => "rss_logo"}, "RSS") . "\n"; } else { - print $cgi->a({-href => "$my_uri?" . esc_param("a=opml"), -class => "rss_logo"}, "OPML") . "\n"; + print $cgi->a({-href => href(action=>"opml"), -class => "rss_logo"}, "OPML") . "\n"; } print "\n" . "\n" . @@ -1263,7 +1265,7 @@ sub git_difftree_body { "" . $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, "blob"); if ($to_id ne $from_id) { # modified - print $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$file)}, "diff"); + print " | " . $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$file)}, "diff"); } print " | " . $cgi->a({-href => href(action=>"history", hash_base=>$hash, file_name=>$file)}, "history") . "\n"; print "\n"; @@ -1674,16 +1676,16 @@ sub git_project_list { print "\n"; } $alternate ^= 1; - print "" . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary"), + print "" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"), -class => "list"}, esc_html($pr->{'path'})) . "\n" . "" . esc_html($pr->{'descr'}) . "\n" . "" . chop_str($pr->{'owner'}, 15) . "\n"; print "{'commit'}{'age'}) . "\">" . $pr->{'commit'}{'age_string'} . "\n" . "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary")}, "summary") . " | " . - $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=shortlog")}, "shortlog") . " | " . - $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=log")}, "log") . + $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary") . " | " . + $cgi->a({-href => href(project=>$pr->{'path'}, action=>"shortlog")}, "shortlog") . " | " . + $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . "\n" . "\n"; } @@ -2051,11 +2053,11 @@ sub git_tree { my $refs = git_get_references(); my $ref = format_ref_marker($refs, $hash_base); git_header_html(); - my $base_key = ""; + my %base_key = (); my $base = ""; my $have_blame = git_get_project_config_bool ('blame'); if (defined $hash_base && (my %co = parse_commit($hash_base))) { - $base_key = ";hb=$hash_base"; + $base_key{hash_base} = $hash_base; git_print_page_nav('tree','', $hash_base); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base); } else { @@ -2086,23 +2088,23 @@ sub git_tree { print "" . mode_str($t_mode) . "\n"; if ($t_type eq "blob") { print "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$t_hash$base_key;f=$base$t_name"), -class => "list"}, esc_html($t_name)) . + $cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key), -class => "list"}, esc_html($t_name)) . "\n" . "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$t_hash$base_key;f=$base$t_name")}, "blob"); + $cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, "blob"); if ($have_blame) { - print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$t_hash$base_key;f=$base$t_name")}, "blame"); + print " | " . $cgi->a({-href => href(action=>"blame", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, "blame"); } - print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;h=$t_hash;hb=$hash_base;f=$base$t_name")}, "history") . - " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$t_hash;f=$base$t_name")}, "raw") . + print " | " . $cgi->a({-href => href(action=>"history", hash=>$t_hash, hash_base=>$hash_base, file_name=>"$base$t_name")}, "history") . + " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$t_hash, file_name=>"$base$t_name")}, "raw") . "\n"; } elsif ($t_type eq "tree") { print "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$t_hash$base_key;f=$base$t_name")}, esc_html($t_name)) . + $cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, esc_html($t_name)) . "\n" . "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$t_hash$base_key;f=$base$t_name")}, "tree") . - " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;hb=$hash_base;f=$base$t_name")}, "history") . + $cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, "tree") . + " | " . $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, file_name=>"$base$t_name")}, "history") . "\n"; } print "\n"; @@ -2291,7 +2293,7 @@ sub git_blobdiff { git_header_html(); if (defined $hash_base && (my %co = parse_commit($hash_base))) { my $formats_nav = - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff_plain;h=$hash;hp=$hash_parent")}, "plain"); + $cgi->a({-href => href(action=>"blobdiff_plain", hash=>$hash, hash_parent=>$hash_parent)}, "plain"); git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); } else { @@ -2302,9 +2304,9 @@ sub git_blobdiff { git_print_page_path($file_name, "blob"); print "
\n" . "
blob:" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash_parent;hb=$hash_base;f=$file_name")}, $hash_parent) . + $cgi->a({-href => href(action=>"blob", hash=>$hash_parent, hash_base=>$hash_base, file_name=>$file_name)}, $hash_parent) . " -> blob:" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, $hash) . + $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, $hash) . "
\n"; git_diff_print($hash_parent, $file_name || $hash_parent, $hash, $file_name || $hash); print "
"; @@ -2339,7 +2341,7 @@ sub git_commitdiff { my $refs = git_get_references(); my $ref = format_ref_marker($refs, $co{'id'}); my $formats_nav = - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff_plain;h=$hash;hp=$hash_parent")}, "plain"); + $cgi->a({-href => href(action=>"commitdiff_plain", hash=>$hash, hash_parent=>$hash_parent)}, "plain"); git_header_html(undef, $expires); git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash); @@ -2382,22 +2384,22 @@ sub git_commitdiff { my $file = validate_input(unquote($6)); if ($status eq "A") { print "
" . file_type($to_mode) . ":" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$file")}, $to_id) . "(new)" . + $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, $to_id) . "(new)" . "
\n"; git_diff_print(undef, "/dev/null", $to_id, "b/$file"); } elsif ($status eq "D") { print "
" . file_type($from_mode) . ":" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$from_id;hb=$hash_parent;f=$file")}, $from_id) . "(deleted)" . + $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$hash_parent, file_name=>$file)}, $from_id) . "(deleted)" . "
\n"; git_diff_print($from_id, "a/$file", undef, "/dev/null"); } elsif ($status eq "M") { if ($from_id ne $to_id) { print "
" . file_type($from_mode) . ":" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$from_id;hb=$hash_parent;f=$file")}, $from_id) . + $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 => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$file")}, $to_id); + $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, $to_id) . print "
\n"; git_diff_print($from_id, "a/$file", $to_id, "b/$file"); } @@ -2559,7 +2561,7 @@ sub git_search { print "$co{'age_string_date'}\n" . "" . esc_html(chop_str($co{'author_name'}, 15, 5)) . "\n" . "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$co{'id'}"), -class => "list"}, "" . esc_html(chop_str($co{'title'}, 50)) . "
"); + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}) -class => "list"}, "" . esc_html(chop_str($co{'title'}, 50)) . "
"); my $comment = $co{'comment'}; foreach my $line (@$comment) { if ($line =~ m/^(.*)($searchtext)(.*)$/i) { @@ -2574,8 +2576,8 @@ sub git_search { } print "\n" . "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$co{'id'}")}, "commit") . - " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$co{'id'}")}, "tree"); + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") . + " | " . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); print "\n" . "\n"; } @@ -2612,18 +2614,18 @@ sub git_search { print "$co{'age_string_date'}\n" . "" . esc_html(chop_str($co{'author_name'}, 15, 5)) . "\n" . "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$co{'id'}"), -class => "list"}, "" . + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list"}, "" . esc_html(chop_str($co{'title'}, 50)) . "
"); while (my $setref = shift @files) { my %set = %$setref; - print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$set{'id'};hb=$co{'id'};f=$set{'file'}"), class => "list"}, + print $cgi->a({-href => href(action=>"blob", hash=>$set{'id'}, hash_base=>$co{'id'}, file_name=>$set{'file'}), class => "list"}, "" . esc_html($set{'file'}) . "") . "
\n"; } print "\n" . "" . - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$co{'id'}")}, "commit") . - " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$co{'id'}")}, "tree"); + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") . + " | " . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); print "\n" . "\n"; } @@ -2656,7 +2658,7 @@ sub git_shortlog { my $next_link = ''; if ($#revlist >= (100 * ($page+1)-1)) { $next_link = - $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page+1)), + $cgi->a({-href => href(action=>"shortlog", hash=>$hash, page=>$page+1), -title => "Alt-n"}, "next"); } From 5c95fab017681f6ab21bf82c195bf0a3826fe014 Mon Sep 17 00:00:00 2001 From: Martin Waitz Date: Thu, 17 Aug 2006 00:28:38 +0200 Subject: [PATCH 02/46] gitweb: support for "fp" parameter. The "fp" (file name parent) parameter was previously generated for blob diffs of renamed files. However, it was not used in any code. Now href() can generate "fp" parameters and they are used by the blobdiff code to show the correct file name. Signed-off-by: Martin Waitz Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 4bffbf27f3..43285798e9 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -119,6 +119,13 @@ } } +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)) { @@ -192,6 +199,7 @@ (%) action => "a", project => "p", file_name => "f", + file_parent => "fp", hash => "h", hash_parent => "hp", hash_base => "hb", @@ -1287,8 +1295,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 "\n"; @@ -1309,8 +1316,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 "\n"; } # we should not encounter Unmerged (U) or Unknown (X) status @@ -2304,7 +2310,7 @@ sub git_blobdiff { git_print_page_path($file_name, "blob"); print "
\n" . "
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) . "
\n"; From 6132b7e4bbdbca14aff72d87784909810edefb82 Mon Sep 17 00:00:00 2001 From: Martin Waitz Date: Thu, 17 Aug 2006 00:28:39 +0200 Subject: [PATCH 03/46] gitweb: support for / as home_link. If the webserver is configured to use gitweb even for the root directory of the site, then my_uri is empty which leads to a non-functional home link. Fix that by defaulting to "/" in this case. Signed-off-by: Martin Waitz Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 43285798e9..0dd24679dd 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -34,7 +34,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++"; From 13d02165042c6139905dad38ee8324780d771d99 Mon Sep 17 00:00:00 2001 From: Martin Waitz Date: Thu, 17 Aug 2006 00:28:40 +0200 Subject: [PATCH 04/46] gitweb: fix project list if PATH_INFO=="/". The project list now uses several common header / footer generation functions. These functions only check for "defined $project", but when PATH_INFO just contains a "/" (which is often generated by web servers), then this test fails. Now explicitly undef $project if there is none so that the tests in other gitweb parts work again. Signed-off-by: Martin Waitz Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0dd24679dd..cd9395df93 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -95,8 +95,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"); } From d16d093c2dcdd31b71b278591db18a9b0ccdbe90 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 17 Aug 2006 11:21:23 +0200 Subject: [PATCH 05/46] gitweb: Refactor printing commit message Separate pretty-printing commit message (comment) into git_print_log and git_print_simplified_log subroutines. As of now the former is used in git_commit, the latter in git_log and git_commitdiff. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 132 +++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index cd9395df93..36d3082152 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1186,6 +1186,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 "" . esc_html($line) . "
\n"; + } else { + $signoff = 0; + print format_log_line_html($line) . "
\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) . "
\n"; + } + # end with single empty line + print "
\n" unless $empty; +} + ## ...................................................................... ## functions printing large fragments of HTML @@ -2165,27 +2225,10 @@ sub git_log { "
\n" . "
\n" . "" . esc_html($co{'author_name'}) . " [$ad{'rfc2822'}]
\n" . - "\n" . - "
\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) . "
\n"; - } - if (!$empty) { - print "
\n"; - } + "
\n"; + + print "
\n"; + git_print_simplified_log($co{'comment'}); print "
\n"; } git_footer_html(); @@ -2266,28 +2309,9 @@ sub git_commit { } print "". "\n"; + print "
\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 "" . esc_html($line) . "
\n"; - } else { - $signed = 0; - print format_log_line_html($line) . "
\n"; - } - } + git_print_log($co{'comment'}); print "
\n"; git_difftree_body(\@difftree, $parent); @@ -2353,29 +2377,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 "
\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) . "
\n"; - } + git_print_simplified_log($co{'comment'}, 1); # skip title print "
\n"; foreach my $line (@difftree) { # ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M ls-files.c' From cb9c6e5b0a3772a979aff10f58a2b7fcd0fbe7d9 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 17 Aug 2006 20:59:46 +0530 Subject: [PATCH 06/46] gitweb: Support for snapshot This adds snapshort support in gitweb. To enable one need to set gitweb.snapshot = true in the config file. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 36d3082152..941dce0e88 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -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; @@ -183,6 +184,7 @@ "tag" => \&git_tag, "tags" => \&git_tags, "tree" => \&git_tree, + "snapshot" => \&git_snapshot, ); $action = 'summary' if (!defined($action)); @@ -1389,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); @@ -1413,8 +1416,11 @@ sub git_shortlog_body { print "\n" . "" . $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . - $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . - "\n" . + $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff"); + if ($have_snapshot) { + print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot"); + } + print "\n" . "\n"; } if (defined $extra) { @@ -2181,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) { @@ -2258,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'}; @@ -2293,8 +2323,11 @@ sub git_commit { "" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), class => "list"}, $co{'tree'}) . "" . - "" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree") . - "" . + "" . $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 "" . "\n"; my $parents = $co{'parents'}; foreach my $par (@$parents) { From 3899e7a329aabfc22eca9beb82599e1bb214b3d2 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 17 Aug 2006 13:52:09 -0700 Subject: [PATCH 07/46] gitweb: bugfix: commitdiff regression Fix regression in git_commitdiff() introduced by commit 756d2f064b2419fcdf9cd9c851f352e2a4f75103. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 941dce0e88..18ba4b0d86 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2441,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 "
\n"; git_diff_print($from_id, "a/$file", $to_id, "b/$file"); } From 59fb1c944551083bbd4bccd1b5783488745f6bc4 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 17 Aug 2006 10:39:29 -0700 Subject: [PATCH 08/46] gitweb: bugfix: git_print_page_path() needs the hash base If a file F exists in branch B, but doesn't exist in master branch, then blob_plain needs the hash base in order to properly get the file. The hash base is passed on symbolically so we still preserve the "latest" quality of the link presented by git_print_page_path(). Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 18ba4b0d86..f7c0418c6b 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1177,12 +1177,18 @@ sub git_print_header_div { sub git_print_page_path { my $name = shift; my $type = shift; + my $hb = shift; if (!defined $name) { print "
/
\n"; } elsif (defined $type && $type eq 'blob') { - print "
" . - $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name)}, esc_html($name)) . "
\n"; + print "
"; + if (defined $hb) { + print $cgi->a({-href => href(action=>"blob_plain", hash_base=>$hb, file_name=>$file_name)}, esc_html($name)); + } else { + print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name)}, esc_html($name)); + } + print "
\n"; } else { print "
" . esc_html($name) . "
\n"; } @@ -1874,7 +1880,7 @@ sub git_blame2 { " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, "head"); git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); - git_print_page_path($file_name, $ftype); + git_print_page_path($file_name, $ftype, $hash_base); my @rev_color = (qw(light2 dark2)); my $num_colors = scalar(@rev_color); my $current_color = 0; @@ -1928,7 +1934,7 @@ sub git_blame { " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, "head"); git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); - git_print_page_path($file_name, 'blob'); + git_print_page_path($file_name, 'blob', $hash_base); print "
\n"; print < @@ -2091,7 +2097,7 @@ sub git_blob { "

\n" . "
$hash
\n"; } - git_print_page_path($file_name, "blob"); + git_print_page_path($file_name, "blob", $hash_base); print "
\n"; my $nr; while (my $line = <$fd>) { @@ -2141,7 +2147,7 @@ sub git_tree { if (defined $file_name) { $base = esc_html("$file_name/"); } - git_print_page_path($file_name, 'tree'); + git_print_page_path($file_name, 'tree', $hash_base); print "
\n"; print "\n"; my $alternate = 0; @@ -2365,7 +2371,7 @@ sub git_blobdiff { "

\n" . "
$hash vs $hash_parent
\n"; } - git_print_page_path($file_name, "blob"); + git_print_page_path($file_name, "blob", $hash_base); print "
\n" . "
blob:" . $cgi->a({-href => href(action=>"blob", hash=>$hash_parent, hash_base=>$hash_base, file_name=>($file_parent || $file_name))}, $hash_parent) . @@ -2535,7 +2541,7 @@ sub git_history { if (defined $hash) { $ftype = git_get_type($hash); } - git_print_page_path($file_name, $ftype); + git_print_page_path($file_name, $ftype, $hash_base); open my $fd, "-|", $GIT, "rev-list", "--full-history", $hash_base, "--", $file_name; From f0321866be971bf7dda2464d143e5a156182eba8 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 17 Aug 2006 22:56:23 -0700 Subject: [PATCH 09/46] gitweb: fix snapshot support [jc: when I applied the patch I misread RFC 2616 which mildly recommended against using the name "gzip", which was there only for a historical reason. This fixes the mistake up and uses the content-encoding "x-gzip" again.] Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index f7c0418c6b..f8d1036744 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2202,7 +2202,7 @@ sub git_snapshot { my $filename = basename($project) . "-$hash.tar.gz"; print $cgi->header(-type => 'application/x-tar', - -content-encoding => 'gzip', + -content-encoding => 'x-gzip', '-content-disposition' => "inline; filename=\"$filename\"", -status => '200 OK'); From ddb8d900489216a0bf821a26901a21f89571a1c3 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Sun, 20 Aug 2006 11:53:04 +0530 Subject: [PATCH 10/46] gitweb: Make blame and snapshot a feature. This adds blame and snapshot to the feature associative array. This also helps in enabling or disabling these features via GITWEB_CONFIG and overriding if allowed via project specfic config. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 123 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 23 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index f8d1036744..063735dfe0 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -67,6 +67,68 @@ # (relative to the current git repository) our $mimetypes_file = undef; +# 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...] + +'blame' => {'sub' => \&feature_blame, 'override' => 0, 'default' => [0]}, +'snapshot' => {'sub' => \&feature_snapshot, 'override' => 0, 'default' => ['x-gzip', 'gz', 'gzip']}, + +); + +sub gitweb_check_feature { + my ($name) = @_; + return undef unless exists $feature{$name}; + my ($sub, $override, @defaults) = ($feature{$name}{'sub'}, + $feature{$name}{'override'}, + @{$feature{$name}{'default'}}); + if (!$override) { return @defaults; } + return $sub->(@defaults); +} + +# 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; +# and in project config gitweb.blame = 0|1; + +sub feature_blame { + my ($val) = git_get_project_config('blame', '--bool'); + + if ($val eq 'true') { + return 1; + } elsif ($val eq 'false') { + return 0; + } + + return $_[0]; +} + +# 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; +# and in project config gitweb.snapshot = none|gzip|bzip2 + +sub feature_snapshot { + my ($ctype, $suffix, $command) = @_; + + my ($val) = git_get_project_config('snapshot'); + + if ($val eq 'gzip') { + return ('x-gzip', 'gz', 'gzip'); + } elsif ($val eq 'bzip2') { + return ('x-bzip2', 'bz2', 'bzip2'); + } elsif ($val eq 'none') { + return (); + } + + return ($ctype, $suffix, $command); +} + our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; require $GITWEB_CONFIG if -e $GITWEB_CONFIG; @@ -485,24 +547,21 @@ sub git_get_type { } sub git_get_project_config { - my $key = shift; + my ($key, $type) = @_; return unless ($key); $key =~ s/^gitweb\.//; return if ($key =~ m/\W/); - my $val = qx($GIT repo-config --get gitweb.$key); + my @x = ($GIT, 'repo-config'); + if (defined $type) { push @x, $type; } + push @x, "--get"; + push @x, "gitweb.$key"; + my $val = qx(@x); + chomp $val; return ($val); } -sub git_get_project_config_bool { - my $val = git_get_project_config (@_); - if ($val and $val =~ m/true|yes|on/) { - return (1); - } - return; # implicit false -} - # get hash of given path at given ref sub git_get_hash_by_path { my $base = shift; @@ -1397,7 +1456,10 @@ 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'); + + my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); + my $have_snapshot = (defined $ctype && defined $suffix); + $from = 0 unless defined $from; $to = $#{$revlist} if (!defined $to || $#{$revlist} < $to); @@ -1858,7 +1920,10 @@ sub git_tag { sub git_blame2 { my $fd; my $ftype; - die_error(undef, "Permission denied") if (!git_get_project_config_bool ('blame')); + + if (!gitweb_check_feature('blame')) { + die_error('403 Permission denied', "Permission denied"); + } die_error('404 Not Found', "File name not defined") if (!$file_name); $hash_base ||= git_get_head_hash($project); die_error(undef, "Couldn't find base commit") unless ($hash_base); @@ -1916,7 +1981,10 @@ sub git_blame2 { sub git_blame { my $fd; - die_error('403 Permission denied', "Permission denied") if (!git_get_project_config_bool ('blame')); + + if (!gitweb_check_feature('blame')) { + die_error('403 Permission denied', "Permission denied"); + } die_error('404 Not Found', "File name not defined") if (!$file_name); $hash_base ||= git_get_head_hash($project); die_error(undef, "Couldn't find base commit") unless ($hash_base); @@ -2069,7 +2137,7 @@ sub git_blob { die_error(undef, "No file name defined"); } } - my $have_blame = git_get_project_config_bool ('blame'); + my $have_blame = gitweb_check_feature('blame'); open my $fd, "-|", $GIT, "cat-file", "blob", $hash or die_error(undef, "Couldn't cat $file_name, $hash"); my $mimetype = blob_mimetype($fd, $file_name); @@ -2134,7 +2202,7 @@ sub git_tree { git_header_html(); my %base_key = (); my $base = ""; - my $have_blame = git_get_project_config_bool ('blame'); + my $have_blame = gitweb_check_feature('blame'); if (defined $hash_base && (my %co = parse_commit($hash_base))) { $base_key{hash_base} = $hash_base; git_print_page_nav('tree','', $hash_base); @@ -2195,25 +2263,31 @@ sub git_tree { sub git_snapshot { + my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); + my $have_snapshot = (defined $ctype && defined $suffix); + if (!$have_snapshot) { + die_error('403 Permission denied', "Permission denied"); + } + if (!defined $hash) { $hash = git_get_head_hash($project); } - my $filename = basename($project) . "-$hash.tar.gz"; + my $filename = basename($project) . "-$hash.tar.$suffix"; print $cgi->header(-type => 'application/x-tar', - -content-encoding => 'x-gzip', - '-content-disposition' => "inline; filename=\"$filename\"", - -status => '200 OK'); + -content-encoding => $ctype, + '-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."); + open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | $command" 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 { @@ -2293,7 +2367,10 @@ 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 ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); + my $have_snapshot = (defined $ctype && defined $suffix); + my $formats_nav = ''; if (defined $file_name && defined $co{'parent'}) { my $parent = $co{'parent'}; From 740e67f903ce738b25876f6d60faaff21f70fb4a Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Mon, 21 Aug 2006 23:07:00 +0200 Subject: [PATCH 11/46] gitweb: Added parse_difftree_raw_line function for later use Adds parse_difftree_raw_line function which parses one line of "raw" format diff-tree output into a hash. For later use in git_difftree_body, git_commitdiff and git_commitdiff_plain, git_search. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 063735dfe0..824fc53fd2 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -918,6 +918,33 @@ sub parse_ref { return %ref_item; } +sub parse_difftree_raw_line { + my $line = shift; + my %res; + + # ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M ls-files.c' + # ':100644 100644 7f9281985086971d3877aca27704f2aaf9c448ce bc190ebc71bbd923f2b728e505408f5e54bd073a M rev-tree.c' + if ($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/) { + $res{'from_mode'} = $1; + $res{'to_mode'} = $2; + $res{'from_id'} = $3; + $res{'to_id'} = $4; + $res{'status'} = $5; + $res{'similarity'} = $6; + if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied + ($res{'from_file'}, $res{'to_file'}) = map(unquote, split("\t", $7)); + } else { + $res{'file'} = unquote($7); + } + } + # 'c512b523472485aef4fff9e57b229d9d243c967f' + #elsif ($line =~ m/^([0-9a-fA-F]{40})$/) { + # $res{'commit'} = $1; + #} + + return wantarray ? %res : \%res; +} + ## ...................................................................... ## parse to array of hashes functions From e8e41a9383ff8e1fb22a7abb899b16486ad25fe1 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Mon, 21 Aug 2006 23:08:52 +0200 Subject: [PATCH 12/46] gitweb: Use parse_difftree_raw_line in git_difftree_body Use newly introduced parse_difftree_raw_line function in the git_difftree_body subroutine. While at it correct error in parse_difftree_raw_line (unquote is unprototyped function), and add comment explaining this function. It also refactors git_difftree_body somewhat, and tries to fit it in 80 columns. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 178 ++++++++++++++++++++++++--------------------- 1 file changed, 97 insertions(+), 81 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 824fc53fd2..31a1824d7a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -918,6 +918,7 @@ sub parse_ref { return %ref_item; } +# parse line of git-diff-tree "raw" output sub parse_difftree_raw_line { my $line = shift; my %res; @@ -932,7 +933,7 @@ sub parse_difftree_raw_line { $res{'status'} = $5; $res{'similarity'} = $6; if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied - ($res{'from_file'}, $res{'to_file'}) = map(unquote, split("\t", $7)); + ($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7); } else { $res{'file'} = unquote($7); } @@ -1355,18 +1356,7 @@ sub git_difftree_body { print "
\n"; my $alternate = 0; foreach my $line (@{$difftree}) { - # ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M ls-files.c' - # ':100644 100644 7f9281985086971d3877aca27704f2aaf9c448ce bc190ebc71bbd923f2b728e505408f5e54bd073a M rev-tree.c' - if ($line !~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/) { - next; - } - my $from_mode = $1; - my $to_mode = $2; - my $from_id = $3; - my $to_id = $4; - my $status = $5; - my $similarity = $6; # score - my $file = validate_input(unquote($7)); + my %diff = parse_difftree_raw_line($line); if ($alternate) { print "\n"; @@ -1375,105 +1365,131 @@ sub git_difftree_body { } $alternate ^= 1; - if ($status eq "A") { # created - my $mode_chng = ""; - if (S_ISREG(oct $to_mode)) { - $mode_chng = sprintf(" with mode: %04o", (oct $to_mode) & 0777); + my ($to_mode_oct, $to_mode_str, $to_file_type); + my ($from_mode_oct, $from_mode_str, $from_file_type); + if ($diff{'to_mode'} ne ('0' x 6)) { + $to_mode_oct = oct $diff{'to_mode'}; + if (S_ISREG($to_mode_oct)) { # only for regular file + $to_mode_str = sprintf("%04o", $to_mode_oct & 0777); # permission bits } + $to_file_type = file_type($diff{'to_mode'}); + } + if ($diff{'from_mode'} ne ('0' x 6)) { + $from_mode_oct = oct $diff{'from_mode'}; + if (S_ISREG($to_mode_oct)) { # only for regular file + $from_mode_str = sprintf("%04o", $from_mode_oct & 0777); # permission bits + } + $from_file_type = file_type($diff{'from_mode'}); + } + + if ($diff{'status'} eq "A") { # created + my $mode_chng = "[new $to_file_type"; + $mode_chng .= " with mode: $to_mode_str" if $to_mode_str; + $mode_chng .= "]"; print "\n" . - "\n" . + "\n" . "\n"; - } elsif ($status eq "D") { # deleted + } elsif ($diff{'status'} eq "D") { # deleted + my $mode_chng = "[deleted $from_file_type]"; print "\n" . - "\n" . + $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, + hash_base=>$parent, file_name=>$diff{'file'}), + -class => "list"}, esc_html($diff{'file'})) . + "\n" . + "\n" . "\n" + $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, + hash_base=>$parent, file_name=>$diff{'file'})}, + "blob") . + " | " . + $cgi->a({-href => href(action=>"history", hash_base=>$parent, + file_name=>$diff{'file'})},\ + "history") . + "\n"; - } elsif ($status eq "M" || $status eq "T") { # modified, or type changed + } elsif ($diff{'status'} eq "M" || $diff{'status'} eq "T") { # modified, or type changed my $mode_chnge = ""; - if ($from_mode != $to_mode) { - $mode_chnge = " [changed"; - if (((oct $from_mode) & S_IFMT) != ((oct $to_mode) & S_IFMT)) { - $mode_chnge .= " from " . file_type($from_mode) . " to " . file_type($to_mode); + if ($diff{'from_mode'} != $diff{'to_mode'}) { + $mode_chnge = "[changed"; + if ($from_file_type != $to_file_type) { + $mode_chnge .= " from $from_file_type to $to_file_type"; } - if (((oct $from_mode) & 0777) != ((oct $to_mode) & 0777)) { - if (S_ISREG($from_mode) && S_ISREG($to_mode)) { - $mode_chnge .= sprintf(" mode: %04o->%04o", (oct $from_mode) & 0777, (oct $to_mode) & 0777); - } elsif (S_ISREG($to_mode)) { - $mode_chnge .= sprintf(" mode: %04o", (oct $to_mode) & 0777); + if (($from_mode_oct & 0777) != ($to_mode_oct & 0777)) { + if ($from_mode_str && $to_mode_str) { + $mode_chnge .= " mode: $from_mode_str->$to_mode_str"; + } elsif ($to_mode_str) { + $mode_chnge .= " mode: $to_mode_str"; } } $mode_chnge .= "]\n"; } print "\n" . "\n" . "\n"; - } elsif ($status eq "R") { # renamed - my ($from_file, $to_file) = split "\t", $file; + } elsif ($diff{'status'} eq "R" || $diff{'status'} eq "C") { # renamed or copied + my %status_name = ('R' => 'moved', 'C' => 'copied'); + my $nstatus = $status_name{$diff{'status'}}; my $mode_chng = ""; - if ($from_mode != $to_mode) { - $mode_chng = sprintf(", mode: %04o", (oct $to_mode) & 0777); + if ($diff{'from_mode'} != $diff{'to_mode'}) { + # mode also for directories, so we cannot use $to_mode_str + $mode_chng = sprintf(", mode: %04o", $to_mode_oct & 0777); } print "\n" . - "\n" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash, + hash=>$diff{'to_id'}, file_name=>$diff{'to_file'}), + -class => "list"}, esc_html($diff{'to_file'})) . "\n" . + "\n" . "\n"; - } elsif ($status eq "C") { # copied - my ($from_file, $to_file) = split "\t", $file; - my $mode_chng = ""; - if ($from_mode != $to_mode) { - $mode_chng = sprintf(", mode: %04o", (oct $to_mode) & 0777); - } - print "\n" . - "\n" . - "\n"; } # we should not encounter Unmerged (U) or Unknown (X) status print "\n"; } From 7c278014730dc15bf03b8640b1d406c657447092 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 22 Aug 2006 12:02:48 +0200 Subject: [PATCH 13/46] gitweb: bugfix: a.list formatting regression Fix regression introduced by commit 17d07443188909ef5f8b8c24043cb6d9fef51bca. "a.list" being "bold", makes a myriad of things shown by gitweb in bold font-weight, which is a regression from pre-17d07443188909ef5f8b8c24043cb6d9fef51bca behavior. The fix is to add "subject" class and use this class to replace pre-format_subject_html formatting of subject (comment) via using (or not) ... element. This should go back to the pre-17d0744318... style. Regression noticed by Luben Tuikov. Signed-off-by: Jakub Narebski Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 7 +++++-- gitweb/gitweb.perl | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 9013895857..6c13d9ed10 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -117,11 +117,14 @@ div.list_head { a.list { text-decoration: none; - font-weight: bold; color: #000000; } -table.tags a.list { +a.subject { + font-weight: bold; +} + +table.tags a.subject { font-weight: normal; } diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 31a1824d7a..0e4697731d 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -504,11 +504,11 @@ sub format_subject_html { $extra = '' unless defined($extra); if (length($short) < length($long)) { - return $cgi->a({-href => $href, -class => "list", + return $cgi->a({-href => $href, -class => "list subject", -title => $long}, esc_html($short) . $extra); } else { - return $cgi->a({-href => $href, -class => "list"}, + return $cgi->a({-href => $href, -class => "list subject"}, esc_html($long) . $extra); } } From 63e4220b75d4fd7c8820209193641f3207d24238 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 22 Aug 2006 12:38:59 +0200 Subject: [PATCH 14/46] gitweb: Replace some presentational HTML by CSS Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 3 ++- gitweb/gitweb.perl | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 6c13d9ed10..4821022535 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -42,6 +42,7 @@ div.page_nav a:visited { div.page_path { padding: 8px; + font-weight: bold; border: solid #d9d8d1; border-width: 0px 0px 1px; } @@ -120,7 +121,7 @@ a.list { color: #000000; } -a.subject { +a.subject, a.name { font-weight: bold; } diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0e4697731d..39f719ca55 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1267,17 +1267,17 @@ sub git_print_page_path { my $hb = shift; if (!defined $name) { - print "
/
\n"; + print "
/
\n"; } elsif (defined $type && $type eq 'blob') { - print "
"; + print "
"; if (defined $hb) { print $cgi->a({-href => href(action=>"blob_plain", hash_base=>$hb, file_name=>$file_name)}, esc_html($name)); } else { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name)}, esc_html($name)); } - print "
\n"; + print "
\n"; } else { - print "
" . esc_html($name) . "
\n"; + print "
" . esc_html($name) . "
\n"; } } @@ -1626,7 +1626,7 @@ sub git_tags_body { print "
\n" . "\n" . "\n" . ($tag{'id'} eq $head ? "\n" . "\n" . "\n" . "\n" . "\n" . "\n" . "\n" . "\n" . "\n" . "\n" . "\n" . "\n" . "\n"; print "\n"; - print "\n"; + $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)}, + esc_html($rev)) . "\n"; + print "\n"; print "\n"; print "\n"; } print "
" . - $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file), - -class => "list"}, esc_html($file)) . + $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, + hash_base=>$hash, file_name=>$diff{'file'}), + -class => "list"}, esc_html($diff{'file'})) . "[new " . file_type($to_mode) . "$mode_chng]$mode_chng" . - $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, "blob") . + $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, + hash_base=>$hash, file_name=>$diff{'file'})}, + "blob") . "" . - $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$file), - -class => "list"}, esc_html($file)) . "[deleted " . file_type($from_mode). "]$mode_chng" . - $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$file)}, "blob") . " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$parent, file_name=>$file)}, "history") . - ""; - if ($to_id ne $from_id) { # modified - print $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$file), - -class => "list"}, esc_html($file)); - } else { # mode changed - print $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file), - -class => "list"}, esc_html($file)); + if ($diff{'to_id'} ne $diff{'from_id'}) { # modified + print $cgi->a({-href => href(action=>"blobdiff", hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, file_name=>$diff{'file'}), + -class => "list"}, esc_html($diff{'file'})); + } else { # only mode changed + print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, + hash_base=>$hash, file_name=>$diff{'file'}), + -class => "list"}, esc_html($diff{'file'})); } print "$mode_chnge" . - $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, "blob"); - if ($to_id ne $from_id) { # modified - print " | " . $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$file)}, "diff"); + $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, + hash_base=>$hash, file_name=>$diff{'file'})}, + "blob"); + if ($diff{'to_id'} ne $diff{'from_id'}) { # modified + print " | " . + $cgi->a({-href => href(action=>"blobdiff", hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, file_name=>$diff{'file'})}, + "diff"); } - print " | " . $cgi->a({-href => href(action=>"history", hash_base=>$hash, file_name=>$file)}, "history") . "\n"; + print " | " . + $cgi->a({-href => href(action=>"history", + hash_base=>$hash, file_name=>$diff{'file'})}, + "history"); print "" . - $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file), - -class => "list"}, esc_html($to_file)) . "[moved from " . - $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$from_file), - -class => "list"}, esc_html($from_file)) . - " with " . (int $similarity) . "% similarity$mode_chng][$nstatus from " . + $cgi->a({-href => href(action=>"blob", hash_base=>$parent, + hash=>$diff{'from_id'}, file_name=>$diff{'from_file'}), + -class => "list"}, esc_html($diff{'from_file'})) . + " with " . (int $diff{'similarity'}) . "% similarity$mode_chng]" . - $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file)}, "blob"); - if ($to_id ne $from_id) { + $cgi->a({-href => href(action=>"blob", hash_base=>$hash, + hash=>$diff{'to_id'}, file_name=>$diff{'to_file'})}, + "blob"); + if ($diff{'to_id'} ne $diff{'from_id'}) { print " | " . - $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"); + $cgi->a({-href => href(action=>"blobdiff", hash_base=>$hash, + hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})}, + "diff"); } print "" . - $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file), - -class => "list"}, esc_html($to_file)) . "[copied from " . - $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$from_file), - -class => "list"}, esc_html($from_file)) . - " with " . (int $similarity) . "% similarity$mode_chng]" . - $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 => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$to_file, file_parent=>$from_file)}, "diff"); - } - print "
$tag{'age'}" . $cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'}), - -class => "list"}, "" . esc_html($tag{'name'}) . "") . + -class => "list name"}, esc_html($tag{'name'})) . ""; if (defined $comment) { @@ -1680,7 +1680,7 @@ sub git_heads_body { print "$tag{'age'}" : "") . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'}), - -class => "list"}, "" . esc_html($tag{'name'}) . "") . + -class => "list name"},esc_html($tag{'name'})) . "" . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " . @@ -2729,7 +2729,8 @@ sub git_search { print "$co{'age_string_date'}" . esc_html(chop_str($co{'author_name'}, 15, 5)) . "" . - $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}) -class => "list"}, "" . esc_html(chop_str($co{'title'}, 50)) . "
"); + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, + esc_html(chop_str($co{'title'}, 50)) . "
"); my $comment = $co{'comment'}; foreach my $line (@$comment) { if ($line =~ m/^(.*)($searchtext)(.*)$/i) { @@ -2782,8 +2783,8 @@ sub git_search { print "
$co{'age_string_date'}" . esc_html(chop_str($co{'author_name'}, 15, 5)) . "" . - $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list"}, "" . - esc_html(chop_str($co{'title'}, 50)) . "
"); + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, + esc_html(chop_str($co{'title'}, 50)) . "
"); while (my $setref = shift @files) { my %set = %$setref; print $cgi->a({-href => href(action=>"blob", hash=>$set{'id'}, hash_base=>$co{'id'}, file_name=>$set{'file'}), class => "list"}, From 952c65fc0201c3d506f7c4d7377ec2d8bb346d4b Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 22 Aug 2006 16:52:50 +0200 Subject: [PATCH 15/46] gitweb: Whitespace cleanup: realign, reindent This patch tries (but no too hard) to fit gitweb source in 80 columns, for 2 columns wide tabs, and indent and align source for better readibility. While at it added comment to 'snapshot' entry defaults for %feature hash, corrected "blobl" action in git_blame2 and git_blame to "blob", key of argument to $cgi->a from 'class' to '-class'. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 253 +++++++++++++++++++++++++++++++-------------- 1 file changed, 176 insertions(+), 77 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 39f719ca55..63dc477eab 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -69,22 +69,30 @@ # You define site-wide feature defaults here; override them with # $GITWEB_CONFIG as necessary. -our %feature = -( +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, 'override' => allow-override, 'default' => [ default options...] - -'blame' => {'sub' => \&feature_blame, 'override' => 0, 'default' => [0]}, -'snapshot' => {'sub' => \&feature_snapshot, 'override' => 0, 'default' => ['x-gzip', 'gz', 'gzip']}, + 'blame' => { + 'sub' => \&feature_blame, + 'override' => 0, + 'default' => [0]}, + 'snapshot' => { + 'sub' => \&feature_snapshot, + 'override' => 0, + # => [content-encoding, suffix, program] + 'default' => ['x-gzip', 'gz', 'gzip']}, ); sub gitweb_check_feature { my ($name) = @_; return undef unless exists $feature{$name}; - my ($sub, $override, @defaults) = ($feature{$name}{'sub'}, - $feature{$name}{'override'}, - @{$feature{$name}{'default'}}); + my ($sub, $override, @defaults) = ( + $feature{$name}{'sub'}, + $feature{$name}{'override'}, + @{$feature{$name}{'default'}}); if (!$override) { return @defaults; } return $sub->(@defaults); } @@ -463,7 +471,9 @@ sub format_log_line_html { if ($line =~ m/([0-9a-fA-F]{40})/) { my $hash_text = $1; if (git_get_type($hash_text) eq "commit") { - my $link = $cgi->a({-class => "text", -href => href(action=>"commit", hash=>$hash_text)}, $hash_text); + my $link = + $cgi->a({-href => href(action=>"commit", hash=>$hash_text), + -class => "text"}, $hash_text); $line =~ s/$hash_text/$link/; } } @@ -734,8 +744,10 @@ sub parse_date { $date{'mday'} = $mday; $date{'day'} = $days[$wday]; $date{'month'} = $months[$mon]; - $date{'rfc2822'} = sprintf "%s, %d %s %4d %02d:%02d:%02d +0000", $days[$wday], $mday, $months[$mon], 1900+$year, $hour ,$min, $sec; - $date{'mday-time'} = sprintf "%d %s %02d:%02d", $mday, $months[$mon], $hour ,$min; + $date{'rfc2822'} = sprintf "%s, %d %s %4d %02d:%02d:%02d +0000", + $days[$wday], $mday, $months[$mon], 1900+$year, $hour ,$min, $sec; + $date{'mday-time'} = sprintf "%d %s %02d:%02d", + $mday, $months[$mon], $hour ,$min; $tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/; my $local = $epoch + ((int $1 + ($2/60)) * 3600); @@ -792,7 +804,8 @@ sub parse_commit { @commit_lines = @$commit_text; } else { $/ = "\0"; - open my $fd, "-|", $GIT, "rev-list", "--header", "--parents", "--max-count=1", $commit_id or return; + open my $fd, "-|", $GIT, "rev-list", "--header", "--parents", "--max-count=1", $commit_id + or return; @commit_lines = split '\n', <$fd>; close $fd or return; $/ = "\n"; @@ -1086,12 +1099,15 @@ sub git_header_html { # 'application/xhtml+xml', otherwise send it as plain old 'text/html'. # we have to do this because MSIE sometimes globs '*/*', pretending to # support xhtml+xml but choking when it gets what it asked for. - if (defined $cgi->http('HTTP_ACCEPT') && $cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ && $cgi->Accept('application/xhtml+xml') != 0) { + if (defined $cgi->http('HTTP_ACCEPT') && + $cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ && + $cgi->Accept('application/xhtml+xml') != 0) { $content_type = 'application/xhtml+xml'; } else { $content_type = 'text/html'; } - print $cgi->header(-type=>$content_type, -charset => 'utf-8', -status=> $status, -expires => $expires); + print $cgi->header(-type=>$content_type, -charset => 'utf-8', + -status=> $status, -expires => $expires); print < @@ -1271,9 +1287,12 @@ sub git_print_page_path { } elsif (defined $type && $type eq 'blob') { print "
"; if (defined $hb) { - print $cgi->a({-href => href(action=>"blob_plain", hash_base=>$hb, file_name=>$file_name)}, esc_html($name)); + print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, + hash_base=>$hb)}, + esc_html($name)); } else { - print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name)}, esc_html($name)); + print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name)}, + esc_html($name)); } print "
\n"; } else { @@ -1523,7 +1542,8 @@ sub git_shortlog_body { print "
$co{'age_string_date'}" . esc_html(chop_str($co{'author_name'}, 10)) . ""; - print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref); + print format_subject_html($co{'title'}, $co{'title_short'}, + href(action=>"commit", hash=>$commit), $ref); print "" . $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . @@ -1572,7 +1592,8 @@ sub git_history_body { "" . esc_html(chop_str($co{'author_name'}, 15, 3)) . ""; # originally git_history used chop_str($co{'title'}, 50) - print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref); + print format_subject_html($co{'title'}, $co{'title_short'}, + href(action=>"commit", hash=>$commit), $ref); print "" . $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . @@ -1585,7 +1606,8 @@ sub git_history_body { if (defined $blob_current && defined $blob_parent && $blob_current ne $blob_parent) { print " | " . - $cgi->a({-href => href(action=>"blobdiff", hash=>$blob_current, hash_parent=>$blob_parent, hash_base=>$commit, file_name=>$file_name)}, + $cgi->a({-href => href(action=>"blobdiff", hash=>$blob_current, hash_parent=>$blob_parent, + hash_base=>$commit, file_name=>$file_name)}, "diff to current"); } } @@ -1630,7 +1652,8 @@ sub git_tags_body { ""; if (defined $comment) { - print format_subject_html($comment, $comment_short, href(action=>"tag", hash=>$tag{'id'})); + print format_subject_html($comment, $comment_short, + href(action=>"tag", hash=>$tag{'id'})); } print ""; @@ -1941,13 +1964,17 @@ sub git_tag { "\n" . "\n" . "\n" . - "\n" . - "\n" . + "\n" . + "\n" . "\n"; if (defined($tag{'author'})) { my %ad = parse_date($tag{'epoch'}, $tag{'tz'}); print "\n"; - print "\n"; + print "\n"; } print "
object" . $cgi->a({-class => "list", -href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, $tag{'object'}) . "" . $cgi->a({-href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, $tag{'type'}) . "" . $cgi->a({-class => "list", -href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, + $tag{'object'}) . "" . $cgi->a({-href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, + $tag{'type'}) . "
author" . esc_html($tag{'author'}) . "
" . $ad{'rfc2822'} . sprintf(" (%02d:%02d %s)", $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}) . "
" . $ad{'rfc2822'} . + sprintf(" (%02d:%02d %s)", $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}) . + "
\n\n" . "\n"; @@ -1984,8 +2011,11 @@ sub git_blame2 { or die_error(undef, "Open git-blame failed"); git_header_html(); my $formats_nav = - $cgi->a({-href => href(action=>"blobl", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, "blob") . - " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, "head"); + $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, + "blob") . + " | " . + $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, + "head"); git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); git_print_page_path($file_name, $ftype, $hash_base); @@ -2011,14 +2041,17 @@ sub git_blame2 { } print "
" . - $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)}, esc_html($rev)) . "" . esc_html($lineno) . "" . + esc_html($lineno) . "" . esc_html($data) . "
\n"; print "
"; - close $fd or print "Reading blob failed\n"; + close $fd + or print "Reading blob failed\n"; git_footer_html(); } @@ -2041,8 +2074,11 @@ sub git_blame { or die_error(undef, "Open git-annotate failed"); git_header_html(); my $formats_nav = - $cgi->a({-href => href(action=>"blobl", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, "blob") . - " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, "head"); + $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, + "blob") . + " | " . + $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, + "head"); git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); git_print_page_path($file_name, 'blob', $hash_base); @@ -2106,7 +2142,8 @@ sub git_blame { HTML } # while (my $line = <$fd>) print "\n\n"; - close $fd or print "Reading blob failed.\n"; + close $fd + or print "Reading blob failed.\n"; print "
"; git_footer_html(); } @@ -2193,13 +2230,23 @@ sub git_blob { if (defined $hash_base && (my %co = parse_commit($hash_base))) { if (defined $file_name) { if ($have_blame) { - $formats_nav .= $cgi->a({-href => href(action=>"blame", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, "blame") . " | "; + $formats_nav .= + $cgi->a({-href => href(action=>"blame", hash_base=>$hash_base, + hash=>$hash, file_name=>$file_name)}, + "blame") . + " | "; } $formats_nav .= - $cgi->a({-href => href(action=>"blob_plain", hash=>$hash, file_name=>$file_name)}, "plain") . - " | " . $cgi->a({-href => href(action=>"blob", hash_base=>"HEAD", file_name=>$file_name)}, "head"); + $cgi->a({-href => href(action=>"blob_plain", + hash=>$hash, file_name=>$file_name)}, + "plain") . + " | " . + $cgi->a({-href => href(action=>"blob", + hash_base=>"HEAD", file_name=>$file_name)}, + "head"); } else { - $formats_nav .= $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "plain"); + $formats_nav .= + $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "plain"); } git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); @@ -2215,9 +2262,11 @@ sub git_blob { chomp $line; $nr++; $line = untabify($line); - printf "
%4i %s
\n", $nr, $nr, $nr, esc_html($line); + printf "
%4i %s
\n", + $nr, $nr, $nr, esc_html($line); } - close $fd or print "Reading blob failed.\n"; + close $fd + or print "Reading blob failed.\n"; print ""; git_footer_html(); } @@ -2278,23 +2327,37 @@ sub git_tree { print "" . mode_str($t_mode) . "\n"; if ($t_type eq "blob") { print "" . - $cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key), -class => "list"}, esc_html($t_name)) . + $cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key), + -class => "list"}, esc_html($t_name)) . "\n" . "" . - $cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, "blob"); + $cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, + "blob"); if ($have_blame) { - print " | " . $cgi->a({-href => href(action=>"blame", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, "blame"); + print " | " . + $cgi->a({-href => href(action=>"blame", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, + "blame"); } - print " | " . $cgi->a({-href => href(action=>"history", hash=>$t_hash, hash_base=>$hash_base, file_name=>"$base$t_name")}, "history") . - " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$t_hash, file_name=>"$base$t_name")}, "raw") . + print " | " . + $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + hash=>$t_hash, file_name=>"$base$t_name")}, + "history") . + " | " . + $cgi->a({-href => href(action=>"blob_plain", + hash=>$t_hash, file_name=>"$base$t_name")}, + "raw") . "\n"; } elsif ($t_type eq "tree") { print "" . - $cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, esc_html($t_name)) . + $cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, + esc_html($t_name)) . "\n" . "" . - $cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, "tree") . - " | " . $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, file_name=>"$base$t_name")}, "history") . + $cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)}, + "tree") . + " | " . + $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, file_name=>"$base$t_name")}, + "history") . "\n"; } print "\n"; @@ -2319,10 +2382,9 @@ sub git_snapshot { my $filename = basename($project) . "-$hash.tar.$suffix"; print $cgi->header(-type => 'application/x-tar', - -content-encoding => $ctype, - '-content-disposition' => - "inline; filename=\"$filename\"", - -status => '200 OK'); + -content-encoding => $ctype, + '-content-disposition' => "inline; filename=\"$filename\"", + -status => '200 OK'); open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | $command" or die_error(undef, "Execute git-tar-tree failed."); @@ -2373,7 +2435,8 @@ sub git_log { print "
\n" . "
\n" . $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . - " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . + " | " . + $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . "
\n" . "
\n" . "" . esc_html($co{'author_name'}) . " [$ad{'rfc2822'}]
\n" . @@ -2417,12 +2480,14 @@ sub git_commit { my $formats_nav = ''; if (defined $file_name && defined $co{'parent'}) { my $parent = $co{'parent'}; - $formats_nav .= $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)}, "blame"); + $formats_nav .= + $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)}, + "blame"); } git_header_html(undef, $expires); git_print_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff', - $hash, $co{'tree'}, $hash, - $formats_nav); + $hash, $co{'tree'}, $hash, + $formats_nav); if (defined $co{'parent'}) { git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash); @@ -2435,23 +2500,31 @@ sub git_commit { "" . " $ad{'rfc2822'}"; if ($ad{'hour_local'} < 6) { - printf(" (%02d:%02d %s)", $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}); + printf(" (%02d:%02d %s)", + $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}); } else { - printf(" (%02d:%02d %s)", $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}); + printf(" (%02d:%02d %s)", + $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}); } print "" . "\n"; print "committer" . esc_html($co{'committer'}) . "\n"; - print " $cd{'rfc2822'}" . sprintf(" (%02d:%02d %s)", $cd{'hour_local'}, $cd{'minute_local'}, $cd{'tz_local'}) . "\n"; + print " $cd{'rfc2822'}" . + sprintf(" (%02d:%02d %s)", $cd{'hour_local'}, $cd{'minute_local'}, $cd{'tz_local'}) . + "\n"; print "commit$co{'id'}\n"; print "" . "tree" . "" . - $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), class => "list"}, $co{'tree'}) . + $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), + class => "list"}, $co{'tree'}) . "" . - "" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree"); + "" . + $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 " | " . + $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot"); } print "" . "\n"; @@ -2459,10 +2532,14 @@ sub git_commit { foreach my $par (@$parents) { print "" . "parent" . - "" . $cgi->a({-href => href(action=>"commit", hash=>$par), class => "list"}, $par) . "" . + "" . + $cgi->a({-href => href(action=>"commit", hash=>$par), + class => "list"}, $par) . + "" . "" . $cgi->a({-href => href(action=>"commit", hash=>$par)}, "commit") . - " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$hash, hash_parent=>$par)}, "commitdiff") . + " | " . + $cgi->a({-href => href(action=>"commitdiff", hash=>$hash, hash_parent=>$par)}, "commitdiff") . "" . "\n"; } @@ -2483,7 +2560,9 @@ sub git_blobdiff { git_header_html(); if (defined $hash_base && (my %co = parse_commit($hash_base))) { my $formats_nav = - $cgi->a({-href => href(action=>"blobdiff_plain", hash=>$hash, hash_parent=>$hash_parent)}, "plain"); + $cgi->a({-href => href(action=>"blobdiff_plain", + hash=>$hash, hash_parent=>$hash_parent)}, + "plain"); git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); } else { @@ -2494,12 +2573,16 @@ sub git_blobdiff { git_print_page_path($file_name, "blob", $hash_base); print "
\n" . "
blob:" . - $cgi->a({-href => href(action=>"blob", hash=>$hash_parent, hash_base=>$hash_base, file_name=>($file_parent || $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) . + $cgi->a({-href => href(action=>"blob", hash=>$hash, + hash_base=>$hash_base, file_name=>$file_name)}, + $hash) . "
\n"; git_diff_print($hash_parent, $file_name || $hash_parent, $hash, $file_name || $hash); - print "
"; + print "
"; # page_body git_footer_html(); } @@ -2531,7 +2614,8 @@ sub git_commitdiff { my $refs = git_get_references(); my $ref = format_ref_marker($refs, $co{'id'}); my $formats_nav = - $cgi->a({-href => href(action=>"commitdiff_plain", hash=>$hash, hash_parent=>$hash_parent)}, "plain"); + $cgi->a({-href => href(action=>"commitdiff_plain", hash=>$hash, hash_parent=>$hash_parent)}, + "plain"); git_header_html(undef, $expires); git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash); @@ -2552,22 +2636,30 @@ sub git_commitdiff { my $file = validate_input(unquote($6)); if ($status eq "A") { print "
" . file_type($to_mode) . ":" . - $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, $to_id) . "(new)" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash, + hash=>$to_id, file_name=>$file)}, + $to_id) . "(new)" . "
\n"; git_diff_print(undef, "/dev/null", $to_id, "b/$file"); } elsif ($status eq "D") { print "
" . file_type($from_mode) . ":" . - $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$hash_parent, file_name=>$file)}, $from_id) . "(deleted)" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, + hash=>$from_id, file_name=>$file)}, + $from_id) . "(deleted)" . "
\n"; git_diff_print($from_id, "a/$file", undef, "/dev/null"); } elsif ($status eq "M") { if ($from_id ne $to_id) { print "
" . file_type($from_mode) . ":" . - $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$hash_parent, file_name=>$file)}, $from_id) . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, + hash=>$from_id, 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_base=>$hash, + hash=>$to_id, file_name=>$file)}, + $to_id); print "
\n"; git_diff_print($from_id, "a/$file", $to_id, "b/$file"); } @@ -2607,7 +2699,9 @@ sub git_commitdiff_plain { } } - print $cgi->header(-type => "text/plain", -charset => 'utf-8', '-content-disposition' => "inline; filename=\"git-$hash.patch\""); + print $cgi->header(-type => "text/plain", + -charset => 'utf-8', + '-content-disposition' => "inline; filename=\"git-$hash.patch\""); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); my $comment = $co{'comment'}; print "From: $co{'author'}\n" . @@ -2746,7 +2840,8 @@ sub git_search { print "\n" . "" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") . - " | " . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); + " | " . + $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); print "\n" . "\n"; } @@ -2783,18 +2878,22 @@ sub git_search { print "$co{'age_string_date'}\n" . "" . esc_html(chop_str($co{'author_name'}, 15, 5)) . "\n" . "" . - $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), + -class => "list subject"}, esc_html(chop_str($co{'title'}, 50)) . "
"); while (my $setref = shift @files) { my %set = %$setref; - print $cgi->a({-href => href(action=>"blob", hash=>$set{'id'}, hash_base=>$co{'id'}, file_name=>$set{'file'}), class => "list"}, - "" . esc_html($set{'file'}) . "") . + print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'}, + hash=>$set{'id'}, file_name=>$set{'file'}), + -class => "list"}, + "" . esc_html($set{'file'}) . "") . "
\n"; } print "\n" . "" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") . - " | " . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); + " | " . + $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); print "\n" . "\n"; } From 134a6941ec7f44b9deb2cbb51429ff6a47e0d08b Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 22 Aug 2006 16:55:34 +0200 Subject: [PATCH 16/46] gitweb: Use underscore instead of hyphen to separate words in HTTP headers names Use underscore (which will be turned into hyphen) to separate words in HTTP header names, in keys to CGI header() method, consistently. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 63dc477eab..c4a4f7ffd7 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2198,7 +2198,8 @@ sub git_blob_plain { $save_as .= '.txt'; } - print $cgi->header(-type => "$type", '-content-disposition' => "inline; filename=\"$save_as\""); + print $cgi->header(-type => "$type", + -content_disposition => "inline; filename=\"$save_as\""); undef $/; binmode STDOUT, ':raw'; print <$fd>; @@ -2382,8 +2383,8 @@ sub git_snapshot { my $filename = basename($project) . "-$hash.tar.$suffix"; print $cgi->header(-type => 'application/x-tar', - -content-encoding => $ctype, - '-content-disposition' => "inline; filename=\"$filename\"", + -content_encoding => $ctype, + -content_disposition => "inline; filename=\"$filename\"", -status => '200 OK'); open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | $command" or @@ -2701,7 +2702,7 @@ sub git_commitdiff_plain { print $cgi->header(-type => "text/plain", -charset => 'utf-8', - '-content-disposition' => "inline; filename=\"git-$hash.patch\""); + -content_disposition => "inline; filename=\"git-$hash.patch\""); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); my $comment = $co{'comment'}; print "From: $co{'author'}\n" . From 77a153fd92ae6e4e40e0ccb15c9f808d63e198a0 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 22 Aug 2006 16:59:20 +0200 Subject: [PATCH 17/46] gitweb: Route rest of action subroutines through %actions Route rest of action subroutines, namely git_project_list and git_opml (both of which doesn't need $project) through %actions hash. This has disadvantage that all parameters are read and validated; earlier git_opml was called as soon as $action was parsed and validated, git_project_list was called as soon as $project was parsed and validated. This has advantage that all action dispatch is grouped in one place. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c4a4f7ffd7..ae38eca03e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -155,11 +155,6 @@ sub feature_snapshot { if ($action =~ m/[^0-9a-zA-Z\.\-_]/) { die_error(undef, "Invalid action parameter"); } - # action which does not check rest of parameters - if ($action eq "opml") { - git_opml(); - exit; - } } our $project = ($cgi->param('p') || $ENV{'PATH_INFO'}); @@ -179,9 +174,6 @@ sub feature_snapshot { die_error(undef, "No such project"); } $ENV{'GIT_DIR'} = "$projectroot/$project"; -} else { - git_project_list(); - exit; } our $file_name = $cgi->param('f'); @@ -255,9 +247,16 @@ sub feature_snapshot { "tags" => \&git_tags, "tree" => \&git_tree, "snapshot" => \&git_snapshot, + # those below don't need $project + "opml" => \&git_opml, + "project_list" => \&git_project_list, ); -$action = 'summary' if (!defined($action)); +if (defined $project) { + $action ||= 'summary'; +} else { + $action ||= 'project_list'; +} if (!defined($actions{$action})) { die_error(undef, "Unknown action"); } From 59b9f61a3f76762dc975e99cc05335a3b97ad1f9 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 22 Aug 2006 23:42:53 +0200 Subject: [PATCH 18/46] gitweb: Use here-doc Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 75 +++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ae38eca03e..1c8a2ebe15 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1185,11 +1185,13 @@ sub die_error { my $error = shift || "Malformed query, file missing or permission denied"; git_header_html($status); - print "
\n" . - "

\n" . - "$status - $error\n" . - "
\n" . - "
\n"; + print < +

+$status - $error +
+ +EOF git_footer_html(); exit; } @@ -2022,9 +2024,11 @@ sub git_blame2 { my $num_colors = scalar(@rev_color); my $current_color = 0; my $last_rev; - print "
\n"; - print "\n"; - print "\n"; + print < +
CommitLineData
+ +HTML while (<$fd>) { /^([0-9a-fA-F]{40}).*?(\d+)\)\s{1}(\s*.*)/; my $full_rev = $1; @@ -2566,9 +2570,10 @@ sub git_blobdiff { 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 "
\n" . - "

\n" . - "
$hash vs $hash_parent
\n"; + print <

+
$hash vs $hash_parent
+HTML } git_print_page_path($file_name, "blob", $hash_base); print "
\n" . @@ -2704,9 +2709,11 @@ sub git_commitdiff_plain { -content_disposition => "inline; filename=\"git-$hash.patch\""); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); my $comment = $co{'comment'}; - print "From: $co{'author'}\n" . - "Date: $ad{'rfc2822'} ($ad{'tz_local'})\n". - "Subject: $co{'title'}\n"; + print <; close $fd or die_error(undef, "Reading git-rev-list failed"); print $cgi->header(-type => 'text/xml', -charset => 'utf-8'); - print "\n". - "\n"; - print "\n"; - print "$project\n". - "" . esc_html("$my_url?p=$project;a=summary") . "\n". - "$project log\n". - "en\n"; + print < + + +$project $my_uri $my_url +${\esc_html("$my_url?p=$project;a=summary")} +$project log +en +XML for (my $i = 0; $i <= $#revlist; $i++) { my $commit = $revlist[$i]; @@ -3005,13 +3014,15 @@ sub git_opml { my @list = git_get_projects_list(); print $cgi->header(-type => 'text/xml', -charset => 'utf-8'); - print "\n". - "\n". - "". - " $site_name Git OPML Export\n". - "\n". - "\n". - "\n"; + print < + + + $site_name Git OPML Export + + + +XML foreach my $pr (@list) { my %proj = %$pr; @@ -3030,7 +3041,9 @@ sub git_opml { my $html = "$my_url?p=$proj{'path'};a=summary"; print "\n"; } - print "\n". - "\n". - "\n"; + print < + + +XML } From 1149fecfc270a2effc344897989f40afe449a72c Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 22 Aug 2006 19:05:24 +0200 Subject: [PATCH 19/46] gitweb: Drop the href() params which keys are not in %mapping If someone would enter parameter name incorrectly, and some key of %params is not found in %mapping hash, the parameter is now ignored. Change introduced by Martin Waitz in commit 756d2f064b2419fcdf9cd9c851f352e2a4f75103 tried to do that, but it left empty value and there was doubled ";;" in returned string. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 1c8a2ebe15..43b1600486 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -285,7 +285,7 @@ (%) my $href = "$my_uri?"; $href .= esc_param( join(";", map { - "$mapping{$_}=$params{$_}" if defined $params{$_} + defined $params{$_} ? "$mapping{$_}=$params{$_}" : () } keys %params ) ); From 498fe00201401b766a200cf423a8ec42b5d5643e Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 22 Aug 2006 19:05:25 +0200 Subject: [PATCH 20/46] gitweb: Sort CGI parameters returned by href() Restore pre-1c2a4f5addce479c619057c6cdc841802139982f ordering of CGI parameters. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 43b1600486..50083e3011 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -267,7 +267,9 @@ sub feature_snapshot { ## action links sub href(%) { - my %mapping = ( + my %params = @_; + + my @mapping = ( action => "a", project => "p", file_name => "f", @@ -278,18 +280,18 @@ (%) page => "pg", searchtext => "s", ); + my %mapping = @mapping; - my %params = @_; $params{"project"} ||= $project; - my $href = "$my_uri?"; - $href .= esc_param( join(";", - map { - defined $params{$_} ? "$mapping{$_}=$params{$_}" : () - } keys %params - ) ); - - return $href; + my @result = (); + for (my $i = 0; $i < @mapping; $i += 2) { + my ($name, $symbol) = ($mapping[$i], $mapping[$i+1]); + if (defined $params{$name}) { + push @result, $symbol . "=" . esc_param($params{$name}); + } + } + return "$my_uri?" . join(';', @result); } From eee08903b2cb9cfaf9ee2cd69a255ace829ae7c5 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 00:15:14 +0200 Subject: [PATCH 21/46] gitweb: Use git-diff-tree patch output for commitdiff Get rid of git_diff_print invocation in git_commitdiff and therefore external diff (/usr/bin/diff) invocation, and use only git-diff-tree to generate patch. git_commitdiff and git_commitdiff_plain are collapsed into one subroutine git_commitdiff, with format (currently 'html' which is default format corresponding to git_commitdiff, and 'plain' corresponding to git_commitdiff_plain) specified in argument. Separate patch (diff) pretty-printing into git_patchset_body. It is used in git_commitdiff. Separate patch (diff) line formatting from git_diff_print into format_diff_line function. It is used in git_patchset_body. While at it, add $hash parameter to git_difftree_body, according to rule that inner functions should use parameter passing, and not global variables. CHANGES TO OUTPUT: * "commitdiff" now products patches with renaming and copying detection (git-diff-tree is invoked with -M and -C options). Empty patches (mode changes and pure renames and copying) are not written currently. Former version broke renaming and copying, and didn't notice mode changes, like this version. * "commitdiff" output is now divided into several div elements of class "log", "patchset" and "patch". * "commitdiff_plain" now only generates X-Git-Tag: line only if there is tag pointing to the current commit. Former version which wrote first tag following current commit was broken[*1*]; besides we are interested rather in tags _preceding_ the commit, and _heads_ following the commit. X-Git-Url: now is current URL; former version tried[*2*] to output URL to HTML version of commitdiff. * "commitdiff_plain" is generated by git-diff-tree, and has therefore has git specific extensions to diff format: "git diff" header and optional extended header lines. FOOTNOTES [*1*] First it generated rev-list starting from HEAD even if hash_base parameter was set, second it wasn't corrected according to changes made in git_get_references (formerly read_info_ref) output, third even for older version of read_info_ref output it didn't work for multiple tags pointing to the current commit (rare). [*2*] It wrote URL for commitdiff without hash_parent, which produces diff to first parent and is not the same as current diff if it is diff of merge commit to non-first parent. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 323 ++++++++++++++++++++++++++++----------------- 1 file changed, 201 insertions(+), 122 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 50083e3011..9367685734 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -524,6 +524,27 @@ sub format_subject_html { } } +sub format_diff_line { + my $line = shift; + my $char = substr($line, 0, 1); + my $diff_class = ""; + + chomp $line; + + if ($char eq '+') { + $diff_class = " add"; + } elsif ($char eq "-") { + $diff_class = " rem"; + } elsif ($char eq "@") { + $diff_class = " chunk_header"; + } elsif ($char eq "\\") { + # skip errors (incomplete lines) + return ""; + } + $line = untabify($line); + return "
" . esc_html($line) . "
\n"; +} + ## ---------------------------------------------------------------------- ## git utility subroutines, invoking git commands @@ -1367,7 +1388,7 @@ sub git_print_simplified_log { ## functions printing large fragments of HTML sub git_difftree_body { - my ($difftree, $parent) = @_; + my ($difftree, $hash, $parent) = @_; print "
\n"; if ($#{$difftree} > 10) { @@ -1518,6 +1539,101 @@ sub git_difftree_body { print "
CommitLineData
\n"; } +sub git_patchset_body { + my ($patchset, $difftree, $hash, $hash_parent) = @_; + + my $patch_idx = 0; + my $in_header = 0; + my $patch_found = 0; + my %diffinfo; + + print "
\n"; + + LINE: foreach my $patch_line (@$patchset) { + + if ($patch_line =~ m/^diff /) { # "git diff" header + # beginning of patch (in patchset) + if ($patch_found) { + # close previous patch + print "
\n"; # class="patch" + } else { + # first patch in patchset + $patch_found = 1; + } + print "
\n"; + + %diffinfo = parse_difftree_raw_line($difftree->[$patch_idx++]); + + # for now, no extended header, hence we skip empty patches + # companion to next LINE if $in_header; + if ($diffinfo{'from_id'} eq $diffinfo{'to_id'}) { # no change + $in_header = 1; + next LINE; + } + + if ($diffinfo{'status'} eq "A") { # added + print "
" . file_type($diffinfo{'to_mode'}) . ":" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash, + hash=>$diffinfo{'to_id'}, file_name=>$diffinfo{'file'})}, + $diffinfo{'to_id'}) . "(new)" . + "
\n"; # class="diff_info" + + } elsif ($diffinfo{'status'} eq "D") { # deleted + print "
" . file_type($diffinfo{'from_mode'}) . ":" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, + hash=>$diffinfo{'from_id'}, file_name=>$diffinfo{'file'})}, + $diffinfo{'from_id'}) . "(deleted)" . + "
\n"; # class="diff_info" + + } elsif ($diffinfo{'status'} eq "R" || # renamed + $diffinfo{'status'} eq "C") { # copied + print "
" . + file_type($diffinfo{'from_mode'}) . ":" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, + hash=>$diffinfo{'from_id'}, file_name=>$diffinfo{'from_file'})}, + $diffinfo{'from_id'}) . + " -> " . + file_type($diffinfo{'to_mode'}) . ":" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash, + hash=>$diffinfo{'to_id'}, file_name=>$diffinfo{'to_file'})}, + $diffinfo{'to_id'}); + print "
\n"; # class="diff_info" + + } else { # modified, mode changed, ... + print "
" . + file_type($diffinfo{'from_mode'}) . ":" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, + hash=>$diffinfo{'from_id'}, file_name=>$diffinfo{'file'})}, + $diffinfo{'from_id'}) . + " -> " . + file_type($diffinfo{'to_mode'}) . ":" . + $cgi->a({-href => href(action=>"blob", hash_base=>$hash, + hash=>$diffinfo{'to_id'}, file_name=>$diffinfo{'file'})}, + $diffinfo{'to_id'}); + print "
\n"; # class="diff_info" + } + + #print "
\n"; + $in_header = 1; + next LINE; + } # start of patch in patchset + + + if ($in_header && $patch_line =~ m/^---/) { + #print "
\n" + $in_header = 0; + } + next LINE if $in_header; + + print format_diff_line($patch_line); + } + print "
\n" if $patch_found; # class="patch" + + print "
\n"; # class="patchset" +} + +# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + sub git_shortlog_body { # uses global variable $project my ($revlist, $from, $to, $refs, $extra) = @_; @@ -2556,7 +2672,7 @@ sub git_commit { git_print_log($co{'comment'}); print "\n"; - git_difftree_body(\@difftree, $parent); + git_difftree_body(\@difftree, $hash, $parent); git_footer_html(); } @@ -2600,7 +2716,7 @@ sub git_blobdiff_plain { } sub git_commitdiff { - mkdir($git_temp, 0700); + my $format = shift || 'html'; my %co = parse_commit($hash); if (!%co) { die_error(undef, "Unknown commit object"); @@ -2608,141 +2724,104 @@ sub git_commitdiff { if (!defined $hash_parent) { $hash_parent = $co{'parent'} || '--root'; } - open my $fd, "-|", $GIT, "diff-tree", '-r', $hash_parent, $hash - or die_error(undef, "Open git-diff-tree failed"); - my @difftree = map { chomp; $_ } <$fd>; - close $fd or die_error(undef, "Reading git-diff-tree failed"); + + # read commitdiff + my $fd; + my @difftree; + my @patchset; + if ($format eq 'html') { + open $fd, "-|", $GIT, "diff-tree", '-r', '-M', '-C', + "--patch-with-raw", "--full-index", $hash_parent, $hash + or die_error(undef, "Open git-diff-tree failed"); + + while (chomp(my $line = <$fd>)) { + # empty line ends raw part of diff-tree output + last unless $line; + push @difftree, $line; + } + @patchset = map { chomp; $_ } <$fd>; + + close $fd + or die_error(undef, "Reading git-diff-tree failed"); + } elsif ($format eq 'plain') { + open $fd, "-|", $GIT, "diff-tree", '-r', '-p', '-B', $hash_parent, $hash + or die_error(undef, "Open git-diff-tree failed"); + } else { + die_error(undef, "Unknown commitdiff format"); + } # non-textual hash id's can be cached my $expires; if ($hash =~ m/^[0-9a-fA-F]{40}$/) { $expires = "+1d"; } - my $refs = git_get_references(); - my $ref = format_ref_marker($refs, $co{'id'}); - my $formats_nav = - $cgi->a({-href => href(action=>"commitdiff_plain", hash=>$hash, hash_parent=>$hash_parent)}, - "plain"); - git_header_html(undef, $expires); - git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav); - git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash); - print "
\n"; - git_print_simplified_log($co{'comment'}, 1); # skip title - print "
\n"; - foreach my $line (@difftree) { - # ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M ls-files.c' - # ':100644 100644 7f9281985086971d3877aca27704f2aaf9c448ce bc190ebc71bbd923f2b728e505408f5e54bd073a M rev-tree.c' - if ($line !~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)\t(.*)$/) { - next; - } - my $from_mode = $1; - my $to_mode = $2; - my $from_id = $3; - my $to_id = $4; - my $status = $5; - my $file = validate_input(unquote($6)); - if ($status eq "A") { - print "
" . file_type($to_mode) . ":" . - $cgi->a({-href => href(action=>"blob", hash_base=>$hash, - hash=>$to_id, file_name=>$file)}, - $to_id) . "(new)" . - "
\n"; - git_diff_print(undef, "/dev/null", $to_id, "b/$file"); - } elsif ($status eq "D") { - print "
" . file_type($from_mode) . ":" . - $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, - hash=>$from_id, file_name=>$file)}, - $from_id) . "(deleted)" . - "
\n"; - git_diff_print($from_id, "a/$file", undef, "/dev/null"); - } elsif ($status eq "M") { - if ($from_id ne $to_id) { - print "
" . - file_type($from_mode) . ":" . - $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, - hash=>$from_id, file_name=>$file)}, - $from_id) . - " -> " . - file_type($to_mode) . ":" . - $cgi->a({-href => href(action=>"blob", hash_base=>$hash, - hash=>$to_id, file_name=>$file)}, - $to_id); - print "
\n"; - git_diff_print($from_id, "a/$file", $to_id, "b/$file"); - } - } - } - print "
\n" . - "
"; - git_footer_html(); -} -sub git_commitdiff_plain { - mkdir($git_temp, 0700); - my %co = parse_commit($hash); - if (!%co) { - die_error(undef, "Unknown commit object"); - } - if (!defined $hash_parent) { - $hash_parent = $co{'parent'} || '--root'; - } - open my $fd, "-|", $GIT, "diff-tree", '-r', $hash_parent, $hash - or die_error(undef, "Open git-diff-tree failed"); - my @difftree = map { chomp; $_ } <$fd>; - close $fd or die_error(undef, "Reading diff-tree failed"); + # write commit message + if ($format eq 'html') { + my $refs = git_get_references(); + my $ref = format_ref_marker($refs, $co{'id'}); + my $formats_nav = + $cgi->a({-href => href(action=>"commitdiff_plain", + hash=>$hash, hash_parent=>$hash_parent)}, + "plain"); - # try to figure out the next tag after this commit - my $tagname; - my $refs = git_get_references("tags"); - open $fd, "-|", $GIT, "rev-list", "HEAD"; - my @commits = map { chomp; $_ } <$fd>; - close $fd; - foreach my $commit (@commits) { - if (defined $refs->{$commit}) { - $tagname = $refs->{$commit} - } - if ($commit eq $hash) { - last; - } - } + git_header_html(undef, $expires); + git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav); + git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash); + print "
\n"; + print "
\n"; + git_print_simplified_log($co{'comment'}, 1); # skip title + print "
\n"; # class="log" - print $cgi->header(-type => "text/plain", - -charset => 'utf-8', - -content_disposition => "inline; filename=\"git-$hash.patch\""); - my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); - my $comment = $co{'comment'}; - print <{$hash}) { + @tagnames = map { s|^tags/|| } $refs->{$hash}; + } + my $filename = basename($project) . "-$hash.patch"; + + print $cgi->header( + -type => 'text/plain', + -charset => 'utf-8', + -expires => $expires, + -content_disposition => qq(inline; filename="$filename")); + my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); + print <self_url() . "\n\n"; + foreach my $line (@{$co{'comment'}}) { + print "$line\n"; } + print "---\n\n"; } + + # write patch + if ($format eq 'html') { + #git_difftree_body(\@difftree, $hash, $hash_parent); + #print "
\n"; + + git_patchset_body(\@patchset, \@difftree, $hash, $hash_parent); + + print "
\n"; # class="page_body" + git_footer_html(); + + } elsif ($format eq 'plain') { + local $/ = undef; + print <$fd>; + close $fd + or print "Reading git-diff-tree failed\n"; + } +} + +sub git_commitdiff_plain { + git_commitdiff('plain'); } sub git_history { From af33ef21bfb0171973393e21deac7621efd2ec7a Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 01:58:49 +0200 Subject: [PATCH 22/46] gitweb: Show information about incomplete lines in commitdiff In format_diff_line, instead of skipping errors/incomplete lines, for example "\ No newline at end of file" in HTML pretty-printing of diff, use "incomplete" class for div. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 4 ++++ gitweb/gitweb.perl | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 4821022535..5eaa24fd24 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -285,6 +285,10 @@ div.diff.chunk_header { color: #990099; } +div.diff.incomplete { + color: #cccccc; +} + div.diff_info { font-family: monospace; color: #000099; diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9367685734..fe9b9ee87a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -539,7 +539,7 @@ sub format_diff_line { $diff_class = " chunk_header"; } elsif ($char eq "\\") { # skip errors (incomplete lines) - return ""; + $diff_class = " incomplete"; } $line = untabify($line); return "
" . esc_html($line) . "
\n"; From 1613b79faa63e3d0c1add4facc286c18cf1204db Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 19:32:13 +0200 Subject: [PATCH 23/46] gitweb: Remove invalid comment in format_diff_line Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 1 - 1 file changed, 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index fe9b9ee87a..1d3d9df752 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -538,7 +538,6 @@ sub format_diff_line { } elsif ($char eq "@") { $diff_class = " chunk_header"; } elsif ($char eq "\\") { - # skip errors (incomplete lines) $diff_class = " incomplete"; } $line = untabify($line); From 157e43b4b0dd5a08eb7a6838192ac58bca62fa5b Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 19:34:36 +0200 Subject: [PATCH 24/46] gitweb: Streamify patch output in git_commitdiff Change output of patch(set) in git_commitdiff from slurping whole diff in @patchset array before processing, to passing file descriptor to git_patchset_body. Advantages: faster, incremental output, smaller memory footprint. Disadvantages: cannot react when there is error during closing file descriptor. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 1d3d9df752..08e0472c61 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1539,7 +1539,7 @@ sub git_difftree_body { } sub git_patchset_body { - my ($patchset, $difftree, $hash, $hash_parent) = @_; + my ($fd, $difftree, $hash, $hash_parent) = @_; my $patch_idx = 0; my $in_header = 0; @@ -1548,7 +1548,9 @@ sub git_patchset_body { print "
\n"; - LINE: foreach my $patch_line (@$patchset) { + LINE: + while (my $patch_line @$fd>) { + chomp $patch_line; if ($patch_line =~ m/^diff /) { # "git diff" header # beginning of patch (in patchset) @@ -2727,7 +2729,6 @@ sub git_commitdiff { # read commitdiff my $fd; my @difftree; - my @patchset; if ($format eq 'html') { open $fd, "-|", $GIT, "diff-tree", '-r', '-M', '-C', "--patch-with-raw", "--full-index", $hash_parent, $hash @@ -2738,13 +2739,11 @@ sub git_commitdiff { last unless $line; push @difftree, $line; } - @patchset = map { chomp; $_ } <$fd>; - close $fd - or die_error(undef, "Reading git-diff-tree failed"); } elsif ($format eq 'plain') { open $fd, "-|", $GIT, "diff-tree", '-r', '-p', '-B', $hash_parent, $hash or die_error(undef, "Open git-diff-tree failed"); + } else { die_error(undef, "Unknown commitdiff format"); } @@ -2806,8 +2805,8 @@ sub git_commitdiff { #git_difftree_body(\@difftree, $hash, $hash_parent); #print "
\n"; - git_patchset_body(\@patchset, \@difftree, $hash, $hash_parent); - + git_patchset_body($fd, \@difftree, $hash, $hash_parent); + close $fd; print "
\n"; # class="page_body" git_footer_html(); From 470b96d4837c5b019f15c8a5b013501724236de4 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 19:37:04 +0200 Subject: [PATCH 25/46] gitweb: Add git_get_{following,preceding}_references functions Adds git_get_following_references function, based on code which was used in git_commitdiff_plain to generate X-Git-Tag: header, and companion git_get_preceding_references function. Both functions return array of all references of given type (as returned by git_get_references) following/preceding given commit in array (list) context, and last following/first preceding ref in scalar context. Stripping ref (list of refs) of "$type/" (e.g. "tags/") is left to caller. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 08e0472c61..b964302a5a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -749,6 +749,58 @@ sub git_get_references { return \%refs; } +sub git_get_following_references { + my $hash = shift || return undef; + my $type = shift; + my $base = shift || $hash_base || "HEAD"; + + my $refs = git_get_references($type); + open my $fd, "-|", $GIT, "rev-list", $base + or return undef; + my @commits = map { chomp; $_ } <$fd>; + close $fd + or return undef; + + my @reflist; + my $lastref; + + foreach my $commit (@commits) { + foreach my $ref (@{$refs->{$commit}}) { + $lastref = $ref; + push @reflist, $lastref; + } + if ($commit eq $hash) { + last; + } + } + + return wantarray ? @reflist : $lastref; +} + +sub git_get_preceding_references { + my $hash = shift || return undef; + my $type = shift; + + my $refs = git_get_references($type); + open my $fd, "-|", $GIT, "rev-list", $hash + or return undef; + my @commits = map { chomp; $_ } <$fd>; + close $fd + or return undef; + + my @reflist; + my $firstref; + + foreach my $commit (@commits) { + foreach my $ref (@{$refs->{$commit}}) { + $firstref = $ref unless $firstref; + push @reflist, $ref; + } + } + + return wantarray ? @reflist : $firstref; +} + ## ---------------------------------------------------------------------- ## parse to hash functions From 3066c359c63d1dc32db5147ebf015fe9bba4c5bb Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 19:39:32 +0200 Subject: [PATCH 26/46] gitweb: Faster return from git_get_preceding_references if possible Return on first ref found when git_get_preceding_references is called in scalar context Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index b964302a5a..01452d2c74 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -789,16 +789,15 @@ sub git_get_preceding_references { or return undef; my @reflist; - my $firstref; foreach my $commit (@commits) { foreach my $ref (@{$refs->{$commit}}) { - $firstref = $ref unless $firstref; + return $ref unless wantarray; push @reflist, $ref; } } - return wantarray ? @reflist : $firstref; + return @reflist; } ## ---------------------------------------------------------------------- From 56a322f16113119bcc3770ef9565297ab59c29d2 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 19:41:23 +0200 Subject: [PATCH 27/46] gitweb: Add git_get_rev_name_tags function Add git_get_rev_name_tags function, for later use in git_commitdiff('plain') for X-Git-Tag: header. This function, contrary to the call to git_get_following_references($hash, "tags"); _does_ strip "tags/" and returns bare tag name. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 01452d2c74..7aa6838836 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -800,6 +800,22 @@ sub git_get_preceding_references { return @reflist; } +sub git_get_rev_name_tags { + my $hash = shift || return undef; + + open my $fd, "-|", $GIT, "name-rev", "--tags", $hash + or return; + my $name_rev = <$fd>; + close $fd; + + if ($name_rev =~ m|^$hash tags/(.*)$|) { + return $1; + } else { + # catches also '$hash undefined' output + return undef; + } +} + ## ---------------------------------------------------------------------- ## parse to hash functions From edf735abfad53a07ae91ca60576386f239bf7482 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 19:45:30 +0200 Subject: [PATCH 28/46] gitweb: Use git_get_name_rev_tags for commitdiff_plain X-Git-Tag: header Use git_get_rev_name_tags function for X-Git-Tag: header in git_commitdiff('plain'), i.e. for commitdiff_plain action. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7aa6838836..50e405f6fe 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2840,10 +2840,7 @@ sub git_commitdiff { } elsif ($format eq 'plain') { my $refs = git_get_references("tags"); - my @tagnames; - if (exists $refs->{$hash}) { - @tagnames = map { s|^tags/|| } $refs->{$hash}; - } + my $tagname = git_get_rev_name_tags($hash); my $filename = basename($project) . "-$hash.patch"; print $cgi->header( @@ -2857,10 +2854,9 @@ sub git_commitdiff { Date: $ad{'rfc2822'} ($ad{'tz_local'}) Subject: $co{'title'} TEXT - foreach my $tag (@tagnames) { - print "X-Git-Tag: $tag\n"; - } + print "X-Git-Tag: $tagname\n" if $tagname; print "X-Git-Url: " . $cgi->self_url() . "\n\n"; + foreach my $line (@{$co{'comment'}}) { print "$line\n"; } From 420e92f255982564a782b6ea8cd3c522f48c7d12 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 24 Aug 2006 23:53:54 +0200 Subject: [PATCH 29/46] gitweb: Add support for hash_parent_base parameter for blobdiffs Add support for hash_parent_base in input validation part and in href() function. Add proper hash_parent_base to all calls to blobdiff and blobdiff_plain action URLs. Use hash_parent_base as hash_base for blobs of hash_parent. To be used in future rewrite of git_blobdiff and git_blobdiff_plain. While at it, move project before action in ordering CGI parameters in href(). Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 50e405f6fe..80de7b6b67 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -211,6 +211,13 @@ sub feature_snapshot { } } +our $hash_parent_base = $cgi->param('hpb'); +if (defined $hash_parent_base) { + if (!validate_input($hash_parent_base)) { + die_error(undef, "Invalid hash parent base parameter"); + } +} + our $page = $cgi->param('pg'); if (defined $page) { if ($page =~ m/[^0-9]$/) { @@ -270,13 +277,14 @@ (%) my %params = @_; my @mapping = ( - action => "a", project => "p", + action => "a", file_name => "f", file_parent => "fp", hash => "h", hash_parent => "hp", hash_base => "hb", + hash_parent_base => "hpb", page => "pg", searchtext => "s", ); @@ -1543,8 +1551,10 @@ sub git_difftree_body { } print ""; if ($diff{'to_id'} ne $diff{'from_id'}) { # modified - print $cgi->a({-href => href(action=>"blobdiff", hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, - hash_base=>$hash, file_name=>$diff{'file'}), + print $cgi->a({-href => href(action=>"blobdiff", + hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, hash_parent_base=>$parent, + file_name=>$diff{'file'}), -class => "list"}, esc_html($diff{'file'})); } else { # only mode changed print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, @@ -1559,8 +1569,10 @@ sub git_difftree_body { "blob"); if ($diff{'to_id'} ne $diff{'from_id'}) { # modified print " | " . - $cgi->a({-href => href(action=>"blobdiff", hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, - hash_base=>$hash, file_name=>$diff{'file'})}, + $cgi->a({-href => href(action=>"blobdiff", + hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, hash_parent_base=>$parent, + file_name=>$diff{'file'})}, "diff"); } print " | " . @@ -1592,8 +1604,9 @@ sub git_difftree_body { "blob"); if ($diff{'to_id'} ne $diff{'from_id'}) { print " | " . - $cgi->a({-href => href(action=>"blobdiff", hash_base=>$hash, + $cgi->a({-href => href(action=>"blobdiff", hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, hash_parent_base=>$parent, file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})}, "diff"); } @@ -1793,8 +1806,10 @@ sub git_history_body { if (defined $blob_current && defined $blob_parent && $blob_current ne $blob_parent) { print " | " . - $cgi->a({-href => href(action=>"blobdiff", hash=>$blob_current, hash_parent=>$blob_parent, - hash_base=>$commit, file_name=>$file_name)}, + $cgi->a({-href => href(action=>"blobdiff", + hash=>$blob_current, hash_parent=>$blob_parent, + hash_base=>$hash_base, hash_parent_base=>$commit, + file_name=>$file_name)}, "diff to current"); } } @@ -2751,7 +2766,9 @@ sub git_blobdiff { if (defined $hash_base && (my %co = parse_commit($hash_base))) { my $formats_nav = $cgi->a({-href => href(action=>"blobdiff_plain", - hash=>$hash, hash_parent=>$hash_parent)}, + 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_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); @@ -2765,7 +2782,7 @@ sub git_blobdiff { print "
\n" . "
blob:" . $cgi->a({-href => href(action=>"blob", hash=>$hash_parent, - hash_base=>$hash_base, file_name=>($file_parent || $file_name))}, + hash_base=>$hash_parent_base, file_name=>($file_parent || $file_name))}, $hash_parent) . " -> blob:" . $cgi->a({-href => href(action=>"blob", hash=>$hash, From fe87585e53860f1c89a088e91c08dd89b6702a74 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 20:59:39 +0200 Subject: [PATCH 30/46] gitweb: Allow for pre-parsed difftree info in git_patchset_body Preparation for converting git_blobdiff and git_blobdiff_plain to use git-diff-tree patch format to generate patches. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 55 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 80de7b6b67..56a47ab633 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1624,7 +1624,7 @@ sub git_patchset_body { my $patch_idx = 0; my $in_header = 0; my $patch_found = 0; - my %diffinfo; + my $diffinfo; print "
\n"; @@ -1643,54 +1643,59 @@ sub git_patchset_body { } print "
\n"; - %diffinfo = parse_difftree_raw_line($difftree->[$patch_idx++]); + if (ref($difftree->[$patch_idx]) eq "HASH") { + $diffinfo = $difftree->[$patch_idx]; + } else { + $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]); + } + $patch_idx++; # for now, no extended header, hence we skip empty patches # companion to next LINE if $in_header; - if ($diffinfo{'from_id'} eq $diffinfo{'to_id'}) { # no change + if ($diffinfo->{'from_id'} eq $diffinfo->{'to_id'}) { # no change $in_header = 1; next LINE; } - if ($diffinfo{'status'} eq "A") { # added - print "
" . file_type($diffinfo{'to_mode'}) . ":" . + if ($diffinfo->{'status'} eq "A") { # added + print "
" . file_type($diffinfo->{'to_mode'}) . ":" . $cgi->a({-href => href(action=>"blob", hash_base=>$hash, - hash=>$diffinfo{'to_id'}, file_name=>$diffinfo{'file'})}, - $diffinfo{'to_id'}) . "(new)" . + hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})}, + $diffinfo->{'to_id'}) . "(new)" . "
\n"; # class="diff_info" - } elsif ($diffinfo{'status'} eq "D") { # deleted - print "
" . file_type($diffinfo{'from_mode'}) . ":" . + } elsif ($diffinfo->{'status'} eq "D") { # deleted + print "
" . file_type($diffinfo->{'from_mode'}) . ":" . $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, - hash=>$diffinfo{'from_id'}, file_name=>$diffinfo{'file'})}, - $diffinfo{'from_id'}) . "(deleted)" . + hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})}, + $diffinfo->{'from_id'}) . "(deleted)" . "
\n"; # class="diff_info" - } elsif ($diffinfo{'status'} eq "R" || # renamed - $diffinfo{'status'} eq "C") { # copied + } elsif ($diffinfo->{'status'} eq "R" || # renamed + $diffinfo->{'status'} eq "C") { # copied print "
" . - file_type($diffinfo{'from_mode'}) . ":" . + file_type($diffinfo->{'from_mode'}) . ":" . $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, - hash=>$diffinfo{'from_id'}, file_name=>$diffinfo{'from_file'})}, - $diffinfo{'from_id'}) . + hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'from_file'})}, + $diffinfo->{'from_id'}) . " -> " . - file_type($diffinfo{'to_mode'}) . ":" . + file_type($diffinfo->{'to_mode'}) . ":" . $cgi->a({-href => href(action=>"blob", hash_base=>$hash, - hash=>$diffinfo{'to_id'}, file_name=>$diffinfo{'to_file'})}, - $diffinfo{'to_id'}); + hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'to_file'})}, + $diffinfo->{'to_id'}); print "
\n"; # class="diff_info" } else { # modified, mode changed, ... print "
" . - file_type($diffinfo{'from_mode'}) . ":" . + file_type($diffinfo->{'from_mode'}) . ":" . $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, - hash=>$diffinfo{'from_id'}, file_name=>$diffinfo{'file'})}, - $diffinfo{'from_id'}) . + hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})}, + $diffinfo->{'from_id'}) . " -> " . - file_type($diffinfo{'to_mode'}) . ":" . + file_type($diffinfo->{'to_mode'}) . ":" . $cgi->a({-href => href(action=>"blob", hash_base=>$hash, - hash=>$diffinfo{'to_id'}, file_name=>$diffinfo{'file'})}, - $diffinfo{'to_id'}); + hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})}, + $diffinfo->{'to_id'}); print "
\n"; # class="diff_info" } From e4e4f825455f2903e4d015e51c09ec0527a0be86 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 21:04:13 +0200 Subject: [PATCH 31/46] gitweb: Parse two-line from-file/to-file diff header in git_patchset_body Parse two-line from-file/to-file unified diff header in git_patchset_body directly, instead of leaving pretty-printing to format_diff_line function. Hashes as from-file/to-file are replaced by proper from-file and to-file names (from $diffinfo); in the future we can put hyperlinks there. This makes possible to do blobdiff with only blobs hashes. The lines in two-line unified diff header have now class "from_file" and "to_file"; the style is chosen to match previous output (classes "rem" and "add" because of '-' and '+' as first character of patch line). Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 2 ++ gitweb/gitweb.perl | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 5eaa24fd24..0912361ac8 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -273,10 +273,12 @@ td.mode { font-family: monospace; } +div.diff.to_file, div.diff.add { color: #008800; } +div.diff.from_file, div.diff.rem { color: #cc0000; } diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 56a47ab633..b2159bb820 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1706,8 +1706,24 @@ sub git_patchset_body { if ($in_header && $patch_line =~ m/^---/) { - #print "
\n" + #print "
\n"; # class="diff extended_header" $in_header = 0; + + my $file = $diffinfo->{'from_file'}; + $file ||= $diffinfo->{'file'}; + $patch_line =~ s|a/[0-9a-fA-F]{40}|a/$file|g; + print "
" . esc_html($patch_line) . "
\n"; + + $patch_line = <$fd>; + chomp $patch_line; + + #$patch_line =~ m/^+++/; + $file = $diffinfo->{'to_file'}; + $file ||= $diffinfo->{'file'}; + $patch_line =~ s|b/[0-9a-fA-F]{40}|b/$file|g; + print "
" . esc_html($patch_line) . "
\n"; + + next LINE; } next LINE if $in_header; From ef10ee877f6d4db4c9bc65d0e36b3670f0fe114e Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 21:05:07 +0200 Subject: [PATCH 32/46] gitweb: Add invisible hyperlink to from-file/to-file diff header Change replacing hashes as from-file/to-file with filenames from difftree to adding invisible (except underlining on hover/mouseover) hyperlink to from-file/to-file blob. /dev/null as from-file or to-file is not changed (is not hyperlinked). This makes two-file from-file/to-file unified diff header parsing in git_patchset_body more generic, and not only for legacy blobdiffs. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 10 ++++++++++ gitweb/gitweb.perl | 14 ++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 0912361ac8..afd9e8a565 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -273,11 +273,21 @@ td.mode { font-family: monospace; } +div.diff a.list { + text-decoration: none; +} + +div.diff a.list:hover { + text-decoration: underline; +} + +div.diff.to_file a.list, div.diff.to_file, div.diff.add { color: #008800; } +div.diff.from_file a.list, div.diff.from_file, div.diff.rem { color: #cc0000; diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index b2159bb820..29953429ee 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1711,8 +1711,11 @@ sub git_patchset_body { my $file = $diffinfo->{'from_file'}; $file ||= $diffinfo->{'file'}; - $patch_line =~ s|a/[0-9a-fA-F]{40}|a/$file|g; - print "
" . esc_html($patch_line) . "
\n"; + $file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, + hash=>$diffinfo->{'from_id'}, file_name=>$file), + -class => "list"}, esc_html($file)); + $patch_line =~ s|a/.*$|a/$file|g; + print "
$patch_line
\n"; $patch_line = <$fd>; chomp $patch_line; @@ -1720,8 +1723,11 @@ sub git_patchset_body { #$patch_line =~ m/^+++/; $file = $diffinfo->{'to_file'}; $file ||= $diffinfo->{'file'}; - $patch_line =~ s|b/[0-9a-fA-F]{40}|b/$file|g; - print "
" . esc_html($patch_line) . "
\n"; + $file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash, + hash=>$diffinfo->{'to_id'}, file_name=>$file), + -class => "list"}, esc_html($file)); + $patch_line =~ s|b/.*|b/$file|g; + print "
$patch_line
\n"; next LINE; } From c2c8ff24380efe0149815fc014445e31f81c3403 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 21:05:45 +0200 Subject: [PATCH 33/46] gitweb: Always display link to blobdiff_plain in git_blobdiff Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 29953429ee..e631188ee1 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2790,18 +2790,18 @@ sub git_commit { sub git_blobdiff { mkdir($git_temp, 0700); git_header_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"); if (defined $hash_base && (my %co = parse_commit($hash_base))) { - 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_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); } else { print <

+
$hash vs $hash_parent
HTML } From 990dd0de51530a47f4c8fad961268d4b8545a7be Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 21:06:49 +0200 Subject: [PATCH 34/46] gitweb: Change here-doc back for style consistency in git_blobdiff Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e631188ee1..40f65bee0e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2800,10 +2800,8 @@ sub git_blobdiff { 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 <
$formats_nav
-
$hash vs $hash_parent
-HTML + print "

$formats_nav
\n"; + print "
$hash vs $hash_parent
\n"; } git_print_page_path($file_name, "blob", $hash_base); print "
\n" . From 7c5e2ebb5d8ca3d8428e19593c69a4f329d64855 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 21:13:34 +0200 Subject: [PATCH 35/46] gitweb: Use git-diff-tree or git-diff patch output for blobdiff This is second part of removing gitweb dependency on external diff (used in git_diff_print). Get rid of git_diff_print invocation in git_blobdiff, and use either git-diff-tree (when both hash_base and hash_parent_base are provided) patch format or git-diff patch format (when only hash and hash_parent are provided) for output. Supported URI schemes, and output formats: * New URI scheme: both hash_base and hash_parent_base (trees-ish containing blobs versions we want to compare) are provided. Also either filename is provided, or hash (of blob) is provided (we try to find filename then). For this scheme we have copying and renames detection, mode changes, file types etc., and information extended diff header is correct. * Old URI scheme: hash_parent_base is not provided, we use hash and hash_parent to directly compare blobs using git-diff. If no filename is given, blobs hashes are used in place of filenames. This scheme has always "blob" as file type, it cannot detect mode changes, and we rely on CGI parameters to provide name of the file. Added git_to_hash subroutine, which transforms symbolic name or list of symbolic name to hash or list of hashes using git-rev-parse. To have "blob" instead of "unknown" (or "file" regardless of the type) in "gitweb diff header" for legacy scheme, file_type function now returns its argument if it is not octal string. Added support for fake "2" status code in git_patchset_body. Such code is generated by git_blobdiff in legacy scheme case. ATTENTION: The order of arguments (operands) to git-diff is reversed (sic!) to have correct diff in the legacy (no hash_parent_base) case. $hash_parent, $hash ordering is commented out, as it gives reversed patch (at least for git version 1.4.1.1) as compared to output in new scheme and output of older gitweb version. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 149 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 132 insertions(+), 17 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 40f65bee0e..0fa35f3369 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -454,7 +454,13 @@ sub mode_str { # convert file mode in octal to file type string sub file_type { - my $mode = oct shift; + my $mode = shift; + + if ($mode !~ m/^[0-7]+$/) { + return $mode; + } else { + $mode = oct $mode; + } if (S_ISDIR($mode & S_IFMT)) { return "directory"; @@ -618,6 +624,26 @@ sub git_get_hash_by_path { return $3; } +# converts symbolic name to hash +sub git_to_hash { + my @params = @_; + return undef unless @params; + + open my $fd, "-|", $GIT, "rev-parse", @params + or return undef; + my @hashes = map { chomp; $_ } <$fd>; + close $fd; + + if (wantarray) { + return @hashes; + } elsif (scalar(@hashes) == 1) { + # single hash + return $hashes[0]; + } else { + return \@hashes; + } +} + ## ...................................................................... ## git utility functions, directly accessing git repository @@ -1672,7 +1698,8 @@ sub git_patchset_body { "
\n"; # class="diff_info" } elsif ($diffinfo->{'status'} eq "R" || # renamed - $diffinfo->{'status'} eq "C") { # copied + $diffinfo->{'status'} eq "C" || # copied + $diffinfo->{'status'} eq "2") { # with two filenames (from git_blobdiff) print "
" . file_type($diffinfo->{'from_mode'}) . ":" . $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent, @@ -2788,14 +2815,102 @@ sub git_commit { } sub git_blobdiff { - mkdir($git_temp, 0700); - git_header_html(); + my $fd; + my @difftree; + my %diffinfo; + + # preparing $fd and %diffinfo for git_patchset_body + # new style URI + if (defined $hash_base && defined $hash_parent_base) { + if (defined $file_name) { + # read raw output + open $fd, "-|", $GIT, "diff-tree", '-r', '-M', '-C', $hash_parent_base, $hash_base, + "--", $file_name + or die_error(undef, "Open git-diff-tree failed"); + @difftree = map { chomp; $_ } <$fd>; + close $fd + or die_error(undef, "Reading git-diff-tree failed"); + @difftree + or die_error('404 Not Found', "Blob diff not found"); + + } elsif (defined $hash) { # try to find filename from $hash + if ($hash !~ /[0-9a-fA-F]{40}/) { + $hash = git_to_hash($hash); + } + + # read filtered raw output + open $fd, "-|", $GIT, "diff-tree", '-r', '-M', '-C', $hash_parent_base, $hash_base + or die_error(undef, "Open git-diff-tree failed"); + @difftree = + # ':100644 100644 03b21826... 3b93d5e7... M ls-files.c' + # $hash == to_id + grep { /^:[0-7]{6} [0-7]{6} [0-9a-fA-F]{40} $hash/ } + map { chomp; $_ } <$fd>; + close $fd + or die_error(undef, "Reading git-diff-tree failed"); + @difftree + or die_error('404 Not Found', "Blob diff not found"); + + } else { + die_error('404 Not Found', "Missing one of the blob diff parameters"); + } + + if (@difftree > 1) { + die_error('404 Not Found', "Ambiguous blob diff specification"); + } + + %diffinfo = parse_difftree_raw_line($difftree[0]); + $file_parent ||= $diffinfo{'from_file'} || $file_name || $diffinfo{'file'}; + $file_name ||= $diffinfo{'to_file'} || $diffinfo{'file'}; + + $hash_parent ||= $diffinfo{'from_id'}; + $hash ||= $diffinfo{'to_id'}; + + # open patch output + open $fd, "-|", $GIT, "diff-tree", '-r', '-p', '-M', '-C', $hash_parent_base, $hash_base, + "--", $file_name + or die_error(undef, "Open git-diff-tree failed"); + } + + # old/legacy style URI + if (!%diffinfo && # if new style URI failed + defined $hash && defined $hash_parent) { + # fake git-diff-tree raw output + $diffinfo{'from_mode'} = $diffinfo{'to_mode'} = "blob"; + $diffinfo{'from_id'} = $hash_parent; + $diffinfo{'to_id'} = $hash; + if (defined $file_name) { + if (defined $file_parent) { + $diffinfo{'status'} = '2'; + $diffinfo{'from_file'} = $file_parent; + $diffinfo{'to_file'} = $file_name; + } else { # assume not renamed + $diffinfo{'status'} = '1'; + $diffinfo{'from_file'} = $file_name; + $diffinfo{'to_file'} = $file_name; + } + } else { # no filename given + $diffinfo{'status'} = '2'; + $diffinfo{'from_file'} = $hash_parent; + $diffinfo{'to_file'} = $hash; + } + + #open $fd, "-|", $GIT, "diff", '-p', $hash_parent, $hash + open $fd, "-|", $GIT, "diff", '-p', $hash, $hash_parent + or die_error(undef, "Open git-diff failed"); + } else { + die_error('404 Not Found', "Missing one of the blob diff parameters") + unless %diffinfo; + } + + # 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); @@ -2803,19 +2918,19 @@ sub git_blobdiff { print "

$formats_nav
\n"; print "
$hash vs $hash_parent
\n"; } - git_print_page_path($file_name, "blob", $hash_base); - print "
\n" . - "
blob:" . - $cgi->a({-href => href(action=>"blob", hash=>$hash_parent, - hash_base=>$hash_parent_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) . - "
\n"; - git_diff_print($hash_parent, $file_name || $hash_parent, $hash, $file_name || $hash); - print "
"; # page_body + if (defined $file_name) { + git_print_page_path($file_name, "blob", $hash_base); + } else { + print "
\n"; + } + + # patch + print "
\n"; + + git_patchset_body($fd, [ \%diffinfo ], $hash_base, $hash_parent_base); + close $fd; + + print "
\n"; # class="page_body" git_footer_html(); } From 9b71b1f6b3b57b3771151d252a5e22886524a154 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 21:14:49 +0200 Subject: [PATCH 36/46] gitweb: git_blobdiff_plain is git_blobdiff('plain') git_blobdiff and git_blobdiff_plain are now collapsed into one subroutine git_blobdiff, with format (currently 'html' which is default format corresponding to git_blobdiff, and 'plain' corresponding to git_blobdiff_plain) specified in argument. blobdiff_plain format is now generated either by git-diff-tree or by git-diff. Added X-Git-Url: header. From-file and to-file name in header are corrected. Note that for now commitdiff_plain does not detect renames and copying, while blobdiff_plain does. While at it, set expires to "+1d" for non-textual hash ids. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 93 +++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 25 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0fa35f3369..11b3fdc178 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2815,9 +2815,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 +2869,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,6 +2904,13 @@ sub git_blobdiff { $diffinfo{'to_file'} = $hash; } + # 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 open $fd, "-|", $GIT, "diff", '-p', $hash, $hash_parent or die_error(undef, "Open git-diff failed"); @@ -2904,40 +2920,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); + 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 "

$formats_nav
\n"; + print "
$hash vs $hash_parent
\n"; + } + if (defined $file_name) { + git_print_page_path($file_name, "blob", $hash_base); + } else { + print "
\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 "

$formats_nav
\n"; - print "
$hash vs $hash_parent
\n"; - } - if (defined $file_name) { - git_print_page_path($file_name, "blob", $hash_base); - } else { - print "
\n"; + die_error(undef, "Unknown blobdiff format"); } # patch - print "
\n"; + if ($format eq 'html') { + print "
\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 "
\n"; # class="page_body" - git_footer_html(); + print "
\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 { From 8cce8e3ddb2c2f7e0ab028012ae4dc729c8bf3f9 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 21:15:27 +0200 Subject: [PATCH 37/46] gitweb: Remove git_diff_print subroutine Remove git_diff_print subroutine, used to print diff in previous versions of "diff" actions, namely git_commitdiff, git_commitdiff_plain, git_blobdiff, git_blobdiff_plain. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 71 ---------------------------------------------- 1 file changed, 71 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 11b3fdc178..35f0da1ba7 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1975,77 +1975,6 @@ sub git_heads_body { print "\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 "
" . esc_html($line) . "
\n"; - } - } - close $fd; - - if (defined $from) { - unlink($from_tmp); - } - if (defined $to) { - unlink($to_tmp); - } -} - - ## ====================================================================== ## ====================================================================== ## actions From 903acca75329841996bbf0c3a32a7cfeb3ae0d0f Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Fri, 25 Aug 2006 21:35:27 +0200 Subject: [PATCH 38/46] gitweb: Remove creating directory for temporary files Remove $git_temp variable which held location for temporary files needed by git_diff_print, and removed creating $git_temp directory. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 35f0da1ba7..0ae18103c1 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -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 || "/"; @@ -144,9 +141,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 From 73c9083f52ac918b530c51887bbf5fd0a1119b4c Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 26 Aug 2006 12:33:17 +0200 Subject: [PATCH 39/46] gitweb: Remove workaround for git-diff bug fixed in f82cd3c Remove workaround in git_blobdiff for error in git-diff (showing reversed diff for diff of blobs), corrected in commit f82cd3c Fix "git diff blob1 blob2" showing the diff in reverse. which is post 1.4.2-rc2 commit. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e00a6ed6e0..5d321e9b3b 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2834,8 +2834,7 @@ sub git_blobdiff { } # open patch output - #open $fd, "-|", $GIT, "diff", '-p', $hash_parent, $hash - open $fd, "-|", $GIT, "diff", '-p', $hash, $hash_parent + 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") From 17848fc67cf466b805f35608230f4df898943ec1 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 26 Aug 2006 19:14:22 +0200 Subject: [PATCH 40/46] gitweb: Improve comments about gitweb features configuration Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 5d321e9b3b..2db99c3600 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -67,9 +67,16 @@ # 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() to check if is enabled 'blame' => { 'sub' => \&feature_blame, @@ -95,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 { @@ -113,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 { From f2e73302994b6072e556df1af998c0afd643e833 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 26 Aug 2006 19:14:25 +0200 Subject: [PATCH 41/46] gitweb: blobs defined by non-textual hash ids can be cached Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 2db99c3600..0df59af821 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2363,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); @@ -2386,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>; @@ -2397,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); @@ -2414,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) { From 090525541ffd3f52867d5d26de5e02ce4998460b Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 26 Aug 2006 23:33:58 +0200 Subject: [PATCH 42/46] gitweb: Fix typo in git_difftree_body Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0df59af821..ba5024af14 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1556,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") . "\n"; From c8a99d76749aeaa6b7fd8555724a4921eb677a37 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 26 Aug 2006 19:14:23 +0200 Subject: [PATCH 43/46] gitweb: Fix typo in git_patchset_body Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ba5024af14..7b458bcf8e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1656,7 +1656,7 @@ sub git_patchset_body { print "
\n"; LINE: - while (my $patch_line @$fd>) { + while (my $patch_line = <$fd>) { chomp $patch_line; if ($patch_line =~ m/^diff /) { # "git diff" header From 023782bd4df765b0555b8abc1830d9a90cdccca2 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sun, 27 Aug 2006 23:44:38 +0200 Subject: [PATCH 44/46] gitweb: Remove unused git_get_{preceding,following}_references Remove unused (and with errors in implementation) git_get_{preceding,following}_references subroutines. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 51 ---------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7b458bcf8e..9aa7e4df41 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -784,57 +784,6 @@ sub git_get_references { return \%refs; } -sub git_get_following_references { - my $hash = shift || return undef; - my $type = shift; - my $base = shift || $hash_base || "HEAD"; - - my $refs = git_get_references($type); - open my $fd, "-|", $GIT, "rev-list", $base - or return undef; - my @commits = map { chomp; $_ } <$fd>; - close $fd - or return undef; - - my @reflist; - my $lastref; - - foreach my $commit (@commits) { - foreach my $ref (@{$refs->{$commit}}) { - $lastref = $ref; - push @reflist, $lastref; - } - if ($commit eq $hash) { - last; - } - } - - return wantarray ? @reflist : $lastref; -} - -sub git_get_preceding_references { - my $hash = shift || return undef; - my $type = shift; - - my $refs = git_get_references($type); - open my $fd, "-|", $GIT, "rev-list", $hash - or return undef; - my @commits = map { chomp; $_ } <$fd>; - close $fd - or return undef; - - my @reflist; - - foreach my $commit (@commits) { - foreach my $ref (@{$refs->{$commit}}) { - return $ref unless wantarray; - push @reflist, $ref; - } - } - - return @reflist; -} - sub git_get_rev_name_tags { my $hash = shift || return undef; From 0aea33762b1262d11fb43eda9f3fc152b5622cca Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sun, 27 Aug 2006 23:45:26 +0200 Subject: [PATCH 45/46] gitweb: Remove git_to_hash function Remove git_to_hash function, which was to translate symbolic reference to hash, and it's use in git_blobdiff. We don't try so hard to guess filename if it was not provided. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9aa7e4df41..8d28207b1f 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -625,26 +625,6 @@ sub git_get_hash_by_path { return $3; } -# converts symbolic name to hash -sub git_to_hash { - my @params = @_; - return undef unless @params; - - open my $fd, "-|", $GIT, "rev-parse", @params - or return undef; - my @hashes = map { chomp; $_ } <$fd>; - close $fd; - - if (wantarray) { - return @hashes; - } elsif (scalar(@hashes) == 1) { - # single hash - return $hashes[0]; - } else { - return \@hashes; - } -} - ## ...................................................................... ## git utility functions, directly accessing git repository @@ -2733,6 +2713,9 @@ sub git_blobdiff { if ($hash !~ /[0-9a-fA-F]{40}/) { $hash = git_to_hash($hash); } + } elsif (defined $hash && + $hash =~ /[0-9a-fA-F]{40}/) { + # try to find filename from $hash # read filtered raw output open $fd, "-|", $GIT, "diff-tree", '-r', '-M', '-C', $hash_parent_base, $hash_base From 6bcf4b46c9a4ba7a6e5c78201c619fa41ac76a99 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sun, 27 Aug 2006 23:49:36 +0200 Subject: [PATCH 46/46] gitweb: Use @diff_opts, default ('M'), as git-diff and git-diff-tree paramete Added new global configuration variable @diff_opts, which holds additional options (parameters) to git-diff and git-diff-tree, usually dealing rename/copying detection. Default value is '-M', taken from git_commit subroutine. Description of options and their approximate cost by Junio C Hamano. Changes: * git_commitdiff, git_blobdiff and git_blobdiff_plain now use '-M' instead of '-M', '-C' * git-diff now uses the same options as git-diff-tree * git_comittdiff_plain now uses '-M' instead of '-B' and is now rename-aware * git_rss uses now '-M' instead of () Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8d28207b1f..1430a7a8aa 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -141,6 +141,16 @@ sub feature_snapshot { return ($ctype, $suffix, $command); } +# rename detection options for git-diff and git-diff-tree +# - default is '-M', with the cost proportional to +# (number of removed files) * (number of new files). +# - more costly is '-C' (or '-C', '-M'), with the cost proportional to +# (number of changed files + number of removed files) * (number of new files) +# - even more costly is '-C', '--find-copies-harder' with cost +# (number of files in the original tree) * (number of new files) +# - one might want to include '-B' option, e.g. '-B', '-M' +our @diff_opts = ('-M'); # taken from git_commit + our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; require $GITWEB_CONFIG if -e $GITWEB_CONFIG; @@ -2593,7 +2603,7 @@ sub git_commit { if (!defined $parent) { $parent = "--root"; } - open my $fd, "-|", $GIT, "diff-tree", '-r', '-M', $parent, $hash + open my $fd, "-|", $GIT, "diff-tree", '-r', @diff_opts, $parent, $hash or die_error(undef, "Open git-diff-tree failed"); my @difftree = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading git-diff-tree failed"); @@ -2700,7 +2710,7 @@ sub git_blobdiff { if (defined $hash_base && defined $hash_parent_base) { if (defined $file_name) { # read raw output - open $fd, "-|", $GIT, "diff-tree", '-r', '-M', '-C', $hash_parent_base, $hash_base, + open $fd, "-|", $GIT, "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base, "--", $file_name or die_error(undef, "Open git-diff-tree failed"); @difftree = map { chomp; $_ } <$fd>; @@ -2718,7 +2728,7 @@ sub git_blobdiff { # try to find filename from $hash # read filtered raw output - open $fd, "-|", $GIT, "diff-tree", '-r', '-M', '-C', $hash_parent_base, $hash_base + open $fd, "-|", $GIT, "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base or die_error(undef, "Open git-diff-tree failed"); @difftree = # ':100644 100644 03b21826... 3b93d5e7... M ls-files.c' @@ -2752,7 +2762,8 @@ sub git_blobdiff { } # open patch output - open $fd, "-|", $GIT, "diff-tree", '-r', '-p', '-M', '-C', $hash_parent_base, $hash_base, + open $fd, "-|", $GIT, "diff-tree", '-r', @diff_opts, + '-p', $hash_parent_base, $hash_base, "--", $file_name or die_error(undef, "Open git-diff-tree failed"); } @@ -2787,7 +2798,7 @@ sub git_blobdiff { } # open patch output - open $fd, "-|", $GIT, "diff", '-p', $hash_parent, $hash + open $fd, "-|", $GIT, "diff", '-p', @diff_opts, $hash_parent, $hash or die_error(undef, "Open git-diff failed"); } else { die_error('404 Not Found', "Missing one of the blob diff parameters") @@ -2872,7 +2883,7 @@ sub git_commitdiff { my $fd; my @difftree; if ($format eq 'html') { - open $fd, "-|", $GIT, "diff-tree", '-r', '-M', '-C', + open $fd, "-|", $GIT, "diff-tree", '-r', @diff_opts, "--patch-with-raw", "--full-index", $hash_parent, $hash or die_error(undef, "Open git-diff-tree failed"); @@ -2883,7 +2894,8 @@ sub git_commitdiff { } } elsif ($format eq 'plain') { - open $fd, "-|", $GIT, "diff-tree", '-r', '-p', '-B', $hash_parent, $hash + open $fd, "-|", $GIT, "diff-tree", '-r', @diff_opts, + '-p', $hash_parent, $hash or die_error(undef, "Open git-diff-tree failed"); } else { @@ -3192,9 +3204,12 @@ sub git_rss { last; } my %cd = parse_date($co{'committer_epoch'}); - open $fd, "-|", $GIT, "diff-tree", '-r', $co{'parent'}, $co{'id'} or next; + open $fd, "-|", $GIT, "diff-tree", '-r', @diff_opts, + $co{'parent'}, $co{'id'} + or next; my @difftree = map { chomp; $_ } <$fd>; - close $fd or next; + close $fd + or next; print "\n" . "" . sprintf("%d %s %02d:%02d", $cd{'mday'}, $cd{'month'}, $cd{'hour'}, $cd{'minute'}) . " - " . esc_html($co{'title'}) .