From 7720224cebde08186627ab7bdb06018905d84e30 Mon Sep 17 00:00:00 2001 From: Yasushi SHOJI Date: Tue, 29 Jan 2008 21:16:02 +0900 Subject: gitweb: Convert generated contents to utf8 in commitdiff_plain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the commit message, or commit author contains non-ascii, it must be converted from Perl internal representation to utf-8, to follow what got declared in HTTP header. Use to_utf8() to do the conversion. This necessarily replaces here-doc with "print" statements. Signed-off-by: Yasushi SHOJI Acked-by: İsmail Dönmez Acked-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 6256641ace..80e3d0ac47 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -5048,16 +5048,15 @@ sub git_commitdiff { -expires => $expires, -content_disposition => 'inline; filename="' . "$filename" . '"'); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); - print <self_url() . "\n\n"; foreach my $line (@{$co{'comment'}}) { - print "$line\n"; + print to_utf8($line) . "\n"; } print "---\n\n"; } -- cgit v1.3 From c1dcf7ebf222e7c24b89b40bc00a6ca5e9e2eec6 Mon Sep 17 00:00:00 2001 From: Bruno Ribas Date: Wed, 30 Jan 2008 03:37:56 -0200 Subject: gitweb: Make use of the $git_dir variable at sub git_get_project_description Signed-off-by: Bruno Ribas Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 80e3d0ac47..ae2d05763f 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1606,7 +1606,7 @@ sub git_get_project_description { my $path = shift; $git_dir = "$projectroot/$path"; - open my $fd, "$projectroot/$path/description" + open my $fd, "$git_dir/description" or return git_get_project_config('description'); my $descr = <$fd>; close $fd; -- cgit v1.3 From e62a641de17b172ffc4d3a803085c8afbfbec3d1 Mon Sep 17 00:00:00 2001 From: Florian La Roche Date: Sun, 3 Feb 2008 12:38:46 +0100 Subject: gitweb: Make feed entries point to commitdiff view Change feeds entries (feeds items) from pointing (linking) to 'commit' view to pointing to 'commitdiff' view. First, feed entries have whatchanged-like list of files which were modified in a commit, so 'commitdiff' view more naturally reflects feed entry (is more naturally alternate / extended version of a feed item). Second, this way the patches are shown directly and code review is done more easily via watching feeds. [jn: Rewritten commit message] Signed-off-by: Florian La Roche Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ae2d05763f..8ef2735c58 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -5565,7 +5565,7 @@ XML or next; # print element (entry, item) - my $co_url = href(-full=>1, action=>"commit", hash=>$commit); + my $co_url = href(-full=>1, action=>"commitdiff", hash=>$commit); if ($format eq 'rss') { print "\n" . "" . esc_html($co{'title'}) . "\n" . -- cgit v1.3 From 201945eeb3b52400e16bb36bf60c56a849c62f32 Mon Sep 17 00:00:00 2001 From: Bruno Ribas Date: Wed, 6 Feb 2008 15:15:12 -0200 Subject: gitweb: Make use of the $git_dir variable at sub git_get_project_url_list Signed-off-by: Bruno Ribas Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8ef2735c58..5e88637b5e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1620,7 +1620,7 @@ sub git_get_project_url_list { my $path = shift; $git_dir = "$projectroot/$path"; - open my $fd, "$projectroot/$path/cloneurl" + open my $fd, "$git_dir/cloneurl" or return wantarray ? @{ config_to_multi(git_get_project_config('url')) } : config_to_multi(git_get_project_config('url')); -- cgit v1.3 From b59012ef4e7dde1895d988736c7df64f68b1e940 Mon Sep 17 00:00:00 2001 From: Bruno Ribas Date: Fri, 8 Feb 2008 14:38:04 -0200 Subject: gitweb: Use the config file to set repository owner's name. Now gitweb checks if gitweb.owner exists before trying to get filesystem's owner. Allow to use configuration variable gitweb.owner set the repository owner, it checks the gitweb.owner, if not set it uses filesystem directory's owner. Useful when we don't want to maintain project list file, and all repository directories have to have the same owner (for example when the same SSH account is shared for all projects, using ssh_acl to control access instead). Signed-off-by: Bruno Ribas Signed-off-by: Junio C Hamano --- gitweb/README | 4 ++++ gitweb/gitweb.perl | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/README b/gitweb/README index 4c8bedf744..2163071047 100644 --- a/gitweb/README +++ b/gitweb/README @@ -233,6 +233,10 @@ You can use the following files in repository: Displayed in the project summary page. You can use multiple-valued gitweb.url repository configuration variable for that, but the file takes precendence. + * gitweb.owner + You can use the gitweb.owner repository configuration variable to set + repository's owner. It is displayed in the project list and summary + page. If it's not set, filesystem directory's owner is used. * various gitweb.* config variables (in config) Read description of %feature hash for detailed list, and some descriptions. diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8ef2735c58..c8fe22a961 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1759,6 +1759,7 @@ sub git_get_project_owner { my $owner; return undef unless $project; + $git_dir = "$projectroot/$project"; if (!defined $gitweb_project_owner) { git_get_project_list_from_file(); @@ -1767,8 +1768,11 @@ sub git_get_project_owner { if (exists $gitweb_project_owner->{$project}) { $owner = $gitweb_project_owner->{$project}; } + if (!defined $owner){ + $owner = git_get_project_config('owner'); + } if (!defined $owner) { - $owner = get_file_owner("$projectroot/$project"); + $owner = get_file_owner("$git_dir"); } return $owner; -- cgit v1.3 From 850b90a51d5ed122cee5c2f3ad4c3e513a05259a Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 16 Feb 2008 23:07:46 +0100 Subject: gitweb: Fix displaying unchopped argument in chop_and_escape_str Do not use esc_html to escape [title] _attribute_ of a HTML element, and quote unprintable characters. Replace unprintable characters by '?' and use CGI method to generate HTML element and do the escaping. This caused bug noticed by Martin Koegler, Message-ID: <20080216130037.GA14571@auto.tuwien.ac.at> that for bad commit encoding in author name, the title attribute (here to show full, not shortened name) had embedded HTML code in it, result of quoting unprintable characters the gitweb/HTML way. This of course broke the HTML, causing page being not displayed in XML validating web browsers. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 5e88637b5e..47e3a41346 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -866,8 +866,8 @@ sub chop_and_escape_str { if ($chopped eq $str) { return esc_html($chopped); } else { - return qq{} . - esc_html($chopped) . qq{}; + $str =~ s/([[:cntrl:]])/?/g; + return $cgi->span({-title=>$str}, esc_html($chopped)); } } -- cgit v1.3 From c84c483ffdfc45d8143fd6f6620361aba91d1080 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sun, 17 Feb 2008 18:48:13 +0100 Subject: gitweb: Add new option -nohtml to quot_xxx subroutines Add support for new option -nohtml to quot_cec and quot_upr subroutines, to have output not wrapped in HTML tags. This makes those subroutines suitable to quoting attributes values, and for plain text output quoting. Currently this API is not used yet. While at it fix whitespace, and use ';' as delimiter, not separator. The option to not wrap quot_cec output in HTML tag were proposed originally in patch: "Don't open a XML tag while another one is already open" Message-ID: <20080216191628.GK30676@schiele.dyndns.org> by Robert Schiele. Originally the parameter was named '-notag', was also supportted by esc_html (but not esc_path) which passed it down to quot_cec. Mentioned patch was meant to fix the bug Martin Koegler reported in his mail "Invalid html output repo.or.cz (alt-git.git)" Message-ID: <20080216130037.GA14571@auto.tuwien.ac.at> which was fixed in different way (do not use esc_html to escape and quote HTML attributes). Signed-off-by: Robert Schiele Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 47e3a41346..8779ca8174 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -753,29 +753,40 @@ sub esc_path { # Make control characters "printable", using character escape codes (CEC) sub quot_cec { my $cntrl = shift; + my %opts = @_; my %es = ( # character escape codes, aka escape sequences - "\t" => '\t', # tab (HT) - "\n" => '\n', # line feed (LF) - "\r" => '\r', # carrige return (CR) - "\f" => '\f', # form feed (FF) - "\b" => '\b', # backspace (BS) - "\a" => '\a', # alarm (bell) (BEL) - "\e" => '\e', # escape (ESC) - "\013" => '\v', # vertical tab (VT) - "\000" => '\0', # nul character (NUL) - ); + "\t" => '\t', # tab (HT) + "\n" => '\n', # line feed (LF) + "\r" => '\r', # carrige return (CR) + "\f" => '\f', # form feed (FF) + "\b" => '\b', # backspace (BS) + "\a" => '\a', # alarm (bell) (BEL) + "\e" => '\e', # escape (ESC) + "\013" => '\v', # vertical tab (VT) + "\000" => '\0', # nul character (NUL) + ); my $chr = ( (exists $es{$cntrl}) ? $es{$cntrl} : sprintf('\%03o', ord($cntrl)) ); - return "$chr"; + if ($opts{-nohtml}) { + return $chr; + } else { + return "$chr"; + } } # Alternatively use unicode control pictures codepoints, # Unicode "printable representation" (PR) sub quot_upr { my $cntrl = shift; + my %opts = @_; + my $chr = sprintf('&#%04d;', 0x2400+ord($cntrl)); - return "$chr"; + if ($opts{-nohtml}) { + return $chr; + } else { + return "$chr"; + } } # git may return quoted and escaped filenames @@ -800,7 +811,7 @@ sub unquote { return chr(oct($seq)); } elsif (exists $es{$seq}) { # C escape sequence, aka character escape code - return $es{$seq} + return $es{$seq}; } # quoted ordinary character return $seq; -- cgit v1.3 From afa9b620f9432491a453d752e8bf62860d7834c0 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Thu, 14 Feb 2008 09:22:30 +0100 Subject: gitweb: Fix bug in href(..., -replay=>1) when using 'pathinfo' form URLs generated by href(..., -replay=>1) (which includes 'next page' links and alternate view links) didn't set project info correctly when current page URL is in pathinfo form. This resulted in broken links such like: http://www.example.com/w/ARRAY(0x85a5318)?a=shortlog;pg=1 if the 'pathinfo' feature was used, or http://www.example.com/w/?a=shortlog;pg=1 if it wasn't, instead of correct: http://www.example.com/w/project.git?a=shortlog;pg=1 This was caused by the fact that href() always replays params in the arrayref form, were they multivalued or singlevalued, and the code dealing with 'pathinfo' feature couldn't deal with $params{'project'} being arrayref. Setting $params{'project'} is moved before replaying params; this ensures that 'project' parameter is processed correctly. Noticed-by: Peter Oberndorfer Noticed-by: Wincent Colaiuta Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8008260f6b..8ed6d04417 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -611,6 +611,8 @@ sub href(%) { ); my %mapping = @mapping; + $params{'project'} = $project unless exists $params{'project'}; + if ($params{-replay}) { while (my ($name, $symbol) = each %mapping) { if (!exists $params{$name}) { @@ -620,8 +622,6 @@ sub href(%) { } } - $params{'project'} = $project unless exists $params{'project'}; - my ($use_pathinfo) = gitweb_check_feature('pathinfo'); if ($use_pathinfo) { # use PATH_INFO for project name -- cgit v1.3 From be8b9063810f0c47f825c47045c7ca137f520edb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 22 Feb 2008 17:33:47 +0100 Subject: gitweb: Better chopping in commit search results When searching commit messages (commit search), if matched string is too long, the generated HTML was munged leading to an ill-formed XHTML document. Now gitweb chop leading, trailing and matched parts, HTML escapes those parts, then composes and marks up match info. HTML output is never chopped. Limiting matched info to 80 columns (with slop) is now done by dividing remaining characters after chopping match equally to leading and trailing part, not by chopping composed and HTML marked output. Noticed-by: Jean-Baptiste Quenot Signed-off-by: Junio C Hamano Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8ed6d04417..326e27cf88 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3784,18 +3784,24 @@ sub git_search_grep_body { print "$co{'age_string_date'}\n" . "" . $author . "\n" . "" . - $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, - chop_and_escape_str($co{'title'}, 50) . "
"); + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), + -class => "list subject"}, + chop_and_escape_str($co{'title'}, 50) . "
"); my $comment = $co{'comment'}; foreach my $line (@$comment) { if ($line =~ m/^(.*)($search_regexp)(.*)$/i) { - my $lead = esc_html($1) || ""; - $lead = chop_str($lead, 30, 10); - my $match = esc_html($2) || ""; - my $trail = esc_html($3) || ""; - $trail = chop_str($trail, 30, 10); - my $text = "$lead$match$trail"; - print chop_str($text, 80, 5) . "
\n"; + my ($lead, $match, $trail) = ($1, $2, $3); + $match = chop_str($match, 70, 5); # in case match is very long + my $contextlen = (80 - len($match))/2; # is left for the remainder + $contextlen = 30 if ($contextlen > 30); # but not too much + $lead = chop_str($lead, $contextlen, 10); + $trail = chop_str($trail, $contextlen, 10); + + $lead = esc_html($lead); + $match = esc_html($match); + $trail = esc_html($trail); + + print "$lead$match$trail
"; } } print "\n" . -- cgit v1.3 From 9d561ad324fc8942919981f2c80360e22896989c Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 23 Feb 2008 22:37:08 +0100 Subject: gitweb: Fix bugs in git_search_grep_body: it's length(), not len() Use int(/2) to get integer value for a substring length. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 326e27cf88..e8226b16f4 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3792,7 +3792,7 @@ sub git_search_grep_body { if ($line =~ m/^(.*)($search_regexp)(.*)$/i) { my ($lead, $match, $trail) = ($1, $2, $3); $match = chop_str($match, 70, 5); # in case match is very long - my $contextlen = (80 - len($match))/2; # is left for the remainder + my $contextlen = int((80 - length($match))/2); # for the remainder $contextlen = 30 if ($contextlen > 30); # but not too much $lead = chop_str($lead, $contextlen, 10); $trail = chop_str($trail, $contextlen, 10); -- cgit v1.3 From b8d97d07fd5025232cae74cfc9a555abd9ac390e Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Mon, 25 Feb 2008 21:07:57 +0100 Subject: gitweb: Better cutting matched string and its context Improve look of commit search output ('search' view) by better cutting of matched string and its context in match info, as suggested by Junio. For example, if you are looking for "very long search string" in the following line: Could somebody test this with very long search string, and see how you would now see: ...this with <>, and see... instead of: Could som... <>, and see... (where <> denotes emphasized / colored fragment; matched fragment to be more exact). For this feature, support for fourth [optional] parameter to chop_str subroutine was added. This fourth parameter is used to denote where to cut string to make it shorter. chop_str can now cut at the beginning (from the _left_ side of the string), in the middle (_center_ of the string), or at the end (from the _right_ side of the string); cutting from right is the default: chop_str(somestring, len, slop, 'left') -> ' ...string' chop_str(somestring, len, slop, 'center') -> 'som ... ing' chop_str(somestring, len, slop, 'right') -> 'somestr... ' If you want to use default slop (default additional length), use undef as value for third parameter to chop_str. While at it, return from chop_str early if given string is so short that chop_str couldn't shorten it. Simplify also regexp used by chop_str. Make ellipsis (dots) stick to shortened fragment for cutting at ends, to better see which part got shortened. Simplify passing all arguments to chop_str in chop_and_escape_str subroutine. This was needed to pass additional options to chop_str. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 73 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 16 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e8226b16f4..fc95e2ca85 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -848,32 +848,73 @@ sub project_in_list { ## ---------------------------------------------------------------------- ## HTML aware string manipulation +# Try to chop given string on a word boundary between position +# $len and $len+$add_len. If there is no word boundary there, +# chop at $len+$add_len. Do not chop if chopped part plus ellipsis +# (marking chopped part) would be longer than given string. sub chop_str { my $str = shift; my $len = shift; my $add_len = shift || 10; + my $where = shift || 'right'; # 'left' | 'center' | 'right' # allow only $len chars, but don't cut a word if it would fit in $add_len # if it doesn't fit, cut it if it's still longer than the dots we would add - $str =~ m/^(.{0,$len}[^ \/\-_:\.@]{0,$add_len})(.*)/; - my $body = $1; - my $tail = $2; - if (length($tail) > 4) { - $tail = " ..."; - $body =~ s/&[^;]*$//; # remove chopped character entities + # remove chopped character entities entirely + + # when chopping in the middle, distribute $len into left and right part + # return early if chopping wouldn't make string shorter + if ($where eq 'center') { + return $str if ($len + 5 >= length($str)); # filler is length 5 + $len = int($len/2); + } else { + return $str if ($len + 4 >= length($str)); # filler is length 4 + } + + # regexps: ending and beginning with word part up to $add_len + my $endre = qr/.{$len}\w{0,$add_len}/; + my $begre = qr/\w{0,$add_len}.{$len}/; + + if ($where eq 'left') { + $str =~ m/^(.*?)($begre)$/; + my ($lead, $body) = ($1, $2); + if (length($lead) > 4) { + $body =~ s/^[^;]*;// if ($lead =~ m/&[^;]*$/); + $lead = " ..."; + } + return "$lead$body"; + + } elsif ($where eq 'center') { + $str =~ m/^($endre)(.*)$/; + my ($left, $str) = ($1, $2); + $str =~ m/^(.*?)($begre)$/; + my ($mid, $right) = ($1, $2); + if (length($mid) > 5) { + $left =~ s/&[^;]*$//; + $right =~ s/^[^;]*;// if ($mid =~ m/&[^;]*$/); + $mid = " ... "; + } + return "$left$mid$right"; + + } else { + $str =~ m/^($endre)(.*)$/; + my $body = $1; + my $tail = $2; + if (length($tail) > 4) { + $body =~ s/&[^;]*$//; + $tail = "... "; + } + return "$body$tail"; } - return "$body$tail"; } # takes the same arguments as chop_str, but also wraps a around the # result with a title attribute if it does get chopped. Additionally, the # string is HTML-escaped. sub chop_and_escape_str { - my $str = shift; - my $len = shift; - my $add_len = shift || 10; + my ($str) = @_; - my $chopped = chop_str($str, $len, $add_len); + my $chopped = chop_str(@_); if ($chopped eq $str) { return esc_html($chopped); } else { @@ -3791,11 +3832,11 @@ sub git_search_grep_body { foreach my $line (@$comment) { if ($line =~ m/^(.*)($search_regexp)(.*)$/i) { my ($lead, $match, $trail) = ($1, $2, $3); - $match = chop_str($match, 70, 5); # in case match is very long - my $contextlen = int((80 - length($match))/2); # for the remainder - $contextlen = 30 if ($contextlen > 30); # but not too much - $lead = chop_str($lead, $contextlen, 10); - $trail = chop_str($trail, $contextlen, 10); + $match = chop_str($match, 70, 5, 'center'); + my $contextlen = int((80 - length($match))/2); + $contextlen = 30 if ($contextlen > 30); + $lead = chop_str($lead, $contextlen, 10, 'left'); + $trail = chop_str($trail, $contextlen, 10, 'right'); $lead = esc_html($lead); $match = esc_html($match); -- cgit v1.3 From 311e552e7674be620bd930ddada307c15140c6ac Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Feb 2008 13:22:06 +0100 Subject: gitweb: Change parse_commits signature to allow for multiple options Change order of parameters in parse_commits() to have $filename before @args (extra options), to allow for multiple extra options, for example both '--grep=' and '--fixed-strings'. Change all callers to follow new calling convention. Originally by Petr Baudis, in http://repo.or.cz/git/gitweb.git: b98f0a7c gitweb: Clearly distinguish regexp / exact match searches Signed-off-by: Petr Baudis Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index fc95e2ca85..3b4b15a5f0 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2079,7 +2079,7 @@ sub parse_commit { } sub parse_commits { - my ($commit_id, $maxcount, $skip, $arg, $filename) = @_; + my ($commit_id, $maxcount, $skip, $filename, @args) = @_; my @cos; $maxcount ||= 1; @@ -2089,7 +2089,7 @@ sub parse_commits { open my $fd, "-|", git_cmd(), "rev-list", "--header", - ($arg ? ($arg) : ()), + @args, ("--max-count=" . $maxcount), ("--skip=" . $skip), @extra_options, @@ -5172,7 +5172,7 @@ sub git_history { $ftype = git_get_type($hash); } - my @commitlist = parse_commits($hash_base, 101, (100 * $page), "--full-history", $file_name); + my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history"); my $paging_nav = ''; if ($page > 0) { @@ -5255,7 +5255,7 @@ sub git_search { $greptype = "--committer="; } $greptype .= $search_regexp; - my @commitlist = parse_commits($hash, 101, (100 * $page), $greptype); + my @commitlist = parse_commits($hash, 101, (100 * $page), undef, $greptype); my $paging_nav = ''; if ($page > 0) { @@ -5507,7 +5507,7 @@ sub git_feed { # log/feed of current (HEAD) branch, log of given branch, history of file/directory my $head = $hash || 'HEAD'; - my @commitlist = parse_commits($head, 150, 0, undef, $file_name); + my @commitlist = parse_commits($head, 150, 0, $file_name); my %latest_commit; my %latest_date; -- cgit v1.3 From 0270cd0eeaff06f6bee1b52d5cdffb1a6e69c15a Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Feb 2008 13:22:07 +0100 Subject: gitweb: Simplify fixed string search Use '--fixed-strings' option to git-rev-list to simplify and improve searching commit messages (commit search). It allows to search for example for "don't" successfully from gitweb. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 3b4b15a5f0..90cf78e436 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -5254,14 +5254,16 @@ sub git_search { } elsif ($searchtype eq 'committer') { $greptype = "--committer="; } - $greptype .= $search_regexp; - my @commitlist = parse_commits($hash, 101, (100 * $page), undef, $greptype); + $greptype .= $searchtext; + my @commitlist = parse_commits($hash, 101, (100 * $page), undef, + $greptype, '--fixed-strings'); my $paging_nav = ''; if ($page > 0) { $paging_nav .= $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype)}, + searchtext=>$searchtext, + searchtype=>$searchtype)}, "first"); $paging_nav .= " ⋅ " . $cgi->a({-href => href(-replay=>1, page=>$page-1), -- cgit v1.3 From 0e55991987e490a69bc549f6f789b34489c953a7 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Tue, 26 Feb 2008 13:22:08 +0100 Subject: gitweb: Clearly distinguish regexp / exact match searches This patch does a couple of things: * Makes commit/author/committer search case insensitive To be consistent with the grep search; I see no convincing reason for the search to be case sensitive, and you might get in trouble especially with contributors e.g. from Japan or France where they sometimes like to uppercase their last name. * Makes grep search by default search for fixed strings. * Introduces 're' checkbox that enables POSIX extended regexp searches This works for all the search types. The idea comes from Jakub. It does not make much sense (and is not easy at all) to untangle most of these changes from each other, thus they all go in a single patch. [jn: Cherry-picked from Pasky's http://repo.or.cz/git/gitweb.git] Signed-off-by: Petr Baudis Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 90cf78e436..20dc5d59c2 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -472,13 +472,15 @@ if (defined $searchtype) { } } +our $search_use_regexp = $cgi->param('sr'); + our $searchtext = $cgi->param('s'); our $search_regexp; if (defined $searchtext) { if (length($searchtext) < 2) { die_error(undef, "At least two characters are required for search parameter"); } - $search_regexp = quotemeta $searchtext; + $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext; } # now read PATH_INFO and use it as alternative to parameters @@ -608,6 +610,7 @@ sub href(%) { searchtype => "st", snapshot_format => "sf", extra_options => "opt", + search_use_regexp => "sr", ); my %mapping = @mapping; @@ -2584,6 +2587,10 @@ EOF $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . " search:\n", $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . + "" . + $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', + -checked => $search_use_regexp) . + "" . "" . $cgi->end_form() . "\n"; } @@ -5256,7 +5263,8 @@ sub git_search { } $greptype .= $searchtext; my @commitlist = parse_commits($hash, 101, (100 * $page), undef, - $greptype, '--fixed-strings'); + $greptype, '--regexp-ignore-case', + $search_use_regexp ? '--extended-regexp' : '--fixed-strings'); my $paging_nav = ''; if ($page > 0) { @@ -5300,8 +5308,9 @@ sub git_search { my $git_command = git_cmd_str(); my $searchqtext = $searchtext; $searchqtext =~ s/'/'\\''/; + my $pickaxe_flags = $search_use_regexp ? '--pickaxe-regex' : ''; open my $fd, "-|", "$git_command rev-list $hash | " . - "$git_command diff-tree -r --stdin -S\'$searchqtext\'"; + "$git_command diff-tree -r --stdin -S\'$searchqtext\' $pickaxe_flags"; undef %co; my @files; while (my $line = <$fd>) { @@ -5365,7 +5374,9 @@ sub git_search { my $alternate = 1; my $matches = 0; $/ = "\n"; - open my $fd, "-|", git_cmd(), 'grep', '-n', '-i', '-E', $searchtext, $co{'tree'}; + open my $fd, "-|", git_cmd(), 'grep', '-n', + $search_use_regexp ? ('-E', '-i') : '-F', + $searchtext, $co{'tree'}; my $lastfile = ''; while (my $line = <$fd>) { chomp $line; @@ -5395,7 +5406,7 @@ sub git_search { print "
Binary file
\n"; } else { $ltext = untabify($ltext); - if ($ltext =~ m/^(.*)($searchtext)(.*)$/i) { + if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) { $ltext = esc_html($1, -nbsp=>1); $ltext .= ''; $ltext .= esc_html($2, -nbsp=>1); @@ -5430,27 +5441,31 @@ sub git_search_help { git_header_html(); git_print_page_nav('','', $hash,$hash,$hash); print <Pattern is by default a normal string that is matched precisely (but without +regard to case, except in the case of pickaxe). However, when you check the re checkbox, +the pattern entered is recognized as the POSIX extended +regular expression (also case +insensitive).

commit
-
The commit messages and authorship information will be scanned for the given string.
+
The commit messages and authorship information will be scanned for the given pattern.
EOT my ($have_grep) = gitweb_check_feature('grep'); if ($have_grep) { print <grep
All files in the currently selected tree (HEAD unless you are explicitly browsing - a different one) are searched for the given -regular expression -(POSIX extended) and the matches are listed. On large -trees, this search can take a while and put some strain on the server, so please use it with -some consideration.
+ a different one) are searched for the given pattern. On large trees, this search can take +a while and put some strain on the server, so please use it with some consideration. Note that +due to git-grep peculiarity, currently if regexp mode is turned off, the matches are +case-sensitive. EOT } print <author -
Name and e-mail of the change author and date of birth of the patch will be scanned for the given string.
+
Name and e-mail of the change author and date of birth of the patch will be scanned for the given pattern.
committer
-
Name and e-mail of the committer and date of commit will be scanned for the given string.
+
Name and e-mail of the committer and date of commit will be scanned for the given pattern.
EOT my ($have_pickaxe) = gitweb_check_feature('pickaxe'); if ($have_pickaxe) { @@ -5458,7 +5473,8 @@ EOT
pickaxe
All commits that caused the string to appear or disappear from any file (changes that added, removed or "modified" the string) will be listed. This search can take a while and -takes a lot of strain on the server, so please use it wisely.
+takes a lot of strain on the server, so please use it wisely. Note that since you may be +interested even in changes just changing the case as well, this search is case sensitive. EOT } print "
\n"; -- cgit v1.3 From 6dfbb304be5a5e260321c5f47626582dbe2c62f0 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sun, 2 Mar 2008 16:57:14 +0100 Subject: gitweb: Mark first match when searching commit messages Due to greediness of a pattern, gitweb used to mark (show) last match in line, if there are more than one match in line. Now it shows first. Showing all matches in a line would require further work. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 20dc5d59c2..922dee98b9 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3837,7 +3837,7 @@ sub git_search_grep_body { chop_and_escape_str($co{'title'}, 50) . "
"); my $comment = $co{'comment'}; foreach my $line (@$comment) { - if ($line =~ m/^(.*)($search_regexp)(.*)$/i) { + if ($line =~ m/^(.*?)($search_regexp)(.*)$/i) { my ($lead, $match, $trail) = ($1, $2, $3); $match = chop_str($match, 70, 5, 'center'); my $contextlen = int((80 - length($match))/2); -- cgit v1.3 From c582abae46725504cee9ff91816c979989632f07 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Wed, 5 Mar 2008 09:31:55 +0100 Subject: gitweb: Fix and simplify pickaxe search Instead of using "git-rev-list | git-diff-tree" pipeline for pickaxe search, use git-log with appropriate options. Besides reducing number of forks by one, this allows to use list form of open, which in turn allow to not worry about quoting arguments and to avoid forking shell. The options to git-log were chosen to reduce required changes in pickaxe git command output parsing; gitweb still parses returned commits one by one. Parsing "pickaxe" output is simplified: git_search now reuses parse_difftree_raw_line and writes affected files as they arrive using the fact that commit name goes always before [raw] diff. While at it long bug of pickaxe search was fixed, namely that the last commit found by pickaxe search was never shown. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 85 +++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 42 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 922dee98b9..ec73cb1256 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -5305,51 +5305,19 @@ sub git_search { print "\n"; my $alternate = 1; $/ = "\n"; - my $git_command = git_cmd_str(); - my $searchqtext = $searchtext; - $searchqtext =~ s/'/'\\''/; - my $pickaxe_flags = $search_use_regexp ? '--pickaxe-regex' : ''; - open my $fd, "-|", "$git_command rev-list $hash | " . - "$git_command diff-tree -r --stdin -S\'$searchqtext\' $pickaxe_flags"; + open my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts, + '--pretty=format:%H', '--no-abbrev', '--raw', "-S$searchtext", + ($search_use_regexp ? '--pickaxe-regex' : ()); undef %co; my @files; while (my $line = <$fd>) { - if (%co && $line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)\t(.*)$/) { - my %set; - $set{'file'} = $6; - $set{'from_id'} = $3; - $set{'to_id'} = $4; - $set{'id'} = $set{'to_id'}; - if ($set{'id'} =~ m/0{40}/) { - $set{'id'} = $set{'from_id'}; - } - if ($set{'id'} =~ m/0{40}/) { - next; - } - push @files, \%set; - } elsif ($line =~ m/^([0-9a-fA-F]{40})$/){ + chomp $line; + next unless $line; + + my %set = parse_difftree_raw_line($line); + if (defined $set{'commit'}) { + # finish previous commit if (%co) { - if ($alternate) { - print "\n"; - } else { - print "\n"; - } - $alternate ^= 1; - my $author = chop_and_escape_str($co{'author_name'}, 15, 5); - print "\n" . - "\n" . - "\n" . "\n" . "\n"; } - %co = parse_commit($1); + + if ($alternate) { + print "\n"; + } else { + print "\n"; + } + $alternate ^= 1; + %co = parse_commit($set{'commit'}); + my $author = chop_and_escape_str($co{'author_name'}, 15, 5); + print "\n" . + "\n" . + "\n" . + "\n" . + "\n"; + } + print "
$co{'age_string_date'}" . $author . "" . - $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), - -class => "list subject"}, - chop_and_escape_str($co{'title'}, 50) . "
"); - while (my $setref = shift @files) { - my %set = %$setref; - print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'}, - hash=>$set{'id'}, file_name=>$set{'file'}), - -class => "list"}, - "" . esc_path($set{'file'}) . "") . - "
\n"; - } print "
" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") . @@ -5358,11 +5326,44 @@ sub git_search { print "
$co{'age_string_date'}$author" . + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), + -class => "list subject"}, + chop_and_escape_str($co{'title'}, 50) . "
"); + } elsif (defined $set{'to_id'}) { + next if ($set{'to_id'} =~ m/^0{40}$/); + + print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'}, + hash=>$set{'to_id'}, file_name=>$set{'to_file'}), + -class => "list"}, + "" . esc_path($set{'file'}) . "") . + "
\n"; } } close $fd; + # finish last commit (warning: repetition!) + if (%co) { + print "
" . + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") . + " | " . + $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); + print "
\n"; } -- cgit v1.3 From 17a8b25005bb09b03bee7ddac5412c7d29675eef Mon Sep 17 00:00:00 2001 From: Gerrit Pape Date: Wed, 26 Mar 2008 18:11:19 +0000 Subject: gitweb: fallback to system-wide config file if default config does not exist From a distribution point of view, configuration files for applications should reside in /etc/. On the other hand it's convenient for multiple instances of gitweb (e.g. virtual web servers on a single machine) to have a per-instance configuration file, just as gitweb currently supports through the file gitweb_config.perl next to the cgi. To support both at runtime, this commit introduces GITWEB_CONFIG_SYSTEM as a system-wide configuration file which will be used as a fallback if the config file sprecified throug GITWEB_CONFIG does not exist. See also http://bugs.debian.org/450592 Signed-off-by: Gerrit Pape Acked-by: Jakub Narebski Signed-off-by: Junio C Hamano --- Makefile | 1 + gitweb/INSTALL | 6 +++++- gitweb/README | 9 ++++++++- gitweb/gitweb.perl | 7 ++++++- 4 files changed, 20 insertions(+), 3 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/Makefile b/Makefile index 7c70b00b82..a88acf6efd 100644 --- a/Makefile +++ b/Makefile @@ -189,6 +189,7 @@ ETC_GITCONFIG = $(sysconfdir)/gitconfig # default configuration for gitweb GITWEB_CONFIG = gitweb_config.perl +GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf GITWEB_HOME_LINK_STR = projects GITWEB_SITENAME = GITWEB_PROJECTROOT = /pub/git diff --git a/gitweb/INSTALL b/gitweb/INSTALL index 9cd5b0a2b1..743f2d4442 100644 --- a/gitweb/INSTALL +++ b/gitweb/INSTALL @@ -95,7 +95,11 @@ for gitweb (in gitweb/README). by default it is file named gitweb_config.perl in the same place as gitweb.cgi script. You can control default place for config file using GITWEB_CONFIG build configuration variable, and you can set it - using GITWEB_CONFIG environmental variable. + using GITWEB_CONFIG environmental variable. If this file does not + exist, gitweb looks for a system-wide configuration file, normally + /etc/gitweb.conf. You can change the default using the + GITWEB_CONFIG_SYSTEM build configuration variable, and override it + through GITWEB_CONFIG_SYSTEM environmental variable. - Gitweb config file is [fragment] of perl code. You can set variables using "our $variable = value"; text from "#" character until the end diff --git a/gitweb/README b/gitweb/README index 2163071047..8dfe335f73 100644 --- a/gitweb/README +++ b/gitweb/README @@ -100,13 +100,20 @@ You can specify the following configuration variables when building GIT: is set when gitweb.cgi is executed, then the file specified in the environment variable will be loaded instead of the file specified when gitweb.cgi was created. [Default: gitweb_config.perl] + * GITWEB_CONFIG_SYSTEM + This Perl file will be loaded using 'do' as a fallback if GITWEB_CONFIG + does not exist. If the environment variable GITWEB_CONFIG_SYSTEM is set + when gitweb.cgi is executed, then the file specified in the environment + variable will be loaded instead of the file specified when gitweb.cgi was + created. [Default: /etc/gitweb.conf] Runtime gitweb configuration ---------------------------- You can adjust gitweb behaviour using the file specified in `GITWEB_CONFIG` -(defaults to 'gitweb_config.perl' in the same directory as the CGI). +(defaults to 'gitweb_config.perl' in the same directory as the CGI), and +as a fallback `GITWEB_CONFIG_SYSTEM` (defaults to /etc/gitweb.conf). The most notable thing that is not configurable at compile time are the optional features, stored in the '%features' variable. diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ec73cb1256..f73cfca539 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -369,7 +369,12 @@ sub filter_snapshot_fmts { } our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; -do $GITWEB_CONFIG if -e $GITWEB_CONFIG; +if (-e $GITWEB_CONFIG) { + do $GITWEB_CONFIG; +} else { + our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++"; + do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM; +} # version of the core git binary our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown"; -- cgit v1.3 From 4ed4a347168d6714c6beca7d7702473229c9d8f1 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 5 Apr 2008 21:13:24 +0100 Subject: Revert "gitweb: Add 'status_str' to parse_difftree_raw_line output" This reverts commit 6aa6f92fda47cc4ee5f599895e8a5a327fb6f9ab. It caused is_deleted() subroutine to output warnings when dealing with old, legacy gitweb blobdiff URLs without either 'hb' or 'hpb' parameters. This fixes http://bugs.debian.org/469083 Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ec73cb1256..73d098a433 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2164,7 +2164,7 @@ sub parse_difftree_raw_line { $res{'to_mode'} = $2; $res{'from_id'} = $3; $res{'to_id'} = $4; - $res{'status'} = $res{'status_str'} = $5; + $res{'status'} = $5; $res{'similarity'} = $6; if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied ($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7); @@ -2180,7 +2180,6 @@ 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); } @@ -3002,7 +3001,7 @@ sub fill_from_file_info { sub is_deleted { my $diffinfo = shift; - return $diffinfo->{'status_str'} =~ /D/; + return $diffinfo->{'to_id'} eq ('0' x 40); } # does patch correspond to [previous] difftree raw line -- cgit v1.3 From 5634cf24766f8700804ca55f5e8567c88538a5b0 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sun, 13 Apr 2008 14:12:15 +0200 Subject: gitweb: Fix 'history' view for deleted files with history When asked for history of a file which is not present in given branch ("HEAD", i.e. current branch, or given by transient $hash_hase ('hb') parameter), but is present deeper in the history (meaning that "git rev-list --full-history $hash_base -- $file_name" is not empty), and there is no $hash ('h') parameter set for a file, gitweb would spew multiple of "Use of uninitialized value" warnings, and some links would be missing. This commit fixes this bug. This bug occurs in the rare cases when "git log -- " is empty and "git log --full-history -- " is not, or to be more exact in the cases when full-history starts later than given branch. It can happen if you are using handcrafted gitwb URL, or if you follow generic 'history' link or bookmark for a file which got deleted. Gitweb tried to get file type ('tree', or 'blob', or even 'commit') from the commit we start searching from (where the file was not present), and not among found commits. This was the cause of "Use of uninitialized value" warnings. This commit also add tests for such situation to t9500 test. While we are it, return HTTP error if there is _no_ history; it means that file or directory was not found (for given branch). Also error out if type of item could not be found: it should not happen now, but better be sure. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 18 +++++++++++++++--- t/t9500-gitweb-standalone-no-errors.sh | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 73d098a433..746153ffe8 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -5171,14 +5171,26 @@ sub git_history { my $refs = git_get_references(); my $limit = sprintf("--max-count=%i", (100 * ($page+1))); + my @commitlist = parse_commits($hash_base, 101, (100 * $page), + $file_name, "--full-history"); + if (!@commitlist) { + die_error('404 Not Found', "No such file or directory on given branch"); + } + if (!defined $hash && defined $file_name) { - $hash = git_get_hash_by_path($hash_base, $file_name); + # some commits could have deleted file in question, + # and not have it in tree, but one of them has to have it + for (my $i = 0; $i <= @commitlist; $i++) { + $hash = git_get_hash_by_path($commitlist[$i]{'id'}, $file_name); + last if defined $hash; + } } if (defined $hash) { $ftype = git_get_type($hash); } - - my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history"); + if (!defined $ftype) { + die_error(undef, "Unknown type of object"); + } my $paging_nav = ''; if ($page > 0) { diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 796cd7dba0..061a2596d3 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -483,6 +483,22 @@ test_expect_success \ 'gitweb_run "p=.git;a=history;f=file"' test_debug 'cat gitweb.log' +test_expect_success \ + 'logs: history (implicit HEAD, non-existent file)' \ + 'gitweb_run "p=.git;a=history;f=non-existent"' +test_debug 'cat gitweb.log' + +test_expect_success \ + 'logs: history (implicit HEAD, deleted file)' \ + 'git checkout master && + echo "to be deleted" > deleted_file && + git add deleted_file && + git commit -m "Add file to be deleted" && + git rm deleted_file && + git commit -m "Delete file" && + gitweb_run "p=.git;a=history;f=deleted_file"' +test_debug 'cat gitweb.log' + # ---------------------------------------------------------------------- # feed generation -- cgit v1.3 From bbd4c307fc315847c975efd4c9aa32eb0e8470fb Mon Sep 17 00:00:00 2001 From: "martin f. krafft" Date: Sun, 20 Apr 2008 23:03:56 +0200 Subject: Escape project name in regexp The project name, when used in a regular expression, needs to be quoted properly, so that stuff like '++' in the project name does not cause Perl to barf. Related info: http://bugs.debian.org/476076 This is a bug in Perl's CGI.pm, but fixing that exposed a similar bug in gitweb.perl Signed-off-by: martin f. krafft Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 746153ffe8..4abd7ac1ad 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -506,7 +506,7 @@ sub evaluate_path_info { } # do not change any parameters if an action is given using the query string return if $action; - $path_info =~ s,^$project/*,,; + $path_info =~ s,^\Q$project\E/*,,; my ($refname, $pathname) = split(/:/, $path_info, 2); if (defined $pathname) { # we got "project.git/branch:filename" or "project.git/branch:dir/" -- cgit v1.3 From 85d17a123ba59b90744e311e40f80fd8838fbdc5 Mon Sep 17 00:00:00 2001 From: "martin f. krafft" Date: Sun, 20 Apr 2008 23:23:38 +0200 Subject: Escape project names before creating pathinfo URLs If a project name contains special URL characters like +, gitweb's links break in subtle ways. The solution is to pass the project name through esc_url() and using the return value. Signed-off-by: martin f. krafft Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 4abd7ac1ad..12843a4846 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -628,7 +628,7 @@ sub href(%) { my ($use_pathinfo) = gitweb_check_feature('pathinfo'); if ($use_pathinfo) { # use PATH_INFO for project name - $href .= "/$params{'project'}" if defined $params{'project'}; + $href .= "/".esc_url($params{'project'}) if defined $params{'project'}; delete $params{'project'}; # Summary just uses the project path URL @@ -2570,7 +2570,7 @@ EOF my $action = $my_uri; my ($use_pathinfo) = gitweb_check_feature('pathinfo'); if ($use_pathinfo) { - $action .= "/$project"; + $action .= "/".esc_url($project); } else { $cgi->param("p", $project); } -- cgit v1.3 From 3562198b7da7ef6597af27b3a7fcaeee41608999 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sun, 20 Apr 2008 22:09:48 +0200 Subject: gitweb: Use feed link according to current view Michael G. Noll said in comments to the "Switching my code repository from Subversion (SVN) to git" article (http://tinyurl.com/37v67l) in his "My digital moleskine" blog, that one of the things he is missing in gitweb from SVN::Web is an RSS feed with news/information of the current view (including RSS feed for single file or directory). This is not exactly true, as since refactoring feed generation in af6feeb (gitweb: Refactor feed generation, make output prettier, add Atom feed, 2006-11-19), gitweb can generate feeds (RSS or Atom) for history of a given branch, history limited to a given directory, or history of a given file. Nevertheless this required handcrafting the URL to get wanted RSS feed. This commit makes gitweb select feed links in the HTML header and in page footer depending on current view (action). It is more elaborate, and I guess more correct, than simple patch adding $hash ('h') parameter to *all* URLs, including feed links, by Jean-Baptiste Quenot Subject: [PATCH] gitweb: Add hash parameter in feed URL when a hash is specified in the current request Message-ID: If $hash ('h') or $hash_base ('hb') parameter is a branch name (i.e. it starts with 'refs/heads/'; all generated URLs use this form to discriminate between tags and heads), it is used in feed URLs; if $file_name ('f') is defined, it is used in feed URLs. Feed title is set according to the kind of web feed: it is either 'log' for generic feed, 'log of ', 'history of ' for generic history (using implicit or explicit HEAD, i.e. current branch) or 'history of on '. There are special cases: 'heads' and 'forks' views should use OPML providing list of available feeds; 'tags' probably also should use OPML; there is no web feed equivalent to 'search' view. Currently all those cases fallback to (show) default feed. Such feed link uses "generic" class, and is shown in slightly lighter color for distinction. Currently feed can have but one starting point, and does not support negative (exclude) commit arguments. Therefore for now for *diff views it is chosen that feed follow the "to" part: to-name, to-commit for 'blobdiff', 'treediff' and 'commitdiff' views. Generating parameters for href() for feed link was separated (refactored) into get_feed_info() subroutine. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 8 ++++ gitweb/gitweb.perl | 121 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 104 insertions(+), 25 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 446a1c333b..aa0eeca247 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -464,6 +464,14 @@ a.rss_logo:hover { background-color: #ee5500; } +a.rss_logo.generic { + background-color: #ff8800; +} + +a.rss_logo.generic:hover { + background-color: #ee7700; +} + span.refs span { padding: 0px 4px; font-size: 70%; diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index f83567ec39..2facf2db7a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -592,7 +592,7 @@ exit; ## ====================================================================== ## action links -sub href(%) { +sub href (%) { my %params = @_; # default is to use -absolute url() i.e. $my_uri my $href = $params{-full} ? $my_url : $my_uri; @@ -1448,6 +1448,46 @@ sub format_snapshot_links { } } +## ...................................................................... +## functions returning values to be passed, perhaps after some +## transformation, to other functions; e.g. returning arguments to href() + +# returns hash to be passed to href to generate gitweb URL +# in -title key it returns description of link +sub get_feed_info { + my $format = shift || 'Atom'; + my %res = (action => lc($format)); + + # feed links are possible only for project views + 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); + + my $branch; + # branches refs uses 'refs/heads/' prefix (fullname) to differentiate + # from tag links; this also makes possible to detect branch links + if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) || + (defined $hash && $hash =~ m!^refs/heads/(.*)$!)) { + $branch = $1; + } + # find log type for feed description (title) + my $type = 'log'; + if (defined $file_name) { + $type = "history of $file_name"; + $type .= "/" if ($action eq 'tree'); + $type .= " on '$branch'" if (defined $branch); + } else { + $type = "log of $branch" if (defined $branch); + } + + $res{-title} = $type; + $res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef); + $res{'file_name'} = $file_name; + + return %res; +} + ## ---------------------------------------------------------------------- ## git utility subroutines, invoking git commands @@ -2510,30 +2550,49 @@ EOF } } if (defined $project) { - printf(''."\n", - esc_param($project), href(action=>"rss")); - printf(''."\n", - esc_param($project), href(action=>"rss", - extra_options=>"--no-merges")); - printf(''."\n", - esc_param($project), href(action=>"atom")); - printf(''."\n", - esc_param($project), href(action=>"atom", - extra_options=>"--no-merges")); + my %href_params = get_feed_info(); + if (!exists $href_params{'-title'}) { + $href_params{'-title'} = 'log'; + } + + foreach my $format qw(RSS Atom) { + my $type = lc($format); + my %link_attr = ( + '-rel' => 'alternate', + '-title' => "$project - $href_params{'-title'} - $format feed", + '-type' => "application/$type+xml" + ); + + $href_params{'action'} = $type; + $link_attr{'-href'} = href(%href_params); + print "\n"; + + $href_params{'extra_options'} = '--no-merges'; + $link_attr{'-href'} = href(%href_params); + $link_attr{'-title'} .= ' (no merges)'; + print "\n"; + } + } else { printf(''."\n", + 'href="%s" type="text/plain; charset=utf-8" />'."\n", $site_name, href(project=>undef, action=>"project_index")); printf(''."\n", + 'href="%s" type="text/x-opml" />'."\n", $site_name, href(project=>undef, action=>"opml")); } if (defined $favicon) { - print qq(\n); + print qq(\n); } print "\n" . @@ -2601,23 +2660,35 @@ EOF } sub git_footer_html { + my $feed_class = 'rss_logo'; + print "
\n"; if (defined $project) { my $descr = git_get_project_description($project); if (defined $descr) { print "\n"; } - print $cgi->a({-href => href(action=>"rss"), - -class => "rss_logo"}, "RSS") . " "; - print $cgi->a({-href => href(action=>"atom"), - -class => "rss_logo"}, "Atom") . "\n"; + + my %href_params = get_feed_info(); + if (!%href_params) { + $feed_class .= ' generic'; + } + $href_params{'-title'} ||= 'log'; + + foreach my $format qw(RSS Atom) { + $href_params{'action'} = lc($format); + print $cgi->a({-href => href(%href_params), + -title => "$href_params{'-title'} $format feed", + -class => $feed_class}, $format)."\n"; + } + } else { print $cgi->a({-href => href(project=>undef, action=>"opml"), - -class => "rss_logo"}, "OPML") . " "; + -class => $feed_class}, "OPML") . " "; print $cgi->a({-href => href(project=>undef, action=>"project_index"), - -class => "rss_logo"}, "TXT") . "\n"; + -class => $feed_class}, "TXT") . "\n"; } - print "
\n" ; + print "\n"; # class="page_footer" if (-f $site_footer) { open (my $fd, $site_footer); -- cgit v1.3 From dee2775a29440ca8a52bb5bd09a6de6cd29f69cc Mon Sep 17 00:00:00 2001 From: Anders Waldenborg Date: Wed, 21 May 2008 13:44:43 +0200 Subject: gitweb: Convert string to internal form before chopping in chop_str Fix chop_str not to cut in middle of utf8 multibyte chars. Without this fix at least author name in short log may cut in middle of a multibyte char. When the result comes to esc_html to_utf8 is called again, which doesn't find valid utf8 and decodes using $fallback_encoding making it even worse. This also have the nice side effect that it actually tries to show the first 10 _characters_, not the number of characters that happened to fit into 10 bytes. Signed-off-by: Anders Waldenborg Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 2facf2db7a..8308e2208e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -866,6 +866,10 @@ sub chop_str { my $add_len = shift || 10; my $where = shift || 'right'; # 'left' | 'center' | 'right' + # Make sure perl knows it is utf8 encoded so we don't + # cut in the middle of a utf8 multibyte char. + $str = to_utf8($str); + # allow only $len chars, but don't cut a word if it would fit in $add_len # if it doesn't fit, cut it if it's still longer than the dots we would add # remove chopped character entities entirely -- cgit v1.3 From 1f684dc01c6a45341e8e47d8393f0ef66fdfc398 Mon Sep 17 00:00:00 2001 From: Lea Wiemann Date: Wed, 28 May 2008 01:25:42 +0200 Subject: gitweb: only display "next" links in logs if there is a next page There was a bug in the implementation of the "next" links in format_paging_nav (for log and shortlog), which caused the next links to always be displayed, even if there is no next page. This fixes it. Signed-off-by: Lea Wiemann Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 12843a4846..345acf4520 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2676,7 +2676,7 @@ sub git_print_page_nav { } sub format_paging_nav { - my ($action, $hash, $head, $page, $nrevs) = @_; + my ($action, $hash, $head, $page, $has_next_link) = @_; my $paging_nav; @@ -2694,7 +2694,7 @@ sub format_paging_nav { $paging_nav .= " ⋅ prev"; } - if ($nrevs >= (100 * ($page+1)-1)) { + if ($has_next_link) { $paging_nav .= " ⋅ " . $cgi->a({-href => href(-replay=>1, page=>$page+1), -accesskey => "n", -title => "Alt-n"}, "next"); @@ -4585,7 +4585,7 @@ sub git_log { my @commitlist = parse_commits($hash, 101, (100 * $page)); - my $paging_nav = format_paging_nav('log', $hash, $head, $page, (100 * ($page+1))); + my $paging_nav = format_paging_nav('log', $hash, $head, $page, $#commitlist >= 100); git_header_html(); git_print_page_nav('log','', $hash,undef,undef, $paging_nav); @@ -5505,7 +5505,7 @@ sub git_shortlog { my @commitlist = parse_commits($hash, 101, (100 * $page)); - my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, (100 * ($page+1))); + my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, $#commitlist >= 100); my $next_link = ''; if ($#commitlist >= 100) { $next_link = -- cgit v1.3 From f70dda250e33dd17f6fdff17d15287391d8b0952 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Mon, 2 Jun 2008 11:54:41 +0200 Subject: gitweb: Fix "next" link on bottom of page Fix search form generation to not modify $cgi->param(...)'s. In git_header_html() we used to use $cgi->hidden(-name => "a") etc. to generate hidden fields; unfortunately to use this form it is required to modify $cgi->param("a") etc., which makes href(-replay,...) use wrong replay values. This for example made the "next" link on the bottom of the page has a=search instead of a=$action, and thus fails to get you to the next page. Because in CGI the value of a hidden field is "sticky", there is no way to modify it short of modifying $cgi->param(...). Therefore it got replaced by generating element [semi] directly. Alternate solution would be for href(-replay,...) to use values saved in global variables, such as $action etc., instead of (re)reading them from $cgi->param($symbol). The bad link was reported by Kai Blin through http://bugs.debian.org/481902 Reported-by: Kai Blin Signed-off-by: Jakub Narebski Tested-by: Gerrit Pape Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 57a19058a4..55fb100534 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2623,7 +2623,7 @@ EOF print "\n"; my ($have_search) = gitweb_check_feature('search'); - if ((defined $project) && ($have_search)) { + if (defined $project && $have_search) { if (!defined $searchtext) { $searchtext = ""; } @@ -2639,16 +2639,13 @@ EOF my ($use_pathinfo) = gitweb_check_feature('pathinfo'); if ($use_pathinfo) { $action .= "/".esc_url($project); - } else { - $cgi->param("p", $project); } - $cgi->param("a", "search"); - $cgi->param("h", $search_hash); print $cgi->startform(-method => "get", -action => $action) . "
\n" . - (!$use_pathinfo && $cgi->hidden(-name => "p") . "\n") . - $cgi->hidden(-name => "a") . "\n" . - $cgi->hidden(-name => "h") . "\n" . + (!$use_pathinfo && + $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") . + $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" . + $cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" . $cgi->popup_menu(-name => 'st', -default => 'commit', -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) . $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . -- cgit v1.3 From 7f718e8b46b37a9e1caf58a372938817f04885d9 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 3 Jun 2008 16:47:10 +0200 Subject: gitweb: Add charset info to "raw" output of 'text/plain' blobs Earlier "blob_plain" view sent "charset=utf-8" only when gitweb guessed the content type to be text by reading from it, and not when the MIME type was obtained from /etc/mime.types, or when gitweb couldn't guess mimetype and used $default_blob_plain_mimetype. This fixes the bug by always add charset info from $default_text_plain_charset (if it is defined) to "raw" (a=blob_plain) output for 'text/plain' blobs. Generating information for Content-Type: header got separated into blob_contenttype() subroutine; adding charset info in a special case was removed from blob_mimetype(), which now should return mimetype only. While at it cleanup code a bit: put subroutine parameter initialization first, make error message more robust (when $file_name is not defined) if more cryptic, remove unnecessary '"' around variable ("$var" -> $var). Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 55fb100534..198772c210 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2481,8 +2481,7 @@ sub blob_mimetype { return $default_blob_plain_mimetype unless $fd; if (-T $fd) { - return 'text/plain' . - ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : ''); + return 'text/plain'; } elsif (! $filename) { return 'application/octet-stream'; } elsif ($filename =~ m/\.png$/i) { @@ -2496,6 +2495,17 @@ sub blob_mimetype { } } +sub blob_contenttype { + my ($fd, $file_name, $type) = @_; + + $type ||= blob_mimetype($fd, $file_name); + if ($type eq 'text/plain' && defined $default_text_plain_charset) { + $type .= "; charset=$default_text_plain_charset"; + } + + return $type; +} + ## ====================================================================== ## functions printing HTML: header, footer, error page @@ -4374,6 +4384,7 @@ sub git_heads { } sub git_blob_plain { + my $type = shift; my $expires; if (!defined $hash) { @@ -4389,13 +4400,13 @@ sub git_blob_plain { $expires = "+1d"; } - my $type = shift; open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash - or die_error(undef, "Couldn't cat $file_name, $hash"); + or die_error(undef, "Open git-cat-file blob '$hash' failed"); - $type ||= blob_mimetype($fd, $file_name); + # content-type (can include charset) + $type = blob_contenttype($fd, $file_name, $type); - # save as filename, even when no $file_name is given + # "save as" filename, even when no $file_name is given my $save_as = "$hash"; if (defined $file_name) { $save_as = $file_name; @@ -4404,9 +4415,9 @@ sub git_blob_plain { } print $cgi->header( - -type => "$type", - -expires=>$expires, - -content_disposition => 'inline; filename="' . "$save_as" . '"'); + -type => $type, + -expires => $expires, + -content_disposition => 'inline; filename="' . $save_as . '"'); undef $/; binmode STDOUT, ':raw'; print <$fd>; -- cgit v1.3 From 3a5b919cf220651b681b5f036bf3bd1c61e36ef2 Mon Sep 17 00:00:00 2001 From: Rafael Garcia-Suarez Date: Fri, 6 Jun 2008 09:53:32 +0200 Subject: gitweb: remove git_blame and rename git_blame2 to git_blame git_blame is dead code. It's possible to plug it in place of git_blame2, but I don't know whether anyone does still that, because git_blame2 can now be considered stable enough, I think. Signed-off-by: Rafael Garcia-Suarez Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 101 ++--------------------------------------------------- 1 file changed, 2 insertions(+), 99 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 198772c210..8d1f3e0547 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -539,7 +539,7 @@ $git_dir = "$projectroot/$project" if $project; # dispatch my %actions = ( - "blame" => \&git_blame2, + "blame" => \&git_blame, "blobdiff" => \&git_blobdiff, "blobdiff_plain" => \&git_blobdiff_plain, "blob" => \&git_blob, @@ -4152,7 +4152,7 @@ sub git_tag { git_footer_html(); } -sub git_blame2 { +sub git_blame { my $fd; my $ftype; @@ -4260,103 +4260,6 @@ HTML git_footer_html(); } -sub git_blame { - my $fd; - - my ($have_blame) = gitweb_check_feature('blame'); - if (!$have_blame) { - die_error('403 Permission denied', "Permission denied"); - } - die_error('404 Not Found', "File name not defined") if (!$file_name); - $hash_base ||= git_get_head_hash($project); - die_error(undef, "Couldn't find base commit") unless ($hash_base); - my %co = parse_commit($hash_base) - or die_error(undef, "Reading commit failed"); - if (!defined $hash) { - $hash = git_get_hash_by_path($hash_base, $file_name, "blob") - or die_error(undef, "Error lookup file"); - } - open ($fd, "-|", git_cmd(), "annotate", '-l', '-t', '-r', $file_name, $hash_base) - or die_error(undef, "Open git-annotate failed"); - git_header_html(); - my $formats_nav = - $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, - "blob") . - " | " . - $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, - "history") . - " | " . - $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, - "HEAD"); - git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); - git_print_header_div('commit', esc_html($co{'title'}), $hash_base); - git_print_page_path($file_name, 'blob', $hash_base); - print "
\n"; - print < - - Commit - Age - Author - Line - Data - -HTML - my @line_class = (qw(light dark)); - my $line_class_len = scalar (@line_class); - my $line_class_num = $#line_class; - while (my $line = <$fd>) { - my $long_rev; - my $short_rev; - my $author; - my $time; - my $lineno; - my $data; - my $age; - my $age_str; - my $age_class; - - chomp $line; - $line_class_num = ($line_class_num + 1) % $line_class_len; - - if ($line =~ m/^([0-9a-fA-F]{40})\t\(\s*([^\t]+)\t(\d+) [+-]\d\d\d\d\t(\d+)\)(.*)$/) { - $long_rev = $1; - $author = $2; - $time = $3; - $lineno = $4; - $data = $5; - } else { - print qq( Unable to parse: $line\n); - next; - } - $short_rev = substr ($long_rev, 0, 8); - $age = time () - $time; - $age_str = age_string ($age); - $age_str =~ s/ / /g; - $age_class = age_class($age); - $author = esc_html ($author); - $author =~ s/ / /g; - - $data = untabify($data); - $data = esc_html ($data); - - print < - $long_rev)}" class="text">$short_rev.. - $age_str - $author - $lineno - $data - -HTML - } # while (my $line = <$fd>) - print "\n\n"; - close $fd - or print "Reading blob failed.\n"; - print "
"; - git_footer_html(); -} - sub git_tags { my $head = git_get_head_hash($project); git_header_html(); -- cgit v1.3 From 69913415655839b3add5d930ebbea1be8a5b60a9 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 10 Jun 2008 19:21:01 +0200 Subject: gitweb: Separate filling list of projects info Extract filling project list info, i.e. adding age, description, owner and forks information, into fill_project_list_info() subroutine. This is preparation for smart pagination and smart searching (to make it possible to calculate/generate info only for those projects which will be shown). Small changes compared to original version to improve readability (comments, names of variables, named loops). Additionally, store both full ('descr_long') and shortened ('descr') project description in Perl's internal form (using to_utf8). Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 198772c210..d7a9809027 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3559,21 +3559,24 @@ sub git_patchset_body { # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -sub git_project_list_body { - my ($projlist, $order, $from, $to, $extra, $no_header) = @_; - - my ($check_forks) = gitweb_check_feature('forks'); - +# fills project list info (age, description, owner, forks) for each +# project in the list, removing invalid projects from returned list +# NOTE: modifies $projlist, but does not remove entries from it +sub fill_project_list_info { + my ($projlist, $check_forks) = @_; my @projects; + + PROJECT: foreach my $pr (@$projlist) { - my (@aa) = git_get_last_activity($pr->{'path'}); - unless (@aa) { - next; + my (@activity) = git_get_last_activity($pr->{'path'}); + unless (@activity) { + next PROJECT; } - ($pr->{'age'}, $pr->{'age_string'}) = @aa; + ($pr->{'age'}, $pr->{'age_string'}) = @activity; if (!defined $pr->{'descr'}) { my $descr = git_get_project_description($pr->{'path'}) || ""; - $pr->{'descr_long'} = to_utf8($descr); + $descr = to_utf8($descr); + $pr->{'descr_long'} = $descr; $pr->{'descr'} = chop_str($descr, $projects_list_description_width, 5); } if (!defined $pr->{'owner'}) { @@ -3585,14 +3588,22 @@ sub git_project_list_body { ($pname !~ /\/$/) && (-d "$projectroot/$pname")) { $pr->{'forks'} = "-d $projectroot/$pname"; - } - else { + } else { $pr->{'forks'} = 0; } } push @projects, $pr; } + return @projects; +} + +sub git_project_list_body { + my ($projlist, $order, $from, $to, $extra, $no_header) = @_; + + my ($check_forks) = gitweb_check_feature('forks'); + my @projects = fill_project_list_info($projlist, $check_forks); + $order ||= $default_projects_order; $from = 0 unless defined $from; $to = $#projects if (!defined $to || $#projects < $to); -- cgit v1.3 From 7da0f3a46daac50782a71e8a6eb12355d49c419d Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 10 Jun 2008 19:21:44 +0200 Subject: gitweb: Separate generating 'sort by' table header Extract generating table header cell, for tables which can be sorted by its columns, into print_sort_th_str() and print_sort_th_num() subroutines, and print_sort_th() driver subroutine. This avoids repetition, and should make further improvements (like JavaScript sorting) easier. The subroutine uses now "replay" link, so it is generic enough to be able to use it for other tables which can be sorted by column, like for example 'heads' and 'tags' view (sort by name, or sort by age). Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 76 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 37 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index d7a9809027..c7882f24f7 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3598,6 +3598,36 @@ sub fill_project_list_info { return @projects; } +# print 'sort by' element, either sorting by $key if $name eq $order +# (changing $list), or generating 'sort by $name' replay link otherwise +sub print_sort_th { + my ($str_sort, $name, $order, $key, $header, $list) = @_; + $key ||= $name; + $header ||= ucfirst($name); + + if ($order eq $name) { + if ($str_sort) { + @$list = sort {$a->{$key} cmp $b->{$key}} @$list; + } else { + @$list = sort {$a->{$key} <=> $b->{$key}} @$list; + } + print "$header\n"; + } else { + print "" . + $cgi->a({-href => href(-replay=>1, order=>$name), + -class => "header"}, $header) . + "\n"; + } +} + +sub print_sort_th_str { + print_sort_th(1, @_); +} + +sub print_sort_th_num { + print_sort_th(0, @_); +} + sub git_project_list_body { my ($projlist, $order, $from, $to, $extra, $no_header) = @_; @@ -3614,43 +3644,15 @@ sub git_project_list_body { if ($check_forks) { print "\n"; } - if ($order eq "project") { - @projects = sort {$a->{'path'} cmp $b->{'path'}} @projects; - print "Project\n"; - } else { - print "" . - $cgi->a({-href => href(project=>undef, order=>'project'), - -class => "header"}, "Project") . - "\n"; - } - if ($order eq "descr") { - @projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects; - print "Description\n"; - } else { - print "" . - $cgi->a({-href => href(project=>undef, order=>'descr'), - -class => "header"}, "Description") . - "\n"; - } - if ($order eq "owner") { - @projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects; - print "Owner\n"; - } else { - print "" . - $cgi->a({-href => href(project=>undef, order=>'owner'), - -class => "header"}, "Owner") . - "\n"; - } - if ($order eq "age") { - @projects = sort {$a->{'age'} <=> $b->{'age'}} @projects; - print "Last Change\n"; - } else { - print "" . - $cgi->a({-href => href(project=>undef, order=>'age'), - -class => "header"}, "Last Change") . - "\n"; - } - print "\n" . + print_sort_th_str('project', $order, 'path', + 'Project', \@projects); + print_sort_th_str('descr', $order, 'descr_long', + 'Description', \@projects); + print_sort_th_str('owner', $order, 'owner', + 'Owner', \@projects); + print_sort_th_num('age', $order, 'age', + 'Last Change', \@projects); + print "\n" . # for links "\n"; } my $alternate = 1; -- cgit v1.3 From 66115d363a93b9e7c9b937773c0c30f81b766d45 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 14 Jun 2008 20:37:59 +0200 Subject: gitweb: Make it work with $GIT containing spaces This fixes single point where $GIT (which can contain full path to git binary) with embedded spaces gave errors. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 198772c210..4de964792f 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -377,7 +377,7 @@ if (-e $GITWEB_CONFIG) { } # version of the core git binary -our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown"; +our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown"; $projects_list ||= $projectroot; -- cgit v1.3 From 516381d50ba7acb66f260461f4d566ab9b6df107 Mon Sep 17 00:00:00 2001 From: Lea Wiemann Date: Tue, 17 Jun 2008 23:46:35 +0200 Subject: gitweb: quote commands properly when calling the shell This eliminates the function git_cmd_str, which was used for composing command lines, and adds a quote_command function, which quotes all of its arguments (as in quote.c). Signed-off-by: Lea Wiemann Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 4de964792f..d7ee2673cb 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1500,9 +1500,13 @@ sub git_cmd { return $GIT, '--git-dir='.$git_dir; } -# returns path to the core git executable and the --git-dir parameter as string -sub git_cmd_str { - return join(' ', git_cmd()); +# quote the given arguments for passing them to the shell +# quote_command("command", "arg 1", "arg with ' and ! characters") +# => "'command' 'arg 1' 'arg with '\'' and '\!' characters'" +# Try to avoid using this function wherever possible. +sub quote_command { + return join(' ', + map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ )); } # get HEAD ref of given project as hash @@ -4633,7 +4637,6 @@ sub git_snapshot { $hash = git_get_head_hash($project); } - my $git_command = git_cmd_str(); my $name = $project; $name =~ s,([^/])/*\.git$,$1,; $name = basename($name); @@ -4641,11 +4644,12 @@ sub git_snapshot { $name =~ s/\047/\047\\\047\047/g; my $cmd; $filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}"; - $cmd = "$git_command archive " . - "--format=$known_snapshot_formats{$format}{'format'} " . - "--prefix=\'$name\'/ $hash"; + $cmd = quote_command( + git_cmd(), 'archive', + "--format=$known_snapshot_formats{$format}{'format'}", + "--prefix=$name/", $hash); if (exists $known_snapshot_formats{$format}{'compressor'}) { - $cmd .= ' | ' . join ' ', @{$known_snapshot_formats{$format}{'compressor'}}; + $cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}}); } print $cgi->header( @@ -4858,8 +4862,8 @@ sub git_object { if ($hash || ($hash_base && !defined $file_name)) { my $object_id = $hash || $hash_base; - my $git_command = git_cmd_str(); - open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null" + open my $fd, "-|", quote_command( + git_cmd(), 'cat-file', '-t', $object_id) . ' 2> /dev/null' or die_error('404 Not Found', "Object does not exist"); $type = <$fd>; chomp $type; -- cgit v1.3 From 61fb0b75d138032c7600fe86640897b900f2fd4f Mon Sep 17 00:00:00 2001 From: Lea Wiemann Date: Tue, 17 Jun 2008 08:25:28 +0200 Subject: gitweb: remove unused parse_ref method The parse_ref method became unused in cd1464083c, but the author decided to leave it in. Now it gets in the way of refactoring, so let's remove it. Signed-off-by: Lea Wiemann Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 43 ------------------------------------------- 1 file changed, 43 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index d7ee2673cb..49b01d8c25 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2162,49 +2162,6 @@ sub parse_commits { return wantarray ? @cos : \@cos; } -# parse ref from ref_file, given by ref_id, with given type -sub parse_ref { - my $ref_file = shift; - my $ref_id = shift; - my $type = shift || git_get_type($ref_id); - my %ref_item; - - $ref_item{'type'} = $type; - $ref_item{'id'} = $ref_id; - $ref_item{'epoch'} = 0; - $ref_item{'age'} = "unknown"; - if ($type eq "tag") { - my %tag = parse_tag($ref_id); - $ref_item{'comment'} = $tag{'comment'}; - if ($tag{'type'} eq "commit") { - my %co = parse_commit($tag{'object'}); - $ref_item{'epoch'} = $co{'committer_epoch'}; - $ref_item{'age'} = $co{'age_string'}; - } elsif (defined($tag{'epoch'})) { - my $age = time - $tag{'epoch'}; - $ref_item{'epoch'} = $tag{'epoch'}; - $ref_item{'age'} = age_string($age); - } - $ref_item{'reftype'} = $tag{'type'}; - $ref_item{'name'} = $tag{'name'}; - $ref_item{'refid'} = $tag{'object'}; - } elsif ($type eq "commit"){ - my %co = parse_commit($ref_id); - $ref_item{'reftype'} = "commit"; - $ref_item{'name'} = $ref_file; - $ref_item{'title'} = $co{'title'}; - $ref_item{'refid'} = $ref_id; - $ref_item{'epoch'} = $co{'committer_epoch'}; - $ref_item{'age'} = $co{'age_string'}; - } else { - $ref_item{'reftype'} = $type; - $ref_item{'name'} = $ref_file; - $ref_item{'refid'} = $ref_id; - } - - return %ref_item; -} - # parse line of git-diff-tree "raw" output sub parse_difftree_raw_line { my $line = shift; -- cgit v1.3 From 074afaa0cf69e7d49bc00d969f57893c9ddea748 Mon Sep 17 00:00:00 2001 From: Lea Wiemann Date: Thu, 19 Jun 2008 22:03:21 +0200 Subject: gitweb: standarize HTTP status codes Many error status codes simply default to 403 Forbidden, which is not correct in most cases. This patch makes gitweb return semantically correct status codes. For convenience the die_error function now only takes the status code without reason as first parameter (e.g. 404 instead of "404 Not Found"), and it now defaults to 500 (Internal Server Error), even though the default is not used anywhere. Also documented status code conventions in die_error. Signed-off-by: Lea Wiemann Acked-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 211 ++++++++++++++++++++++++++--------------------------- 1 file changed, 105 insertions(+), 106 deletions(-) (limited to 'gitweb/gitweb.perl') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 49b01d8c25..5351da2c11 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -386,7 +386,7 @@ $projects_list ||= $projectroot; our $action = $cgi->param('a'); if (defined $action) { if ($action =~ m/[^0-9a-zA-Z\.\-_]/) { - die_error(undef, "Invalid action parameter"); + die_error(400, "Invalid action parameter"); } } @@ -399,21 +399,21 @@ if (defined $project) { ($export_ok && !(-e "$projectroot/$project/$export_ok")) || ($strict_export && !project_in_list($project))) { undef $project; - die_error(undef, "No such project"); + die_error(404, "No such project"); } } our $file_name = $cgi->param('f'); if (defined $file_name) { if (!validate_pathname($file_name)) { - die_error(undef, "Invalid file parameter"); + die_error(400, "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"); + die_error(400, "Invalid file parent parameter"); } } @@ -421,21 +421,21 @@ if (defined $file_parent) { our $hash = $cgi->param('h'); if (defined $hash) { if (!validate_refname($hash)) { - die_error(undef, "Invalid hash parameter"); + die_error(400, "Invalid hash parameter"); } } our $hash_parent = $cgi->param('hp'); if (defined $hash_parent) { if (!validate_refname($hash_parent)) { - die_error(undef, "Invalid hash parent parameter"); + die_error(400, "Invalid hash parent parameter"); } } our $hash_base = $cgi->param('hb'); if (defined $hash_base) { if (!validate_refname($hash_base)) { - die_error(undef, "Invalid hash base parameter"); + die_error(400, "Invalid hash base parameter"); } } @@ -447,10 +447,10 @@ our @extra_options = $cgi->param('opt'); if (defined @extra_options) { foreach my $opt (@extra_options) { if (not exists $allowed_options{$opt}) { - die_error(undef, "Invalid option parameter"); + die_error(400, "Invalid option parameter"); } if (not grep(/^$action$/, @{$allowed_options{$opt}})) { - die_error(undef, "Invalid option parameter for this action"); + die_error(400, "Invalid option parameter for this action"); } } } @@ -458,7 +458,7 @@ if (defined @extra_options) { our $hash_parent_base = $cgi->param('hpb'); if (defined $hash_parent_base) { if (!validate_refname($hash_parent_base)) { - die_error(undef, "Invalid hash parent base parameter"); + die_error(400, "Invalid hash parent base parameter"); } } @@ -466,14 +466,14 @@ if (defined $hash_parent_base) { our $page = $cgi->param('pg'); if (defined $page) { if ($page =~ m/[^0-9]/) { - die_error(undef, "Invalid page parameter"); + die_error(400, "Invalid page parameter"); } } our $searchtype = $cgi->param('st'); if (defined $searchtype) { if ($searchtype =~ m/[^a-z]/) { - die_error(undef, "Invalid searchtype parameter"); + die_error(400, "Invalid searchtype parameter"); } } @@ -483,7 +483,7 @@ our $searchtext = $cgi->param('s'); our $search_regexp; if (defined $searchtext) { if (length($searchtext) < 2) { - die_error(undef, "At least two characters are required for search parameter"); + die_error(403, "At least two characters are required for search parameter"); } $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext; } @@ -580,11 +580,11 @@ if (!defined $action) { } } if (!defined($actions{$action})) { - die_error(undef, "Unknown action"); + die_error(400, "Unknown action"); } if ($action !~ m/^(opml|project_list|project_index)$/ && !$project) { - die_error(undef, "Project needed"); + die_error(400, "Project needed"); } $actions{$action}->(); exit; @@ -1665,7 +1665,7 @@ sub git_get_hash_by_path { $path =~ s,/+$,,; open my $fd, "-|", git_cmd(), "ls-tree", $base, "--", $path - or die_error(undef, "Open git-ls-tree failed"); + or die_error(500, "Open git-ls-tree failed"); my $line = <$fd>; close $fd or return undef; @@ -2127,7 +2127,7 @@ sub parse_commit { "--max-count=1", $commit_id, "--", - or die_error(undef, "Open git-rev-list failed"); + or die_error(500, "Open git-rev-list failed"); %co = parse_commit_text(<$fd>, 1); close $fd; @@ -2152,7 +2152,7 @@ sub parse_commits { $commit_id, "--", ($filename ? ($filename) : ()) - or die_error(undef, "Open git-rev-list failed"); + or die_error(500, "Open git-rev-list failed"); while (my $line = <$fd>) { my %co = parse_commit_text($line); push @cos, \%co; @@ -2672,11 +2672,26 @@ sub git_footer_html { ""; } +# die_error(, ) +# Example: die_error(404, 'Hash not found') +# By convention, use the following status codes (as defined in RFC 2616): +# 400: Invalid or missing CGI parameters, or +# requested object exists but has wrong type. +# 403: Requested feature (like "pickaxe" or "snapshot") not enabled on +# this server or project. +# 404: Requested object/revision/project doesn't exist. +# 500: The server isn't configured properly, or +# an internal error occurred (e.g. failed assertions caused by bugs), or +# an unknown error occurred (e.g. the git binary died unexpectedly). sub die_error { - my $status = shift || "403 Forbidden"; - my $error = shift || "Malformed query, file missing or permission denied"; - - git_header_html($status); + my $status = shift || 500; + my $error = shift || "Internal server error"; + + my %http_responses = (400 => '400 Bad Request', + 403 => '403 Forbidden', + 404 => '404 Not Found', + 500 => '500 Internal Server Error'); + git_header_html($http_responses{$status}); print <

@@ -3924,12 +3939,12 @@ sub git_search_grep_body { sub git_project_list { my $order = $cgi->param('o'); if (defined $order && $order !~ m/none|project|descr|owner|age/) { - die_error(undef, "Unknown order parameter"); + die_error(400, "Unknown order parameter"); } my @list = git_get_projects_list(); if (!@list) { - die_error(undef, "No projects found"); + die_error(404, "No projects found"); } git_header_html(); @@ -3947,12 +3962,12 @@ sub git_project_list { sub git_forks { my $order = $cgi->param('o'); if (defined $order && $order !~ m/none|project|descr|owner|age/) { - die_error(undef, "Unknown order parameter"); + die_error(400, "Unknown order parameter"); } my @list = git_get_projects_list($project); if (!@list) { - die_error(undef, "No forks found"); + die_error(404, "No forks found"); } git_header_html(); @@ -4081,7 +4096,7 @@ sub git_tag { my %tag = parse_tag($hash); if (! %tag) { - die_error(undef, "Unknown tag object"); + die_error(404, "Unknown tag object"); } git_print_header_div('commit', esc_html($tag{'name'}), $hash); @@ -4117,26 +4132,25 @@ sub git_blame2 { my $fd; my $ftype; - my ($have_blame) = gitweb_check_feature('blame'); - if (!$have_blame) { - die_error('403 Permission denied', "Permission denied"); - } - die_error('404 Not Found', "File name not defined") if (!$file_name); + gitweb_check_feature('blame') + or die_error(403, "Blame view not allowed"); + + die_error(400, "No file name given") unless $file_name; $hash_base ||= git_get_head_hash($project); - die_error(undef, "Couldn't find base commit") unless ($hash_base); + die_error(404, "Couldn't find base commit") unless ($hash_base); my %co = parse_commit($hash_base) - or die_error(undef, "Reading commit failed"); + or die_error(404, "Commit not found"); if (!defined $hash) { $hash = git_get_hash_by_path($hash_base, $file_name, "blob") - or die_error(undef, "Error looking up file"); + or die_error(404, "Error looking up file"); } $ftype = git_get_type($hash); if ($ftype !~ "blob") { - die_error('400 Bad Request', "Object is not a blob"); + die_error(400, "Object is not a blob"); } open ($fd, "-|", git_cmd(), "blame", '-p', '--', $file_name, $hash_base) - or die_error(undef, "Open git-blame failed"); + or die_error(500, "Open git-blame failed"); git_header_html(); my $formats_nav = $cgi->a({-href => href(action=>"blob", -replay=>1)}, @@ -4198,7 +4212,7 @@ HTML print "\n"; } open (my $dd, "-|", git_cmd(), "rev-parse", "$full_rev^") - or die_error(undef, "Open git-rev-parse failed"); + or die_error(500, "Open git-rev-parse failed"); my $parent_commit = <$dd>; close $dd; chomp($parent_commit); @@ -4352,9 +4366,9 @@ sub git_blob_plain { if (defined $file_name) { my $base = $hash_base || git_get_head_hash($project); $hash = git_get_hash_by_path($base, $file_name, "blob") - or die_error(undef, "Error lookup file"); + or die_error(404, "Cannot find file"); } else { - die_error(undef, "No file name defined"); + die_error(400, "No file name defined"); } } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) { # blobs defined by non-textual hash id's can be cached @@ -4362,7 +4376,7 @@ sub git_blob_plain { } open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash - or die_error(undef, "Open git-cat-file blob '$hash' failed"); + or die_error(500, "Open git-cat-file blob '$hash' failed"); # content-type (can include charset) $type = blob_contenttype($fd, $file_name, $type); @@ -4394,9 +4408,9 @@ sub git_blob { if (defined $file_name) { my $base = $hash_base || git_get_head_hash($project); $hash = git_get_hash_by_path($base, $file_name, "blob") - or die_error(undef, "Error lookup file"); + or die_error(404, "Cannot find file"); } else { - die_error(undef, "No file name defined"); + die_error(400, "No file name defined"); } } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) { # blobs defined by non-textual hash id's can be cached @@ -4405,7 +4419,7 @@ sub git_blob { my ($have_blame) = gitweb_check_feature('blame'); open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash - or die_error(undef, "Couldn't cat $file_name, $hash"); + or die_error(500, "Couldn't cat $file_name, $hash"); my $mimetype = blob_mimetype($fd, $file_name); if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)! && -B $fd) { close $fd; @@ -4486,9 +4500,9 @@ sub git_tree { } $/ = "\0"; open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash - or die_error(undef, "Open git-ls-tree failed"); + or die_error(500, "Open git-ls-tree failed"); my @entries = map { chomp; $_ } <$fd>; - close $fd or die_error(undef, "Reading tree failed"); + close $fd or die_error(404, "Reading tree failed"); $/ = "\n"; my $refs = git_get_references(); @@ -4578,16 +4592,16 @@ sub git_snapshot { my $format = $cgi->param('sf'); if (!@supported_fmts) { - die_error('403 Permission denied', "Permission denied"); + die_error(403, "Snapshots not allowed"); } # default to first supported snapshot format $format ||= $supported_fmts[0]; if ($format !~ m/^[a-z0-9]+$/) { - die_error(undef, "Invalid snapshot format parameter"); + die_error(400, "Invalid snapshot format parameter"); } elsif (!exists($known_snapshot_formats{$format})) { - die_error(undef, "Unknown snapshot format"); + die_error(400, "Unknown snapshot format"); } elsif (!grep($_ eq $format, @supported_fmts)) { - die_error(undef, "Unsupported snapshot format"); + die_error(403, "Unsupported snapshot format"); } if (!defined $hash) { @@ -4615,7 +4629,7 @@ sub git_snapshot { -status => '200 OK'); open my $fd, "-|", $cmd - or die_error(undef, "Execute git-archive failed"); + or die_error(500, "Execute git-archive failed"); binmode STDOUT, ':raw'; print <$fd>; binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi @@ -4683,10 +4697,8 @@ sub git_log { sub git_commit { $hash ||= $hash_base || "HEAD"; - my %co = parse_commit($hash); - if (!%co) { - die_error(undef, "Unknown commit object"); - } + my %co = parse_commit($hash) + or die_error(404, "Unknown commit object"); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'}); @@ -4726,9 +4738,9 @@ sub git_commit { @diff_opts, (@$parents <= 1 ? $parent : '-c'), $hash, "--" - or die_error(undef, "Open git-diff-tree failed"); + or die_error(500, "Open git-diff-tree failed"); @difftree = map { chomp; $_ } <$fd>; - close $fd or die_error(undef, "Reading git-diff-tree failed"); + close $fd or die_error(404, "Reading git-diff-tree failed"); # non-textual hash id's can be cached my $expires; @@ -4821,33 +4833,33 @@ sub git_object { open my $fd, "-|", quote_command( git_cmd(), 'cat-file', '-t', $object_id) . ' 2> /dev/null' - or die_error('404 Not Found', "Object does not exist"); + or die_error(404, "Object does not exist"); $type = <$fd>; chomp $type; close $fd - or die_error('404 Not Found', "Object does not exist"); + or die_error(404, "Object does not exist"); # - hash_base and file_name } elsif ($hash_base && defined $file_name) { $file_name =~ s,/+$,,; system(git_cmd(), "cat-file", '-e', $hash_base) == 0 - or die_error('404 Not Found', "Base object does not exist"); + or die_error(404, "Base object does not exist"); # here errors should not hapen open my $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $file_name - or die_error(undef, "Open git-ls-tree failed"); + or die_error(500, "Open git-ls-tree failed"); my $line = <$fd>; close $fd; #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' unless ($line && $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/) { - die_error('404 Not Found', "File or directory for given base does not exist"); + die_error(404, "File or directory for given base does not exist"); } $type = $2; $hash = $3; } else { - die_error('404 Not Found', "Not enough information to find object"); + die_error(400, "Not enough information to find object"); } print $cgi->redirect(-uri => href(action=>$type, -full=>1, @@ -4872,12 +4884,12 @@ sub git_blobdiff { open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base, "--", (defined $file_parent ? $file_parent : ()), $file_name - or die_error(undef, "Open git-diff-tree failed"); + or die_error(500, "Open git-diff-tree failed"); @difftree = map { chomp; $_ } <$fd>; close $fd - or die_error(undef, "Reading git-diff-tree failed"); + or die_error(404, "Reading git-diff-tree failed"); @difftree - or die_error('404 Not Found', "Blob diff not found"); + or die_error(404, "Blob diff not found"); } elsif (defined $hash && $hash =~ /[0-9a-fA-F]{40}/) { @@ -4886,23 +4898,23 @@ sub git_blobdiff { # read filtered raw output open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base, "--" - or die_error(undef, "Open git-diff-tree failed"); + or die_error(500, "Open git-diff-tree failed"); @difftree = # ':100644 100644 03b21826... 3b93d5e7... M ls-files.c' # $hash == to_id grep { /^:[0-7]{6} [0-7]{6} [0-9a-fA-F]{40} $hash/ } map { chomp; $_ } <$fd>; close $fd - or die_error(undef, "Reading git-diff-tree failed"); + or die_error(404, "Reading git-diff-tree failed"); @difftree - or die_error('404 Not Found', "Blob diff not found"); + or die_error(404, "Blob diff not found"); } else { - die_error('404 Not Found', "Missing one of the blob diff parameters"); + die_error(400, "Missing one of the blob diff parameters"); } if (@difftree > 1) { - die_error('404 Not Found', "Ambiguous blob diff specification"); + die_error(400, "Ambiguous blob diff specification"); } %diffinfo = parse_difftree_raw_line($difftree[0]); @@ -4923,7 +4935,7 @@ sub git_blobdiff { '-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"); + or die_error(500, "Open git-diff-tree failed"); } # old/legacy style URI @@ -4959,9 +4971,9 @@ sub git_blobdiff { open $fd, "-|", git_cmd(), "diff", @diff_opts, '-p', ($format eq 'html' ? "--full-index" : ()), $hash_parent, $hash, "--" - or die_error(undef, "Open git-diff failed"); + or die_error(500, "Open git-diff failed"); } else { - die_error('404 Not Found', "Missing one of the blob diff parameters") + die_error(400, "Missing one of the blob diff parameters") unless %diffinfo; } @@ -4994,7 +5006,7 @@ sub git_blobdiff { print "X-Git-Url: " . $cgi->self_url() . "\n\n"; } else { - die_error(undef, "Unknown blobdiff format"); + die_error(400, "Unknown blobdiff format"); } # patch @@ -5029,10 +5041,8 @@ sub git_blobdiff_plain { sub git_commitdiff { my $format = shift || 'html'; $hash ||= $hash_base || "HEAD"; - my %co = parse_commit($hash); - if (!%co) { - die_error(undef, "Unknown commit object"); - } + my %co = parse_commit($hash) + or die_error(404, "Unknown commit object"); # choose format for commitdiff for merge if (! defined $hash_parent && @{$co{'parents'}} > 1) { @@ -5114,7 +5124,7 @@ sub git_commitdiff { open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, "--no-commit-id", "--patch-with-raw", "--full-index", $hash_parent_param, $hash, "--" - or die_error(undef, "Open git-diff-tree failed"); + or die_error(500, "Open git-diff-tree failed"); while (my $line = <$fd>) { chomp $line; @@ -5126,10 +5136,10 @@ sub git_commitdiff { } elsif ($format eq 'plain') { open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, '-p', $hash_parent_param, $hash, "--" - or die_error(undef, "Open git-diff-tree failed"); + or die_error(500, "Open git-diff-tree failed"); } else { - die_error(undef, "Unknown commitdiff format"); + die_error(400, "Unknown commitdiff format"); } # non-textual hash id's can be cached @@ -5212,19 +5222,15 @@ sub git_history { $page = 0; } my $ftype; - my %co = parse_commit($hash_base); - if (!%co) { - die_error(undef, "Unknown commit object"); - } + my %co = parse_commit($hash_base) + or die_error(404, "Unknown commit object"); my $refs = git_get_references(); my $limit = sprintf("--max-count=%i", (100 * ($page+1))); my @commitlist = parse_commits($hash_base, 101, (100 * $page), - $file_name, "--full-history"); - if (!@commitlist) { - die_error('404 Not Found', "No such file or directory on given branch"); - } + $file_name, "--full-history") + or die_error(404, "No such file or directory on given branch"); if (!defined $hash && defined $file_name) { # some commits could have deleted file in question, @@ -5238,7 +5244,7 @@ sub git_history { $ftype = git_get_type($hash); } if (!defined $ftype) { - die_error(undef, "Unknown type of object"); + die_error(500, "Unknown type of object"); } my $paging_nav = ''; @@ -5276,19 +5282,16 @@ sub git_history { } sub git_search { - my ($have_search) = gitweb_check_feature('search'); - if (!$have_search) { - die_error('403 Permission denied', "Permission denied"); - } + gitweb_check_feature('search') or die_error(403, "Search is disabled"); if (!defined $searchtext) { - die_error(undef, "Text field empty"); + die_error(400, "Text field is empty"); } if (!defined $hash) { $hash = git_get_head_hash($project); } my %co = parse_commit($hash); if (!%co) { - die_error(undef, "Unknown commit object"); + die_error(404, "Unknown commit object"); } if (!defined $page) { $page = 0; @@ -5298,16 +5301,12 @@ sub git_search { if ($searchtype eq 'pickaxe') { # pickaxe may take all resources of your box and run for several minutes # with every query - so decide by yourself how public you make this feature - my ($have_pickaxe) = gitweb_check_feature('pickaxe'); - if (!$have_pickaxe) { - die_error('403 Permission denied', "Permission denied"); - } + gitweb_check_feature('pickaxe') + or die_error(403, "Pickaxe is disabled"); } if ($searchtype eq 'grep') { - my ($have_grep) = gitweb_check_feature('grep'); - if (!$have_grep) { - die_error('403 Permission denied', "Permission denied"); - } + gitweb_check_feature('grep') + or die_error(403, "Grep is disabled"); } git_header_html(); @@ -5581,7 +5580,7 @@ sub git_feed { # Atom: http://www.atomenabled.org/developers/syndication/ # RSS: http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ if ($format ne 'rss' && $format ne 'atom') { - die_error(undef, "Unknown web feed format"); + die_error(400, "Unknown web feed format"); } # log/feed of current (HEAD) branch, log of given branch, history of file/directory -- cgit v1.3