1package SVNLog::Controller::LogUpdate;
2
3use strict;
4use base 'Catalyst::Controller';
5
6use XML::Simple;
7use XML::Atom::SimpleFeed;
8use Data::UUID;
9
10sub doupdate : Local
11{
12	my ($self, $c) = @_;
13
14	my $latest = SVNLog::Model::CDBI::Logentry->maximum_value_of('revision') || 0;
15	my $min = $latest;
16	my $max = 'HEAD';
17
18	my $svn_cmd_data = '--username '.$c->config->{svn}{username}.' --password '.$c->config->{svn}{password}.' '.$c->config->{svn}{url};
19	my $log_xml = `svn log --xml --verbose -r $min:$max $svn_cmd_data`;
20	die "SVN request failed" if not (defined $log_xml and $log_xml =~ m~</log>~);
21
22	my $log = XMLin($log_xml, ContentKey => 'path');
23
24	my $max_seen = -1;
25
26	$c->transaction(sub {
27		for my $logentry (ref $log->{logentry} eq 'ARRAY' ? @{$log->{logentry}} : ($log->{logentry}))
28		{
29			$max_seen = $logentry->{revision} if $logentry->{revision} > $max_seen;
30			next if $logentry->{revision} <= $latest;
31
32			my $paths = $logentry->{paths}->{path};
33			delete $logentry->{paths};
34
35			# Convert <msg></msg> into just a string (because XML::Simple doesn't know that's what it should be)
36			$logentry->{msg} = '' if ref $logentry->{msg};
37
38			my $entry = SVNLog::Model::CDBI::Logentry->insert($logentry);
39
40			for my $path (ref $paths eq 'ARRAY' ? @$paths : ($paths))
41			{
42				SVNLog::Model::CDBI::Paths->insert({logentry => $entry->id, filter_copyfrom(%$path)});
43			}
44		}
45	}) or $c->log->error("Transaction failed: " . $c->error->[-1]);
46
47	add_default_public_msgs($c);
48
49	open my $text_fh, '>', $c->config->{output}{filename} or die $!;
50	print $text_fh $self->generate_text($c);
51	open my $feed_fh, '>', $c->config->{output}{filename_feed} or die $!;
52	print $feed_fh $self->generate_feed($c);
53
54	$c->res->body("Updated log to $max_seen.");
55}
56
57sub defaultise : Local
58{
59	my ($self, $c) = @_;
60	add_default_public_msgs($c);
61	$c->res->body("Done");
62}
63
64# (To reset the database:
65#  delete from public_message; delete from sqlite_sequence where name = "public_message";
66# )
67
68sub add_default_public_msgs
69{
70	my ($c) = @_;
71
72	$c->transaction(sub {
73		my @unmessaged = SVNLog::Model::CDBI::Logentry->retrieve_from_sql(qq{
74			NOT (SELECT COUNT(*) FROM public_message WHERE public_message.logentry = logentry.id)
75			ORDER BY logentry.id
76		});
77		for my $logentry (@unmessaged)
78		{
79			my @lines;
80			for (split /\n/, $logentry->msg)
81			{
82				push @lines, $_ if s/^#\s*//;
83			}
84			my $msg = join "\n", @lines;
85
86			SVNLog::Model::CDBI::PublicMessage->insert({
87				logentry => $logentry->id,
88				msg => $msg,
89			});
90		}
91	});
92}
93
94sub createtext : Local
95{
96	my ($self, $c) = @_;
97	my $out = $self->generate_text($c);
98	$c->res->body($out);
99}
100
101sub createfeed : Local
102{
103	my ($self, $c) = @_;
104	my $out = $self->generate_feed($c);
105	$c->res->body($out);
106}
107
108sub get_log_entries
109{
110	my ($days, $max) = @_;
111	my @logentries = ();
112	for (SVNLog::Model::CDBI::Logentry->recent($days))
113	{
114		my $msg = $_->public_msg;
115		next unless defined $msg and $msg->msg; # skip ones with empty messages
116
117		push @logentries, $_;
118
119		last if $max and @logentries >= $max;
120	}
121	return @logentries;
122}
123
124sub generate_text
125{
126	my ($self, $c) = @_;
127
128	my $feed_url = $c->config->{output}{feed_url};
129	my $out = <<EOF;
130<!DOCTYPE html>
131<title>0 A.D. Revision Log</title>
132<style>
133body {
134  color: #fff;
135  margin: 3px;
136  background-color: #000;
137  font-family: Geneva, Arial, Helvetica, sans-serif;
138  font-size: 10px;
139}
140img {
141  border: 0;
142}
143</style>
144<a href="$feed_url" target="_top"><img alt="Atom feed" title="Subscribe to feed of revision log" src="/feed-icon-16x16.png" style="float: right"></a>
145EOF
146
147	my @logentries = get_log_entries(28, 10);
148
149	for (@logentries)
150	{
151		my ($revision, $author, $date, $msg) = ($_->revision, $_->author, $_->date, $_->public_msg);
152
153		$date =~ s/T.*Z//;
154		$out .= <<EOF;
155<b>revision:</b> $revision<br>
156<b>author:</b> $author<br>
157<b>date:</b> $date<br>
158EOF
159		my $text = $msg->msg;
160		$text =~ s/&/&amp;/g;
161		$text =~ s/</&lt;/g;
162		$text =~ s/>/&gt;/g;
163		$text =~ s/\n/<br>/g;
164		$out .= $text . "\n<hr>\n";
165	}
166
167	if (not @logentries)
168	{
169		$out .= 'Sorry, no data is available right now.';
170	}
171
172	return $out;
173}
174
175sub generate_feed
176{
177	my ($self, $c) = @_;
178
179	my $uid_gen = new Data::UUID;
180
181	my $feed_url = $c->config->{output}{feed_url};
182
183	my $feed = new XML::Atom::SimpleFeed(
184		title => "0 A.D. Revision Log",
185		link => "http://play0ad.com/",
186		link => { rel => 'self', href => $feed_url },
187		id => "urn:uuid:" . $uid_gen->create_from_name_str('WFG SVN feed', 'feed'),
188	);
189
190	my @logentries = get_log_entries(7);
191
192	for (@logentries)
193	{
194		my ($revision, $author, $date, $msg) = ($_->revision, $_->author, $_->date, $_->public_msg);
195
196		my $uid = $uid_gen->create_from_name_str('WFG SVN feed', $revision);
197
198		$feed->add_entry(
199			title => "Revision $revision - ".$msg->msg,
200			id => "urn:uuid:$uid",
201			author => $author,
202			content => $msg->msg,
203			published => $date,
204			updated => $date,
205			link => "http://play0ad.com/",
206		);
207	}
208
209	return $feed->as_string;
210}
211
212sub filter_copyfrom
213{
214	my @r = @_;
215	s/^(copyfrom)-(rev|path)$/$1_$2/ for @r;
216	@r;
217}
218
2191;
220