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.statsvn.input;
24
25 import java.io.IOException;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.Properties;
34 import java.util.Set;
35 import java.util.SortedSet;
36 import java.util.TreeSet;
37 import java.util.regex.Pattern;
38
39 import net.sf.statcvs.Messages;
40 import net.sf.statcvs.input.CommitListBuilder;
41 import net.sf.statcvs.input.NoLineCountException;
42 import net.sf.statcvs.model.Author;
43 import net.sf.statcvs.model.Directory;
44 import net.sf.statcvs.model.Repository;
45 import net.sf.statcvs.model.SymbolicName;
46 import net.sf.statcvs.model.VersionedFile;
47 import net.sf.statcvs.output.ConfigurationOptions;
48 import net.sf.statcvs.util.FilePatternMatcher;
49 import net.sf.statcvs.util.FileUtils;
50 import net.sf.statsvn.output.SvnConfigurationOptions;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public class Builder implements SvnLogBuilder {
71 private final Set atticFileNames = new HashSet();
72
73 private final Map authors = new HashMap();
74
75 private FileBuilder currentFileBuilder = null;
76
77 private final Map directories = new HashMap();
78
79 private final FilePatternMatcher excludePattern;
80
81 private final Map fileBuilders = new HashMap();
82
83 private final FilePatternMatcher includePattern;
84
85 private String projectName = null;
86
87 private final RepositoryFileManager repositoryFileManager;
88
89 private Date startDate = null;
90
91 private final Map symbolicNames = new HashMap();
92
93 private final Pattern tagsPattern;
94
95
96
97
98
99
100
101
102
103
104
105 public Builder(final RepositoryFileManager repositoryFileManager, final FilePatternMatcher includePattern, final FilePatternMatcher excludePattern,
106 final Pattern tagsPattern) {
107 this.repositoryFileManager = repositoryFileManager;
108 this.includePattern = includePattern;
109 this.excludePattern = excludePattern;
110 this.tagsPattern = tagsPattern;
111 directories.put("", Directory.createRoot());
112 }
113
114
115
116
117
118
119
120
121
122
123 public void addToAttic(final String filename) {
124 if (!atticFileNames.contains(filename)) {
125 atticFileNames.add(filename);
126 }
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 public void buildFile(final String filename, final boolean isBinary, final boolean isInAttic, final Map revBySymnames, final Map dateBySymnames) {
151 if (fileBuilders.containsKey(filename)) {
152 currentFileBuilder = (FileBuilder) fileBuilders.get(filename);
153 } else {
154 currentFileBuilder = new FileBuilder(this, filename, isBinary, revBySymnames, dateBySymnames);
155 fileBuilders.put(filename, currentFileBuilder);
156 if (isInAttic) {
157 addToAttic(filename);
158 }
159 }
160 }
161
162
163
164
165
166
167
168 public void buildModule(final String moduleName) {
169 this.projectName = moduleName;
170 }
171
172
173
174
175
176
177
178 public void buildRevision(final RevisionData data) {
179
180 currentFileBuilder.addRevisionData(data);
181
182 if (startDate == null || startDate.compareTo(data.getDate()) > 0) {
183 startDate = data.getDate();
184 }
185 }
186
187
188
189
190
191
192 public Repository createRepository() {
193
194 if (startDate == null) {
195 return new Repository();
196 }
197
198 final Repository result = new Repository();
199 final Iterator it = fileBuilders.values().iterator();
200 while (it.hasNext()) {
201 final FileBuilder fileBuilder = (FileBuilder) it.next();
202 final VersionedFile file = fileBuilder.createFile(startDate);
203 if (file == null) {
204 continue;
205 }
206 result.addFile(file);
207 SvnConfigurationOptions.getTaskLogger().log("adding " + file.getFilenameWithPath() + " (" + file.getRevisions().size() + " revisions)");
208 }
209
210
211 final SortedSet revisions = result.getRevisions();
212 final List commits = new CommitListBuilder(revisions).createCommitList();
213 result.setCommits(commits);
214
215
216 result.setSymbolicNames(getMatchingSymbolicNames());
217
218 SvnConfigurationOptions.getTaskLogger().log("SYMBOLIC NAMES - " + symbolicNames);
219
220 return result;
221 }
222
223
224
225
226
227
228 public Set getAtticFileNames() {
229 return atticFileNames;
230 }
231
232
233
234
235
236
237
238
239 public Author getAuthor(String name) {
240 if (name == null || name.length() == 0) {
241 name = Messages.getString("AUTHOR_UNKNOWN");
242 }
243
244 final String lowerCaseName = name.toLowerCase(Locale.getDefault());
245 final boolean bAnon = SvnConfigurationOptions.isAnonymize();
246 if (this.authors.containsKey(lowerCaseName)) {
247 return (Author) this.authors.get(lowerCaseName);
248 }
249
250 Author newAuthor;
251 if (bAnon) {
252
253 newAuthor = new Author(AuthorAnonymizingProvider.getNewName());
254 } else {
255 newAuthor = new Author(name);
256 }
257
258 final Properties p = ConfigurationOptions.getConfigProperties();
259 this.authors.put(lowerCaseName, newAuthor);
260 if (p != null && !bAnon) {
261 newAuthor.setRealName(p.getProperty("user." + lowerCaseName + ".realName"));
262 newAuthor.setHomePageUrl(p.getProperty("user." + lowerCaseName + ".url"));
263 newAuthor.setImageUrl(p.getProperty("user." + lowerCaseName + ".image"));
264 newAuthor.setEmail(p.getProperty("user." + lowerCaseName + ".email"));
265 }
266 return newAuthor;
267 }
268
269
270
271
272
273
274
275
276 public Directory getDirectory(final String filename) {
277 final int lastSlash = filename.lastIndexOf('/');
278 if (lastSlash == -1) {
279 return getDirectoryForPath("");
280 }
281 return getDirectoryForPath(filename.substring(0, lastSlash + 1));
282 }
283
284
285
286
287
288
289 private Directory getDirectoryForPath(final String path) {
290 if (directories.containsKey(path)) {
291 return (Directory) directories.get(path);
292 }
293 final Directory parent = getDirectoryForPath(FileUtils.getParentDirectoryPath(path));
294 final Directory newDirectory = parent.createSubdirectory(FileUtils.getDirectoryName(path));
295 directories.put(path, newDirectory);
296 return newDirectory;
297 }
298
299
300
301
302
303
304
305
306 public Map getFileBuilders() {
307 return fileBuilders;
308 }
309
310
311
312
313 public int getLOC(final String filename) throws NoLineCountException {
314 if (repositoryFileManager == null) {
315 throw new NoLineCountException("no RepositoryFileManager");
316 }
317
318 return repositoryFileManager.getLinesOfCode(filename);
319 }
320
321 public String getProjectName() {
322 return projectName;
323 }
324
325
326
327
328 public String getRevision(final String filename) throws IOException {
329 if (repositoryFileManager == null) {
330 throw new IOException("no RepositoryFileManager");
331 }
332 return repositoryFileManager.getRevision(filename);
333 }
334
335
336
337
338
339
340
341
342 public SymbolicName getSymbolicName(final String name, final Date date) {
343 SymbolicName sym = (SymbolicName) symbolicNames.get(name);
344
345 if (sym != null) {
346 return sym;
347 } else {
348 sym = new SymbolicName(name, date);
349 symbolicNames.put(name, sym);
350
351 return sym;
352 }
353 }
354
355
356
357
358
359
360
361
362
363
364 public boolean matchesPatterns(final String filename) {
365 if (excludePattern != null && excludePattern.matches(filename)) {
366 return false;
367 }
368 if (includePattern != null) {
369 return includePattern.matches(filename);
370 }
371 return true;
372 }
373
374
375
376
377
378
379
380
381 public boolean matchesTagPatterns(final String tag) {
382 if (tagsPattern != null) {
383 return tagsPattern.matcher(tag).matches();
384 }
385 return false;
386 }
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402 public synchronized void updateRevision(final String filename, final String revisionNumber, final int linesAdded, final int linesRemoved) {
403 final FileBuilder fb = (FileBuilder) fileBuilders.get(filename);
404 if (fb != null) {
405 fb.updateRevision(revisionNumber, linesAdded, linesRemoved);
406 }
407 }
408
409
410
411
412 private SortedSet getMatchingSymbolicNames() {
413 final TreeSet result = new TreeSet();
414 if (this.tagsPattern == null) {
415 return result;
416 }
417 for (final Iterator it = this.symbolicNames.values().iterator(); it.hasNext();) {
418 final SymbolicName sn = (SymbolicName) it.next();
419 if (sn.getDate() != null && this.tagsPattern.matcher(sn.getName()).matches()) {
420 result.add(sn);
421 }
422 }
423 return result;
424 }
425
426 private static final class AuthorAnonymizingProvider {
427 private AuthorAnonymizingProvider() {
428
429 }
430
431 private static int count = 0;
432
433 static synchronized String getNewName() {
434 return "author" + (String.valueOf(++count));
435 }
436
437 }
438 }