X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/642fbafd9a631157f11947752c41c3b98d46a4fece7a7c2a7e8a66d3c03ee601..3425bbdec70034ac0d88f89e3c38b4bd6cbcf9450123257ecc7476ffd999ec29:/gitweb.cgi diff --git a/gitweb.cgi b/gitweb.cgi index 42f15d1..3dd7eb1 100755 --- a/gitweb.cgi +++ b/gitweb.cgi @@ -2,8 +2,8 @@ # gitweb - simple web interface to track changes in git repositories # -# (C) 2005, Kay Sievers -# (C) 2005, Christian Gierke +# (C) 2005-2006, Kay Sievers +# (C) 2005, Christian Gierke # # This program is licensed under the GPLv2 @@ -17,7 +17,7 @@ use Fcntl ':mode'; binmode STDOUT, ':utf8'; my $cgi = new CGI; -my $version = "261"; +my $version = "267"; my $my_url = $cgi->url(); my $my_uri = $cgi->url(-absolute => 1); my $rss_link = ""; @@ -203,6 +203,9 @@ if (!defined $action || $action eq "summary") { } elsif ($action eq "tag") { git_tag(); exit; +} elsif ($action eq "blame") { + git_blame(); + exit; } else { undef $action; die_error(undef, "Unknown action."); @@ -253,7 +256,7 @@ sub git_header_html { - + @@ -396,6 +399,24 @@ sub git_get_type { return $type; } +sub git_read_head { + my $project = shift; + my $oENV = $ENV{'GIT_DIR'}; + my $retval = undef; + $ENV{'GIT_DIR'} = "$projectroot/$project"; + if (open my $fd, "-|", "$gitbin/git-rev-parse", "--verify", "HEAD") { + my $head = <$fd>; + close $fd; + if (defined $head && $head =~ /^([0-9a-fA-F]{40})$/) { + $retval = $1; + } + } + if (defined $oENV) { + $ENV{'GIT_DIR'} = $oENV; + } + return $retval; +} + sub git_read_hash { my $path = shift; @@ -769,7 +790,7 @@ sub get_file_owner { } my $owner = $gcos; $owner =~ s/[,;].*$//; - return $owner; + return decode("utf8", $owner, Encode::FB_DEFAULT); } sub git_read_projects { @@ -805,7 +826,7 @@ sub git_read_projects { if (-e "$projectroot/$path/HEAD") { my $pr = { path => $path, - owner => $owner, + owner => decode("utf8", $owner, Encode::FB_DEFAULT), }; push @list, $pr } @@ -816,6 +837,25 @@ sub git_read_projects { return @list; } +sub git_get_project_config { + my $key = shift; + + return unless ($key); + $key =~ s/^gitweb\.//; + return if ($key =~ m/\W/); + + my $val = qx(git-repo-config --get gitweb.$key); + return ($val); +} + +sub git_get_project_config_bool { + my $val = git_get_project_config (@_); + if ($val and $val =~ m/true|yes|on/) { + return (1); + } + return; # implicit false +} + sub git_project_list { my @list = git_read_projects(); my @projects; @@ -823,7 +863,7 @@ sub git_project_list { die_error(undef, "No project found."); } foreach my $pr (@list) { - my $head = git_read_hash("$pr->{'path'}/HEAD"); + my $head = git_read_head($pr->{'path'}); if (!defined $head) { next; } @@ -994,7 +1034,7 @@ sub git_read_refs { sub git_summary { my $descr = git_read_description($project) || "none"; - my $head = git_read_hash("$project/HEAD"); + my $head = git_read_head($project); my %co = git_read_commit($head); my %cd = date_str($co{'committer_epoch'}, $co{'committer_tz'}); @@ -1007,7 +1047,7 @@ sub git_summary { $pr = unescape($pr); $ow = unescape($ow); if ($pr eq $project) { - $owner = $ow; + $owner = decode("utf8", $ow, Encode::FB_DEFAULT); last; } } @@ -1034,7 +1074,7 @@ sub git_summary { "owner$owner\n" . "last change$cd{'rfc2822'}\n" . "\n"; - open my $fd, "-|", "$gitbin/git-rev-list --max-count=17 " . git_read_hash("$project/HEAD") or die_error(undef, "Open failed."); + open my $fd, "-|", "$gitbin/git-rev-list --max-count=17 " . git_read_head($project) or die_error(undef, "Open failed."); my (@revlist) = map { chomp; $_ } <$fd>; close $fd; print "
\n" . @@ -1172,7 +1212,7 @@ sub git_summary { } sub git_tag { - my $head = git_read_hash("$project/HEAD"); + my $head = git_read_head($project); git_header_html(); print "
\n" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") . @@ -1210,8 +1250,110 @@ sub git_tag { git_footer_html(); } +sub git_blame { + my $fd; + die_error('403 Permission denied', "Permission denied.") if (!git_get_project_config_bool ('blame')); + die_error('404 Not Found', "What file will it be, master?") if (!$file_name); + $hash_base ||= git_read_head($project); + die_error(undef, "Reading commit failed.") unless ($hash_base); + my %co = git_read_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, "-|", "$gitbin/git-annotate", '-l', '-t', '-r', $file_name, $hash_base) + or die_error(undef, "Open failed."); + git_header_html(); + print "
\n" . + $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") . + " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") . + " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") . + " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") . + " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") . + " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "
\n"; + print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") . + " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head") . "
\n"; + print "
\n". + "
" . + $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) . + "
\n"; + print "
" . esc_html($file_name) . "
\n"; + 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_style; + + 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_style = 'font-style: italic;'; + $age_style .= ' color: #009900; background: transparent;' if ($age < 60*60*24*2); + $age_style .= ' font-weight: bold;' if ($age < 60*60*2); + $author = esc_html ($author); + $author =~ s/ / /g; + # escape tabs + while ((my $pos = index($data, "\t")) != -1) { + if (my $count = (8 - ($pos % 8))) { + my $spaces = ' ' x $count; + $data =~ s/\t/$spaces/; + } + } + $data = esc_html ($data); + $data =~ s/ / /g; + + print < + $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_read_hash("$project/HEAD"); + my $head = git_read_head($project); git_header_html(); print "
\n" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") . @@ -1270,7 +1412,7 @@ sub git_tags { } sub git_heads { - my $head = git_read_hash("$project/HEAD"); + my $head = git_read_head($project); git_header_html(); print "
\n" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") . @@ -1343,9 +1485,10 @@ sub git_get_hash_by_path { sub git_blob { if (!defined $hash && defined $file_name) { - my $base = $hash_base || git_read_hash("$project/HEAD"); + my $base = $hash_base || git_read_head($project); $hash = git_get_hash_by_path($base, $file_name, "blob") || die_error(undef, "Error lookup file."); } + my $have_blame = git_get_project_config_bool ('blame'); open my $fd, "-|", "$gitbin/git-cat-file blob $hash" or die_error(undef, "Open failed."); git_header_html(); if (defined $hash_base && (my %co = git_read_commit($hash_base))) { @@ -1357,6 +1500,9 @@ sub git_blob { " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") . " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "
\n"; if (defined $file_name) { + if ($have_blame) { + print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$hash;hb=$hash_base;f=$file_name")}, "blame") . " | "; + } print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash;f=$file_name")}, "plain") . " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;hb=HEAD;f=$file_name")}, "head") . "
\n"; } else { @@ -1407,13 +1553,13 @@ sub git_blob_plain { sub git_tree { if (!defined $hash) { - $hash = git_read_hash("$project/HEAD"); + $hash = git_read_head($project); if (defined $file_name) { - my $base = $hash_base || git_read_hash("$project/HEAD"); + my $base = $hash_base || $hash; $hash = git_get_hash_by_path($base, $file_name, "tree"); } if (!defined $hash_base) { - $hash_base = git_read_hash("$project/HEAD"); + $hash_base = $hash; } } $/ = "\0"; @@ -1478,6 +1624,7 @@ sub git_tree { "\n" . "" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$t_hash$base_key;f=$base$t_name")}, "blob") . +# " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$t_hash$base_key;f=$base$t_name")}, "blame") . " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;h=$hash_base;f=$base$t_name")}, "history") . "\n"; } elsif ($t_type eq "tree") { @@ -1497,7 +1644,7 @@ sub git_tree { sub git_rss { # http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ - open my $fd, "-|", "$gitbin/git-rev-list --max-count=150 " . git_read_hash("$project/HEAD") or die_error(undef, "Open failed."); + open my $fd, "-|", "$gitbin/git-rev-list --max-count=150 " . git_read_head($project) or die_error(undef, "Open failed."); my (@revlist) = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading rev-list failed."); print $cgi->header(-type => 'text/xml', -charset => 'utf-8'); @@ -1566,7 +1713,7 @@ sub git_opml { foreach my $pr (@list) { my %proj = %$pr; - my $head = git_read_hash("$proj{'path'}/HEAD"); + my $head = git_read_head($proj{'path'}); if (!defined $head) { next; } @@ -1587,7 +1734,7 @@ sub git_opml { } sub git_log { - my $head = git_read_hash("$project/HEAD"); + my $head = git_read_head($project); if (!defined $hash) { $hash = $head; } @@ -1707,8 +1854,8 @@ sub git_commit { } my $refs = read_info_ref(); my $ref = ""; - if (defined $refs->{$hash}) { - $ref = " " . esc_html($refs->{$hash}) . ""; + if (defined $refs->{$co{'id'}}) { + $ref = " " . esc_html($refs->{$co{'id'}}) . ""; } git_header_html(undef, $expires); print "
\n" . @@ -1949,8 +2096,8 @@ sub git_commitdiff { } my $refs = read_info_ref(); my $ref = ""; - if (defined $refs->{$hash}) { - $ref = " " . esc_html($refs->{$hash}) . ""; + if (defined $refs->{$co{'id'}}) { + $ref = " " . esc_html($refs->{$co{'id'}}) . ""; } git_header_html(undef, $expires); print "
\n" . @@ -2083,7 +2230,7 @@ sub git_commitdiff_plain { sub git_history { if (!defined $hash) { - $hash = git_read_hash("$project/HEAD"); + $hash = git_read_head($project); } my %co = git_read_commit($hash); if (!%co) { @@ -2105,7 +2252,7 @@ sub git_history { "
\n"; print "
/" . esc_html($file_name) . "
\n"; - open my $fd, "-|", "$gitbin/git-rev-list $hash | $gitbin/git-diff-tree -r --stdin \'$file_name\'"; + open my $fd, "-|", "$gitbin/git-rev-list $hash | $gitbin/git-diff-tree -r --stdin -- \'$file_name\'"; my $commit; print "\n"; my $alternate = 0; @@ -2159,7 +2306,7 @@ sub git_search { die_error("", "Text field empty."); } if (!defined $hash) { - $hash = git_read_hash("$project/HEAD"); + $hash = git_read_head($project); } my %co = git_read_commit($hash); if (!%co) { @@ -2300,7 +2447,7 @@ sub git_search { } sub git_shortlog { - my $head = git_read_hash("$project/HEAD"); + my $head = git_read_head($project); if (!defined $hash) { $hash = $head; }