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