2
StatSVN - SVN Subversion statistics generation
3
Copyright (C) 2006 Benoit Xhenseval
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Lesser General Public
8
License as published by the Free Software Foundation; either
9
version 2.1 of the License, or (at your option) any later version.
11
This library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Lesser General Public License for more details.
16
You should have received a copy of the GNU Lesser General Public
17
License along with this library; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
package net.sf.statsvn.output;
23
import java.io.BufferedWriter;
25
import java.io.FileWriter;
26
import java.io.IOException;
27
import java.io.InputStream;
28
import java.io.Writer;
29
import java.util.Calendar;
30
import java.util.Date;
31
import java.util.Iterator;
32
import java.util.SortedSet;
34
import net.sf.statcvs.Messages;
35
import net.sf.statcvs.model.Directory;
36
import net.sf.statcvs.model.Revision;
37
import net.sf.statcvs.model.VersionedFile;
38
import net.sf.statcvs.output.ConfigurationOptions;
39
import net.sf.statcvs.output.ReportConfig;
40
import net.sf.statcvs.pages.HTML;
41
import net.sf.statcvs.pages.NavigationNode;
42
import net.sf.statcvs.pages.Page;
43
import net.sf.statcvs.util.FileUtils;
46
* New report that Repo Map, a jtreemap-based report (applet) that shows the
47
* entire source tree in a hierarchical manner, the size of each box is related
48
* to LOC and the colour to the changes over the last 30 days (red -loc, green
51
* @author Benoit Xhenseval (www.objectlab.co.uk)
52
* @see http://jtreemap.sourceforge.net for more about JTreeMap.
54
public class RepoMapPageMaker {
55
private static final int DAYS_FROM_LAST_DATE = 30;
57
private static final String WEB_FILE_PATH = "web-files/";
59
private static final String REPO_FILE = "repomap-data.txt";
61
private final Date deadline;
63
private final Date currentDate;
65
private final ReportConfig config;
67
private int indent = 0;
70
* @see net.sf.statcvs.output.HTMLPage#HTMLPage(Repository)
72
public RepoMapPageMaker(final ReportConfig config) {
73
final Calendar cal = Calendar.getInstance();
74
if (config !=null && config.getRepository() != null && config.getRepository().getLastDate()!=null) {
75
cal.setTime(config.getRepository().getLastDate());
77
currentDate = cal.getTime();
78
cal.add(Calendar.DATE, -DAYS_FROM_LAST_DATE);
79
deadline = cal.getTime();
83
public NavigationNode toFile() {
84
final Page page = this.config.createPage("repomap", Messages.getString("REPOMAP_TITLE"), Messages.getString("REPOMAP_TITLE"));
85
page.addRawAttribute(Messages.getString("REPOMAP_START_DATE"), HTML.getDate(deadline));
86
page.addRawAttribute(Messages.getString("REPOMAP_END_DATE"), HTML.getDate(currentDate));
88
page.addRawContent("<p>" + Messages.getString("REPOMAP_DESCRIPTION") + "</p>");
89
page.addRawContent("<p>" + getApplet() + "</p>");
90
page.addRawContent("<p><small>This page uses <a href=\"http://jtreemap.sourceforge.net\">JTreeMap</a>.</small></p>");
91
buildXmlForJTreeMap();
96
private String getApplet() {
97
return "<applet archive=\"./" + Messages.getString("JTREEMAP_JAR") + "\" code=\"net.sf.jtreemap.swing.example.JTreeMapAppletExample\""
98
+ " width=\"940\" height=\"600\"><param name=\"dataFile\" value=\"" + REPO_FILE + "\"/>" + "<param name=\"viewTree\" value=\"true\"/>"
99
+ "<param name=\"showWeight\" value=\"true\"/>" + "<param name=\"valuePrefix\" value=\"Change:\"/>"
100
+ "<param name=\"weightPrefix\" value=\"LOC:\"/>" + "<param name=\"dataFileType\" value=\"xml\"/>"
101
+ "<param name=\"colorProvider\" value=\"HSBLog\"/>" + "</applet>";
104
private void buildXmlForJTreeMap() {
105
BufferedWriter out = null;
107
copyJar(Messages.getString("JTREEMAP_JAR"));
108
out = new BufferedWriter(new FileWriter(ConfigurationOptions.getOutputDir() + REPO_FILE));
109
out.write("<?xml version='1.0' encoding='ISO-8859-1'?>\n");
110
// out.append("<!DOCTYPE root SYSTEM \"TreeMap.dtd\" >\n");
111
out.write("<root>\n");
112
final Iterator it = config.getRepository().getDirectories().iterator();
114
final Directory dir = (Directory) it.next();
115
doDirectory(out, dir);
117
out.write("</root>");
118
} catch (final IOException e) {
124
} catch (final IOException e) {
125
SvnConfigurationOptions.getTaskLogger().error(e.toString());
131
private void copyJar(final String jtreemapJar) throws IOException {
132
InputStream stream = null;
134
stream = RepoMapPageMaker.class.getResourceAsStream(WEB_FILE_PATH + jtreemapJar);
135
if (stream != null) {
136
FileUtils.copyFile(stream, new File(ConfigurationOptions.getOutputDir() + jtreemapJar));
138
throw new IOException("The stream to " + (WEB_FILE_PATH + jtreemapJar) + " failed, is it copied in the jar?");
141
if (stream != null) {
147
private void addSpaces(final int count, final BufferedWriter out) throws IOException {
148
out.write(getSpaces(count));
151
private String getSpaces(final int count) {
152
final StringBuffer result = new StringBuffer();
153
for (int i = 0; i < count; i++) {
156
return result.toString();
159
private void doDirectory(final BufferedWriter out, final Directory dir) throws IOException {
161
SvnConfigurationOptions.getTaskLogger().log("Directory:" + getSpaces(indent) + dir.getName());
168
final SortedSet set = dir.getSubdirectories();
169
final SortedSet files = dir.getFiles();
170
final String name = dir.isRoot() ? Messages.getString("NAVIGATION_ROOT") : dir.getName();
171
boolean addedBranch = false;
172
if (indent > 1 && set != null && !set.isEmpty()) {
174
addSpaces(indent, out);
175
out.write("<branch>\n");
176
addSpaces(indent + 2, out);
179
} else if (indent == 1) {
180
addSpaces(indent, out);
184
for (final Iterator it2 = set.iterator(); it2.hasNext();) {
185
doDirectory(out, (Directory) it2.next());
188
addedBranch = handleEachFileInDir(out, files, name, addedBranch);
190
addSpaces(indent, out);
191
out.write("</branch>\n");
196
private boolean handleEachFileInDir(final BufferedWriter out, final SortedSet files, final String name, boolean addedBranch) throws IOException {
197
if (files != null && !files.isEmpty()) {
198
for (final Iterator file = files.iterator(); file.hasNext();) {
199
final VersionedFile vfile = (VersionedFile) file.next();
201
int loc = vfile.getCurrentLinesOfCode();
203
SvnConfigurationOptions.getTaskLogger().log("File:" + vfile.getFilename() + " LOC:" + loc);
205
int delta = calculateTotalDelta(vfile);
207
loc = Math.abs(delta);
214
addSpaces(indent, out);
215
out.write("<branch>\n");
216
addSpaces(indent + 2, out);
221
addSpaces(indent + 2, out);
223
labelTag(out, vfile.getFilename());
224
tag(out, "weight", String.valueOf(loc));
225
final double percentage = ((double) delta) / (double) loc * 100.0;
226
tag(out, "value", String.valueOf(percentage));
227
out.write("</leaf>\n");
228
SvnConfigurationOptions.getTaskLogger().log("===========>>> LOC=" + loc + " totalDelta=" + delta + " Delta%=" + percentage);
234
private int calculateTotalDelta(final VersionedFile vfile) {
236
final SortedSet revisions = vfile.getRevisions();
237
// take all deltas for the last 30 days.
238
for (final Iterator rev = revisions.iterator(); rev.hasNext();) {
239
final Revision revision = (Revision) rev.next();
241
SvnConfigurationOptions.getTaskLogger().log(
242
"Revision " + revision.getDate() + " file:" + vfile.getFilename() + " Dead:" + vfile.isDead() + " LOC:" + revision.getLines() + " delta:"
243
+ revision.getLinesDelta());
245
if (deadline.before(revision.getDate())) {
246
delta += revision.getLinesDelta();
248
SvnConfigurationOptions.getTaskLogger().log(
249
"Revision " + revision.getRevisionNumber() + " Delta:" + revision.getLinesDelta() + " totalDelta:" + delta + " LOC:"
250
+ revision.getLines() + " Dead:" + revision.isDead());
256
private void labelTag(final Writer result, final String name) throws IOException {
257
if (name == null || name.length() == 0) {
258
tag(result, "label", "[root]");
260
tag(result, "label", name);
264
private void tag(final Writer result, final String tagName, final String value) throws IOException {
266
result.write(tagName);
270
result.write(tagName);