| 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 |
# Model object for handling topic file data.
|
|
|
9 |
|
|
|
10 |
package Codestriker::Model::Delta;
|
|
|
11 |
|
|
|
12 |
use strict;
|
|
|
13 |
use Encode qw(decode_utf8);
|
|
|
14 |
|
|
|
15 |
# Create the appropriate delta rows for this review. This gets called
|
|
|
16 |
# by File::get_deltas. It passes in the result of a sql query on the
|
|
|
17 |
# delta table.
|
|
|
18 |
sub new {
|
|
|
19 |
my $class = shift;
|
|
|
20 |
my $self = {};
|
|
|
21 |
bless $self;
|
|
|
22 |
|
|
|
23 |
$self->{filename} = decode_utf8($_[1]);
|
|
|
24 |
$self->{revision} = $_[2];
|
|
|
25 |
$self->{binary} = $_[3];
|
|
|
26 |
$self->{old_linenumber} = $_[4];
|
|
|
27 |
$self->{new_linenumber} = $_[5];
|
|
|
28 |
$self->{text} = decode_utf8($_[6]);
|
|
|
29 |
$self->{description} = (defined $_[7]) ? decode_utf8($_[7]) : "";
|
|
|
30 |
$self->{filenumber} = $_[8];
|
|
|
31 |
$self->{repmatch} = $_[9];
|
|
|
32 |
$self->{only_delta_in_file} = 0;
|
|
|
33 |
|
|
|
34 |
return $self;
|
|
|
35 |
}
|
|
|
36 |
|
|
|
37 |
# Retrieve the number of lines in the data for a given file.
|
|
|
38 |
# Input -1 for filenumber for a full file list of a specific topic.
|
|
|
39 |
sub get_delta_size($$$) {
|
|
|
40 |
my ($type, $topicid, $filenumber) = @_;
|
|
|
41 |
|
|
|
42 |
my @deltas = ();
|
|
|
43 |
@deltas = $type->get_deltas($topicid, $filenumber);
|
|
|
44 |
|
|
|
45 |
my $addedLines = 0;
|
|
|
46 |
my $removedLines = 0;
|
|
|
47 |
|
|
|
48 |
for (my $i = 0; $i <= $#deltas; $i++) {
|
|
|
49 |
my $delta = $deltas[$i];
|
|
|
50 |
my @lines = split '\n', $delta->{text};
|
|
|
51 |
|
|
|
52 |
for (my $j = 0; $j <= $#lines; $j++) {
|
|
|
53 |
my @aLine = $lines[$j];
|
|
|
54 |
if (scalar( grep !/^\+/, @aLine ) == 0) {
|
|
|
55 |
$addedLines++;
|
|
|
56 |
} elsif (scalar( grep !/^\-/, @aLine ) == 0) {
|
|
|
57 |
$removedLines++;
|
|
|
58 |
}
|
|
|
59 |
}
|
|
|
60 |
}
|
|
|
61 |
|
|
|
62 |
my $numLines = "";
|
|
|
63 |
|
|
|
64 |
# Return the changes if one is non zero.
|
|
|
65 |
if (($removedLines != 0) || ($addedLines != 0)) {
|
|
|
66 |
$numLines = "+$addedLines,-$removedLines";
|
|
|
67 |
}
|
|
|
68 |
|
|
|
69 |
return $numLines;
|
|
|
70 |
}
|
|
|
71 |
|
|
|
72 |
|
|
|
73 |
# Retrieve the ordered list of deltas that comprise this review.
|
|
|
74 |
# Input -1 for filenumber for a full file list of a specific topic.
|
|
|
75 |
sub get_delta_set($$$) {
|
|
|
76 |
my ($type, $topicid, $filenumber) = @_;
|
|
|
77 |
return $type->get_deltas($topicid, $filenumber);
|
|
|
78 |
}
|
|
|
79 |
|
|
|
80 |
# Retrieve the delta for the specific filename and linenumber.
|
|
|
81 |
sub get_delta($$$) {
|
|
|
82 |
my ($type, $topicid, $filenumber, $linenumber, $new) = @_;
|
|
|
83 |
|
|
|
84 |
# Grab all the deltas for this file, and grab the delta with the highest
|
|
|
85 |
# starting line number lower than or equal to the specific linenumber,
|
|
|
86 |
# and matching the same file number.
|
|
|
87 |
my @deltas = $type->get_deltas($topicid, $filenumber);
|
|
|
88 |
my $found_delta = undef;
|
|
|
89 |
for (my $i = 0; $i <= $#deltas; $i++) {
|
|
|
90 |
my $delta = $deltas[$i];
|
|
|
91 |
my $delta_linenumber = $new ?
|
|
|
92 |
$delta->{new_linenumber} : $delta->{old_linenumber};
|
|
|
93 |
if ($delta_linenumber <= $linenumber) {
|
|
|
94 |
$found_delta = $delta;
|
|
|
95 |
} else {
|
|
|
96 |
# Passed the delta of interest, return the previous one found.
|
|
|
97 |
return $found_delta;
|
|
|
98 |
}
|
|
|
99 |
}
|
|
|
100 |
|
|
|
101 |
# Return the matching delta found, if any.
|
|
|
102 |
return $found_delta;
|
|
|
103 |
}
|
|
|
104 |
|
|
|
105 |
# Retrieve the ordered list of deltas applied to a specific file. Class factory
|
|
|
106 |
# method, returns a list of delta objects.
|
|
|
107 |
sub get_deltas($$$) {
|
|
|
108 |
my ($type, $topicid, $filenumber) = @_;
|
|
|
109 |
|
|
|
110 |
# Obtain a database connection.
|
|
|
111 |
my $dbh = Codestriker::DB::DBI->get_connection();
|
|
|
112 |
|
|
|
113 |
# Setup the appropriate statement and execute it.
|
|
|
114 |
my $select_deltas =
|
|
|
115 |
$dbh->prepare_cached('SELECT delta_sequence, filename, revision, ' .
|
|
|
116 |
'binaryfile, old_linenumber, new_linenumber, ' .
|
|
|
117 |
'deltatext, description, topicfile.sequence, ' .
|
|
|
118 |
'repmatch FROM topicfile, delta ' .
|
|
|
119 |
'WHERE delta.topicid = ? AND ' .
|
|
|
120 |
'delta.topicid = topicfile.topicid AND ' .
|
|
|
121 |
'delta.file_sequence = topicfile.sequence ' .
|
|
|
122 |
(($filenumber != -1) ?
|
|
|
123 |
'AND topicfile.sequence = ? ' : '') .
|
|
|
124 |
'ORDER BY delta_sequence ASC');
|
|
|
125 |
|
|
|
126 |
my $success = defined $select_deltas;
|
|
|
127 |
if ($filenumber != -1) {
|
|
|
128 |
$success &&= $select_deltas->execute($topicid, $filenumber);
|
|
|
129 |
} else {
|
|
|
130 |
$success &&= $select_deltas->execute($topicid);
|
|
|
131 |
}
|
|
|
132 |
|
|
|
133 |
# Store the results into an array of objects.
|
|
|
134 |
my @results = ();
|
|
|
135 |
if ($success) {
|
|
|
136 |
my @data;
|
|
|
137 |
while (@data = $select_deltas->fetchrow_array()) {
|
|
|
138 |
my $delta = Codestriker::Model::Delta->new( @data );
|
|
|
139 |
push @results, $delta;
|
|
|
140 |
}
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
# The delta object needs to know if there are only delta objects
|
|
|
144 |
# in this file so it can figure out if the delta is a new file.
|
|
|
145 |
|
|
|
146 |
# Set the 'only_delta_in_file' field for each delta.
|
|
|
147 |
if (scalar(@results) > 0) {
|
|
|
148 |
# Assume the first delta is the only delta unless proven otherwise.
|
|
|
149 |
$results[0]->{only_delta_in_file} = 1;
|
|
|
150 |
for (my $i = 1; $i < scalar(@results); $i++) {
|
|
|
151 |
if ($results[$i-1]->{filenumber} == $results[$i]->{filenumber}) {
|
|
|
152 |
# If the previous file has the same filenumber, then
|
|
|
153 |
# we know that neither the current file nor the
|
|
|
154 |
# previous file are the only deltas for the file.
|
|
|
155 |
$results[$i]->{only_delta_in_file} = 0;
|
|
|
156 |
$results[$i-1]->{only_delta_in_file} = 0;
|
|
|
157 |
} else {
|
|
|
158 |
# This is the first delta of a file. We'll assume it's the
|
|
|
159 |
# only delta for this file. If there are more deltas, the next
|
|
|
160 |
# loop will correct the assumption.
|
|
|
161 |
$results[$i]->{only_delta_in_file} = 1;
|
|
|
162 |
}
|
|
|
163 |
}
|
|
|
164 |
}
|
|
|
165 |
|
|
|
166 |
Codestriker::DB::DBI->release_connection($dbh, $success);
|
|
|
167 |
die $dbh->errstr unless $success;
|
|
|
168 |
|
|
|
169 |
return @results;
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
|
|
|
173 |
# This function looks at the delta, and will return 1 if the delta looks like
|
|
|
174 |
# it is a delta for a completly new file. This happens when a new file is added
|
|
|
175 |
# to SCM system, or the user updated a plain old text document to be reviewed
|
|
|
176 |
# without diffs. We need this function because we want to format this case
|
|
|
177 |
# special.
|
|
|
178 |
sub is_delta_new_file
|
|
|
179 |
{
|
|
|
180 |
my $self = shift;
|
|
|
181 |
|
|
|
182 |
# All of the following must be true:
|
|
|
183 |
# - one delta for the entire file
|
|
|
184 |
# - delta must start at line 1 (0ld, and new)
|
|
|
185 |
my $is_new_file = 0;
|
|
|
186 |
if ($self->{only_delta_in_file} &&
|
|
|
187 |
$self->{old_linenumber} == 0 &&
|
|
|
188 |
$self->{new_linenumber} == 1) {
|
|
|
189 |
# All of the delta text lines must start with +.
|
|
|
190 |
my @lines = split '\n', $self->{text};
|
|
|
191 |
if ( scalar( grep !/^\+/, @lines ) == 0) {
|
|
|
192 |
$is_new_file = 1;
|
|
|
193 |
}
|
|
|
194 |
}
|
|
|
195 |
|
|
|
196 |
return $is_new_file;
|
|
|
197 |
}
|
|
|
198 |
|
|
|
199 |
1;
|