1 20 package net.sf.clirr.ant; 21 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.util.Iterator ; 25 import java.util.LinkedList ; 26 import java.util.List ; 27 28 import net.sf.clirr.core.Checker; 29 import net.sf.clirr.core.CheckerException; 30 import net.sf.clirr.core.ClassFilter; 31 import net.sf.clirr.core.ClassSelector; 32 import net.sf.clirr.core.PlainDiffListener; 33 import net.sf.clirr.core.XmlDiffListener; 34 import net.sf.clirr.core.internal.ClassLoaderUtil; 35 import net.sf.clirr.core.internal.bcel.BcelTypeArrayBuilder; 36 import net.sf.clirr.core.spi.JavaType; 37 38 import org.apache.bcel.classfile.JavaClass; 39 import org.apache.tools.ant.BuildException; 40 import org.apache.tools.ant.DirectoryScanner; 41 import org.apache.tools.ant.Project; 42 import org.apache.tools.ant.Task; 43 import org.apache.tools.ant.types.FileSet; 44 import org.apache.tools.ant.types.Path; 45 import org.apache.tools.ant.types.PatternSet; 46 47 48 52 public final class AntTask extends Task 53 { 54 private static final String FORMATTER_TYPE_PLAIN = "plain"; 55 private static final String FORMATTER_TYPE_XML = "xml"; 56 57 60 public static final class Formatter 61 { 62 private String type = null; 63 private String outFile = null; 64 65 public String getOutFile() 66 { 67 return outFile; 68 } 69 70 public void setOutFile(String outFile) 71 { 72 this.outFile = outFile; 73 } 74 75 public String getType() 76 { 77 return type; 78 } 79 80 public void setType(String type) 81 { 82 String lowerCase = type.toLowerCase(); 83 if (!lowerCase.equals(FORMATTER_TYPE_XML) 84 && !lowerCase.equals(FORMATTER_TYPE_PLAIN)) 85 { 86 throw new BuildException( 87 "Illegal formatter type, only plain and xml are supported"); 88 } 89 90 this.type = type; 91 } 92 } 93 94 97 private static class CompoundClassFilter implements ClassFilter 98 { 99 private final ClassFilter patternSetFilter; 100 private final ClassFilter scopeSelector; 101 102 public CompoundClassFilter(ClassFilter patternSetFilter, ClassFilter scopeSelector) 103 { 104 this.patternSetFilter = patternSetFilter; 105 this.scopeSelector = scopeSelector; 106 } 107 108 public boolean isSelected(JavaClass clazz) 109 { 110 return patternSetFilter.isSelected(clazz) && scopeSelector.isSelected(clazz); 111 } 112 } 113 114 private FileSet origFiles = null; 115 private FileSet newFiles = null; 116 private Path newClassPath = null; 117 private Path origClassPath = null; 118 119 private boolean failOnBinError = true; 120 private boolean failOnBinWarning = false; 121 private boolean failOnSrcError = true; 122 private boolean failOnSrcWarning = false; 123 private List formatters = new LinkedList (); 124 private List patternSets = new LinkedList (); 125 126 127 public Path createNewClassPath() 128 { 129 if (newClassPath == null) 130 { 131 newClassPath = new Path(getProject()); 132 } 133 return newClassPath.createPath(); 134 } 135 136 public void setNewClassPath(Path path) 137 { 138 if (newClassPath == null) 139 { 140 newClassPath = path; 141 } 142 else 143 { 144 newClassPath.append(path); 145 } 146 } 147 148 public Path createOrigClassPath() 149 { 150 if (origClassPath == null) 151 { 152 origClassPath = new Path(getProject()); 153 } 154 return origClassPath.createPath(); 155 } 156 157 public void setOrigClassPath(Path path) 158 { 159 if (origClassPath == null) 160 { 161 origClassPath = path; 162 } 163 else 164 { 165 origClassPath.append(path); 166 } 167 } 168 169 public void addOrigFiles(FileSet origFiles) 170 { 171 if (this.origFiles != null) 172 { 173 throw new BuildException(); 174 } 175 this.origFiles = origFiles; 176 } 177 178 public void addNewFiles(FileSet newFiles) 179 { 180 if (this.newFiles != null) 181 { 182 throw new BuildException(); 183 } 184 this.newFiles = newFiles; 185 } 186 187 public void setFailOnBinError(boolean failOnBinError) 188 { 189 this.failOnBinError = failOnBinError; 190 } 191 192 public void setFailOnBinWarning(boolean failOnBinWarning) 193 { 194 this.failOnBinWarning = failOnBinWarning; 195 } 196 197 public void setFailOnSrcError(boolean failOnSrcError) 198 { 199 this.failOnSrcError = failOnSrcError; 200 } 201 202 public void setFailOnSrcWarning(boolean failOnSrcWarning) 203 { 204 this.failOnSrcWarning = failOnSrcWarning; 205 } 206 207 public void addFormatter(Formatter formatter) 208 { 209 formatters.add(formatter); 210 } 211 212 public void addApiClasses(PatternSet set) 213 { 214 patternSets.add(set); 215 } 216 217 public void execute() 218 { 219 log("Running Clirr, built from tag $Name: RELEASE_CLIRR_0_6 $", Project.MSG_VERBOSE); 220 221 if (origFiles == null || newFiles == null) 222 { 223 throw new BuildException( 224 "Missing nested filesets origFiles and newFiles.", getLocation()); 225 } 226 227 if (newClassPath == null) 228 { 229 newClassPath = new Path(getProject()); 230 } 231 232 if (origClassPath == null) 233 { 234 origClassPath = new Path(getProject()); 235 } 236 237 final File [] origJars = scanFileSet(origFiles); 238 final File [] newJars = scanFileSet(newFiles); 239 240 if (origJars.length == 0) 241 { 242 throw new BuildException( 243 "No files in nested fileset origFiles - nothing to check!" 244 + " Please check your fileset specification."); 245 } 246 247 if (newJars.length == 0) 248 { 249 throw new BuildException( 250 "No files in nested fileset newFiles - nothing to check!" 251 + " Please check your fileset specification."); 252 } 253 254 final ClassLoader origThirdPartyLoader = createClasspathLoader(origClassPath); 255 final ClassLoader newThirdPartyLoader = createClasspathLoader(newClassPath); 256 257 final Checker checker = new Checker(); 258 final ChangeCounter counter = new ChangeCounter(); 259 260 boolean formattersWriteToStdOut = false; 261 262 for (Iterator it = formatters.iterator(); it.hasNext();) 263 { 264 Formatter formatter = (Formatter) it.next(); 265 final String type = formatter.getType(); 266 final String outFile = formatter.getOutFile(); 267 268 formattersWriteToStdOut = formattersWriteToStdOut || outFile == null; 269 270 try 271 { 272 if (FORMATTER_TYPE_PLAIN.equals(type)) 273 { 274 checker.addDiffListener(new PlainDiffListener(outFile)); 275 } 276 else if (FORMATTER_TYPE_XML.equals(type)) 277 { 278 checker.addDiffListener(new XmlDiffListener(outFile)); 279 } 280 } 281 catch (IOException ex) 282 { 283 log("unable to initialize formatter: " + ex.getMessage(), 284 Project.MSG_WARN); 285 } 286 } 287 288 if (!formattersWriteToStdOut) 289 { 290 checker.addDiffListener(new AntLogger(this)); 291 } 292 293 checker.addDiffListener(counter); 294 try 295 { 296 ClassFilter classSelector = buildClassFilter(); 297 final JavaType[] origClasses = 298 BcelTypeArrayBuilder.createClassSet(origJars, origThirdPartyLoader, classSelector); 299 300 final JavaType[] newClasses = 301 BcelTypeArrayBuilder.createClassSet(newJars, newThirdPartyLoader, classSelector); 302 303 checker.reportDiffs(origClasses, newClasses); 304 } 305 catch (CheckerException ex) 306 { 307 throw new BuildException(ex.getMessage()); 308 } 309 310 if ((counter.getBinWarnings() > 0 && failOnBinWarning) 311 || (counter.getBinErrors() > 0 && failOnBinError)) 312 { 313 throw new BuildException("detected binary incompatible API changes"); 314 } 315 316 if ((counter.getSrcWarnings() > 0 && failOnSrcWarning) 317 || (counter.getSrcErrors() > 0 && failOnSrcError)) 318 { 319 throw new BuildException("detected source incompatible API changes"); 320 } 321 } 322 323 private ClassFilter buildClassFilter() 324 { 325 final PatternSetFilter patternSetFilter = new PatternSetFilter(getProject(), patternSets); 326 final ClassFilter scopeSelector = new ClassSelector(ClassSelector.MODE_UNLESS); 327 return new CompoundClassFilter(patternSetFilter, scopeSelector); 328 } 329 330 331 private ClassLoader createClasspathLoader(Path classpath) 332 { 333 final String [] cpEntries = classpath.list(); 334 return ClassLoaderUtil.createClassLoader(cpEntries); 335 } 336 337 private File [] scanFileSet(FileSet fs) 338 { 339 Project prj = getProject(); 340 DirectoryScanner scanner = fs.getDirectoryScanner(prj); 341 scanner.scan(); 342 File basedir = scanner.getBasedir(); 343 String [] fileNames = scanner.getIncludedFiles(); 344 File [] ret = new File [fileNames.length]; 345 for (int i = 0; i < fileNames.length; i++) 346 { 347 String fileName = fileNames[i]; 348 ret[i] = new File (basedir, fileName); 349 } 350 return ret; 351 } 352 353 } 354 | Popular Tags |