From: Junio C Hamano Date: Tue, 20 Mar 2012 22:53:30 +0000 (-0700) Subject: Merge branch 'maint-1.7.8' into maint X-Git-Tag: v1.7.10-rc2~4^2 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/0f360763c02d1230614e23f94fb298dab0162aa0?ds=inline;hp=-c Merge branch 'maint-1.7.8' into maint * maint-1.7.8: t/Makefile: Use $(sort ...) explicitly where needed gitweb: Fix actionless dispatch for non-existent objects i18n of multi-line advice messages --- 0f360763c02d1230614e23f94fb298dab0162aa0 diff --combined builtin/revert.c index 0d8020cf64,00df5266d5..df63794e05 --- a/builtin/revert.c +++ b/builtin/revert.c @@@ -343,11 -343,10 +343,10 @@@ static void print_advice(int show_hint return; } - if (show_hint) { - advise("after resolving the conflicts, mark the corrected paths"); - advise("with 'git add ' or 'git rm '"); - advise("and commit the result with 'git commit'"); - } + if (show_hint) + advise(_("after resolving the conflicts, mark the corrected paths\n" + "with 'git add ' or 'git rm '\n" + "and commit the result with 'git commit'")); } static void write_message(struct strbuf *msgbuf, const char *filename) @@@ -700,47 -699,44 +699,47 @@@ static int format_todo(struct strbuf *b struct replay_opts *opts) { struct commit_list *cur = NULL; - struct commit_message msg = { NULL, NULL, NULL, NULL, NULL }; const char *sha1_abbrev = NULL; const char *action_str = opts->action == REVERT ? "revert" : "pick"; + const char *subject; + int subject_len; for (cur = todo_list; cur; cur = cur->next) { sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV); - if (get_message(cur->item, &msg)) - return error(_("Cannot get commit message for %s"), sha1_abbrev); - strbuf_addf(buf, "%s %s %s\n", action_str, sha1_abbrev, msg.subject); + subject_len = find_commit_subject(cur->item->buffer, &subject); + strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev, + subject_len, subject); } return 0; } -static struct commit *parse_insn_line(char *start, struct replay_opts *opts) +static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts) { unsigned char commit_sha1[20]; - char sha1_abbrev[40]; enum replay_action action; - int insn_len = 0; - char *p, *q; + char *end_of_object_name; + int saved, status, padding; - if (!prefixcmp(start, "pick ")) { + if (!prefixcmp(bol, "pick")) { action = CHERRY_PICK; - insn_len = strlen("pick"); - p = start + insn_len + 1; - } else if (!prefixcmp(start, "revert ")) { + bol += strlen("pick"); + } else if (!prefixcmp(bol, "revert")) { action = REVERT; - insn_len = strlen("revert"); - p = start + insn_len + 1; + bol += strlen("revert"); } else return NULL; - q = strchr(p, ' '); - if (!q) + /* Eat up extra spaces/ tabs before object name */ + padding = strspn(bol, " \t"); + if (!padding) return NULL; - q++; + bol += padding; - strlcpy(sha1_abbrev, p, q - p); + end_of_object_name = bol + strcspn(bol, " \t\n"); + saved = *end_of_object_name; + *end_of_object_name = '\0'; + status = get_sha1(bol, commit_sha1); + *end_of_object_name = saved; /* * Verify that the action matches up with the one in @@@ -753,7 -749,7 +752,7 @@@ return NULL; } - if (get_sha1(sha1_abbrev, commit_sha1) < 0) + if (status < 0) return NULL; return lookup_commit_reference(commit_sha1); @@@ -768,12 -764,13 +767,12 @@@ static int parse_insn_buffer(char *buf int i; for (i = 1; *p; i++) { - commit = parse_insn_line(p, opts); + char *eol = strchrnul(p, '\n'); + commit = parse_insn_line(p, eol, opts); if (!commit) return error(_("Could not parse line %d."), i); next = commit_list_append(commit, next); - p = strchrnul(p, '\n'); - if (*p) - p++; + p = *eol ? eol + 1 : eol; } if (!*todo_list) return error(_("No commits parsed.")); @@@ -905,7 -902,7 +904,7 @@@ static int rollback_single_pick(void if (!file_exists(git_path("CHERRY_PICK_HEAD")) && !file_exists(git_path("REVERT_HEAD"))) return error(_("no cherry-pick or revert in progress")); - if (!resolve_ref("HEAD", head_sha1, 0, NULL)) + if (read_ref_full("HEAD", head_sha1, 0, NULL)) return error(_("cannot resolve HEAD")); if (is_null_sha1(head_sha1)) return error(_("cannot abort from a branch yet to be born")); diff --combined gitweb/gitweb.perl index b9c33ba31d,6cf38853b5..b67972ec5d --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@@ -52,7 -52,7 +52,7 @@@ sub evaluate_uri # as base URL. # Therefore, if we needed to strip PATH_INFO, then we know that we have # to build the base URL ourselves: - our $path_info = $ENV{"PATH_INFO"}; + our $path_info = decode_utf8($ENV{"PATH_INFO"}); if ($path_info) { if ($my_url =~ s,\Q$path_info\E$,, && $my_uri =~ s,\Q$path_info\E$,, && @@@ -759,7 -759,6 +759,7 @@@ our @cgi_param_mapping = extra_options => "opt", search_use_regexp => "sr", ctag => "by_tag", + diff_style => "ds", # this must be last entry (for manipulation from JavaScript) javascript => "js" ); @@@ -816,9 -815,9 +816,9 @@@ sub evaluate_query_params while (my ($name, $symbol) = each %cgi_param_mapping) { if ($symbol eq 'opt') { - $input_params{$name} = [ $cgi->param($symbol) ]; + $input_params{$name} = [ map { decode_utf8($_) } $cgi->param($symbol) ]; } else { - $input_params{$name} = $cgi->param($symbol); + $input_params{$name} = decode_utf8($cgi->param($symbol)); } } } @@@ -1073,16 -1072,7 +1073,16 @@@ sub evaluate_and_validate_params if (length($searchtext) < 2) { die_error(403, "At least two characters are required for search parameter"); } - $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext; + if ($search_use_regexp) { + $search_regexp = $searchtext; + if (!eval { qr/$search_regexp/; 1; }) { + (my $error = $@) =~ s/ at \S+ line \d+.*\n?//; + die_error(400, "Invalid search regexp '$search_regexp'", + esc_html($error)); + } + } else { + $search_regexp = quotemeta $searchtext; + } } } @@@ -1132,8 -1122,10 +1132,10 @@@ sub dispatch if (!defined $action) { if (defined $hash) { $action = git_get_type($hash); + $action or die_error(404, "Object does not exist"); } elsif (defined $hash_base && defined $file_name) { $action = git_get_type("$hash_base:$file_name"); + $action or die_error(404, "File or directory does not exist"); } elsif (defined $project) { $action = 'summary'; } else { @@@ -2236,119 -2228,93 +2238,119 @@@ sub format_diff_cc_simplified return $result; } -# format patch (diff) line (not to be used for diff headers) -sub format_diff_line { - my $line = shift; - my ($from, $to) = @_; - my $diff_class = ""; - - chomp $line; +sub diff_line_class { + my ($line, $from, $to) = @_; + # ordinary diff + my $num_sign = 1; + # combined diff 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"; - } + $num_sign = scalar @{$from->{'href'}}; + } + + my @diff_line_classifier = ( + { regexp => qr/^\@\@{$num_sign} /, class => "chunk_header"}, + { regexp => qr/^\\/, class => "incomplete" }, + { regexp => qr/^ {$num_sign}/, class => "ctx" }, + # classifier for context must come before classifier add/rem, + # or we would have to use more complicated regexp, for example + # qr/(?= {0,$m}\+)[+ ]{$num_sign}/, where $m = $num_sign - 1; + { regexp => qr/^[+ ]{$num_sign}/, class => "add" }, + { regexp => qr/^[- ]{$num_sign}/, class => "rem" }, + ); + for my $clsfy (@diff_line_classifier) { + return $clsfy->{'class'} + if ($line =~ $clsfy->{'regexp'}); } - $line = untabify($line); - if ($from && $to && $line =~ m/^\@{2} /) { - my ($from_text, $from_start, $from_lines, $to_text, $to_start, $to_lines, $section) = - $line =~ m/^\@{2} (-(\d+)(?:,(\d+))?) (\+(\d+)(?:,(\d+))?) \@{2}(.*)$/; - $from_lines = 0 unless defined $from_lines; - $to_lines = 0 unless defined $to_lines; + # fallback + return ""; +} - if ($from->{'href'}) { - $from_text = $cgi->a({-href=>"$from->{'href'}#l$from_start", - -class=>"list"}, $from_text); - } - if ($to->{'href'}) { - $to_text = $cgi->a({-href=>"$to->{'href'}#l$to_start", - -class=>"list"}, $to_text); - } - $line = "@@ $from_text $to_text @@" . - "" . esc_html($section, -nbsp=>1) . ""; - return "
$line
\n"; - } elsif ($from && $to && $line =~ m/^\@{3}/) { - my ($prefix, $ranges, $section) = $line =~ m/^(\@+) (.*?) \@+(.*)$/; - my (@from_text, @from_start, @from_nlines, $to_text, $to_start, $to_nlines); +# assumes that $from and $to are defined and correctly filled, +# and that $line holds a line of chunk header for unified diff +sub format_unidiff_chunk_header { + my ($line, $from, $to) = @_; - @from_text = split(' ', $ranges); - for (my $i = 0; $i < @from_text; ++$i) { - ($from_start[$i], $from_nlines[$i]) = - (split(',', substr($from_text[$i], 1)), 0); - } + my ($from_text, $from_start, $from_lines, $to_text, $to_start, $to_lines, $section) = + $line =~ m/^\@{2} (-(\d+)(?:,(\d+))?) (\+(\d+)(?:,(\d+))?) \@{2}(.*)$/; - $to_text = pop @from_text; - $to_start = pop @from_start; - $to_nlines = pop @from_nlines; + $from_lines = 0 unless defined $from_lines; + $to_lines = 0 unless defined $to_lines; - $line = "$prefix "; - for (my $i = 0; $i < @from_text; ++$i) { - if ($from->{'href'}[$i]) { - $line .= $cgi->a({-href=>"$from->{'href'}[$i]#l$from_start[$i]", - -class=>"list"}, $from_text[$i]); - } else { - $line .= $from_text[$i]; - } - $line .= " "; - } - if ($to->{'href'}) { - $line .= $cgi->a({-href=>"$to->{'href'}#l$to_start", - -class=>"list"}, $to_text); + if ($from->{'href'}) { + $from_text = $cgi->a({-href=>"$from->{'href'}#l$from_start", + -class=>"list"}, $from_text); + } + if ($to->{'href'}) { + $to_text = $cgi->a({-href=>"$to->{'href'}#l$to_start", + -class=>"list"}, $to_text); + } + $line = "@@ $from_text $to_text @@" . + "" . esc_html($section, -nbsp=>1) . ""; + return $line; +} + +# assumes that $from and $to are defined and correctly filled, +# and that $line holds a line of chunk header for combined diff +sub format_cc_diff_chunk_header { + my ($line, $from, $to) = @_; + + my ($prefix, $ranges, $section) = $line =~ m/^(\@+) (.*?) \@+(.*)$/; + my (@from_text, @from_start, @from_nlines, $to_text, $to_start, $to_nlines); + + @from_text = split(' ', $ranges); + for (my $i = 0; $i < @from_text; ++$i) { + ($from_start[$i], $from_nlines[$i]) = + (split(',', substr($from_text[$i], 1)), 0); + } + + $to_text = pop @from_text; + $to_start = pop @from_start; + $to_nlines = pop @from_nlines; + + $line = "$prefix "; + for (my $i = 0; $i < @from_text; ++$i) { + if ($from->{'href'}[$i]) { + $line .= $cgi->a({-href=>"$from->{'href'}[$i]#l$from_start[$i]", + -class=>"list"}, $from_text[$i]); } else { - $line .= $to_text; + $line .= $from_text[$i]; } - $line .= " $prefix" . - "" . esc_html($section, -nbsp=>1) . ""; - return "
$line
\n"; + $line .= " "; + } + if ($to->{'href'}) { + $line .= $cgi->a({-href=>"$to->{'href'}#l$to_start", + -class=>"list"}, $to_text); + } else { + $line .= $to_text; + } + $line .= " $prefix
" . + "" . esc_html($section, -nbsp=>1) . ""; + return $line; +} + +# process patch (diff) line (not to be used for diff headers), +# returning class and HTML-formatted (but not wrapped) line +sub process_diff_line { + my $line = shift; + my ($from, $to) = @_; + + my $diff_class = diff_line_class($line, $from, $to); + + chomp $line; + $line = untabify($line); + + if ($from && $to && $line =~ m/^\@{2} /) { + $line = format_unidiff_chunk_header($line, $from, $to); + return $diff_class, $line; + + } elsif ($from && $to && $line =~ m/^\@{3}/) { + $line = format_cc_diff_chunk_header($line, $from, $to); + return $diff_class, $line; + } - return "
" . esc_html($line, -nbsp=>1) . "
\n"; + return $diff_class, esc_html($line, -nbsp=>1); } # Generates undef or something like "_snapshot_" or "snapshot (_tbz2_ _zip_)", @@@ -2400,7 -2366,7 +2402,7 @@@ sub get_feed_info return unless (defined $project); # some views should link to OPML, or to generic project feed, # or don't have specific feed yet (so they should use generic) - return if ($action =~ /^(?:tags|heads|forks|tag|search)$/x); + return if (!$action || $action =~ /^(?:tags|heads|forks|tag|search)$/x); my $branch; # branches refs uses 'refs/heads/' prefix (fullname) to differentiate @@@ -2774,7 -2740,7 +2776,7 @@@ sub git_populate_project_tagcloud } my $cloud; - my $matched = $cgi->param('by_tag'); + my $matched = $input_params{'ctag'}; if (eval { require HTML::TagCloud; 1; }) { $cloud = HTML::TagCloud->new; foreach my $ctag (sort keys %ctags_lc) { @@@ -2845,8 -2811,8 +2847,8 @@@ sub git_get_projects_list my $dir = $projects_list; # remove the trailing "/" $dir =~ s!/+$!!; - my $pfxlen = length("$projects_list"); - my $pfxdepth = ($projects_list =~ tr!/!!); + my $pfxlen = length("$dir"); + my $pfxdepth = ($dir =~ tr!/!!); # when filtering, search only given subdirectory if ($filter) { $dir .= "/$filter"; @@@ -2978,10 -2944,10 +2980,10 @@@ sub filter_forks_from_projects_list sub search_projects_list { my ($projlist, %opts) = @_; my $tagfilter = $opts{'tagfilter'}; - my $searchtext = $opts{'searchtext'}; + my $search_re = $opts{'search_regexp'}; return @$projlist - unless ($tagfilter || $searchtext); + unless ($tagfilter || $search_re); my @projects; PROJECT: @@@ -2993,10 -2959,10 +2995,10 @@@ grep { lc($_) eq lc($tagfilter) } keys %{$pr->{'ctags'}}; } - if ($searchtext) { + if ($search_re) { next unless - $pr->{'path'} =~ /$searchtext/ || - $pr->{'descr_long'} =~ /$searchtext/; + $pr->{'path'} =~ /$search_re/ || + $pr->{'descr_long'} =~ /$search_re/; } push @projects, $pr; @@@ -3880,7 -3846,7 +3882,7 @@@ sub print_search_form -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) . $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . " search:\n", - $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . + $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" . "" . $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', -checked => $search_use_regexp) . @@@ -4870,97 -4836,8 +4872,97 @@@ sub git_difftree_body print "\n"; } +sub print_sidebyside_diff_chunk { + my @chunk = @_; + my (@ctx, @rem, @add); + + return unless @chunk; + + # incomplete last line might be among removed or added lines, + # or both, or among context lines: find which + for (my $i = 1; $i < @chunk; $i++) { + if ($chunk[$i][0] eq 'incomplete') { + $chunk[$i][0] = $chunk[$i-1][0]; + } + } + + # guardian + push @chunk, ["", ""]; + + foreach my $line_info (@chunk) { + my ($class, $line) = @$line_info; + + # print chunk headers + if ($class && $class eq 'chunk_header') { + print $line; + next; + } + + ## print from accumulator when type of class of lines change + # empty contents block on start rem/add block, or end of chunk + if (@ctx && (!$class || $class eq 'rem' || $class eq 'add')) { + print join '', + '
', + '
', + @ctx, + '
', + '
', + @ctx, + '
', + '
'; + @ctx = (); + } + # empty add/rem block on start context block, or end of chunk + if ((@rem || @add) && (!$class || $class eq 'ctx')) { + if (!@add) { + # pure removal + print join '', + '
', + '
', + @rem, + '
', + '
'; + } elsif (!@rem) { + # pure addition + print join '', + '
', + '
', + @add, + '
', + '
'; + } else { + # assume that it is change + print join '', + '
', + '
', + @rem, + '
', + '
', + @add, + '
', + '
'; + } + @rem = @add = (); + } + + ## adding lines to accumulator + # guardian value + last unless $line; + # rem, add or change + if ($class eq 'rem') { + push @rem, $line; + } elsif ($class eq 'add') { + push @add, $line; + } + # context line + if ($class eq 'ctx') { + push @ctx, $line; + } + } +} + sub git_patchset_body { - my ($fd, $difftree, $hash, @hash_parents) = @_; + my ($fd, $diff_style, $difftree, $hash, @hash_parents) = @_; my ($hash_parent) = $hash_parents[0]; my $is_combined = (@hash_parents > 1); @@@ -4970,7 -4847,6 +4972,7 @@@ my $diffinfo; my $to_name; my (%from, %to); + my @chunk; # for side-by-side diff print "
\n"; @@@ -5077,29 -4953,10 +5079,29 @@@ next PATCH if ($patch_line =~ m/^diff /); - print format_diff_line($patch_line, \%from, \%to); + my ($class, $line) = process_diff_line($patch_line, \%from, \%to); + my $diff_classes = "diff"; + $diff_classes .= " $class" if ($class); + $line = "
$line
\n"; + + if ($diff_style eq 'sidebyside' && !$is_combined) { + if ($class eq 'chunk_header') { + print_sidebyside_diff_chunk(@chunk); + @chunk = ( [ $class, $line ] ); + } else { + push @chunk, [ $class, $line ]; + } + } else { + # default 'inline' style and unknown styles + print $line; + } } } continue { + if (@chunk) { + print_sidebyside_diff_chunk(@chunk); + @chunk = (); + } print "
\n"; # class="patch" } @@@ -5289,9 -5146,9 +5291,9 @@@ sub git_project_list_body my $check_forks = gitweb_check_feature('forks'); my $show_ctags = gitweb_check_feature('ctags'); - my $tagfilter = $show_ctags ? $cgi->param('by_tag') : undef; + my $tagfilter = $show_ctags ? $input_params{'ctag'} : undef; $check_forks = undef - if ($tagfilter || $searchtext); + if ($tagfilter || $search_regexp); # filtering out forks before filling info allows to do less work @projects = filter_forks_from_projects_list(\@projects) @@@ -5299,9 -5156,9 +5301,9 @@@ @projects = fill_project_list_info(\@projects); # searching projects require filling to be run before it @projects = search_projects_list(\@projects, - 'searchtext' => $searchtext, + 'search_regexp' => $search_regexp, 'tagfilter' => $tagfilter) - if ($tagfilter || $searchtext); + if ($tagfilter || $search_regexp); $order ||= $default_projects_order; $from = 0 unless defined $from; @@@ -5577,7 -5434,7 +5579,7 @@@ sub git_tags_body sub git_heads_body { # uses global variable $project - my ($headlist, $head, $from, $to, $extra) = @_; + my ($headlist, $head_at, $from, $to, $extra) = @_; $from = 0 unless defined $from; $to = $#{$headlist} if (!defined $to || $#{$headlist} < $to); @@@ -5586,7 -5443,7 +5588,7 @@@ for (my $i = $from; $i <= $to; $i++) { my $entry = $headlist->[$i]; my %ref = %$entry; - my $curr = $ref{'id'} eq $head; + my $curr = defined $head_at && $ref{'id'} eq $head_at; if ($alternate) { print "\n"; } else { @@@ -5845,7 -5702,7 +5847,7 @@@ sub git_search_files my %co = @_; local $/ = "\n"; - open my $fd, "-|", git_cmd(), 'grep', '-n', + open my $fd, "-|", git_cmd(), 'grep', '-n', '-z', $search_use_regexp ? ('-E', '-i') : '-F', $searchtext, $co{'tree'} or die_error(500, "Open git-grep failed"); @@@ -5859,7 -5716,6 +5861,7 @@@ my $alternate = 1; my $matches = 0; my $lastfile = ''; + my $file_href; while (my $line = <$fd>) { chomp $line; my ($file, $lno, $ltext, $binary); @@@ -5868,8 -5724,7 +5870,8 @@@ $file = $1; $binary = 1; } else { - (undef, $file, $lno, $ltext) = split(/:/, $line, 4); + ($file, $lno, $ltext) = split(/\0/, $line, 3); + $file =~ s/^$co{'tree'}://; } if ($file ne $lastfile) { $lastfile and print "\n"; @@@ -5878,10 -5733,10 +5880,10 @@@ } else { print "\n"; } + $file_href = href(action=>"blob", hash_base=>$co{'id'}, + file_name=>$file); print "". - $cgi->a({-href => href(action=>"blob", hash=>$co{'hash'}, - file_name=>"$file"), - -class => "list"}, esc_path($file)); + $cgi->a({-href => $file_href, -class => "list"}, esc_path($file)); print "\n"; $lastfile = $file; } @@@ -5899,9 -5754,10 +5901,9 @@@ $ltext = esc_html($ltext, -nbsp=>1); } print "
" . - $cgi->a({-href => href(action=>"blob", hash=>$co{'hash'}, - file_name=>"$file").'#l'.$lno, - -class => "linenr"}, sprintf('%4i', $lno)) - . ' ' . $ltext . "
\n"; + $cgi->a({-href => $file_href.'#l'.$lno, + -class => "linenr"}, sprintf('%4i', $lno)) . + ' ' . $ltext . "\n"; } } if ($lastfile) { @@@ -6002,7 -5858,7 +6004,7 @@@ sub git_project_list } print $cgi->startform(-method => "get") . "

Search:\n" . - $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . + $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" . "

" . $cgi->end_form() . "\n"; git_project_list_body(\@list, $order); @@@ -6205,7 -6061,7 +6207,7 @@@ sub git_tag sub git_blame_common { my $format = shift || 'porcelain'; - if ($format eq 'porcelain' && $cgi->param('js')) { + if ($format eq 'porcelain' && $input_params{'javascript'}) { $format = 'incremental'; $action = 'blame_incremental'; # for page title etc } @@@ -7098,7 -6954,6 +7100,7 @@@ sub git_object sub git_blobdiff { my $format = shift || 'html'; + my $diff_style = $input_params{'diff_style'} || 'inline'; my $fd; my @difftree; @@@ -7177,7 -7032,6 +7179,7 @@@ my $formats_nav = $cgi->a({-href => href(action=>"blobdiff_plain", -replay=>1)}, "raw"); + $formats_nav .= diff_style_nav($diff_style); 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); @@@ -7209,8 -7063,7 +7211,8 @@@ if ($format eq 'html') { print "
\n"; - git_patchset_body($fd, [ \%diffinfo ], $hash_base, $hash_parent_base); + git_patchset_body($fd, $diff_style, + [ \%diffinfo ], $hash_base, $hash_parent_base); close $fd; print "
\n"; # class="page_body" @@@ -7235,31 -7088,9 +7237,31 @@@ sub git_blobdiff_plain git_blobdiff('plain'); } +# assumes that it is added as later part of already existing navigation, +# so it returns "| foo | bar" rather than just "foo | bar" +sub diff_style_nav { + my ($diff_style, $is_combined) = @_; + $diff_style ||= 'inline'; + + return "" if ($is_combined); + + my @styles = (inline => 'inline', 'sidebyside' => 'side by side'); + my %styles = @styles; + @styles = + @styles[ map { $_ * 2 } 0..$#styles/2 ]; + + return join '', + map { " | ".$_ } + map { + $_ eq $diff_style ? $styles{$_} : + $cgi->a({-href => href(-replay=>1, diff_style => $_)}, $styles{$_}) + } @styles; +} + sub git_commitdiff { my %params = @_; my $format = $params{-format} || 'html'; + my $diff_style = $input_params{'diff_style'} || 'inline'; my ($patch_max) = gitweb_get_feature('patches'); if ($format eq 'patch') { @@@ -7285,7 -7116,6 +7287,7 @@@ $cgi->a({-href => href(action=>"patch", -replay=>1)}, "patch"); } + $formats_nav .= diff_style_nav($diff_style, @{$co{'parents'}} > 1); if (defined $hash_parent && $hash_parent ne '-c' && $hash_parent ne '--cc') { @@@ -7303,8 -7133,8 +7305,8 @@@ } } $formats_nav .= ': ' . - $cgi->a({-href => href(action=>"commitdiff", - hash=>$hash_parent)}, + $cgi->a({-href => href(-replay=>1, + hash=>$hash_parent, hash_base=>undef)}, esc_html($hash_parent_short)) . ')'; } elsif (!$co{'parent'}) { @@@ -7314,28 -7144,28 +7316,28 @@@ # single parent commit $formats_nav .= ' (parent: ' . - $cgi->a({-href => href(action=>"commitdiff", - hash=>$co{'parent'})}, + $cgi->a({-href => href(-replay=>1, + hash=>$co{'parent'}, hash_base=>undef)}, esc_html(substr($co{'parent'}, 0, 7))) . ')'; } else { # merge commit if ($hash_parent eq '--cc') { $formats_nav .= ' | ' . - $cgi->a({-href => href(action=>"commitdiff", + $cgi->a({-href => href(-replay=>1, hash=>$hash, hash_parent=>'-c')}, 'combined'); } else { # $hash_parent eq '-c' $formats_nav .= ' | ' . - $cgi->a({-href => href(action=>"commitdiff", + $cgi->a({-href => href(-replay=>1, hash=>$hash, hash_parent=>'--cc')}, 'compact'); } $formats_nav .= ' (merge: ' . join(' ', map { - $cgi->a({-href => href(action=>"commitdiff", - hash=>$_)}, + $cgi->a({-href => href(-replay=>1, + hash=>$_, hash_base=>undef)}, esc_html(substr($_, 0, 7))); } @{$co{'parents'}} ) . ')'; @@@ -7464,8 -7294,7 +7466,8 @@@ $use_parents ? @{$co{'parents'}} : $hash_parent); print "
\n"; - git_patchset_body($fd, \@difftree, $hash, + git_patchset_body($fd, $diff_style, + \@difftree, $hash, $use_parents ? @{$co{'parents'}} : $hash_parent); close $fd; print "\n"; # class="page_body" diff --combined t/Makefile index 52a23fffc4,66ceefefcc..b5048ab77b --- a/t/Makefile +++ b/t/Makefile @@@ -17,9 -17,9 +17,9 @@@ DEFAULT_TEST_TARGET ?= tes # Shell quote; SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) - T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) - TSVN = $(wildcard t91[0-9][0-9]-*.sh) - TGITWEB = $(wildcard t95[0-9][0-9]-*.sh) + T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) + TSVN = $(sort $(wildcard t91[0-9][0-9]-*.sh)) + TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh)) all: $(DEFAULT_TEST_TARGET) @@@ -73,4 -73,42 +73,4 @@@ gitweb-test valgrind: $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind" -# Smoke testing targets --include ../GIT-VERSION-FILE -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo unknown') -uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo unknown') - -test-results: - mkdir -p test-results - -test-results/git-smoke.tar.gz: test-results - $(PERL_PATH) ./harness \ - --archive="test-results/git-smoke.tar.gz" \ - $(T) - -smoke: test-results/git-smoke.tar.gz - -SMOKE_UPLOAD_FLAGS = -ifdef SMOKE_USERNAME - SMOKE_UPLOAD_FLAGS += -F username="$(SMOKE_USERNAME)" -F password="$(SMOKE_PASSWORD)" -endif -ifdef SMOKE_COMMENT - SMOKE_UPLOAD_FLAGS += -F comments="$(SMOKE_COMMENT)" -endif -ifdef SMOKE_TAGS - SMOKE_UPLOAD_FLAGS += -F tags="$(SMOKE_TAGS)" -endif - -smoke_report: smoke - curl \ - -H "Expect: " \ - -F project=Git \ - -F architecture="$(uname_M)" \ - -F platform="$(uname_S)" \ - -F revision="$(GIT_VERSION)" \ - -F report_file=@test-results/git-smoke.tar.gz \ - $(SMOKE_UPLOAD_FLAGS) \ - http://smoke.git.nix.is/app/projects/process_add_report/1 \ - | grep -v ^Redirecting - -.PHONY: pre-clean $(T) aggregate-results clean valgrind smoke smoke_report +.PHONY: pre-clean $(T) aggregate-results clean valgrind diff --combined t/t9500-gitweb-standalone-no-errors.sh index 858a649cb6,94365bb006..90bb6050c1 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@@ -273,53 -273,6 +273,53 @@@ test_expect_success 'commitdiff(2): directory becomes symlink' \ 'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=foo-symlinked-to-bar"' +# ---------------------------------------------------------------------- +# commitdiff testing (incomplete lines) + +test_expect_success 'setup incomplete lines' ' + cat >file<<-\EOF && + Dominus regit me, + et nihil mihi deerit. + In loco pascuae ibi me collocavit, + super aquam refectionis educavit me; + animam meam convertit, + deduxit me super semitas jusitiae, + propter nomen suum. + CHANGE_ME + EOF + git commit -a -m "Preparing for incomplete lines" && + echo "incomplete" | tr -d "\\012" >>file && + git commit -a -m "Add incomplete line" && + git tag incomplete_lines_add && + sed -e s/CHANGE_ME/change_me/ file+ && + mv -f file+ file && + git commit -a -m "Incomplete context line" && + git tag incomplete_lines_ctx && + echo "Dominus regit me," >file && + echo "incomplete line" | tr -d "\\012" >>file && + git commit -a -m "Change incomplete line" && + git tag incomplete_lines_chg + echo "Dominus regit me," >file && + git commit -a -m "Remove incomplete line" && + git tag incomplete_lines_rem +' + +test_expect_success 'commitdiff(1): addition of incomplete line' ' + gitweb_run "p=.git;a=commitdiff;h=incomplete_lines_add" +' + +test_expect_success 'commitdiff(1): incomplete line as context line' ' + gitweb_run "p=.git;a=commitdiff;h=incomplete_lines_ctx" +' + +test_expect_success 'commitdiff(1): change incomplete line' ' + gitweb_run "p=.git;a=commitdiff;h=incomplete_lines_chg" +' + +test_expect_success 'commitdiff(1): removal of incomplete line' ' + gitweb_run "p=.git;a=commitdiff;h=incomplete_lines_rem" +' + # ---------------------------------------------------------------------- # commit, commitdiff: merge, large test_expect_success \ @@@ -329,8 -282,7 +329,8 @@@ git add b && git commit -a -m "On branch" && git checkout master && - git pull . b' + git pull . b && + git tag merge_commit' test_expect_success \ 'commit(0): merge commit' \ @@@ -379,29 -331,6 +379,29 @@@ test_expect_success 'commitdiff(1): large commit' \ 'gitweb_run "p=.git;a=commitdiff;h=b"' +# ---------------------------------------------------------------------- +# side-by-side diff + +test_expect_success 'side-by-side: addition of incomplete line' ' + gitweb_run "p=.git;a=commitdiff;h=incomplete_lines_add;ds=sidebyside" +' + +test_expect_success 'side-by-side: incomplete line as context line' ' + gitweb_run "p=.git;a=commitdiff;h=incomplete_lines_ctx;ds=sidebyside" +' + +test_expect_success 'side-by-side: changed incomplete line' ' + gitweb_run "p=.git;a=commitdiff;h=incomplete_lines_chg;ds=sidebyside" +' + +test_expect_success 'side-by-side: removal of incomplete line' ' + gitweb_run "p=.git;a=commitdiff;h=incomplete_lines_rem;ds=sidebyside" +' + +test_expect_success 'side-by-side: merge commit' ' + gitweb_run "p=.git;a=commitdiff;h=merge_commit;ds=sidebyside" +' + # ---------------------------------------------------------------------- # tags testing @@@ -474,6 -403,14 +474,14 @@@ test_expect_success 'path_info: project/branch:dir/' \ 'gitweb_run "" "/.git/master:foo/"' + test_expect_success \ + 'path_info: project/branch (non-existent)' \ + 'gitweb_run "" "/.git/non-existent"' + + test_expect_success \ + 'path_info: project/branch:filename (non-existent branch)' \ + 'gitweb_run "" "/.git/non-existent:non-existent"' + test_expect_success \ 'path_info: project/branch:file (non-existent)' \ 'gitweb_run "" "/.git/master:non-existent"' @@@ -629,45 -566,6 +637,45 @@@ test_expect_success 'config override: tree view, features enabled in repo config (2)' \ 'gitweb_run "p=.git;a=tree"' +# ---------------------------------------------------------------------- +# searching + +cat >>gitweb_config.perl <<\EOF + +# enable search +$feature{'search'}{'default'} = [1]; +$feature{'grep'}{'default'} = [1]; +$feature{'pickaxe'}{'default'} = [1]; +EOF + +test_expect_success \ + 'search: preparation' \ + 'echo "1st MATCH" >>file && + echo "2nd MATCH" >>file && + echo "MATCH" >>bar && + git add file bar && + git commit -m "Added MATCH word"' + +test_expect_success \ + 'search: commit author' \ + 'gitweb_run "p=.git;a=search;h=HEAD;st=author;s=A+U+Thor"' + +test_expect_success \ + 'search: commit message' \ + 'gitweb_run "p=.git;a=search;h=HEAD;st=commitr;s=MATCH"' + +test_expect_success \ + 'search: grep' \ + 'gitweb_run "p=.git;a=search;h=HEAD;st=grep;s=MATCH"' + +test_expect_success \ + 'search: pickaxe' \ + 'gitweb_run "p=.git;a=search;h=HEAD;st=pickaxe;s=MATCH"' + +test_expect_success \ + 'search: projects' \ + 'gitweb_run "a=project_list;s=.git"' + # ---------------------------------------------------------------------- # non-ASCII in README.html @@@ -770,13 -668,4 +778,13 @@@ test_expect_success 'echo "\$projects_list_group_categories = 1;" >>gitweb_config.perl && gitweb_run' +# ---------------------------------------------------------------------- +# unborn branches + +test_expect_success \ + 'unborn HEAD: "summary" page (with "heads" subview)' \ + 'git checkout orphan_branch || git checkout --orphan orphan_branch && + test_when_finished "git checkout master" && + gitweb_run "p=.git;a=summary"' + test_done