1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.sf.statcvs.input;
24
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Date;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.SortedSet;
32 import java.util.TreeSet;
33 import java.util.logging.Logger;
34
35 import net.sf.statcvs.model.Revision;
36 import net.sf.statcvs.model.VersionedFile;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class FileBuilder {
62 private static Logger logger = Logger.getLogger(FileBuilder.class.getName());
63
64 private final Builder builder;
65 private final String name;
66 private final boolean isBinary;
67 private final List revisions = new ArrayList();
68 private RevisionData lastAdded = null;
69 private final Map revBySymnames;
70
71 private int locDelta;
72 private boolean flagLocalFileNotFound = false;
73 private boolean flagUnexpectedLocalRevision = false;
74 private boolean flagNoLocalCVSMetadata = false;
75
76
77
78
79
80
81
82
83
84 public FileBuilder(final Builder builder, final String name, final boolean isBinary, final Map revBySymnames) {
85 this.builder = builder;
86 this.name = name;
87 this.isBinary = isBinary;
88 this.revBySymnames = revBySymnames;
89
90 logger.fine("logging " + name);
91 }
92
93
94
95
96
97
98
99
100 public void addRevisionData(final RevisionData data) {
101 if (!data.isOnTrunk()) {
102 return;
103 }
104 if (isBinary && !data.isCreation()) {
105 data.setLines(0, 0);
106 }
107 this.revisions.add(data);
108 lastAdded = data;
109
110 locDelta += getLOCChange(data);
111 }
112
113
114
115
116
117
118
119
120
121
122 public VersionedFile createFile(final Date beginOfLogDate) {
123 if (isFilteredFile() || !fileExistsInLogPeriod()) {
124 return null;
125 }
126 if (revisions.size() == 1 && lastAdded.isAddOnSubbranch()) {
127 return null;
128 }
129
130 final VersionedFile file = new VersionedFile(name, builder.getDirectory(name));
131
132 if (revisions.isEmpty()) {
133 buildBeginOfLogRevision(file, beginOfLogDate, getFinalLOC(), null);
134 return file;
135 }
136
137 final Iterator it = revisions.iterator();
138 RevisionData currentData = (RevisionData) it.next();
139 int currentLOC = getFinalLOC();
140 RevisionData previousData;
141 int previousLOC;
142 SortedSet symbolicNames;
143
144 while (it.hasNext()) {
145 previousData = currentData;
146 previousLOC = currentLOC;
147 currentData = (RevisionData) it.next();
148 currentLOC = previousLOC - getLOCChange(previousData);
149
150
151 symbolicNames = createSymbolicNamesCollection(previousData);
152
153 if (previousData.isChangeOrRestore()) {
154 if (currentData.isDeletion() || currentData.isAddOnSubbranch()) {
155 buildCreationRevision(file, previousData, previousLOC, symbolicNames);
156 } else {
157 buildChangeRevision(file, previousData, previousLOC, symbolicNames);
158 }
159 } else if (previousData.isDeletion()) {
160 buildDeletionRevision(file, previousData, previousLOC, symbolicNames);
161 } else {
162 logger.warning("illegal state in " + file.getFilenameWithPath() + ":" + previousData.getRevisionNumber());
163 }
164 }
165
166
167 symbolicNames = createSymbolicNamesCollection(currentData);
168
169 final int nextLinesOfCode = currentLOC - getLOCChange(currentData);
170 if (currentData.isCreation()) {
171 buildCreationRevision(file, currentData, currentLOC, symbolicNames);
172 } else if (currentData.isDeletion()) {
173 buildDeletionRevision(file, currentData, currentLOC, symbolicNames);
174 buildBeginOfLogRevision(file, beginOfLogDate, nextLinesOfCode, symbolicNames);
175 } else if (currentData.isChangeOrRestore()) {
176 buildChangeRevision(file, currentData, currentLOC, symbolicNames);
177 buildBeginOfLogRevision(file, beginOfLogDate, nextLinesOfCode, symbolicNames);
178 } else if (currentData.isAddOnSubbranch()) {
179
180 } else {
181 logger.warning("illegal state in " + file.getFilenameWithPath() + ":" + currentData.getRevisionNumber());
182 }
183 return file;
184 }
185
186 public boolean hasUnexpectedLocalRevision() {
187 return this.flagUnexpectedLocalRevision;
188 }
189
190 public boolean hasLocalFileNotFound() {
191 return this.flagLocalFileNotFound;
192 }
193
194 public boolean hasLocalCVSMetadata() {
195 return !this.flagNoLocalCVSMetadata;
196 }
197
198
199
200
201
202
203
204
205
206 private int getFinalLOC() {
207 if (isBinary) {
208 return 0;
209 } else if (lastAdded != null && lastAdded.isAddOnSubbranch()) {
210 return locDelta;
211 }
212
213 String revision = null;
214 try {
215 revision = builder.getRevision(name);
216 } catch (final IOException e) {
217 if (!finalRevisionIsDead()) {
218 logger.info(e.getMessage());
219 this.flagNoLocalCVSMetadata = true;
220 }
221 revision = "???";
222 }
223
224 try {
225 if ("1.1".equals(revision)) {
226 return builder.getLOC(name) + locDelta;
227 } else {
228 if (!revisions.isEmpty()) {
229 final RevisionData firstAdded = (RevisionData) revisions.get(0);
230 if (!finalRevisionIsDead() && !firstAdded.getRevisionNumber().equals(revision)) {
231 if (!"???".equals(revision)) {
232 logger.info(this.name + " should be at " + firstAdded.getRevisionNumber() + " but is at " + revision);
233 }
234 this.flagUnexpectedLocalRevision = true;
235 }
236 }
237 return builder.getLOC(name);
238 }
239 } catch (final NoLineCountException e) {
240 if (!finalRevisionIsDead()) {
241 logger.info("No line count for " + this.name);
242 this.flagLocalFileNotFound = true;
243 }
244 return approximateFinalLOC();
245 }
246 }
247
248
249
250
251
252
253 private boolean finalRevisionIsDead() {
254 if (revisions.isEmpty()) {
255 return false;
256 }
257 return ((RevisionData) revisions.get(0)).isDeletion();
258 }
259
260
261
262
263
264
265
266
267
268
269 private int approximateFinalLOC() {
270 int max = 0;
271 int current = 0;
272 final Iterator it = revisions.iterator();
273 while (it.hasNext()) {
274 final RevisionData data = (RevisionData) it.next();
275 current += data.getLinesAdded();
276 max = Math.max(current, max);
277 current -= data.getLinesRemoved();
278 }
279 return max;
280 }
281
282
283
284
285
286
287
288
289
290 private int getLOCChange(final RevisionData data) {
291 return data.getLinesAdded() - data.getLinesRemoved();
292 }
293
294 private void buildCreationRevision(final VersionedFile file, final RevisionData data, final int loc, final SortedSet symbolicNames) {
295 file.addInitialRevision(data.getRevisionNumber(), builder.getAuthor(data.getLoginName()), data.getDate(), data.getComment(), loc, symbolicNames);
296 }
297
298 private void buildChangeRevision(final VersionedFile file, final RevisionData data, final int loc, final SortedSet symbolicNames) {
299 file.addChangeRevision(data.getRevisionNumber(), builder.getAuthor(data.getLoginName()), data.getDate(), data.getComment(), loc, data.getLinesAdded()
300 - data.getLinesRemoved(), Math.min(data.getLinesAdded(), data.getLinesRemoved()), symbolicNames);
301 }
302
303 private void buildDeletionRevision(final VersionedFile file, final RevisionData data, final int loc, final SortedSet symbolicNames) {
304 file.addDeletionRevision(data.getRevisionNumber(), builder.getAuthor(data.getLoginName()), data.getDate(), data.getComment(), loc, symbolicNames);
305 }
306
307 private void buildBeginOfLogRevision(final VersionedFile file, final Date beginOfLogDate, final int loc, final SortedSet symbolicNames) {
308 final Date date = new Date(beginOfLogDate.getTime() - 60000);
309 file.addBeginOfLogRevision(date, loc, symbolicNames);
310 }
311
312
313
314
315
316
317
318 private boolean isFilteredFile() {
319 return !this.builder.matchesPatterns(this.name);
320 }
321
322
323
324
325
326
327
328
329
330
331
332 private boolean fileExistsInLogPeriod() {
333 if (revisions.size() > 0) {
334 return true;
335 }
336 try {
337 builder.getLOC(name);
338 return true;
339 } catch (final NoLineCountException fileDoesNotExistInTimespan) {
340 return false;
341 }
342 }
343
344
345
346
347
348
349
350
351
352 private SortedSet createSymbolicNamesCollection(final RevisionData revisionData) {
353 SortedSet symbolicNames = null;
354
355 final Iterator symIt = revBySymnames.keySet().iterator();
356 while (symIt.hasNext()) {
357 final String symName = (String) symIt.next();
358 final String rev = (String) revBySymnames.get(symName);
359 if (revisionData.getRevisionNumber().equals(rev)) {
360 if (symbolicNames == null) {
361 symbolicNames = new TreeSet();
362 }
363 logger.fine("adding revision " + name + "," + revisionData.getRevisionNumber() + " to symname " + symName);
364 symbolicNames.add(builder.getSymbolicName(symName));
365 }
366 }
367
368 return symbolicNames;
369 }
370 }