X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/61b8e5f83a6c26520b415e1a93584f4ba9610ab9dc78275c19186ea4b928755d..9bef2fa6d80a0b2fa2a21c83dc3908f6637da2811ab2281aab0efa260f4d3ff3:/gitweb.perl diff --git a/gitweb.perl b/gitweb.perl index f7b5315..5fe3f7f 100755 --- a/gitweb.perl +++ b/gitweb.perl @@ -19,7 +19,7 @@ use File::Basename qw(basename); binmode STDOUT, ':utf8'; BEGIN { - CGI->compile() if $ENV{MOD_PERL}; + CGI->compile() if $ENV{'MOD_PERL'}; } our $cgi = new CGI; @@ -72,6 +72,10 @@ our $logo_label = "git homepage"; # source of projects list our $projects_list = "++GITWEB_LIST++"; +# default order of projects list +# valid values are none, project, descr, owner, and age +our $default_projects_order = "project"; + # show repository only if this file exists # (only effective if this variable evaluates to true) our $export_ok = "++GITWEB_EXPORT_OK++"; @@ -177,8 +181,8 @@ our %feature = ( # projects matching $projname/*.git will not be shown in the main # projects list, instead a '+' mark will be added to $projname # there and a 'forks' view will be enabled for the project, listing - # all the forks. This feature is supported only if project list - # is taken from a directory, not file. + # all the forks. If project list is taken from a file, forks have + # to be listed after the main project. # To enable system wide have in $GITWEB_CONFIG # $feature{'forks'}{'default'} = [1]; @@ -561,12 +565,6 @@ sub validate_refname { return $input; } -# very thin wrapper for decode("utf8", $str, Encode::FB_DEFAULT); -sub to_utf8 { - my $str = shift; - return decode("utf8", $str, Encode::FB_DEFAULT); -} - # quote unsafe chars, but keep the slash, even when it's not # correct, but quoted slashes look too horrible in bookmarks sub esc_param { @@ -591,8 +589,8 @@ sub esc_html ($;%) { my $str = shift; my %opts = @_; - $str = to_utf8($str); - $str = escapeHTML($str); + $str = decode_utf8($str); + $str = $cgi->escapeHTML($str); if ($opts{'-nbsp'}) { $str =~ s/ / /g; } @@ -605,8 +603,8 @@ sub esc_path { my $str = shift; my %opts = @_; - $str = to_utf8($str); - $str = escapeHTML($str); + $str = decode_utf8($str); + $str = $cgi->escapeHTML($str); if ($opts{'-nbsp'}) { $str =~ s/ / /g; } @@ -835,7 +833,7 @@ sub file_type_long { ## ---------------------------------------------------------------------- ## functions returning short HTML fragments, or transforming HTML fragments -## which don't beling to other sections +## which don't belong to other sections # format line of commit message. sub format_log_line_html { @@ -888,7 +886,7 @@ sub format_subject_html { if (length($short) < length($long)) { return $cgi->a({-href => $href, -class => "list subject", - -title => to_utf8($long)}, + -title => decode_utf8($long)}, esc_html($short) . $extra); } else { return $cgi->a({-href => $href, -class => "list subject"}, @@ -900,19 +898,34 @@ sub format_subject_html { sub format_diff_line { my $line = shift; my ($from, $to) = @_; - 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 "\\") { - $diff_class = " incomplete"; + if ($from && $to && ref($from->{'href'}) eq "ARRAY") { + # combined diff + my $prefix = substr($line, 0, scalar @{$from->{'href'}}); + if ($line =~ m/^\@{3}/) { + $diff_class = " chunk_header"; + } elsif ($line =~ m/^\\/) { + $diff_class = " incomplete"; + } elsif ($prefix =~ tr/+/+/) { + $diff_class = " add"; + } elsif ($prefix =~ tr/-/-/) { + $diff_class = " rem"; + } + } else { + # assume ordinary diff + my $char = substr($line, 0, 1); + if ($char eq '+') { + $diff_class = " add"; + } elsif ($char eq '-') { + $diff_class = " rem"; + } elsif ($char eq '@') { + $diff_class = " chunk_header"; + } elsif ($char eq "\\") { + $diff_class = " incomplete"; + } } $line = untabify($line); if ($from && $to && $line =~ m/^\@{2} /) { @@ -933,6 +946,39 @@ sub format_diff_line { $line = "@@ $from_text $to_text @@" . "" . esc_html($section, -nbsp=>1) . ""; return "
| " . + $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, + file_name=>$diff{'to_file'}, + hash_base=>$hash), + -class => "list"}, esc_path($diff{'to_file'})) . + " | \n"; + } else { + print "" . + esc_path($diff{'to_file'}) . + " | \n"; + } + + if ($action eq 'commitdiff') { + # link to patch + $patchno++; + print "" . + $cgi->a({-href => "#patch$patchno"}, "patch") . + " | " . + " | \n"; + } + + my $has_history = 0; + my $not_deleted = 0; + for (my $i = 0; $i < $diff{'nparents'}; $i++) { + my $hash_parent = $parents[$i]; + my $from_hash = $diff{'from_id'}[$i]; + my $from_path = $diff{'from_file'}[$i]; + my $status = $diff{'status'}[$i]; + + $has_history ||= ($status ne 'A'); + $not_deleted ||= ($status ne 'D'); + + if ($status eq 'A') { + print "| | \n"; + } elsif ($status eq 'D') { + print "" . + $cgi->a({-href => href(action=>"blob", + hash_base=>$hash, + hash=>$from_hash, + file_name=>$from_path)}, + "blob" . ($i+1)) . + " | | \n"; + } else { + if ($diff{'to_id'} eq $from_hash) { + print ""; + } else { + print " | "; + } + print $cgi->a({-href => href(action=>"blobdiff", + hash=>$diff{'to_id'}, + hash_parent=>$from_hash, + hash_base=>$hash, + hash_parent_base=>$hash_parent, + file_name=>$diff{'to_file'}, + file_parent=>$from_path)}, + "diff" . ($i+1)) . + " | | \n"; + } + } + + print ""; + if ($not_deleted) { + print $cgi->a({-href => href(action=>"blob", + hash=>$diff{'to_id'}, + file_name=>$diff{'to_file'}, + hash_base=>$hash)}, + "blob"); + print " | " if ($has_history); + } + if ($has_history) { + print $cgi->a({-href => href(action=>"history", + file_name=>$diff{'to_file'}, + hash_base=>$hash)}, + "history"); + } + print " | \n"; + + print "\n"; + next; # instead of 'else' clause, to avoid extra indent + } + # else ordinary diff + 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)) { @@ -2240,7 +2464,7 @@ sub git_difftree_body { } print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, hash_base=>$hash, file_name=>$diff{'file'})}, - "blob") . " | "; + "blob"); print "\n"; } elsif ($diff{'status'} eq "D") { # deleted @@ -2373,9 +2597,11 @@ sub git_difftree_body { } sub git_patchset_body { - my ($fd, $difftree, $hash, $hash_parent) = @_; + my ($fd, $difftree, $hash, @hash_parents) = @_; + my ($hash_parent) = $hash_parents[0]; my $patch_idx = 0; + my $patch_number = 0; my $patch_line; my $diffinfo; my (%from, %to); @@ -2397,6 +2623,7 @@ sub git_patchset_body { # git diff header #assert($patch_line =~ m/^diff /) if DEBUG; #assert($patch_line !~ m!$/$!) if DEBUG; # is chomp-ed + $patch_number++; push @diff_header, $patch_line; # extended diff header @@ -2409,18 +2636,20 @@ sub git_patchset_body { if ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) { $from_id = $1; $to_id = $2; + } elsif ($patch_line =~ m/^index ((?:[0-9a-fA-F]{40},)+[0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) { + $from_id = [ split(',', $1) ]; + $to_id = $2; } push @diff_header, $patch_line; } - #last PATCH unless $patch_line; my $last_patch_line = $patch_line; # check if current patch belong to current raw line # and parse raw git-diff line if needed if (defined $diffinfo && - $diffinfo->{'from_id'} eq $from_id && - $diffinfo->{'to_id'} eq $to_id) { + from_ids_eq($diffinfo->{'from_id'}, $from_id) && + $diffinfo->{'to_id'} eq $to_id) { # this is split patch print ""; print $cgi->a({ -href => "$blamed#l$orig_lineno", - -id => "l$lineno", - -class => "linenr" }, - esc_html($lineno)); + -id => "l$lineno", + -class => "linenr" }, + esc_html($lineno)); print " | "; print "" . esc_html($data) . " | \n"; print "\n"; @@ -3610,7 +3900,7 @@ sub git_snapshot { $hash = git_get_head_hash($project); } - my $filename = basename($project) . "-$hash.tar.$suffix"; + my $filename = decode_utf8(basename($project)) . "-$hash.tar.$suffix"; print $cgi->header( -type => "application/$ctype", @@ -3621,8 +3911,8 @@ sub git_snapshot { my $name = $project; $name =~ s/\047/\047\\\047\047/g; open my $fd, "-|", - "$git archive --format=tar --prefix=\'$name\'/ $hash | $command" - or die_error(undef, "Execute git-tar-tree failed."); + "$git archive --format=tar --prefix=\'$name\'/ $hash | $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 @@ -3719,7 +4009,7 @@ sub git_commit { $formats_nav .= '(merge: ' . join(' ', map { - $cgi->a({-href => href(action=>"commitdiff", + $cgi->a({-href => href(action=>"commit", hash=>$_)}, esc_html(substr($_, 0, 7))); } @$parents ) . @@ -3734,7 +4024,7 @@ sub git_commit { # difftree output is not printed for merges open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id", @diff_opts, $parent, $hash, "--" - or die_error(undef, "Open git-diff-tree failed"); + or die_error(undef, "Open git-diff-tree failed"); @difftree = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading git-diff-tree failed"); } @@ -3885,7 +4175,7 @@ sub git_blobdiff { # read raw output open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base, - "--", $file_name + "--", (defined $file_parent ? $file_parent : ()), $file_name or die_error(undef, "Open git-diff-tree failed"); @difftree = map { chomp; $_ } <$fd>; close $fd @@ -3934,8 +4224,9 @@ sub git_blobdiff { # open patch output open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, - '-p', $hash_parent_base, $hash_base, - "--", $file_name + '-p', ($format eq 'html' ? "--full-index" : ()), + $hash_parent_base, $hash_base, + "--", (defined $file_parent ? $file_parent : ()), $file_name or die_error(undef, "Open git-diff-tree failed"); } @@ -3969,7 +4260,8 @@ sub git_blobdiff { } # open patch output - open $fd, "-|", git_cmd(), "diff", '-p', @diff_opts, + open $fd, "-|", git_cmd(), "diff", @diff_opts, + '-p', ($format eq 'html' ? "--full-index" : ()), $hash_parent, $hash, "--" or die_error(undef, "Open git-diff failed"); } else { @@ -4304,13 +4596,13 @@ sub git_search { if ($page > 0) { $paging_nav .= $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype)}, - "first"); + searchtext=>$searchtext, searchtype=>$searchtype)}, + "first"); $paging_nav .= " ⋅ " . $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype, - page=>$page-1), - -accesskey => "p", -title => "Alt-p"}, "prev"); + searchtext=>$searchtext, searchtype=>$searchtype, + page=>$page-1), + -accesskey => "p", -title => "Alt-p"}, "prev"); } else { $paging_nav .= "first"; $paging_nav .= " ⋅ prev"; @@ -4318,9 +4610,9 @@ sub git_search { if ($#commitlist >= 100) { $paging_nav .= " ⋅ " . $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype, - page=>$page+1), - -accesskey => "n", -title => "Alt-n"}, "next"); + searchtext=>$searchtext, searchtype=>$searchtype, + page=>$page+1), + -accesskey => "n", -title => "Alt-n"}, "next"); } else { $paging_nav .= " ⋅ next"; } @@ -4328,9 +4620,9 @@ sub git_search { if ($#commitlist >= 100) { $next_link = $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype, - page=>$page+1), - -accesskey => "n", -title => "Alt-n"}, "next"); + searchtext=>$searchtext, searchtype=>$searchtype, + page=>$page+1), + -accesskey => "n", -title => "Alt-n"}, "next"); } git_print_page_nav('','', $hash,$co{'tree'},$hash, $paging_nav);