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.statcvs.util.StringUtils; |
51 | |
import net.sf.statsvn.output.SvnConfigurationOptions; |
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | 814 | public class Builder implements SvnLogBuilder { |
72 | 262 | private final Set atticFileNames = new HashSet(); |
73 | 814 | |
74 | 262 | private final Map authors = new HashMap(); |
75 | 814 | |
76 | 262 | private FileBuilder currentFileBuilder = null; |
77 | 814 | |
78 | 262 | private final Map directories = new HashMap(); |
79 | |
|
80 | |
private final FilePatternMatcher excludePattern; |
81 | 814 | |
82 | 262 | private final Map fileBuilders = new HashMap(); |
83 | |
|
84 | |
private final FilePatternMatcher includePattern; |
85 | 814 | |
86 | 262 | private String projectName = null; |
87 | |
|
88 | |
private final RepositoryFileManager repositoryFileManager; |
89 | 814 | |
90 | 262 | private Date startDate = null; |
91 | 814 | |
92 | 262 | private final Map symbolicNames = new HashMap(); |
93 | |
|
94 | |
private final Pattern tagsPattern; |
95 | |
|
96 | |
public void clean() { |
97 | 2 | atticFileNames.clear(); |
98 | 2 | authors.clear(); |
99 | 2 | directories.clear(); |
100 | 2 | fileBuilders.clear(); |
101 | 2 | symbolicNames.clear(); |
102 | 2 | } |
103 | |
|
104 | |
|
105 | |
|
106 | 814 | |
107 | 1010 | |
108 | 1010 | |
109 | 1010 | |
110 | 1010 | |
111 | 1010 | |
112 | 1010 | |
113 | 196 | |
114 | |
public Builder(final RepositoryFileManager repositoryFileManager, final FilePatternMatcher includePattern, final FilePatternMatcher excludePattern, |
115 | 66 | final Pattern tagsPattern) { |
116 | 66 | this.repositoryFileManager = repositoryFileManager; |
117 | 66 | this.includePattern = includePattern; |
118 | 66 | this.excludePattern = excludePattern; |
119 | 66 | this.tagsPattern = tagsPattern; |
120 | 66 | directories.put("", Directory.createRoot()); |
121 | 66 | } |
122 | |
|
123 | |
|
124 | 11954 | |
125 | 8622 | |
126 | 1108 | |
127 | 11954 | |
128 | 1996 | |
129 | |
|
130 | |
|
131 | |
|
132 | |
public void addToAttic(final String filename) { |
133 | 996 | if (!atticFileNames.contains(filename)) { |
134 | 552 | atticFileNames.add(filename); |
135 | |
} |
136 | 996 | } |
137 | |
|
138 | |
|
139 | |
|
140 | |
|
141 | |
|
142 | |
|
143 | |
|
144 | |
|
145 | |
|
146 | |
|
147 | |
|
148 | |
|
149 | |
|
150 | |
|
151 | 136405 | |
152 | 131024 | |
153 | 18040 | |
154 | 28165 | |
155 | 32909 | |
156 | 32909 | |
157 | 10122 | |
158 | 900 | |
159 | |
public void buildFile(final String filename, final boolean isBinary, final boolean isInAttic, final Map revBySymnames, final Map dateBySymnames) { |
160 | 147771 | if (fileBuilders.containsKey(filename)) { |
161 | 31804 | currentFileBuilder = (FileBuilder) fileBuilders.get(filename); |
162 | |
} else { |
163 | 2346 | currentFileBuilder = new FileBuilder(this, filename, isBinary, revBySymnames, dateBySymnames); |
164 | 2346 | fileBuilders.put(filename, currentFileBuilder); |
165 | 2346 | if (isInAttic) { |
166 | 448 | addToAttic(filename); |
167 | |
} |
168 | |
} |
169 | 11765 | } |
170 | 493 | |
171 | 94 | |
172 | |
|
173 | |
|
174 | |
|
175 | |
|
176 | |
|
177 | |
public void buildModule(final String moduleName) { |
178 | 32 | this.projectName = moduleName; |
179 | 32 | } |
180 | 162706 | |
181 | 27176 | |
182 | 162706 | |
183 | 42352 | |
184 | 2584 | |
185 | 162706 | |
186 | 27176 | |
187 | |
public void buildRevision(final RevisionData data) { |
188 | |
|
189 | 13558 | currentFileBuilder.addRevisionData(data); |
190 | |
|
191 | 13558 | if (startDate == null || startDate.compareTo(data.getDate()) > 0) { |
192 | 1264 | startDate = data.getDate(); |
193 | |
} |
194 | 13971 | } |
195 | 125 | |
196 | 6 | |
197 | |
|
198 | 388 | |
199 | 482 | |
200 | 26216 | |
201 | 30158 | public Repository createRepository() { |
202 | 30064 | |
203 | 30098 | if (startDate == null) { |
204 | 4404 | return new Repository(); |
205 | 18 | } |
206 | 25662 | |
207 | 30006 | final Repository result = new Repository(); |
208 | 26799 | final Iterator it = fileBuilders.values().iterator(); |
209 | 6488 | while (it.hasNext()) { |
210 | 2144 | final FileBuilder fileBuilder = (FileBuilder) it.next(); |
211 | 2532 | final VersionedFile file = fileBuilder.createFile(startDate); |
212 | 2626 | if (file == null) { |
213 | 488 | continue; |
214 | 94 | } |
215 | 2138 | result.addFile(file); |
216 | 2526 | SvnConfigurationOptions.getTaskLogger().log("adding " + file.getFilenameWithPath() + " (" + file.getRevisions().size() + " revisions)"); |
217 | 2232 | } |
218 | 388 | |
219 | 94 | |
220 | 420 | final SortedSet revisions = result.getRevisions(); |
221 | 126 | final List commits = new CommitListBuilder(revisions).createCommitList(); |
222 | 32 | result.setCommits(commits); |
223 | |
|
224 | |
|
225 | 32 | result.setSymbolicNames(getMatchingSymbolicNames()); |
226 | |
|
227 | 32 | SvnConfigurationOptions.getTaskLogger().log("SYMBOLIC NAMES - " + symbolicNames); |
228 | |
|
229 | 107 | return result; |
230 | 18 | } |
231 | |
|
232 | |
|
233 | |
|
234 | |
|
235 | |
|
236 | |
|
237 | |
public Set getAtticFileNames() { |
238 | 6 | return atticFileNames; |
239 | |
} |
240 | 133241 | |
241 | 22282 | |
242 | 0 | |
243 | |
|
244 | 133241 | |
245 | 155523 | |
246 | 155523 | |
247 | 154864 | |
248 | 22132 | public Author getAuthor(String name) { |
249 | 11102 | if (name == null || name.length() == 0) { |
250 | 0 | name = Messages.getString("AUTHOR_UNKNOWN"); |
251 | 659 | } |
252 | 150 | |
253 | 11102 | String lowerCaseName = name.toLowerCase(Locale.getDefault()); |
254 | 11102 | final boolean bAnon = SvnConfigurationOptions.isAnonymize(); |
255 | 11761 | if (this.authors.containsKey(lowerCaseName)) { |
256 | 11198 | return (Author) this.authors.get(lowerCaseName); |
257 | |
} |
258 | 659 | |
259 | 809 | Author newAuthor; |
260 | 713 | if (bAnon) { |
261 | 809 | |
262 | 809 | newAuthor = new Author(AuthorAnonymizingProvider.getNewName()); |
263 | 659 | } else { |
264 | 863 | newAuthor = new Author(name); |
265 | 243 | } |
266 | 659 | |
267 | 297 | final Properties p = ConfigurationOptions.getConfigProperties(); |
268 | 243 | |
269 | 54 | if (p != null) { |
270 | 54 | String replacementUser = p.getProperty("user." + lowerCaseName + ".replacedBy"); |
271 | 243 | |
272 | 297 | if (StringUtils.isNotEmpty(replacementUser)) { |
273 | 0 | replacementUser = replacementUser.toLowerCase(); |
274 | 150 | if (this.authors.containsKey(replacementUser)) { |
275 | 150 | return (Author) this.authors.get(replacementUser); |
276 | 393 | } |
277 | 16319 | lowerCaseName = replacementUser; |
278 | 16319 | newAuthor = new Author(lowerCaseName); |
279 | 653 | } |
280 | 150 | } |
281 | 15816 | |
282 | 204 | if (p != null && !bAnon) { |
283 | 54 | newAuthor.setRealName(p.getProperty("user." + lowerCaseName + ".realName")); |
284 | 54 | newAuthor.setHomePageUrl(p.getProperty("user." + lowerCaseName + ".url")); |
285 | 204 | newAuthor.setImageUrl(p.getProperty("user." + lowerCaseName + ".image")); |
286 | 204 | newAuthor.setEmail(p.getProperty("user." + lowerCaseName + ".email")); |
287 | 9747 | newAuthor.setTwitterUserName(p.getProperty("user." + name.toLowerCase() + ".twitterUsername")); |
288 | 9747 | newAuthor.setTwitterUserId(p.getProperty("user." + name.toLowerCase() + ".twitterUserId")); |
289 | 351 | String val = p.getProperty("user." + name.toLowerCase() + ".twitterIncludeFlash"); |
290 | 17944 | if (val != null && val.length() > 0) { |
291 | 25715 | newAuthor.setTwitterIncludeFlash(Boolean.valueOf(val).booleanValue()); |
292 | |
} |
293 | 1625 | val = p.getProperty("user." + name.toLowerCase() + ".twitterIncludeHtml"); |
294 | 1625 | if (val != null && val.length() > 0) { |
295 | 1571 | newAuthor.setTwitterIncludeHtml(Boolean.valueOf(val).booleanValue()); |
296 | 1571 | } |
297 | |
} |
298 | 54 | this.authors.put(lowerCaseName, newAuthor); |
299 | 54 | return newAuthor; |
300 | 10629 | } |
301 | 9693 | |
302 | 4360 | |
303 | 5296 | |
304 | 1108 | |
305 | 936 | |
306 | 5124 | |
307 | 89910 | |
308 | |
|
309 | |
public Directory getDirectory(final String filename) { |
310 | 2154 | final int lastSlash = filename.lastIndexOf('/'); |
311 | 2154 | if (lastSlash == -1) { |
312 | 66 | return getDirectoryForPath(""); |
313 | |
} |
314 | 15937 | return getDirectoryForPath(filename.substring(0, lastSlash + 1)); |
315 | 4862 | } |
316 | 4360 | |
317 | 53946 | |
318 | 14223 | |
319 | 438 | |
320 | 438 | |
321 | 438 | |
322 | 16 | private Directory getDirectoryForPath(final String path) { |
323 | 2362 | if (directories.containsKey(path)) { |
324 | 10461 | return (Directory) directories.get(path); |
325 | 36 | } |
326 | 208 | final Directory parent = getDirectoryForPath(FileUtils.getParentDirectoryPath(path)); |
327 | 208 | final Directory newDirectory = parent.createSubdirectory(FileUtils.getDirectoryName(path)); |
328 | 8479 | directories.put(path, newDirectory); |
329 | 14061 | return newDirectory; |
330 | 128 | } |
331 | |
|
332 | 37710 | |
333 | |
|
334 | |
|
335 | |
|
336 | |
|
337 | |
|
338 | |
|
339 | 12035 | public Map getFileBuilders() { |
340 | 12084 | return fileBuilders; |
341 | |
} |
342 | 8235 | |
343 | 3704 | |
344 | |
|
345 | 0 | |
346 | 0 | public int getLOC(final String filename) throws NoLineCountException { |
347 | 1852 | if (repositoryFileManager == null) { |
348 | 8 | throw new NoLineCountException("no RepositoryFileManager"); |
349 | 0 | } |
350 | |
|
351 | 1838 | return repositoryFileManager.getLinesOfCode(filename); |
352 | |
} |
353 | 0 | |
354 | 3728 | public String getProjectName() { |
355 | 50 | return projectName; |
356 | 0 | } |
357 | 3680 | |
358 | 0 | |
359 | 0 | |
360 | |
|
361 | 0 | public String getRevision(final String filename) throws IOException { |
362 | 1846 | if (repositoryFileManager == null) { |
363 | 16 | throw new IOException("no RepositoryFileManager"); |
364 | |
} |
365 | 31619 | return repositoryFileManager.getRevision(filename); |
366 | 32 | } |
367 | |
|
368 | 29757 | |
369 | 16 | |
370 | 0 | |
371 | 29741 | |
372 | |
|
373 | 0 | |
374 | 0 | |
375 | 17865 | public SymbolicName getSymbolicName(final String name, final Date date) { |
376 | 18 | SymbolicName sym = (SymbolicName) symbolicNames.get(name); |
377 | |
|
378 | 17847 | if (sym != null) { |
379 | 9 | return sym; |
380 | |
} else { |
381 | 17838 | sym = new SymbolicName(name, date); |
382 | 0 | symbolicNames.put(name, sym); |
383 | 0 | |
384 | 0 | return sym; |
385 | 0 | } |
386 | |
} |
387 | |
|
388 | |
|
389 | |
|
390 | 7998 | |
391 | 12 | |
392 | 0 | |
393 | 7986 | |
394 | 6 | |
395 | 0 | |
396 | 7980 | |
397 | |
public boolean matchesPatterns(final String filename) { |
398 | 3970 | if (excludePattern != null && excludePattern.matches(filename)) { |
399 | 4 | return false; |
400 | |
} |
401 | 3966 | if (includePattern != null) { |
402 | 2 | return includePattern.matches(filename); |
403 | 56160 | } |
404 | 60124 | return true; |
405 | 56160 | } |
406 | |
|
407 | 56160 | |
408 | 0 | |
409 | |
|
410 | 0 | |
411 | |
|
412 | |
|
413 | 33940 | |
414 | 33940 | public boolean matchesTagPatterns(final String tag) { |
415 | 33940 | if (tagsPattern != null) { |
416 | 0 | return tagsPattern.matcher(tag).matches(); |
417 | 33696 | } |
418 | 0 | return false; |
419 | 0 | } |
420 | 0 | |
421 | |
|
422 | 0 | |
423 | 144 | |
424 | 144 | |
425 | 144 | |
426 | |
|
427 | 0 | |
428 | 14976 | |
429 | 0 | |
430 | 14976 | |
431 | 0 | |
432 | 14976 | |
433 | 0 | |
434 | 0 | |
435 | |
public synchronized void updateRevision(final String filename, final String revisionNumber, final int linesAdded, final int linesRemoved) { |
436 | 7488 | final FileBuilder fb = (FileBuilder) fileBuilders.get(filename); |
437 | 0 | if (fb != null) { |
438 | 7582 | fb.updateRevision(revisionNumber, linesAdded, linesRemoved); |
439 | 0 | } |
440 | 7582 | } |
441 | 0 | |
442 | 0 | |
443 | 0 | |
444 | 0 | |
445 | 0 | private SortedSet getMatchingSymbolicNames() { |
446 | 32 | final TreeSet result = new TreeSet(); |
447 | 32 | if (this.tagsPattern == null) { |
448 | 32 | return result; |
449 | |
} |
450 | 0 | for (final Iterator it = this.symbolicNames.values().iterator(); it.hasNext();) { |
451 | 0 | final SymbolicName sn = (SymbolicName) it.next(); |
452 | 0 | if (sn.getDate() != null && this.tagsPattern.matcher(sn.getName()).matches()) { |
453 | 0 | result.add(sn); |
454 | 0 | } |
455 | 0 | } |
456 | 0 | return result; |
457 | |
} |
458 | |
|
459 | 0 | private static final class AuthorAnonymizingProvider { |
460 | 0 | private AuthorAnonymizingProvider() { |
461 | |
|
462 | 0 | } |
463 | |
|
464 | 0 | private static int count = 0; |
465 | |
|
466 | |
static synchronized String getNewName() { |
467 | 0 | return "author" + (String.valueOf(++count)); |
468 | |
} |
469 | |
|
470 | |
} |
471 | |
} |