X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/c17448091bc5f03c7d9135b17b1895263442ac3d722ed7217650006b2f6c2d07..d54561ef6bee91436ad4d8fd465c1931f04d9bfac80f671c558b21acefab459b:/gitweb.cgi
diff --git a/gitweb.cgi b/gitweb.cgi
index 194691c..3cad1f1 100755
--- a/gitweb.cgi
+++ b/gitweb.cgi
@@ -38,10 +38,17 @@ my $home_link = $my_uri;
# html text to include at home page
my $home_text = "indextext.html";
+# URI of default stylesheet
+my $stylesheet = "gitweb.css";
+
# source of projects list
#my $projects_list = $projectroot;
my $projects_list = "index/index.aux";
+# default blob_plain mimetype and default charset for text/plain blob
+my $default_blob_plain_mimetype = 'text/plain';
+my $default_text_plain_charset = undef;
+
# input validation and dispatch
my $action = $cgi->param('a');
if (defined $action) {
@@ -203,6 +210,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.");
@@ -257,68 +267,9 @@ sub git_header_html {
+
$title
$rss_link
-
EOF
@@ -834,6 +785,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;
@@ -1228,6 +1198,108 @@ 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_head($project);
git_header_html();
@@ -1364,6 +1436,7 @@ sub git_blob {
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))) {
@@ -1375,6 +1448,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 {
@@ -1410,15 +1486,46 @@ sub git_blob {
git_footer_html();
}
+sub git_blob_plain_mimetype {
+ my $fd = shift;
+ my $filename = shift;
+
+ # just in case
+ return $default_blob_plain_mimetype unless $fd;
+
+ if (-T $fd) {
+ return 'text/plain' .
+ ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : '');
+ } elsif (! $filename) {
+ return 'application/octet-stream';
+ } elsif ($filename =~ m/\.png$/i) {
+ return 'image/png';
+ } elsif ($filename =~ m/\.gif$/i) {
+ return 'image/gif';
+ } elsif ($filename =~ m/\.jpe?g$/i) {
+ return 'image/jpeg';
+ } else {
+ return 'application/octet-stream';
+ }
+}
+
sub git_blob_plain {
- my $save_as = "$hash.txt";
+ open my $fd, "-|", "$gitbin/git-cat-file blob $hash" or return;
+ my $type = git_blob_plain_mimetype($fd, $file_name);
+
+ # save as filename, even when no $file_name is given
+ my $save_as = "$hash";
if (defined $file_name) {
$save_as = $file_name;
+ } elsif ($type =~ m/^text\//) {
+ $save_as .= '.txt';
}
- print $cgi->header(-type => "text/plain", -charset => 'utf-8', '-content-disposition' => "inline; filename=\"$save_as\"");
- open my $fd, "-|", "$gitbin/git-cat-file blob $hash" or return;
+
+ print $cgi->header(-type => "$type", '-content-disposition' => "inline; filename=\"$save_as\"");
undef $/;
+ binmode STDOUT, ':raw';
print <$fd>;
+ binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
$/ = "\n";
close $fd;
}
@@ -1496,6 +1603,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") {