From 4de741b3e1be564233f0de2c6915a859264fe9b0 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Mon, 25 Sep 2006 22:38:16 -0700 Subject: [PATCH 01/19] gitweb: tree view: eliminate redundant "blob" Binary and non-binary blobs: The "list" table element of tree view is identical to the "blob" link part of the link table element. I.e. clicking on "blob" is identical to clicking on the entry itself. Thus, eliminate "blob" from being shown -- the user can get identical result by simply clicking on the entry itself. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 66be619332..c7ab3b64ca 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1600,34 +1600,35 @@ sub git_print_tree_entry { my %base_key = (); $base_key{hash_base} = $hash_base if defined $hash_base; + # The format of a table row is: mode list link. Where mode is + # the mode of the entry, list is the name of the entry, an href, + # and link is the action links of the entry. + print "" . mode_str($t->{'mode'}) . "\n"; if ($t->{'type'} eq "blob") { print "" . - $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key), - -class => "list"}, esc_html($t->{'name'})) . - "\n" . - "" . - $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - "blob"); + $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key), + -class => "list"}, esc_html($t->{'name'})) . "\n"; + print ""; if ($have_blame) { - print " | " . - $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - "blame"); + print $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key)}, + "blame"); } if (defined $hash_base) { - print " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + if ($have_blame) { + print " | "; + } + print $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, "history"); } print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, - "raw") . - "\n"; + "raw"); + print "\n"; } elsif ($t->{'type'} eq "tree") { print "" . From 0fa105e7f140fc381ea3cbb776465aacefa22265 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Tue, 26 Sep 2006 12:45:37 -0700 Subject: [PATCH 02/19] gitweb: Remove redundant "tree" link In "tree" view, remove redundant "tree" link in the tree listing. It is identical to simply clicking on the tree entry itself. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c7ab3b64ca..fa8a65a808 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1631,18 +1631,14 @@ sub git_print_tree_entry { print "\n"; } elsif ($t->{'type'} eq "tree") { - print "" . - $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, + print ""; + print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}", %base_key)}, - esc_html($t->{'name'})) . - "\n" . - "" . - $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - "tree"); + esc_html($t->{'name'})); + print "\n"; + print ""; if (defined $hash_base) { - print " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + print $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, file_name=>"$basedir$t->{'name'}")}, "history"); } From 65910395c08e3dc4be685a9a9f60adfa61c89aa5 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Tue, 26 Sep 2006 16:45:31 -0700 Subject: [PATCH 03/19] gitweb: extend blame to show links to diff and previous git_blame2() now has two more columns, "Prev" and "Diff", before the "Commit" column, as follows: Prev Diff Commit Line Data SHA Diff SHA N ... ... The "Prev" column shows the SHA of the parent commit, between which this line changed. Clicking on it shows the blame of the file as of the parent commit, for that line. So clicking repeatedly on "Prev" would show you the blame of that file, from the point of view of the changes of that particular line whose "Prev" you're clicking on. The "Diff" column shows "Diff" which is a link to blobdiff between "Prev" and "Commit" commits _for that line_. So clicking on "Diff" would show you the blobdiff (HTML) between the parent commit and this commit which changed that particular line. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index fa8a65a808..e769c8ed6c 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2439,7 +2439,7 @@ sub git_blame2 { print < - + HTML while (<$fd>) { /^([0-9a-fA-F]{40}).*?(\d+)\)\s{1}(\s*.*)/; @@ -2447,6 +2447,8 @@ HTML my $rev = substr($full_rev, 0, 8); my $lineno = $2; my $data = $3; + my %pco = parse_commit($full_rev); + my $parent = $pco{'parent'}; if (!defined $last_rev) { $last_rev = $full_rev; @@ -2455,11 +2457,25 @@ HTML $current_color = ++$current_color % $num_colors; } print "\n"; + # Print the Prev link + print "\n"; + # Print the Diff (blobdiff) link + print "\n"; + # Print the Commit link print "\n"; + # Print the Line number print "\n"; + # Print the Data print "\n"; print "\n"; } From 4b02f48372c72b38d2be7484355222f987f3af97 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:54:24 +0200 Subject: [PATCH 04/19] gitweb: Strip trailing slashes from $path in git_get_hash_by_path It also removes unused local variable $tree 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 e769c8ed6c..4686d9376d 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -710,7 +710,7 @@ sub git_get_hash_by_path { my $path = shift || return undef; my $type = shift; - my $tree = $base; + $path =~ s,/+$,,; open my $fd, "-|", git_cmd(), "ls-tree", $base, "--", $path or die_error(undef, "Open git-ls-tree failed"); From dd1ad5f16708e49722ad455dea8076816054391d Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:56:17 +0200 Subject: [PATCH 05/19] gitweb: Use "return" instead of "return undef" for some subs Use "return" instead of "return undef" when subroutine can return, or always return, non-scalar (list) value. Other places are left as is. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 4686d9376d..eaa42b93cd 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -106,7 +106,7 @@ our %feature = ( sub gitweb_check_feature { my ($name) = @_; - return undef unless exists $feature{$name}; + return unless exists $feature{$name}; my ($sub, $override, @defaults) = ( $feature{$name}{'sub'}, $feature{$name}{'override'}, @@ -781,7 +781,7 @@ sub git_get_projects_list { # 'git%2Fgit.git Linus+Torvalds' # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin' # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman' - open my ($fd), $projects_list or return undef; + open my ($fd), $projects_list or return; while (my $line = <$fd>) { chomp $line; my ($path, $owner) = split ' ', $line; From 24d0693a68008baacd827b1345c957e871488596 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:57:02 +0200 Subject: [PATCH 06/19] gitweb: Split validate_input into validate_pathname and validate_refname Split validate_input subroutine into validate_pathname which is used for $project, $file_name and $file_parent parameters, and validate_refname which is used for $hash, $hash_base, $hash_parent and $hash_parent_base parameters. Reintroduce validation of $file_name and $file_parent parameters, removed in a2f3db2f validate_pathname in addition to what validate_input did checks also for doubled slashes and NUL character. It does not check if input is textual hash, and does not check if all characters are from the following set: [a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]. validate_refname first check if the input is textual hash, then checks if it is valid pathname, then checks for invalid characters (according to git-check-ref-format manpage). It does not check if all charactes are from the [a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%] set. We do not have to validate pathnames we got from git. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 65 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index eaa42b93cd..c51313581e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -200,9 +200,10 @@ if (defined $action) { } } +# parameters which are pathnames our $project = $cgi->param('p'); if (defined $project) { - if (!validate_input($project) || + if (!validate_pathname($project) || !(-d "$projectroot/$project") || !(-e "$projectroot/$project/HEAD") || ($export_ok && !(-e "$projectroot/$project/$export_ok")) || @@ -212,38 +213,50 @@ if (defined $project) { } } -# We have to handle those containing any characters: our $file_name = $cgi->param('f'); -our $file_parent = $cgi->param('fp'); +if (defined $file_name) { + if (!validate_pathname($file_name)) { + die_error(undef, "Invalid file parameter"); + } +} +our $file_parent = $cgi->param('fp'); +if (defined $file_parent) { + if (!validate_pathname($file_parent)) { + die_error(undef, "Invalid file parent parameter"); + } +} + +# parameters which are refnames our $hash = $cgi->param('h'); if (defined $hash) { - if (!validate_input($hash)) { + if (!validate_refname($hash)) { die_error(undef, "Invalid hash parameter"); } } our $hash_parent = $cgi->param('hp'); if (defined $hash_parent) { - if (!validate_input($hash_parent)) { + if (!validate_refname($hash_parent)) { die_error(undef, "Invalid hash parent parameter"); } } our $hash_base = $cgi->param('hb'); if (defined $hash_base) { - if (!validate_input($hash_base)) { + if (!validate_refname($hash_base)) { die_error(undef, "Invalid hash base parameter"); } } our $hash_parent_base = $cgi->param('hpb'); if (defined $hash_parent_base) { - if (!validate_input($hash_parent_base)) { + if (!validate_refname($hash_parent_base)) { die_error(undef, "Invalid hash parent base parameter"); } } +# other parameters our $page = $cgi->param('pg'); if (defined $page) { if ($page =~ m/[^0-9]/) { @@ -273,7 +286,7 @@ sub evaluate_path_info { $project =~ s,/*[^/]*$,,; } # validate project - $project = validate_input($project); + $project = validate_pathname($project); if (!$project || ($export_ok && !-e "$projectroot/$project/$export_ok") || ($strict_export && !project_in_list($project))) { @@ -294,12 +307,12 @@ sub evaluate_path_info { } else { $action ||= "blob_plain"; } - $hash_base ||= validate_input($refname); - $file_name ||= $pathname; + $hash_base ||= validate_refname($refname); + $file_name ||= validate_pathname($pathname); } elsif (defined $refname) { # we got "project.git/branch" $action ||= "shortlog"; - $hash ||= validate_input($refname); + $hash ||= validate_refname($refname); } } evaluate_path_info(); @@ -387,16 +400,34 @@ sub href(%) { ## ====================================================================== ## validation, quoting/unquoting and escaping -sub validate_input { - my $input = shift; +sub validate_pathname { + my $input = shift || return undef; + # no '.' or '..' as elements of path, i.e. no '.' nor '..' + # at the beginning, at the end, and between slashes. + # also this catches doubled slashes + if ($input =~ m!(^|/)(|\.|\.\.)(/|$)!) { + return undef; + } + # no null characters + if ($input =~ m!\0!) { + return undef; + } + return $input; +} + +sub validate_refname { + my $input = shift || return undef; + + # textual hashes are O.K. if ($input =~ m/^[0-9a-fA-F]{40}$/) { return $input; } - if ($input =~ m/(^|\/)(|\.|\.\.)($|\/)/) { - return undef; - } - if ($input =~ m/[^a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]/) { + # it must be correct pathname + $input = validate_pathname($input) + or return undef; + # restrictions on ref name according to git-check-ref-format + if ($input =~ m!(/\.|\.\.|[\000-\040\177 ~^:?*\[]|/$)!) { return undef; } return $input; From f93bff8d4531d19938a9afbdc28b8d8f4dc97b32 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:58:41 +0200 Subject: [PATCH 07/19] gitweb: Add git_url subroutine, and use it to quote full URLs Add git_url subroutine, which does what git_param did before commit a2f3db2f5de2a3667b0e038aa65e3e097e642e7d, and is used to quote full URLs, currently only $home_link. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c51313581e..093ee604f4 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -443,6 +443,15 @@ sub esc_param { return $str; } +# quote unsafe chars in whole URL, so some charactrs cannot be quoted +sub esc_url { + my $str = shift; + $str =~ s/([^A-Za-z0-9\-_.~();\/;?:@&=])/sprintf("%%%02X", ord($1))/eg; + $str =~ s/\+/%2B/g; + $str =~ s/ /\+/g; + return $str; +} + # replace invalid utf8 character with SUBSTITUTION sequence sub esc_html { my $str = shift; @@ -1359,7 +1368,7 @@ EOF "" . "\"git\"" . "\n"; - print $cgi->a({-href => esc_param($home_link)}, $home_link_str) . " / "; + print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / "; if (defined $project) { print $cgi->a({-href => href(action=>"summary")}, esc_html($project)); if (defined $action) { From ab41dfbfd4f3f9fedac71550027e9813b11abe3d Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:59:43 +0200 Subject: [PATCH 08/19] gitweb: Quote filename in HTTP Content-Disposition: header Finish work started by commit a2f3db2 (although not documented in commit message) of quoting using quotemeta the filename in HTTP -content_disposition header. Just in case filename contains end of line character. Also use consistent coding style to compute -content_disposition parameter. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 093ee604f4..9349fa1cb3 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2320,7 +2320,7 @@ sub git_project_index { print $cgi->header( -type => 'text/plain', -charset => 'utf-8', - -content_disposition => qq(inline; filename="index.aux")); + -content_disposition => 'inline; filename="index.aux"'); foreach my $pr (@projects) { if (!exists $pr->{'owner'}) { @@ -2682,7 +2682,7 @@ sub git_blob_plain { print $cgi->header( -type => "$type", -expires=>$expires, - -content_disposition => "inline; filename=\"$save_as\""); + -content_disposition => 'inline; filename="' . quotemeta($save_as) . '"'); undef $/; binmode STDOUT, ':raw'; print <$fd>; @@ -2856,10 +2856,11 @@ 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'); + print $cgi->header( + -type => 'application/x-tar', + -content_encoding => $ctype, + -content_disposition => 'inline; filename="' . quotemeta($filename) . '"', + -status => '200 OK'); my $git_command = git_cmd_str(); open my $fd, "-|", "$git_command tar-tree $hash \'$project\' | $command" or @@ -3169,7 +3170,7 @@ sub git_blobdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => qq(inline; filename=") . quotemeta($file_name) . qq(.patch")); + -content_disposition => 'inline; filename="' . quotemeta($file_name) . '.patch"'); print "X-Git-Url: " . $cgi->self_url() . "\n\n"; @@ -3272,7 +3273,7 @@ sub git_commitdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => qq(inline; filename="$filename")); + -content_disposition => 'inline; filename="' . quotemeta($filename) . '"'); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); print < Date: Wed, 27 Sep 2006 17:22:03 -0700 Subject: [PATCH 09/19] Revert "gitweb: extend blame to show links to diff and previous" This concept is very fine, but it makes blame slow across renames and across branches, so revert it. There is a better way to do this. This reverts commit 03d06a8e26f4fbd37800d1e1125c6ecf4c104466. Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9349fa1cb3..0a627846b9 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2479,7 +2479,7 @@ sub git_blame2 { print <
CommitLineData
PrevDiffCommitLineData
"; + print $cgi->a({-href => href(action=>"blame", hash_base=>$parent, file_name=>$file_name)}, + esc_html(substr($parent, 0, 8))); + print ""; + print $cgi->a({-href => href(action=>"blobdiff", file_name=>$file_name, hash_parent_base=>$parent, + hash_base=>$full_rev)}, + esc_html("Diff")); + print "" . $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)}, esc_html($rev)) . "" . esc_html($lineno) . "" . esc_html($data) . "
- + HTML while (<$fd>) { /^([0-9a-fA-F]{40}).*?(\d+)\)\s{1}(\s*.*)/; @@ -2487,8 +2487,6 @@ HTML my $rev = substr($full_rev, 0, 8); my $lineno = $2; my $data = $3; - my %pco = parse_commit($full_rev); - my $parent = $pco{'parent'}; if (!defined $last_rev) { $last_rev = $full_rev; @@ -2497,25 +2495,11 @@ HTML $current_color = ++$current_color % $num_colors; } print "\n"; - # Print the Prev link - print "\n"; - # Print the Diff (blobdiff) link - print "\n"; - # Print the Commit link print "\n"; - # Print the Line number print "\n"; - # Print the Data print "\n"; print "\n"; } From 499faeda1bd131f7c3b216c16eebbe30049728d3 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Wed, 27 Sep 2006 17:23:25 -0700 Subject: [PATCH 10/19] gitweb: Remove excessively redundant entries from git_difftree_body 1) All entries on the left are blobs and clicking on them leads to blobs. No more diff or blob depending on what happened (modified or mode changed) to the file -- this goes to the right, in the "link" column. 2) Remove redundant "blob" from the link column on the right. This can now be had by clicking on the entry itself. This reduces and simplifies the code. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 92 +++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 58 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0a627846b9..88a8bcdbff 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1732,47 +1732,39 @@ sub git_difftree_body { my $mode_chng = "[new $to_file_type"; $mode_chng .= " with mode: $to_mode_str" if $to_mode_str; $mode_chng .= "]"; - print "\n" . - "\n" . - "\n"; + print "\n"; + print "\n"; } elsif ($diff{'status'} eq "D") { # deleted my $mode_chng = "[deleted $from_file_type]"; - print "\n" . - "\n" . - "\n"; + print "\n"; + print "\n"; + "history"); + print "\n"; } elsif ($diff{'status'} eq "M" || $diff{'status'} eq "T") { # modified, or type changed my $mode_chnge = ""; @@ -1791,42 +1783,29 @@ sub git_difftree_body { $mode_chnge .= "]\n"; } print "\n" . - "\n" . - "\n"; + print "\n"; + print "\n"; } elsif ($diff{'status'} eq "R" || $diff{'status'} eq "C") { # renamed or copied @@ -1846,10 +1825,7 @@ sub git_difftree_body { hash=>$diff{'from_id'}, file_name=>$diff{'from_file'}), -class => "list"}, esc_html($diff{'from_file'})) . " with " . (int $diff{'similarity'}) . "% similarity$mode_chng]\n" . - "\n"; } elsif ($diff{'status'} eq "M" || $diff{'status'} eq "T") { # modified, or type changed @@ -1803,8 +1806,11 @@ sub git_difftree_body { } print " | "; } - print $cgi->a({-href => href(action=>"history", - hash_base=>$hash, file_name=>$diff{'file'})}, + print $cgi->a({-href => href(action=>"blame", hash_base=>$hash, + file_name=>$diff{'file'})}, + "blame") . " | "; + print $cgi->a({-href => href(action=>"history", hash_base=>$hash, + file_name=>$diff{'file'})}, "history"); print "\n"; @@ -1830,17 +1836,22 @@ sub git_difftree_body { if ($action eq 'commitdiff') { # link to patch $patchno++; - print " | " . - $cgi->a({-href => "#patch$patchno"}, "patch"); + print $cgi->a({-href => "#patch$patchno"}, "patch"); } else { - 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{'to_file'}, file_parent=>$diff{'from_file'})}, - "diff"); + 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{'to_file'}, file_parent=>$diff{'from_file'})}, + "diff"); } + print " | "; } + print $cgi->a({-href => href(action=>"blame", hash_base=>$parent, + file_name=>$diff{'from_file'})}, + "blame") . " | "; + print $cgi->a({-href => href(action=>"history", hash_base=>$parent, + file_name=>$diff{'from_file'})}, + "history"); print "\n"; } # we should not encounter Unmerged (U) or Unknown (X) status From 6dd36acd32476a474a5b7d2ad309a82c84513abe Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:47:50 -0700 Subject: [PATCH 12/19] gitweb: "alternate" starts with shade (i.e. 1) When displaying a list of rows (difftree, shortlog, etc), the first entry is now printed shaded, i.e. alternate is initialized to 1, as opposed to non-shaded (alternate initialized to 0). This solves the problem when there is only one row to display -- it is displayed shaded to visually indicate that it is "active", part of a "list", etc. (Compare this to the trivial case of more than one entry, where the rows have alternating shade, thus suggesting being part of a "list" of "active" entries, etc.) Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c86ac1dd88..9550bd74ef 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1699,7 +1699,7 @@ sub git_difftree_body { print "\n"; print "
PrevDiffCommitLineData
CommitLineData
"; - print $cgi->a({-href => href(action=>"blame", hash_base=>$parent, file_name=>$file_name)}, - esc_html(substr($parent, 0, 8))); - print ""; - print $cgi->a({-href => href(action=>"blobdiff", file_name=>$file_name, hash_parent_base=>$parent, - hash_base=>$full_rev)}, - esc_html("Diff")); - print "" . $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)}, esc_html($rev)) . "" . esc_html($lineno) . "" . esc_html($data) . "
" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, + print ""; + print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, hash_base=>$hash, file_name=>$diff{'file'}), - -class => "list"}, esc_html($diff{'file'})) . - "$mode_chng" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, - hash_base=>$hash, file_name=>$diff{'file'})}, - "blob"); + -class => "list"}, esc_html($diff{'file'})); + print "$mode_chng"; if ($action eq 'commitdiff') { # link to patch $patchno++; - print " | " . - $cgi->a({-href => "#patch$patchno"}, "patch"); + print $cgi->a({-href => "#patch$patchno"}, "patch"); } print "" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, + print ""; + print $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, hash_base=>$parent, file_name=>$diff{'file'}), - -class => "list"}, esc_html($diff{'file'})) . - "$mode_chng" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, - hash_base=>$parent, file_name=>$diff{'file'})}, - "blob") . - " | "; + -class => "list"}, esc_html($diff{'file'})); + print "$mode_chng"; if ($action eq 'commitdiff') { # link to patch $patchno++; - print " | " . - $cgi->a({-href => "#patch$patchno"}, "patch"); + print $cgi->a({-href => "#patch$patchno"}, "patch"); + print " | "; } print $cgi->a({-href => href(action=>"history", hash_base=>$parent, file_name=>$diff{'file'})}, - "history") . - ""; - 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, 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'}, - hash_base=>$hash, file_name=>$diff{'file'}), - -class => "list"}, esc_html($diff{'file'})); - } - print "$mode_chnge" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, - hash_base=>$hash, file_name=>$diff{'file'})}, - "blob"); + 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"; if ($diff{'to_id'} ne $diff{'from_id'}) { # modified if ($action eq 'commitdiff') { # link to patch $patchno++; - print " | " . - $cgi->a({-href => "#patch$patchno"}, "patch"); + print $cgi->a({-href => "#patch$patchno"}, "patch"); } else { - 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'})}, - "diff"); + 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'})}, + "diff"); } + print " | "; } - print " | " . - $cgi->a({-href => href(action=>"history", - hash_base=>$hash, file_name=>$diff{'file'})}, - "history"); + print $cgi->a({-href => href(action=>"history", + hash_base=>$hash, file_name=>$diff{'file'})}, + "history"); print "" . - $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'}) { if ($action eq 'commitdiff') { # link to patch From eb51ec9c05e6f4b29567f58102e33c453e1a9a57 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Wed, 27 Sep 2006 17:24:49 -0700 Subject: [PATCH 11/19] gitweb: Add history and blame to git_difftree_body() Add blame and history to Deleted files. Add blame and history to Modified or Type changed files. Add blame and history to Renamed or Copied files. This allows us to do blame->commit->blame->commit->blame->... instead of blame->commit->file->blame->commit->file->blame->... which is longer and easier to get wrong. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 88a8bcdbff..c86ac1dd88 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1761,9 +1761,12 @@ sub git_difftree_body { print $cgi->a({-href => "#patch$patchno"}, "patch"); print " | "; } + print $cgi->a({-href => href(action=>"blame", hash_base=>$parent, + file_name=>$diff{'file'})}, + "blame") . " | "; print $cgi->a({-href => href(action=>"history", hash_base=>$parent, - file_name=>$diff{'file'})}, - "history"); + file_name=>$diff{'file'})}, + "history"); print "
\n"; - my $alternate = 0; + my $alternate = 1; my $patchno = 0; foreach my $line (@{$difftree}) { my %diff = parse_difftree_raw_line($line); @@ -1993,7 +1993,7 @@ sub git_shortlog_body { $to = $#{$revlist} if (!defined $to || $#{$revlist} < $to); print "
\n"; - my $alternate = 0; + my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $commit = $revlist->[$i]; #my $ref = defined $refs ? format_ref_marker($refs, $commit) : ''; @@ -2035,7 +2035,7 @@ sub git_history_body { $to = $#{$revlist} unless (defined $to && $to <= $#{$revlist}); print "
\n"; - my $alternate = 0; + my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { if ($revlist->[$i] !~ m/^([0-9a-fA-F]{40})/) { next; @@ -2099,7 +2099,7 @@ sub git_tags_body { $to = $#{$taglist} if (!defined $to || $#{$taglist} < $to); print "
\n"; - my $alternate = 0; + my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $entry = $taglist->[$i]; my %tag = %$entry; @@ -2159,7 +2159,7 @@ sub git_heads_body { $to = $#{$headlist} if (!defined $to || $#{$headlist} < $to); print "
\n"; - my $alternate = 0; + my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $entry = $headlist->[$i]; my %tag = %$entry; @@ -2275,7 +2275,7 @@ sub git_project_list { } print "\n" . "\n"; - my $alternate = 0; + my $alternate = 1; foreach my $pr (@projects) { if ($alternate) { print "\n"; @@ -2793,7 +2793,7 @@ sub git_tree { git_print_page_path($file_name, 'tree', $hash_base); print "
\n"; print "
\n"; - my $alternate = 0; + my $alternate = 1; foreach my $line (@entries) { my %t = parse_ls_tree_line($line, -z => 1); @@ -3389,7 +3389,7 @@ sub git_search { git_print_header_div('commit', esc_html($co{'title'}), $hash); print "
\n"; - my $alternate = 0; + my $alternate = 1; if ($commit_search) { $/ = "\0"; open my $fd, "-|", git_cmd(), "rev-list", "--header", "--parents", $hash or next; From d1d866e9b8d5a6f0dbe490ba3467440bbf87feaf Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:48:40 -0700 Subject: [PATCH 13/19] gitweb: Remove redundant "commit" link from shortlog Remove the redundant "commit" link from shortlog. It can be had by simply clicking on the entry title of the row. Signed-off-by: Luben Tuikov 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 9550bd74ef..5ef4d07ca1 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2013,7 +2013,6 @@ sub git_shortlog_body { href(action=>"commit", hash=>$commit), $ref); print "\n" . "\n" . From de9272f4bd029d0f331d154b59e64d160e6d1d14 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:49:21 -0700 Subject: [PATCH 14/19] gitweb: Factor out gitweb_have_snapshot() Create gitweb_have_snapshot() which returns true of snapshot is available and enabled, else false. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 5ef4d07ca1..97b30aa5c5 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -155,6 +155,13 @@ sub feature_snapshot { return ($ctype, $suffix, $command); } +sub gitweb_have_snapshot { + my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); + my $have_snapshot = (defined $ctype && defined $suffix); + + return $have_snapshot; +} + # To enable system wide have in $GITWEB_CONFIG # $feature{'pickaxe'}{'default'} = [1]; # To have project specific config enable override in $GITWEB_CONFIG @@ -2736,8 +2743,7 @@ sub git_blob { } sub git_tree { - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); - my $have_snapshot = (defined $ctype && defined $suffix); + my $have_snapshot = gitweb_have_snapshot(); if (!defined $hash) { $hash = git_get_head_hash($project); @@ -2813,7 +2819,6 @@ sub git_tree { } sub git_snapshot { - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); my $have_snapshot = (defined $ctype && defined $suffix); if (!$have_snapshot) { @@ -2923,8 +2928,7 @@ sub git_commit { my $refs = git_get_references(); my $ref = format_ref_marker($refs, $co{'id'}); - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); - my $have_snapshot = (defined $ctype && defined $suffix); + my $have_snapshot = gitweb_have_snapshot(); my @views_nav = (); if (defined $file_name && defined $co{'parent'}) { From ba6ef81017a84c2fce822b7ceba74f67dea6919e Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:50:09 -0700 Subject: [PATCH 15/19] gitweb: Add snapshot to shortlog Add snapshot to each commit-row of shortlog. Signed-off-by: Luben Tuikov 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 97b30aa5c5..8ad04570a8 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2021,7 +2021,8 @@ sub git_shortlog_body { print "\n" . "\n" . "\n"; } From a2a3bf7b2baf0ff64c5b5ffc78d54be82d9967f1 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:51:43 -0700 Subject: [PATCH 16/19] gitweb: Don't use quotemeta on internally generated strings Do not use quotemeta on internally generated strings such as filenames of snapshot, blobs, etc. quotemeta quotes any characters not matching /A-Za-z_0-9/. Which means that we get strings like this: before: linux\-2\.6\.git\-5c2d97cb31fb77981797fec46230ca005b865799\.tar\.gz after: linux-2.6.git-5c2d97cb31fb77981797fec46230ca005b865799.tar.gz This patch fixes this. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8ad04570a8..a99e116a4a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2660,7 +2660,7 @@ sub git_blob_plain { print $cgi->header( -type => "$type", -expires=>$expires, - -content_disposition => 'inline; filename="' . quotemeta($save_as) . '"'); + -content_disposition => 'inline; filename="' . "$save_as" . '"'); undef $/; binmode STDOUT, ':raw'; print <$fd>; @@ -2835,7 +2835,7 @@ sub git_snapshot { print $cgi->header( -type => 'application/x-tar', -content_encoding => $ctype, - -content_disposition => 'inline; filename="' . quotemeta($filename) . '"', + -content_disposition => 'inline; filename="' . "$filename" . '"', -status => '200 OK'); my $git_command = git_cmd_str(); @@ -2933,7 +2933,6 @@ sub git_commit { my @views_nav = (); if (defined $file_name && defined $co{'parent'}) { - my $parent = $co{'parent'}; push @views_nav, $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)}, "blame"); @@ -3145,7 +3144,7 @@ sub git_blobdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => 'inline; filename="' . quotemeta($file_name) . '.patch"'); + -content_disposition => 'inline; filename="' . "$file_name" . '.patch"'); print "X-Git-Url: " . $cgi->self_url() . "\n\n"; @@ -3248,7 +3247,7 @@ sub git_commitdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => 'inline; filename="' . quotemeta($filename) . '"'); + -content_disposition => 'inline; filename="' . "$filename" . '"'); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); print < Date: Thu, 28 Sep 2006 17:20:23 -0700 Subject: [PATCH 17/19] gitweb: Remove redundant "commit" from history Remove redundant "commit" from history -- it can be had by clicking on the title of the commit. This commit makes visualization consistent with shortlog, log, etc. Signed-off-by: Luben Tuikov 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 a99e116a4a..caaa371d0e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2071,7 +2071,6 @@ sub git_history_body { href(action=>"commit", hash=>$commit), $ref); print "\n" . "\n" . "\n"; } elsif ($t->{'type'} eq "tree") { @@ -2745,14 +2745,14 @@ sub git_blob { sub git_tree { my $have_snapshot = gitweb_have_snapshot(); + if (!defined $hash_base) { + $hash_base = "HEAD"; + } if (!defined $hash) { - $hash = git_get_head_hash($project); if (defined $file_name) { - my $base = $hash_base || $hash; - $hash = git_get_hash_by_path($base, $file_name, "tree"); - } - if (!defined $hash_base) { - $hash_base = $hash; + $hash = git_get_hash_by_path($hash_base, $file_name, "tree"); + } else { + $hash = $hash_base; } } $/ = "\0";
" . - $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree"); print "" . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . - $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree"); + $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . " | " . + $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot"); print "
" . - $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype); From 6d81c5a2ea6e0b11fdee87d61d073850c17ce6d8 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 17:21:07 -0700 Subject: [PATCH 18/19] gitweb: History: blob and tree are first, then commitdiff, etc Reorder link display in history to be consistent with other list displays: log, shortlog, etc. We now display: blob | commitdiff blob | commitdiff | diff_to_current and tree | commitdiff Instead of the old history format where "blob" and "tree" are between "commitdiff" and "diff_to_current" if present/ applicable. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index caaa371d0e..c8557c85cc 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2071,8 +2071,8 @@ sub git_history_body { href(action=>"commit", hash=>$commit), $ref); print "" . - $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . - $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype); + $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype) . " | " . + $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff"); if ($ftype eq 'blob') { my $blob_current = git_get_hash_by_path($hash_base, $file_name); From 6f7ea5fb333554887656f7f6ec683544ec6e3c22 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Fri, 29 Sep 2006 09:57:43 -0700 Subject: [PATCH 19/19] gitweb: tree view: hash_base and hash are now context sensitive In tree view, by default, hash_base is HEAD and hash is the entry equivalent. Else the user had selected a hash_base or hash, say by clicking on a revision or commit, in which case those values are used. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c8557c85cc..a3c3e7471a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1672,9 +1672,9 @@ sub git_print_tree_entry { "history"); } print " | " . - $cgi->a({-href => href(action=>"blob_plain", - hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, - "raw"); + $cgi->a({-href => href(action=>"blob_plain", hash_base=>$hash_base, + file_name=>"$basedir$t->{'name'}")}, + "raw"); print "