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
062 package net.sourceforge.cobertura.ant;
063
064 import java.io.File;
065 import java.io.IOException;
066 import java.util.ArrayList;
067 import java.util.HashMap;
068 import java.util.List;
069
070 import net.sourceforge.cobertura.util.CommandLineBuilder;
071
072 import org.apache.tools.ant.BuildException;
073 import org.apache.tools.ant.Project;
074 import org.apache.tools.ant.types.FileSet;
075 import org.apache.tools.ant.types.Path;
076
077 public 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 }