@ -425,6 +425,7 @@ my %actions = (
@@ -425,6 +425,7 @@ my %actions = (
"history" => \&git_history,
"log" => \&git_log,
"rss" => \&git_rss,
"atom" => \&git_atom,
"search" => \&git_search,
"search_help" => \&git_search_help,
"shortlog" => \&git_shortlog,
@ -1198,10 +1199,12 @@ sub parse_date {
@@ -1198,10 +1199,12 @@ sub parse_date {
$date{'mday'} = $mday;
$date{'day'} = $days[$wday];
$date{'month'} = $months[$mon];
$date{'rfc2822'} = sprintf "%s, %d %s %4d %02d:%02d:%02d +0000",
$days[$wday], $mday, $months[$mon], 1900+$year, $hour ,$min, $sec;
$date{'rfc2822'} = sprintf "%s, %d %s %4d %02d:%02d:%02d +0000",
$days[$wday], $mday, $months[$mon], 1900+$year, $hour ,$min, $sec;
$date{'mday-time'} = sprintf "%d %s %02d:%02d",
$mday, $months[$mon], $hour ,$min;
$date{'iso-8601'} = sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ",
1900+$year, $mon, $mday, $hour ,$min, $sec;
$tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/;
my $local = $epoch + ((int $1 + ($2/60)) * 3600);
@ -1209,9 +1212,9 @@ sub parse_date {
@@ -1209,9 +1212,9 @@ sub parse_date {
$date{'hour_local'} = $hour;
$date{'minute_local'} = $min;
$date{'tz_local'} = $tz;
$date{'iso-tz'} = sprintf ("%04d-%02d-%02d %02d:%02d:%02d %s",
1900+$year, $mon+1, $mday,
$hour, $min, $sec, $tz);
$date{'iso-tz'} = sprintf("%04d-%02d-%02d %02d:%02d:%02d %s",
1900+$year, $mon+1, $mday,
$hour, $min, $sec, $tz);
return %date;
}
@ -1672,14 +1675,17 @@ EOF
@@ -1672,14 +1675,17 @@ EOF
}
}
if (defined $project) {
printf('<link rel="alternate" title="%s log" '.
'href="%s" type="application/rss+xml"/>'."\n",
printf('<link rel="alternate" title="%s log RSS feed" '.
'href="%s" type="application/rss+xml" />'."\n",
esc_param($project), href(action=>"rss"));
printf('<link rel="alternate" title="%s log Atom feed" '.
'href="%s" type="application/atom+xml" />'."\n",
esc_param($project), href(action=>"atom"));
} else {
printf('<link rel="alternate" title="%s projects list" '.
'href="%s" type="text/plain; charset=utf-8"/>'."\n",
$site_name, href(project=>undef, action=>"project_index"));
printf('<link rel="alternate" title="%s projects logs" '.
printf('<link rel="alternate" title="%s projects feeds" '.
'href="%s" type="text/x-opml"/>'."\n",
$site_name, href(project=>undef, action=>"opml"));
}
@ -1745,7 +1751,9 @@ sub git_footer_html {
@@ -1745,7 +1751,9 @@ sub git_footer_html {
print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
}
print $cgi->a({-href => href(action=>"rss"),
-class => "rss_logo"}, "RSS") . "\n";
-class => "rss_logo"}, "RSS") . " ";
print $cgi->a({-href => href(action=>"atom"),
-class => "rss_logo"}, "Atom") . "\n";
} else {
print $cgi->a({-href => href(project=>undef, action=>"opml"),
-class => "rss_logo"}, "OPML") . " ";
@ -4150,26 +4158,125 @@ sub git_shortlog {
@@ -4150,26 +4158,125 @@ sub git_shortlog {
}
## ......................................................................
## feeds (RSS, OPML)
## feeds (RSS, Atom; OPML)
sub git_rss {
# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
sub git_feed {
my $format = shift || 'atom';
my ($have_blame) = gitweb_check_feature('blame');
# 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");
}
# log/feed of current (HEAD) branch, log of given branch, history of file/directory
my $head = $hash || 'HEAD';
open my $fd, "-|", git_cmd(), "rev-list", "--max-count=150",
git_get_head_hash($project), "--"
$head, "--", (defined $file_name ? $file_name : ())
or die_error(undef, "Open git-rev-list failed");
my @revlist = map { chomp; $_ } <$fd>;
close $fd or die_error(undef, "Reading git-rev-list failed");
print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
print <<XML;
<?xml version="1.0" encoding="utf-8"?>
my %latest_commit;
my %latest_date;
my $content_type = "application/$format+xml";
if (defined $cgi->http('HTTP_ACCEPT') &&
$cgi->Accept('text/xml') > $cgi->Accept($content_type)) {
# browser (feed reader) prefers text/xml
$content_type = 'text/xml';
}
if (defined($revlist[0])) {
%latest_commit = parse_commit($revlist[0]);
%latest_date = parse_date($latest_commit{'committer_epoch'});
print $cgi->header(
-type => $content_type,
-charset => 'utf-8',
-last_modified => $latest_date{'rfc2822'});
} else {
print $cgi->header(
-type => $content_type,
-charset => 'utf-8');
}
# Optimization: skip generating the body if client asks only
# for Last-Modified date.
return if ($cgi->request_method() eq 'HEAD');
# header variables
my $title = "$site_name - $project/$action";
my $feed_type = 'log';
if (defined $hash) {
$title .= " - '$hash'";
$feed_type = 'branch log';
if (defined $file_name) {
$title .= " :: $file_name";
$feed_type = 'history';
}
} elsif (defined $file_name) {
$title .= " - $file_name";
$feed_type = 'history';
}
$title .= " $feed_type";
my $descr = git_get_project_description($project);
if (defined $descr) {
$descr = esc_html($descr);
} else {
$descr = "$project " .
($format eq 'rss' ? 'RSS' : 'Atom') .
" feed";
}
my $owner = git_get_project_owner($project);
$owner = esc_html($owner);
#header
my $alt_url;
if (defined $file_name) {
$alt_url = href(-full=>1, action=>"history", hash=>$hash, file_name=>$file_name);
} elsif (defined $hash) {
$alt_url = href(-full=>1, action=>"log", hash=>$hash);
} else {
$alt_url = href(-full=>1, action=>"summary");
}
print qq!<?xml version="1.0" encoding="utf-8"?>\n!;
if ($format eq 'rss') {
print <<XML;
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>$project $my_uri $my_url</title>
<link>${\esc_html("$my_url?p=$project;a=summary")}</link>
<description>$project log</description>
<language>en</language>
XML
print "<title>$title</title>\n" .
"<link>$alt_url</link>\n" .
"<description>$descr</description>\n" .
"<language>en</language>\n";
} elsif ($format eq 'atom') {
print <<XML;
<feed xmlns="http://www.w3.org/2005/Atom">
XML
print "<title>$title</title>\n" .
"<subtitle>$descr</subtitle>\n" .
'<link rel="alternate" type="text/html" href="' .
$alt_url . '" />' . "\n" .
'<link rel="self" type="' . $content_type . '" href="' .
$cgi->self_url() . '" />' . "\n" .
"<id>" . href(-full=>1) . "</id>\n" .
# use project owner for feed author
"<author><name>$owner</name></author>\n";
if (defined $favicon) {
print "<icon>" . esc_url($favicon) . "</icon>\n";
}
if (defined $logo_url) {
# not twice as wide as tall: 72 x 27 pixels
print "<logo>" . esc_url($logo_url) . "</logo>\n";
}
if (! %latest_date) {
# dummy date to keep the feed valid until commits trickle in:
print "<updated>1970-01-01T00:00:00Z</updated>\n";
} else {
print "<updated>$latest_date{'iso-8601'}</updated>\n";
}
}
# contents
for (my $i = 0; $i <= $#revlist; $i++) {
my $commit = $revlist[$i];
my %co = parse_commit($commit);
@ -4178,42 +4285,100 @@ XML
@@ -4178,42 +4285,100 @@ XML
last;
}
my %cd = parse_date($co{'committer_epoch'});
# get list of changed files
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
$co{'parent'}, $co{'id'}, "--"
$co{'parent'}, $co{'id'}, "--", (defined $file_name ? $file_name : ())
or next;
my @difftree = map { chomp; $_ } <$fd>;
close $fd
or next;
print "<item>\n" .
"<title>" .
sprintf("%d %s %02d:%02d", $cd{'mday'}, $cd{'month'}, $cd{'hour'}, $cd{'minute'}) . " - " . esc_html($co{'title'}) .
"</title>\n" .
"<author>" . esc_html($co{'author'}) . "</author>\n" .
"<pubDate>$cd{'rfc2822'}</pubDate>\n" .
"<guid isPermaLink=\"true\">" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</guid>\n" .
"<link>" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</link>\n" .
"<description>" . esc_html($co{'title'}) . "</description>\n" .
"<content:encoded>" .
"<![CDATA[\n";
# print element (entry, item)
my $co_url = href(-full=>1, action=>"commit", hash=>$commit);
if ($format eq 'rss') {
print "<item>\n" .
"<title>" . esc_html($co{'title'}) . "</title>\n" .
"<author>" . esc_html($co{'author'}) . "</author>\n" .
"<pubDate>$cd{'rfc2822'}</pubDate>\n" .
"<guid isPermaLink=\"true\">$co_url</guid>\n" .
"<link>$co_url</link>\n" .
"<description>" . esc_html($co{'title'}) . "</description>\n" .
"<content:encoded>" .
"<![CDATA[\n";
} elsif ($format eq 'atom') {
print "<entry>\n" .
"<title type=\"html\">" . esc_html($co{'title'}) . "</title>\n" .
"<updated>$cd{'iso-8601'}</updated>\n" .
"<author><name>" . esc_html($co{'author_name'}) . "</name></author>\n" .
# use committer for contributor
"<contributor><name>" . esc_html($co{'committer_name'}) . "</name></contributor>\n" .
"<published>$cd{'iso-8601'}</published>\n" .
"<link rel=\"alternate\" type=\"text/html\" href=\"$co_url\" />\n" .
"<id>$co_url</id>\n" .
"<content type=\"xhtml\" xml:base=\"" . esc_url($my_url) . "\">\n" .
"<div xmlns=\"http://www.w3.org/1999/xhtml\">\n";
}
my $comment = $co{'comment'};
print "<pre>\n";
foreach my $line (@$comment) {
$line = to_utf8($line);
print "$line<br/>\n";
$line = esc_html($line);
print "$line\n";
}
print "<br/>\n";
foreach my $line (@difftree) {
if (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/)) {
next;
print "</pre><ul>\n";
foreach my $difftree_line (@difftree) {
my %difftree = parse_difftree_raw_line($difftree_line);
next if !$difftree{'from_id'};
my $file = $difftree{'file'} || $difftree{'to_file'};
print "<li>" .
"[" .
$cgi->a({-href => href(-full=>1, action=>"blobdiff",
hash=>$difftree{'to_id'}, hash_parent=>$difftree{'from_id'},
hash_base=>$co{'id'}, hash_parent_base=>$co{'parent'},
file_name=>$file, file_parent=>$difftree{'from_file'}),
-title => "diff"}, 'D');
if ($have_blame) {
print $cgi->a({-href => href(-full=>1, action=>"blame",
file_name=>$file, hash_base=>$commit),
-title => "blame"}, 'B');
}
my $file = esc_path(unquote($7));
$file = to_utf8($file);
print "$file<br/>\n";
# if this is not a feed of a file history
if (!defined $file_name || $file_name ne $file) {
print $cgi->a({-href => href(-full=>1, action=>"history",
file_name=>$file, hash=>$commit),
-title => "history"}, 'H');
}
$file = esc_path($file);
print "] ".
"$file</li>\n";
}
if ($format eq 'rss') {
print "</ul>]]>\n" .
"</content:encoded>\n" .
"</item>\n";
} elsif ($format eq 'atom') {
print "</ul>\n</div>\n" .
"</content>\n" .
"</entry>\n";
}
print "]]>\n" .
"</content:encoded>\n" .
"</item>\n";
}
print "</channel></rss>";
# end of feed
if ($format eq 'rss') {
print "</channel>\n</rss>\n";
} elsif ($format eq 'atom') {
print "</feed>\n";
}
}
sub git_rss {
git_feed('rss');
}
sub git_atom {
git_feed('atom');
}
sub git_opml {