Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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;