1 //////////////////////////////////////////////////////////////////////////////
2 // Clirr: compares two versions of a java library for binary compatibility
3 // Copyright (C) 2003 - 2004 Lars Kühne
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 //////////////////////////////////////////////////////////////////////////////
19
20 package net.sf.clirr.ant;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.net.URLClassLoader;
27 import java.util.Iterator;
28 import java.util.LinkedList;
29 import java.util.List;
30
31 import net.sf.clirr.Checker;
32 import net.sf.clirr.event.PlainDiffListener;
33 import net.sf.clirr.event.XmlDiffListener;
34 import org.apache.tools.ant.BuildException;
35 import org.apache.tools.ant.DirectoryScanner;
36 import org.apache.tools.ant.Project;
37 import org.apache.tools.ant.Task;
38 import org.apache.tools.ant.types.FileSet;
39 import org.apache.tools.ant.types.Path;
40
41
42 /***
43 * Implements the Clirr ant task.
44 * @author lkuehne
45 */
46 public final class AntTask extends Task
47 {
48 private static final String FORMATTER_TYPE_PLAIN = "plain";
49 private static final String FORMATTER_TYPE_XML = "xml";
50
51 /***
52 * Output formater.
53 */
54 public static final class Formatter
55 {
56 private String type = null;
57 private String outFile = null;
58
59 public String getOutFile()
60 {
61 return outFile;
62 }
63
64 public void setOutFile(String outFile)
65 {
66 this.outFile = outFile;
67 }
68
69 public String getType()
70 {
71 return type;
72 }
73
74 public void setType(String type)
75 {
76 String lowerCase = type.toLowerCase();
77 if (!lowerCase.equals(FORMATTER_TYPE_XML) && !lowerCase.equals(FORMATTER_TYPE_PLAIN))
78 {
79 throw new BuildException("Illegal formatter type, only plain and xml are supported");
80 }
81
82 this.type = type;
83 }
84 }
85
86
87 private FileSet origFiles = null;
88 private FileSet newFiles = null;
89 private Path newClassPath = null;
90 private Path origClassPath = null;
91
92 private boolean failOnError = true;
93 private boolean failOnWarning = false;
94 private List formatters = new LinkedList();
95
96
97 public Path createNewClassPath()
98 {
99 if (newClassPath == null)
100 {
101 newClassPath = new Path(getProject());
102 }
103 return newClassPath.createPath();
104 }
105
106 public void setNewClassPath(Path path)
107 {
108 if (newClassPath == null)
109 {
110 newClassPath = path;
111 }
112 else
113 {
114 newClassPath.append(path);
115 }
116 }
117
118 public Path createOrigClassPath()
119 {
120 if (origClassPath == null)
121 {
122 origClassPath = new Path(getProject());
123 }
124 return origClassPath.createPath();
125 }
126
127 public void setOrigClassPath(Path path)
128 {
129 if (origClassPath == null)
130 {
131 origClassPath = path;
132 }
133 else
134 {
135 origClassPath.append(path);
136 }
137 }
138
139 public void addOrigFiles(FileSet origFiles)
140 {
141 if (this.origFiles != null)
142 {
143 throw new BuildException();
144 }
145 this.origFiles = origFiles;
146 }
147
148 public void addNewFiles(FileSet newFiles)
149 {
150 if (this.newFiles != null)
151 {
152 throw new BuildException();
153 }
154 this.newFiles = newFiles;
155 }
156
157 public void setFailOnError(boolean failOnError)
158 {
159 this.failOnError = failOnError;
160 }
161
162 public void setFailOnWarning(boolean failOnWarning)
163 {
164 this.failOnWarning = failOnWarning;
165 }
166
167 public void addFormatter(Formatter formatter)
168 {
169 formatters.add(formatter);
170 }
171
172 public void execute()
173 {
174 log("Running Clirr, built from tag $Name: RELEASE_CLIRR_0_3 $", Project.MSG_VERBOSE);
175
176 if (origFiles == null || newFiles == null)
177 {
178 throw new BuildException("Missing nested filesets origFiles and newFiles.", getLocation());
179 }
180
181 if (newClassPath == null)
182 {
183 newClassPath = new Path(getProject());
184 }
185
186 if (origClassPath == null)
187 {
188 origClassPath = new Path(getProject());
189 }
190
191 final File[] origJars = scanFileSet(origFiles);
192 final File[] newJars = scanFileSet(newFiles);
193
194 if (origJars.length == 0)
195 {
196 throw new BuildException("No files in nested fileset origFiles - nothing to check!"
197 + " Please check your fileset specification.");
198 }
199
200 if (newJars.length == 0)
201 {
202 throw new BuildException("No files in nested fileset newFiles - nothing to check!"
203 + " Please check your fileset specification.");
204 }
205
206 final ClassLoader origThirdPartyLoader = createClasspathLoader(origClassPath);
207 final ClassLoader newThirdPartyLoader = createClasspathLoader(newClassPath);
208
209 final Checker checker = new Checker();
210 final ChangeCounter counter = new ChangeCounter();
211
212 boolean formattersWriteToStdOut = false;
213
214 for (Iterator it = formatters.iterator(); it.hasNext();)
215 {
216 Formatter formatter = (Formatter) it.next();
217 final String type = formatter.getType();
218 final String outFile = formatter.getOutFile();
219
220 formattersWriteToStdOut = formattersWriteToStdOut || outFile == null;
221
222 try
223 {
224 if (FORMATTER_TYPE_PLAIN.equals(type))
225 {
226 checker.addDiffListener(new PlainDiffListener(outFile));
227 }
228 else if (FORMATTER_TYPE_XML.equals(type))
229 {
230 checker.addDiffListener(new XmlDiffListener(outFile));
231 }
232 }
233 catch (IOException ex)
234 {
235 log("unable to initialize formatter: " + ex.getMessage(), Project.MSG_WARN);
236 }
237 }
238
239 if (!formattersWriteToStdOut)
240 {
241 checker.addDiffListener(new AntLogger(this));
242 }
243
244 checker.addDiffListener(counter);
245 checker.reportDiffs(origJars, newJars, origThirdPartyLoader, newThirdPartyLoader);
246
247 if (counter.getWarnings() > 0 && failOnWarning || counter.getErrors() > 0 && failOnError)
248 {
249 throw new BuildException("detected incompatible API changes");
250 }
251 }
252
253
254 private ClassLoader createClasspathLoader(Path classpath)
255 {
256 final String[] cpEntries = classpath.list();
257 final URL[] cpUrls = new URL[cpEntries.length];
258 for (int i = 0; i < cpEntries.length; i++)
259 {
260 String cpEntry = cpEntries[i];
261 File entry = new File(cpEntry);
262 try
263 {
264 URL url = entry.toURL();
265 cpUrls[i] = url;
266 }
267 catch (MalformedURLException ex)
268 {
269 final IllegalArgumentException illegalArgEx = new IllegalArgumentException(
270 "Cannot create classLoader from classpath entry " + entry);
271 illegalArgEx.initCause(ex);
272 throw illegalArgEx;
273 }
274 }
275 final URLClassLoader classPathLoader = new URLClassLoader(cpUrls);
276 return classPathLoader;
277 }
278
279 private File[] scanFileSet(FileSet fs)
280 {
281 Project prj = getProject();
282 DirectoryScanner scanner = fs.getDirectoryScanner(prj);
283 scanner.scan();
284 File basedir = scanner.getBasedir();
285 String[] fileNames = scanner.getIncludedFiles();
286 File[] ret = new File[fileNames.length];
287 for (int i = 0; i < fileNames.length; i++)
288 {
289 String fileName = fileNames[i];
290 ret[i] = new File(basedir, fileName);
291 }
292 return ret;
293 }
294 }
This page was automatically generated by Maven