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 }