X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/958ee5f91069d816e25d270522e64a42524242bfcbdc7965177c45e1d84cf6a5..72424a946d4d49d67bf0ac3da402ae68593ae869f73ba33b1060676a6e094e61:/gitweb.perl diff --git a/gitweb.perl b/gitweb.perl index 2f5e9cb..39de505 100755 --- a/gitweb.perl +++ b/gitweb.perl @@ -612,6 +612,15 @@ sub href(%) { ); my %mapping = @mapping; + if ($params{-replay}) { + while (my ($name, $symbol) = each %mapping) { + if (!exists $params{$name}) { + # to allow for multivalued params we use arrayref form + $params{$name} = [ $cgi->param($symbol) ]; + } + } + } + $params{'project'} = $project unless exists $params{'project'}; my ($use_pathinfo) = gitweb_check_feature('pathinfo'); @@ -1424,20 +1433,121 @@ sub git_get_type { return $type; } +# repository configuration +our $config_file = ''; +our %config; + +# store multiple values for single key as anonymous array reference +# single values stored directly in the hash, not as [ ] +sub hash_set_multi { + my ($hash, $key, $value) = @_; + + if (!exists $hash->{$key}) { + $hash->{$key} = $value; + } elsif (!ref $hash->{$key}) { + $hash->{$key} = [ $hash->{$key}, $value ]; + } else { + push @{$hash->{$key}}, $value; + } +} + +# return hash of git project configuration +# optionally limited to some section, e.g. 'gitweb' +sub git_parse_project_config { + my $section_regexp = shift; + my %config; + + local $/ = "\0"; + + open my $fh, "-|", git_cmd(), "config", '-z', '-l', + or return; + + while (my $keyval = <$fh>) { + chomp $keyval; + my ($key, $value) = split(/\n/, $keyval, 2); + + hash_set_multi(\%config, $key, $value) + if (!defined $section_regexp || $key =~ /^(?:$section_regexp)\./o); + } + close $fh; + + return %config; +} + +# convert config value to boolean, 'true' or 'false' +# no value, number > 0, 'true' and 'yes' values are true +# rest of values are treated as false (never as error) +sub config_to_bool { + my $val = shift; + + # strip leading and trailing whitespace + $val =~ s/^\s+//; + $val =~ s/\s+$//; + + return (!defined $val || # section.key + ($val =~ /^\d+$/ && $val) || # section.key = 1 + ($val =~ /^(?:true|yes)$/i)); # section.key = true +} + +# convert config value to simple decimal number +# an optional value suffix of 'k', 'm', or 'g' will cause the value +# to be multiplied by 1024, 1048576, or 1073741824 +sub config_to_int { + my $val = shift; + + # strip leading and trailing whitespace + $val =~ s/^\s+//; + $val =~ s/\s+$//; + + if (my ($num, $unit) = ($val =~ /^([0-9]*)([kmg])$/i)) { + $unit = lc($unit); + # unknown unit is treated as 1 + return $num * ($unit eq 'g' ? 1073741824 : + $unit eq 'm' ? 1048576 : + $unit eq 'k' ? 1024 : 1); + } + return $val; +} + +# convert config value to array reference, if needed +sub config_to_multi { + my $val = shift; + + return ref($val) ? $val : [ $val ]; +} + sub git_get_project_config { my ($key, $type) = @_; + # key sanity check return unless ($key); $key =~ s/^gitweb\.//; return if ($key =~ m/\W/); - my @x = (git_cmd(), 'config'); - if (defined $type) { push @x, $type; } - push @x, "--get"; - push @x, "gitweb.$key"; - my $val = qx(@x); - chomp $val; - return ($val); + # type sanity check + if (defined $type) { + $type =~ s/^--//; + $type = undef + unless ($type eq 'bool' || $type eq 'int'); + } + + # get config + if (!defined $config_file || + $config_file ne "$git_dir/config") { + %config = git_parse_project_config('gitweb'); + $config_file = "$git_dir/config"; + } + + # ensure given type + if (!defined $type) { + return $config{"gitweb.$key"}; + } elsif ($type eq 'bool') { + # backward compatibility: 'git config --bool' returns true/false + return config_to_bool($config{"gitweb.$key"}) ? 'true' : 'false'; + } elsif ($type eq 'int') { + return config_to_int($config{"gitweb.$key"}); + } + return $config{"gitweb.$key"}; } # get hash of given path at given ref @@ -1497,7 +1607,9 @@ sub git_get_path_by_hash { sub git_get_project_description { my $path = shift; - open my $fd, "$projectroot/$path/description" or return undef; + $git_dir = "$projectroot/$path"; + open my $fd, "$projectroot/$path/description" + or return git_get_project_config('description'); my $descr = <$fd>; close $fd; if (defined $descr) { @@ -1509,7 +1621,11 @@ sub git_get_project_description { sub git_get_project_url_list { my $path = shift; - open my $fd, "$projectroot/$path/cloneurl" or return; + $git_dir = "$projectroot/$path"; + open my $fd, "$projectroot/$path/cloneurl" + or return wantarray ? + @{ config_to_multi(git_get_project_config('url')) } : + config_to_multi(git_get_project_config('url')); my @git_project_url_list = map { chomp; $_ } <$fd>; close $fd; @@ -1991,12 +2107,12 @@ sub parse_difftree_raw_line { $res{'to_mode'} = $2; $res{'from_id'} = $3; $res{'to_id'} = $4; - $res{'status'} = $5; + $res{'status'} = $res{'status_str'} = $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); + $res{'from_file'} = $res{'to_file'} = $res{'file'} = unquote($7); } } # '::100755 100755 100755 60e79ca1b01bc8b057abe17ddab484699a7f5fdb 94067cc5f73388f33722d52ae02f44692bc07490 94067cc5f73388f33722d52ae02f44692bc07490 MR git-gui/git-gui.sh' @@ -2007,6 +2123,7 @@ sub parse_difftree_raw_line { $res{'to_mode'} = pop @{$res{'from_mode'}}; $res{'from_id'} = [ split(' ', $3) ]; $res{'to_id'} = pop @{$res{'from_id'}}; + $res{'status_str'} = $4; $res{'status'} = [ split('', $4) ]; $res{'to_file'} = unquote($5); } @@ -2063,7 +2180,10 @@ sub parse_from_to_diffinfo { fill_from_file_info($diffinfo, @parents) unless exists $diffinfo->{'from_file'}; for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) { - $from->{'file'}[$i] = $diffinfo->{'from_file'}[$i] || $diffinfo->{'to_file'}; + $from->{'file'}[$i] = + defined $diffinfo->{'from_file'}[$i] ? + $diffinfo->{'from_file'}[$i] : + $diffinfo->{'to_file'}; if ($diffinfo->{'status'}[$i] ne "A") { # not new (added) file $from->{'href'}[$i] = href(action=>"blob", hash_base=>$parents[$i], @@ -2075,7 +2195,7 @@ sub parse_from_to_diffinfo { } } else { # ordinary (not combined) diff - $from->{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'}; + $from->{'file'} = $diffinfo->{'from_file'}; if ($diffinfo->{'status'} ne "A") { # not new (added) file $from->{'href'} = href(action=>"blob", hash_base=>$hash_parent, hash=>$diffinfo->{'from_id'}, @@ -2085,7 +2205,7 @@ sub parse_from_to_diffinfo { } } - $to->{'file'} = $diffinfo->{'to_file'} || $diffinfo->{'file'}; + $to->{'file'} = $diffinfo->{'to_file'}; if (!is_deleted($diffinfo)) { # file exists in result $to->{'href'} = href(action=>"blob", hash_base=>$hash, hash=>$diffinfo->{'to_id'}, @@ -2506,7 +2626,7 @@ sub format_paging_nav { if ($page > 0) { $paging_nav .= " ⋅ " . - $cgi->a({-href => href(action=>$action, hash=>$hash, page=>$page-1), + $cgi->a({-href => href(-replay=>1, page=>$page-1), -accesskey => "p", -title => "Alt-p"}, "prev"); } else { $paging_nav .= " ⋅ prev"; @@ -2514,7 +2634,7 @@ sub format_paging_nav { if ($nrevs >= (100 * ($page+1)-1)) { $paging_nav .= " ⋅ " . - $cgi->a({-href => href(action=>$action, hash=>$hash, page=>$page+1), + $cgi->a({-href => href(-replay=>1, page=>$page+1), -accesskey => "n", -title => "Alt-n"}, "next"); } else { $paging_nav .= " ⋅ next"; @@ -2819,7 +2939,7 @@ sub fill_from_file_info { sub is_deleted { my $diffinfo = shift; - return $diffinfo->{'to_id'} eq ('0' x 40); + return $diffinfo->{'status_str'} =~ /D/; } # does patch correspond to [previous] difftree raw line @@ -2830,7 +2950,7 @@ sub is_patch_split { my ($diffinfo, $patchinfo) = @_; return defined $diffinfo && defined $patchinfo - && ($diffinfo->{'to_file'} || $diffinfo->{'file'}) eq $patchinfo->{'to_file'}; + && $diffinfo->{'to_file'} eq $patchinfo->{'to_file'}; } @@ -3899,11 +4019,11 @@ sub git_blame2 { or die_error(undef, "Open git-blame failed"); git_header_html(); my $formats_nav = - $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, + $cgi->a({-href => href(action=>"blob", -replay=>1)}, "blob") . " | " . - $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, - "history") . + $cgi->a({-href => href(action=>"history", -replay=>1)}, + "history") . " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, "HEAD"); @@ -4179,18 +4299,15 @@ sub git_blob { if (defined $file_name) { if ($have_blame) { $formats_nav .= - $cgi->a({-href => href(action=>"blame", hash_base=>$hash_base, - hash=>$hash, file_name=>$file_name)}, + $cgi->a({-href => href(action=>"blame", -replay=>1)}, "blame") . " | "; } $formats_nav .= - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, - hash=>$hash, file_name=>$file_name)}, + $cgi->a({-href => href(action=>"history", -replay=>1)}, "history") . " | " . - $cgi->a({-href => href(action=>"blob_plain", - hash=>$hash, file_name=>$file_name)}, + $cgi->a({-href => href(action=>"blob_plain", -replay=>1)}, "raw") . " | " . $cgi->a({-href => href(action=>"blob", @@ -4198,7 +4315,8 @@ sub git_blob { "HEAD"); } else { $formats_nav .= - $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "raw"); + $cgi->a({-href => href(action=>"blob_plain", -replay=>1)}, + "raw"); } git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); @@ -4261,8 +4379,7 @@ sub git_tree { my @views_nav = (); if (defined $file_name) { push @views_nav, - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, - hash=>$hash, file_name=>$file_name)}, + $cgi->a({-href => href(action=>"history", -replay=>1)}, "history"), $cgi->a({-href => href(action=>"tree", hash_base=>"HEAD", file_name=>$file_name)}, @@ -4436,7 +4553,7 @@ sub git_log { } if ($#commitlist >= 100) { print "
\n"; - print $cgi->a({-href => href(action=>"log", hash=>$hash, page=>$page+1), + print $cgi->a({-href => href(-replay=>1, page=>$page+1), -accesskey => "n", -title => "Alt-n"}, "next"); print "
\n"; } @@ -4668,8 +4785,8 @@ sub git_blobdiff { } %diffinfo = parse_difftree_raw_line($difftree[0]); - $file_parent ||= $diffinfo{'from_file'} || $file_name || $diffinfo{'file'}; - $file_name ||= $diffinfo{'to_file'} || $diffinfo{'file'}; + $file_parent ||= $diffinfo{'from_file'} || $file_name; + $file_name ||= $diffinfo{'to_file'}; $hash_parent ||= $diffinfo{'from_id'}; $hash ||= $diffinfo{'to_id'}; @@ -4730,10 +4847,7 @@ sub git_blobdiff { # header 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)}, + $cgi->a({-href => href(action=>"blobdiff_plain", -replay=>1)}, "raw"); git_header_html(undef, $expires); if (defined $hash_base && (my %co = parse_commit($hash_base))) { @@ -4807,8 +4921,7 @@ sub git_commitdiff { my $formats_nav; if ($format eq 'html') { $formats_nav = - $cgi->a({-href => href(action=>"commitdiff_plain", - hash=>$hash, hash_parent=>$hash_parent)}, + $cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)}, "raw"); if (defined $hash_parent && @@ -5003,27 +5116,20 @@ sub git_history { file_name=>$file_name)}, "first"); $paging_nav .= " ⋅ " . - $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, - file_name=>$file_name, page=>$page-1), + $cgi->a({-href => href(-replay=>1, page=>$page-1), -accesskey => "p", -title => "Alt-p"}, "prev"); } else { $paging_nav .= "first"; $paging_nav .= " ⋅ prev"; } - if ($#commitlist >= 100) { - $paging_nav .= " ⋅ " . - $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, - file_name=>$file_name, page=>$page+1), - -accesskey => "n", -title => "Alt-n"}, "next"); - } else { - $paging_nav .= " ⋅ next"; - } my $next_link = ''; if ($#commitlist >= 100) { $next_link = - $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, - file_name=>$file_name, page=>$page+1), + $cgi->a({-href => href(-replay=>1, page=>$page+1), -accesskey => "n", -title => "Alt-n"}, "next"); + $paging_nav .= " ⋅ $next_link"; + } else { + $paging_nav .= " ⋅ next"; } git_header_html(); @@ -5093,30 +5199,23 @@ sub git_search { searchtext=>$searchtext, searchtype=>$searchtype)}, "first"); $paging_nav .= " ⋅ " . - $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype, - page=>$page-1), + $cgi->a({-href => href(-replay=>1, page=>$page-1), -accesskey => "p", -title => "Alt-p"}, "prev"); } else { $paging_nav .= "first"; $paging_nav .= " ⋅ prev"; } + my $next_link = ''; if ($#commitlist >= 100) { - $paging_nav .= " ⋅ " . - $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype, - page=>$page+1), + $next_link = + $cgi->a({-href => href(-replay=>1, page=>$page+1), -accesskey => "n", -title => "Alt-n"}, "next"); + $paging_nav .= " ⋅ $next_link"; } else { $paging_nav .= " ⋅ next"; } - my $next_link = ''; + 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"); } git_print_page_nav('','', $hash,$co{'tree'},$hash, $paging_nav); @@ -5315,7 +5414,7 @@ sub git_shortlog { my $next_link = ''; if ($#commitlist >= 100) { $next_link = - $cgi->a({-href => href(action=>"shortlog", hash=>$hash, page=>$page+1), + $cgi->a({-href => href(-replay=>1, page=>$page+1), -accesskey => "n", -title => "Alt-n"}, "next"); }