001/* 002 * The Apache Software License, Version 1.1 003 * 004 * Copyright (C) 2000-2002 The Apache Software Foundation. All rights 005 * reserved. 006 * Copyright (C) 2003 jcoverage ltd. 007 * Copyright (C) 2005 Mark Doliner 008 * Copyright (C) 2005 Joakim Erdfelt 009 * Copyright (C) 2005 Grzegorz Lukasik 010 * Copyright (C) 2005 Alexei Yudichev 011 * Copyright (C) 2006 John Lewis 012 * Copyright (C) 2006 Jiri Mares 013 * Copyright (C) 2008 Scott Frederick 014 * Copyright (C) 2010 Tad Smith 015 * Copyright (C) 2010 Piotr Tabor 016 * 017 * Redistribution and use in source and binary forms, with or without 018 * modification, are permitted provided that the following conditions 019 * are met: 020 * 021 * 1. Redistributions of source code must retain the above copyright 022 * notice, this list of conditions and the following disclaimer. 023 * 024 * 2. Redistributions in binary form must reproduce the above copyright 025 * notice, this list of conditions and the following disclaimer in 026 * the documentation and/or other materials provided with the 027 * distribution. 028 * 029 * 3. The end-user documentation included with the redistribution, if 030 * any, must include the following acknowlegement: 031 * "This product includes software developed by the 032 * Apache Software Foundation (http://www.apache.org/)." 033 * Alternately, this acknowlegement may appear in the software itself, 034 * if and wherever such third-party acknowlegements normally appear. 035 * 036 * 4. The names "Ant" and "Apache Software 037 * Foundation" must not be used to endorse or promote products derived 038 * from this software without prior written permission. For written 039 * permission, please contact apache@apache.org. 040 * 041 * 5. Products derived from this software may not be called "Apache" 042 * nor may "Apache" appear in their names without prior written 043 * permission of the Apache Group. 044 * 045 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 046 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 047 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 048 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 049 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 050 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 051 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 052 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 053 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 054 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 055 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 056 * SUCH DAMAGE. 057 * ==================================================================== 058 * 059 * This software consists of voluntary contributions made by many 060 * individuals on behalf of the Apache Software Foundation. For more 061 * information on the Apache Software Foundation, please see 062 * <http://www.apache.org/>. 063 */ 064 065package net.sourceforge.cobertura.ant; 066 067import java.io.File; 068import java.io.IOException; 069import java.util.ArrayList; 070import java.util.HashMap; 071import java.util.List; 072 073import net.sourceforge.cobertura.util.CommandLineBuilder; 074 075import org.apache.tools.ant.BuildException; 076import org.apache.tools.ant.Project; 077import org.apache.tools.ant.types.FileSet; 078import org.apache.tools.ant.types.Path; 079 080 081public class InstrumentTask extends CommonMatchingTask 082{ 083 084 private String dataFile = null; 085 086 private File toDir = null; 087 088 final List<Ignore> ignoreRegexs = new ArrayList<Ignore>(); 089 090 final List<IgnoreBranches> ignoreBranchesRegexs = new ArrayList<IgnoreBranches>(); 091 092 final List<IgnoreMethodAnnotation> ignoreMethodAnnotations = new ArrayList<IgnoreMethodAnnotation>(); 093 094 final List<IncludeClasses> includeClassesRegexs = new ArrayList<IncludeClasses>(); 095 096 final List<ExcludeClasses> excludeClassesRegexs = new ArrayList<ExcludeClasses>(); 097 098 boolean ignoreTrivial = false; 099 100 private Integer forkedJVMDebugPort; 101 102 private Path instrumentationClasspath = null; 103 104 boolean threadsafeRigorous = false; 105 106 final private HashMap<String, FileSet> fileSetMap = new HashMap<String, FileSet>(); 107 108 public InstrumentTask() { 109 super(net.sourceforge.cobertura.instrument.Main.class.getCanonicalName()); 110 } 111 112 public Ignore createIgnore() { 113 Ignore ignoreRegex = new Ignore(); 114 ignoreRegexs.add(ignoreRegex); 115 return ignoreRegex; 116 } 117 118 public IgnoreBranches createIgnoreBranches() { 119 IgnoreBranches ignoreBranchesRegex = new IgnoreBranches(); 120 ignoreBranchesRegexs.add(ignoreBranchesRegex); 121 return ignoreBranchesRegex; 122 } 123 124 125 public IgnoreMethodAnnotation createIgnoreMethodAnnotation() { 126 IgnoreMethodAnnotation ignoreAnnotation = new IgnoreMethodAnnotation(); 127 ignoreMethodAnnotations.add(ignoreAnnotation); 128 return ignoreAnnotation; 129 } 130 131 132 public IncludeClasses createIncludeClasses() { 133 IncludeClasses includeClassesRegex = new IncludeClasses(); 134 includeClassesRegexs.add(includeClassesRegex); 135 return includeClassesRegex; 136 } 137 138 public ExcludeClasses createExcludeClasses() { 139 ExcludeClasses excludeClassesRegex = new ExcludeClasses(); 140 excludeClassesRegexs.add(excludeClassesRegex); 141 return excludeClassesRegex; 142 } 143 144 public Path createInstrumentationClasspath() { 145 if (instrumentationClasspath == null) { 146 instrumentationClasspath = new Path(getProject()); 147 } 148 return instrumentationClasspath.createPath(); 149 } 150 151 /* 152 * TODO: Is the following method needed to use a classpath ref? If so, 153 * test it and uncomment it. 154 */ 155 /* 156 public void setInstrumentationClasspathRef(Reference r) 157 { 158 createInstrumentationClasspath().setRefid(r); 159 } 160 */ 161 162 public void execute() throws BuildException { 163 CommandLineBuilder builder = null; 164 try { 165 builder = new CommandLineBuilder(); 166 if (dataFile != null) 167 builder.addArg("--datafile", dataFile); 168 if (toDir != null) 169 builder.addArg("--destination", toDir.getAbsolutePath()); 170 171 for (int i = 0; i < ignoreRegexs.size(); i++) { 172 Ignore ignoreRegex = (Ignore)ignoreRegexs.get(i); 173 builder.addArg("--ignore", ignoreRegex.getRegex()); 174 } 175 176 for (int i = 0; i < ignoreBranchesRegexs.size(); i++) { 177 IgnoreBranches ignoreBranchesRegex = (IgnoreBranches)ignoreBranchesRegexs.get(i); 178 builder.addArg("--ignoreBranches", ignoreBranchesRegex.getRegex()); 179 } 180 181 for (int i = 0; i < ignoreMethodAnnotations.size(); i++) { 182 IgnoreMethodAnnotation ignoreMethodAnn = (IgnoreMethodAnnotation)ignoreMethodAnnotations.get(i); 183 builder.addArg("--ignoreMethodAnnotation", ignoreMethodAnn.getAnnotationName()); 184 } 185 186 for (int i = 0; i < includeClassesRegexs.size(); i++) { 187 IncludeClasses includeClassesRegex = (IncludeClasses)includeClassesRegexs.get(i); 188 builder.addArg("--includeClasses", includeClassesRegex.getRegex()); 189 } 190 191 for (int i = 0; i < excludeClassesRegexs.size(); i++) { 192 ExcludeClasses excludeClassesRegex = (ExcludeClasses)excludeClassesRegexs.get(i); 193 builder.addArg("--excludeClasses", excludeClassesRegex.getRegex()); 194 } 195 196 if (ignoreTrivial) 197 builder.addArg("--ignoreTrivial"); 198 199 if (threadsafeRigorous) 200 builder.addArg("--threadsafeRigorous"); 201 202 if (failOnError) 203 builder.addArg("--failOnError"); 204 205 if (instrumentationClasspath != null) { 206 processInstrumentationClasspath(); 207 } 208 createArgumentsForFilesets(builder); 209 210 builder.saveArgs(); 211 } catch (IOException ioe) { 212 getProject().log("Error creating commands file.", Project.MSG_ERR); 213 throw new BuildException("Unable to create the commands file.", ioe); 214 } 215 216 // Execute GPL licensed code in separate virtual machine 217 getJava().createArg().setValue("--commandsfile"); 218 getJava().createArg().setValue(builder.getCommandLineFile()); 219 if (forkedJVMDebugPort != null && forkedJVMDebugPort.intValue() > 0) { 220 getJava().createJvmarg().setValue("-Xdebug"); 221 getJava().createJvmarg().setValue("-Xrunjdwp:transport=dt_socket,address=" + forkedJVMDebugPort + ",server=y,suspend=y"); 222 } 223 AntUtil.transferCoberturaDataFileProperty(getJava()); 224 if (getJava().executeJava() != 0) { 225 throw new BuildException( 226 "Error instrumenting classes. See messages above."); 227 } 228 229 builder.dispose(); 230 } 231 232 private void processInstrumentationClasspath() { 233 if (includeClassesRegexs.size() == 0) 234 { 235 throw new BuildException("'includeClasses' is required when 'instrumentationClasspath' is used"); 236 } 237 238 String[] sources = instrumentationClasspath.list(); 239 for (int i = 0; i < sources.length; i++) { 240 File fileOrDir = new File(sources[i]); 241 if (fileOrDir.exists()) { 242 if (fileOrDir.isDirectory()) { 243 createFilesetForDirectory(fileOrDir); 244 } else { 245 addFileToFilesets(fileOrDir); 246 } 247 } 248 } 249 } 250 251 private void addFileToFilesets(File file) { 252 File dir = file.getParentFile(); 253 String filename = file.getName(); 254 FileSet fileSet = getFileSet(dir); 255 fileSet.createInclude().setName(filename); 256 } 257 258 private FileSet getFileSet(File dir) { 259 String key = dir.getAbsolutePath(); 260 FileSet fileSet = (FileSet)fileSetMap.get(key); 261 if (fileSet == null) { 262 fileSet = new FileSet(); 263 fileSet.setProject(getProject()); 264 fileSet.setDir(dir); 265 266 // Now add the new fileset to the map and to the fileSets list 267 fileSetMap.put(key, fileSet); 268 addFileset(fileSet); 269 } 270 return fileSet; 271 } 272 273 private void createFilesetForDirectory(File dir) { 274 FileSet fileSet = getFileSet(dir); 275 fileSet.createInclude().setName("**/*.class"); 276 } 277 278 public void setDataFile(String dataFile) { 279 this.dataFile = dataFile; 280 } 281 282 public void setToDir(File toDir) { 283 this.toDir = toDir; 284 } 285 286 public void setIgnoreTrivial(boolean ignoreTrivial) { 287 this.ignoreTrivial = ignoreTrivial; 288 } 289 290 public void setThreadsafeRigorous(boolean threadsafeRigorous) { 291 this.threadsafeRigorous = threadsafeRigorous; 292 } 293 294 public void setForkedJVMDebugPort(Integer forkedJVMDebugPort) { 295 this.forkedJVMDebugPort = forkedJVMDebugPort; 296 } 297}