| 1293 |
dpurdie |
1 |
###############################################################################
|
|
|
2 |
# Codestriker: Copyright (c) 2001, 2002 David Sitsky. All rights reserved.
|
|
|
3 |
# sits@users.sourceforge.net
|
|
|
4 |
#
|
|
|
5 |
# This program is free software; you can redistribute it and modify it under
|
|
|
6 |
# the terms of the GPL.
|
|
|
7 |
|
|
|
8 |
# Action object for handling the viewing of a file.
|
|
|
9 |
|
|
|
10 |
package Codestriker::Action::ViewTopicFile;
|
|
|
11 |
|
|
|
12 |
use strict;
|
|
|
13 |
|
|
|
14 |
use Codestriker::Model::File;
|
|
|
15 |
use Codestriker::Model::Comment;
|
|
|
16 |
use Codestriker::Http::Render;
|
|
|
17 |
use Codestriker::Repository::RepositoryFactory;
|
|
|
18 |
|
|
|
19 |
# If the input is valid, display the topic.
|
|
|
20 |
sub process($$$) {
|
|
|
21 |
my ($type, $http_input, $http_response) = @_;
|
|
|
22 |
|
|
|
23 |
# Retrieve the parameters for this action.
|
|
|
24 |
my $query = $http_response->get_query();
|
|
|
25 |
my $topicid = $http_input->get('topic');
|
|
|
26 |
my $mode = $http_input->get('mode');
|
|
|
27 |
my $tabwidth = $http_input->get('tabwidth');
|
|
|
28 |
my $email = $http_input->get('email');
|
|
|
29 |
my $fn = $http_input->get('fn');
|
|
|
30 |
my $new = $http_input->get('new');
|
|
|
31 |
my $parallel = $http_input->get('parallel');
|
|
|
32 |
my $brmode = $http_input->get('brmode');
|
|
|
33 |
my $fview = $http_input->get('fview');
|
|
|
34 |
|
|
|
35 |
# Check if this action is allowed.
|
|
|
36 |
if (scalar(@Codestriker::valid_repositories) == 0) {
|
|
|
37 |
$http_response->error("This function has been disabled");
|
|
|
38 |
}
|
|
|
39 |
|
|
|
40 |
# Retrieve the appropriate topic details.
|
|
|
41 |
my $topic = Codestriker::Model::Topic->new($topicid);
|
|
|
42 |
|
|
|
43 |
# Retrieve the corresponding repository object.
|
|
|
44 |
my $repository =
|
|
|
45 |
Codestriker::Repository::RepositoryFactory->get($topic->{repository});
|
|
|
46 |
|
|
|
47 |
# Retrieve the deltas corresponding to this file.
|
|
|
48 |
my @deltas = Codestriker::Model::Delta->get_deltas($topicid, $fn);
|
|
|
49 |
|
|
|
50 |
# We need to untaint the filename and revision values, as they will
|
|
|
51 |
# potentially be used to launch an external program.
|
|
|
52 |
$deltas[0]->{filename} =~ /^(.*)$/o;
|
|
|
53 |
my $filename = $1;
|
|
|
54 |
$deltas[0]->{revision} =~ /^(.*)$/o;
|
|
|
55 |
my $revision = $1;
|
|
|
56 |
|
|
|
57 |
# Retrieve the comment details for this topic.
|
|
|
58 |
my @comments = $topic->read_comments();
|
|
|
59 |
|
|
|
60 |
# Load the appropriate original form of this file into memory.
|
|
|
61 |
my ($filedata_max_line_length, @filedata);
|
|
|
62 |
if (!_read_repository_file($filename, $revision, $tabwidth,
|
|
|
63 |
$repository, \@filedata,
|
|
|
64 |
\$filedata_max_line_length)) {
|
|
|
65 |
#
|
|
|
66 |
# 13-Sep-07 SJK: Provide some more info in this message, suggesting the likely root cause.
|
|
|
67 |
#
|
|
|
68 |
#$http_response->error("Couldn't get repository data for $filename " .
|
|
|
69 |
# "$revision: $!");
|
|
|
70 |
$http_response->error("Couldn't get repository data for $filename " .
|
|
|
71 |
"$revision: $!. Check repository $repository->{dynamic_view_name} can navigate to this file.");
|
|
|
72 |
}
|
|
|
73 |
|
|
|
74 |
# This could be done more efficiently, but for now, read through the
|
|
|
75 |
# file, and determine the longest line length for the resulting
|
|
|
76 |
# data that is to be viewed. Note it is not 100% accurate, but it will
|
|
|
77 |
# do for now, to reduce the resulting page size.
|
|
|
78 |
my $max_line_length = $filedata_max_line_length;
|
|
|
79 |
for (my $d = 0; $d <= $#deltas; $d++) {
|
|
|
80 |
my @difflines = split /\n/, $deltas[$d]->{text};
|
|
|
81 |
for (my $i = 0; $i <= $#difflines; $i++) {
|
|
|
82 |
my $line = $difflines[$i];
|
|
|
83 |
if ($line =~ /^\s(.*)$/o || $line =~ /^\+(.*)$/o ||
|
|
|
84 |
$line =~ /^\-(.*)$/o) {
|
|
|
85 |
my $line_length = length($1);
|
|
|
86 |
if ($line_length > $max_line_length) {
|
|
|
87 |
$max_line_length = $line_length;
|
|
|
88 |
}
|
|
|
89 |
}
|
|
|
90 |
}
|
|
|
91 |
}
|
|
|
92 |
|
|
|
93 |
# Output the new file, with the deltas applied.
|
|
|
94 |
my $title;
|
|
|
95 |
if ($parallel) {
|
|
|
96 |
$title = "View File: Parallel view of $filename v$revision";
|
|
|
97 |
} else {
|
|
|
98 |
$title = $new ? "View File: New $filename" :
|
|
|
99 |
"View File: $filename v$revision";
|
|
|
100 |
}
|
|
|
101 |
|
|
|
102 |
$http_response->generate_header(topic=>$topic,
|
|
|
103 |
comments=>\@comments,
|
|
|
104 |
topic_title=>$title,
|
|
|
105 |
mode=>$mode,
|
|
|
106 |
tabwidth=>$tabwidth,
|
|
|
107 |
fview=>$fview,
|
|
|
108 |
repository=>$Codestriker::repository_name_map->{$topic->{repository}},
|
|
|
109 |
reload=>0, cache=>1);
|
|
|
110 |
|
|
|
111 |
# Render the HTML header.
|
|
|
112 |
my $vars = {};
|
|
|
113 |
$vars->{'closehead'} = 1;
|
|
|
114 |
|
|
|
115 |
my $header = Codestriker::Http::Template->new("header");
|
|
|
116 |
$header->process($vars);
|
|
|
117 |
|
|
|
118 |
my $max_digit_width = length($#filedata);
|
|
|
119 |
|
|
|
120 |
# Create a new render object to perform the line rendering.
|
|
|
121 |
my @toc_filenames = ();
|
|
|
122 |
my @toc_revisions = ();
|
|
|
123 |
my @toc_binaries = ();
|
|
|
124 |
my $url_builder = Codestriker::Http::UrlBuilder->new($query);
|
|
|
125 |
my $render =
|
|
|
126 |
Codestriker::Http::Render->new($query, $url_builder, $parallel,
|
|
|
127 |
$max_digit_width, $topicid, $mode,
|
|
|
128 |
\@comments, $tabwidth,
|
|
|
129 |
$repository, \@toc_filenames,
|
|
|
130 |
\@toc_revisions, \@toc_binaries,
|
|
|
131 |
undef, $max_line_length, $brmode,
|
|
|
132 |
$fview);
|
|
|
133 |
# Prepare the output.
|
|
|
134 |
|
|
|
135 |
if ($parallel) {
|
|
|
136 |
$render->print_coloured_table();
|
|
|
137 |
}
|
|
|
138 |
else {
|
|
|
139 |
print "<PRE class=\"ms\">\n";
|
|
|
140 |
}
|
|
|
141 |
|
|
|
142 |
# Read through all the deltas, and apply them to the original form of the
|
|
|
143 |
# file.
|
|
|
144 |
my $delta = undef;
|
|
|
145 |
for (my $delta_index = 0; $delta_index <= $#deltas; $delta_index++) {
|
|
|
146 |
$delta = $deltas[$delta_index];
|
|
|
147 |
|
|
|
148 |
# Output those lines leading up to the start of the next delta.
|
|
|
149 |
# Build up a delta with no changes, and render it.
|
|
|
150 |
my $delta_text = "";
|
|
|
151 |
my $next_delta_linenumber = $delta->{old_linenumber};
|
|
|
152 |
for (my $i = $render->{old_linenumber};
|
|
|
153 |
$i < $next_delta_linenumber; $i++) {
|
|
|
154 |
$delta_text .= " $filedata[$i]\n";
|
|
|
155 |
}
|
|
|
156 |
$render->delta_text($filename, $fn, $revision,
|
|
|
157 |
$render->{old_linenumber},
|
|
|
158 |
$render->{new_linenumber},
|
|
|
159 |
$delta_text, 0, $new, 0);
|
|
|
160 |
|
|
|
161 |
# Render the actual change delta.
|
|
|
162 |
$render->delta_text($filename, $fn, $revision,
|
|
|
163 |
$delta->{old_linenumber},
|
|
|
164 |
$delta->{new_linenumber}, $delta->{text}, 1,
|
|
|
165 |
$new, 1);
|
|
|
166 |
}
|
|
|
167 |
|
|
|
168 |
# Render the tail part of the file, again by building up a delta.
|
|
|
169 |
my $delta_text = "";
|
|
|
170 |
for (my $i = $render->{old_linenumber}; $i <= $#filedata; $i++) {
|
|
|
171 |
$delta_text .= " $filedata[$i]\n";
|
|
|
172 |
}
|
|
|
173 |
$render->delta_text($filename, $fn, $revision, $render->{old_linenumber},
|
|
|
174 |
$render->{new_linenumber}, $delta_text, 0, $new, 0);
|
|
|
175 |
|
|
|
176 |
# Close off the rendering.
|
|
|
177 |
if ($parallel) {
|
|
|
178 |
print $query->end_table();
|
|
|
179 |
}
|
|
|
180 |
else {
|
|
|
181 |
print "</PRE>\n";
|
|
|
182 |
}
|
|
|
183 |
|
|
|
184 |
# Render the HTML trailer.
|
|
|
185 |
my $trailer = Codestriker::Http::Template->new("trailer");
|
|
|
186 |
$trailer->process();
|
|
|
187 |
|
|
|
188 |
print $query->end_html();
|
|
|
189 |
|
|
|
190 |
$http_response->generate_footer();
|
|
|
191 |
|
|
|
192 |
# Fire the topic listener to indicate that the user has viewed the topic.
|
|
|
193 |
Codestriker::TopicListeners::Manager::topic_viewed($email, $topic);
|
|
|
194 |
}
|
|
|
195 |
|
|
|
196 |
# Read the specified repository file and revision into memory. Return true if
|
|
|
197 |
# successful, false otherwise.
|
|
|
198 |
sub _read_repository_file ($$$$$$) {
|
|
|
199 |
my ($filename, $revision, $tabwidth, $repository, $data_array_ref,
|
|
|
200 |
$maxline_length_ref) = @_;
|
|
|
201 |
|
|
|
202 |
# Read the file data.
|
|
|
203 |
$repository->retrieve($filename, $revision, $data_array_ref);
|
|
|
204 |
|
|
|
205 |
#
|
|
|
206 |
# 13-Sep-07 SJK: Return false if no data read from repository
|
|
|
207 |
#
|
|
|
208 |
if ( $#$data_array_ref <= 0 ) {
|
|
|
209 |
return 0;
|
|
|
210 |
}
|
|
|
211 |
|
|
|
212 |
# Determine the maximum line length, and replace tabs with spaces.
|
|
|
213 |
$$maxline_length_ref = 0;
|
|
|
214 |
for (my $i = 1; $i <= $#$data_array_ref; $i++) {
|
|
|
215 |
$$data_array_ref[$i] =
|
|
|
216 |
Codestriker::Http::Render::tabadjust($tabwidth,
|
|
|
217 |
$$data_array_ref[$i], 0);
|
|
|
218 |
my $line_length = length($$data_array_ref[$i]);
|
|
|
219 |
if ($line_length > $$maxline_length_ref) {
|
|
|
220 |
$$maxline_length_ref = $line_length;
|
|
|
221 |
}
|
|
|
222 |
}
|
|
|
223 |
return 1;
|
|
|
224 |
}
|
|
|
225 |
|
|
|
226 |
1;
|