blob: a36bd08a2d278d087b10e34a3cbfc96a2b9c52e1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2017 Richard Hoefter and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Richard Hoefter (richard.hoefter@web.de) - initial API and implementation, bug 95297, bug 97051, bug 128103, bug 201180, bug 161354, bug 313386
* IBM Corporation - nlsing and incorporating into Eclipse, bug 108276, bug 124210, bug 161845, bug 177833
* Nikolay Metchev (N.Metchev@teamphone.com) - bug 108276
* Ryan Fong (rfong@trapezenetworks.com) - bug 201143
*******************************************************************************/
package org.eclipse.ant.internal.ui.datatransfer;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import org.eclipse.ant.internal.core.IAntCoreConstants;
import org.eclipse.ant.internal.ui.AntUIPlugin;
import org.eclipse.ant.internal.ui.model.IAntModelConstants;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Shell;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.xml.sax.SAXException;
/**
* Creates build.xml file.
*/
public class BuildFileCreator {
protected static final String IMPORT_BUILDFILE_PROCESSING_TARGET = "eclipse.ant.import"; //$NON-NLS-1$
protected static final String WARNING = " WARNING: Eclipse auto-generated file." + ExportUtil.NEWLINE + //$NON-NLS-1$
" Any modifications will be overwritten."; //$NON-NLS-1$
protected static final String NOTE = " To include a user specific buildfile here, " + //$NON-NLS-1$
"simply create one in the same" + ExportUtil.NEWLINE + //$NON-NLS-1$
" directory with the processing instruction " + //$NON-NLS-1$
"<?" + IMPORT_BUILDFILE_PROCESSING_TARGET + "?>" + ExportUtil.NEWLINE + //$NON-NLS-1$ //$NON-NLS-2$
" as the first entry and export the buildfile again. "; //$NON-NLS-1$
protected static String BUILD_XML = "build.xml"; //$NON-NLS-1$
protected static String JUNIT_OUTPUT_DIR = "junit"; //$NON-NLS-1$
protected static boolean CHECK_SOURCE_CYCLES = true;
protected static boolean CREATE_ECLIPSE_COMPILE_TARGET = true;
private Document doc;
private Element root;
private IJavaProject project;
private String projectName;
private String projectRoot;
private Map<String, String> variable2valueMap;
private Shell shell;
private Set<String> visited = new TreeSet<>(); // record used subclasspaths
private Node classpathNode;
/**
* Constructor. Please prefer {@link #createBuildFiles(Set, Shell, IProgressMonitor)} if you do not want call the various createXXX() methods
* yourself.
*
* @param project
* create buildfile for this project
* @param shell
* parent instance for dialogs
*/
public BuildFileCreator(IJavaProject project, Shell shell) throws ParserConfigurationException {
this.project = project;
this.projectName = project.getProject().getName();
this.projectRoot = ExportUtil.getProjectRoot(project);
this.variable2valueMap = new LinkedHashMap<>();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
this.doc = dbf.newDocumentBuilder().newDocument();
this.shell = shell;
}
/**
* Create buildfile for given projects.
*
* @param projects
* create buildfiles for these <code>IJavaProject</code> objects
* @param shell
* parent instance for dialogs
* @return project names for which buildfiles were created
* @throws InterruptedException
* thrown when user cancels task
*/
public static List<String> createBuildFiles(Set<IJavaProject> projects, Shell shell, IProgressMonitor pm) throws JavaModelException, ParserConfigurationException, TransformerConfigurationException, TransformerException, IOException, CoreException, InterruptedException {
List<String> res = new ArrayList<>();
try {
createBuildFilesLoop(projects, shell, pm, res);
}
finally {
if (pm != null) {
pm.done();
}
}
return res;
}
private static void createBuildFilesLoop(Set<IJavaProject> projects, Shell shell, IProgressMonitor pm, List<String> res) throws CoreException, ParserConfigurationException, JavaModelException, TransformerConfigurationException, TransformerFactoryConfigurationError, TransformerException, UnsupportedEncodingException {
// determine files to create/change
List<IFile> files = new ArrayList<>();
for (Iterator<IJavaProject> iter = projects.iterator(); iter.hasNext();) {
IJavaProject currentProject = iter.next();
IFile file = currentProject.getProject().getFile(BuildFileCreator.BUILD_XML);
files.add(file);
}
// trigger checkout
Set<IFile> confirmedFiles = ExportUtil.validateEdit(shell, files);
SubMonitor localmonitor = SubMonitor.convert(pm, DataTransferMessages.AntBuildfileExportPage_0, confirmedFiles.size());
try {
Iterator<IJavaProject> iter = projects.iterator();
while (iter.hasNext()) {
IJavaProject currentProject = iter.next();
IFile file = currentProject.getProject().getFile(BuildFileCreator.BUILD_XML);
if (!confirmedFiles.contains(file)) {
continue;
}
localmonitor.setTaskName(NLS.bind(DataTransferMessages.BuildFileCreator_generating_buildfile_for, currentProject.getProject().getName()));
BuildFileCreator instance = new BuildFileCreator(currentProject, shell);
instance.createRoot();
instance.createImports();
EclipseClasspath classpath = new EclipseClasspath(currentProject);
if (CHECK_SOURCE_CYCLES) {
SourceAnalyzer.checkCycles(currentProject, classpath, shell);
}
instance.createClasspaths(classpath);
instance.createInit(classpath.srcDirs, classpath.classDirs, classpath.inclusionLists, classpath.exclusionLists);
instance.createClean(classpath.classDirs);
instance.createCleanAll();
instance.createBuild(classpath.srcDirs, classpath.classDirs, classpath.inclusionLists, classpath.exclusionLists);
instance.createBuildRef();
if (CREATE_ECLIPSE_COMPILE_TARGET) {
instance.addInitEclipseCompiler();
instance.addBuildEclipse();
}
instance.createRun();
instance.addSubProperties(currentProject, classpath);
instance.createProperty();
// write build file
String xml = ExportUtil.toString(instance.doc);
InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8")); //$NON-NLS-1$
if (file.exists()) {
file.setContents(is, true, true, null);
} else {
file.create(is, true, null);
}
if (localmonitor.isCanceled()) {
return;
}
localmonitor.worked(1);
res.add(instance.projectName);
}
}
finally {
if (!localmonitor.isCanceled()) {
localmonitor.done();
}
}
}
/**
* Add property tag.
*/
public void createProperty() {
// read debug options from Eclipse settings
boolean source = JavaCore.GENERATE.equals(project.getOption(JavaCore.COMPILER_SOURCE_FILE_ATTR, true));
boolean lines = JavaCore.GENERATE.equals(project.getOption(JavaCore.COMPILER_LINE_NUMBER_ATTR, true));
boolean vars = JavaCore.GENERATE.equals(project.getOption(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR, true));
List<String> debuglevel = new ArrayList<>();
if (source) {
debuglevel.add("source"); //$NON-NLS-1$
}
if (lines) {
debuglevel.add("lines"); //$NON-NLS-1$
}
if (vars) {
debuglevel.add("vars"); //$NON-NLS-1$
}
if (debuglevel.size() == 0) {
debuglevel.add("none"); //$NON-NLS-1$
}
variable2valueMap.put("debuglevel", ExportUtil.toString(debuglevel, ",")); //$NON-NLS-1$ //$NON-NLS-2$
// "Generated .class files compatibility"
String target = project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true);
variable2valueMap.put("target", target); //$NON-NLS-1$
// "Compiler compliance level"
// String compliance = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
// "Source compatibility"
String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
variable2valueMap.put("source", sourceLevel); //$NON-NLS-1$
// <property name="x" value="y"/>
boolean first = true;
Node node = root.getFirstChild();
for (Iterator<String> iterator = variable2valueMap.keySet().iterator(); iterator.hasNext();) {
String key = iterator.next();
String value = variable2valueMap.get(key);
Element prop = doc.createElement("property"); //$NON-NLS-1$
prop.setAttribute(IAntCoreConstants.NAME, key);
prop.setAttribute(IAntCoreConstants.VALUE, value);
if (first) {
first = false;
} else {
node = node.getNextSibling();
}
node = root.insertBefore(prop, node);
}
// <property environment="env"/>
Element env = doc.createElement("property"); //$NON-NLS-1$
env.setAttribute("environment", "env"); //$NON-NLS-1$ //$NON-NLS-2$
root.insertBefore(env, root.getFirstChild());
}
/**
* Create project tag.
*/
public void createRoot() {
// <project name="hello" default="build" basedir=".">
root = doc.createElement("project"); //$NON-NLS-1$
root.setAttribute(IAntCoreConstants.NAME, projectName);
root.setAttribute(IAntCoreConstants.DEFAULT, "build"); //$NON-NLS-1$
root.setAttribute("basedir", "."); //$NON-NLS-1$ //$NON-NLS-2$
doc.appendChild(root);
// <!-- warning -->
Comment comment = doc.createComment(WARNING + ExportUtil.NEWLINE + NOTE);
doc.insertBefore(comment, root);
}
/**
* Find buildfiles in projectroot directory and automatically import them.
*/
public void createImports() {
// <import file="javadoc.xml"/>
File dir = new File(projectRoot);
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File acceptDir, String name) {
return name.endsWith(".xml"); //$NON-NLS-1$
}
};
File[] files = dir.listFiles(filter);
if (files == null) {
return;
}
for (int i = 0; i < files.length; i++) {
// import file if it is an XML document with marker comment as first
// child
File file = files[i];
Document docCandidate;
try {
docCandidate = ExportUtil.parseXmlFile(file);
NodeList nodes = docCandidate.getChildNodes();
for (int j = 0; j < nodes.getLength(); j++) {
Node node = nodes.item(j);
if (node instanceof ProcessingInstruction
&& IMPORT_BUILDFILE_PROCESSING_TARGET.equals(((ProcessingInstruction) node).getTarget().trim())) {
Element element = doc.createElement("import"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.FILE, file.getName());
root.appendChild(element);
break;
}
}
}
catch (ParserConfigurationException e) {
AntUIPlugin.log("invalid XML file not imported: " + file.getAbsolutePath(), e); //$NON-NLS-1$
}
catch (SAXException e) {
AntUIPlugin.log("invalid XML file not imported: " + file.getAbsolutePath(), e); //$NON-NLS-1$
}
catch (IOException e) {
AntUIPlugin.log("invalid XML file not imported: " + file.getAbsolutePath(), e); //$NON-NLS-1$
}
}
}
/**
* Create classpath tags.
*/
public void createClasspaths(EclipseClasspath classpath) throws JavaModelException {
createClasspaths(null, project, classpath);
}
/**
* Create classpath tags. Allows to specify ID.
*
* @param pathId
* specify id, if null project name is used
*/
public void createClasspaths(String pathId, IJavaProject currentProject, EclipseClasspath classpath) throws JavaModelException {
if (currentProject == null) {
AntUIPlugin.log("project is not loaded in workspace: " + pathId, null); //$NON-NLS-1$
return;
}
// <path id="hello.classpath">
// <pathelement location="${hello.location}/classes"/>
// <pathelement location="${hello.location}/x.jar"/>
// <path refid="${goodbye.classpath}"/>
// </path>
Element element = doc.createElement("path"); //$NON-NLS-1$
String pathid = pathId;
if (pathid == null) {
pathid = currentProject.getProject().getName() + ".classpath"; //$NON-NLS-1$
}
element.setAttribute("id", pathid); //$NON-NLS-1$
visited.add(pathid);
variable2valueMap.putAll(classpath.variable2valueMap);
for (Iterator<String> iter = ExportUtil.removeDuplicates(classpath.rawClassPathEntries).iterator(); iter.hasNext();) {
String entry = iter.next();
if (EclipseClasspath.isProjectReference(entry)) {
Element pathElement = doc.createElement("path"); //$NON-NLS-1$
IJavaProject referencedProject = EclipseClasspath.resolveProjectReference(entry);
if (referencedProject == null) {
AntUIPlugin.log("project is not loaded in workspace: " + pathid, null); //$NON-NLS-1$
continue;
}
String refPathId = referencedProject.getProject().getName() + ".classpath"; //$NON-NLS-1$
pathElement.setAttribute("refid", refPathId); //$NON-NLS-1$
element.appendChild(pathElement);
if (visited.add(refPathId)) {
createClasspaths(null, referencedProject, new EclipseClasspath(referencedProject)); // recursion
}
} else if (EclipseClasspath.isUserLibraryReference(entry) || EclipseClasspath.isLibraryReference(entry)) {
addUserLibrary(element, entry);
} else if (EclipseClasspath.isUserSystemLibraryReference(entry)) {
if (pathid.endsWith(".bootclasspath")) { //$NON-NLS-1$
addUserLibrary(element, entry);
}
} else if (EclipseClasspath.isJreReference(entry)) {
if (pathid.endsWith(".bootclasspath")) { //$NON-NLS-1$
addJre(element);
}
} else {
// prefix with ${project.location}
String prefix = IAntCoreConstants.EMPTY_STRING;
if (!entry.startsWith("${") && // no variable ${var}/classes //$NON-NLS-1$
!projectName.equals(currentProject.getProject().getName())) // not main project
{
String currentProjectRoot = ExportUtil.getProjectRoot(currentProject);
entry = ExportUtil.getRelativePath(entry, currentProjectRoot);
if (!new Path(entry).isAbsolute()) {
prefix = "${" + currentProject.getProject().getName() + ".location}/"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
Element pathElement = doc.createElement("pathelement"); //$NON-NLS-1$
String path = ExportUtil.getRelativePath(prefix + entry, projectRoot);
pathElement.setAttribute(IAntModelConstants.ATTR_LOCATION, path);
element.appendChild(pathElement);
}
}
addToClasspathBlock(element);
}
private void addUserLibrary(Element element, String entry) {
// add classpath reference
Element pathElement = doc.createElement("path"); //$NON-NLS-1$
IClasspathContainer container = EclipseClasspath.resolveUserLibraryReference(entry);
String name = ExportUtil.removePrefixAndSuffix(entry, "${", "}"); //$NON-NLS-1$ //$NON-NLS-2$
pathElement.setAttribute("refid", name); //$NON-NLS-1$
element.appendChild(pathElement);
// add classpath
if (visited.add(entry)) {
Element userElement = doc.createElement("path"); //$NON-NLS-1$
userElement.setAttribute("id", name); //$NON-NLS-1$
IClasspathEntry entries[] = container.getClasspathEntries();
for (int i = 0; i < entries.length; i++) {
String jarFile = entries[i].getPath().toString();
// use ECLIPSE_HOME variable for library jars
if (EclipseClasspath.isLibraryReference(entry)) {
IPath home = JavaCore.getClasspathVariable("ECLIPSE_HOME"); //$NON-NLS-1$
if (home != null && home.isPrefixOf(entries[i].getPath())) {
variable2valueMap.put("ECLIPSE_HOME", home.toString()); //$NON-NLS-1$
jarFile = "${ECLIPSE_HOME}" + jarFile.substring(home.toString().length()); //$NON-NLS-1$
} else if (!new File(jarFile).exists() && jarFile.startsWith('/' + projectName)
&& new File(projectRoot, jarFile.substring(('/' + projectName).length())).exists()) {
// workaround that additional jars are stored with
// leading project root in container object, although
// they are relative and indeed correctly stored in
// build.properties (jars.extra.classpath)
jarFile = jarFile.substring(('/' + projectName).length() + 1);
}
}
jarFile = ExportUtil.getRelativePath(jarFile, projectRoot);
Element userPathElement = doc.createElement("pathelement"); //$NON-NLS-1$
userPathElement.setAttribute(IAntModelConstants.ATTR_LOCATION, jarFile);
userElement.appendChild(userPathElement);
}
addToClasspathBlock(userElement);
}
}
/**
* Add JRE to given classpath.
*
* @param element
* classpath tag
*/
private void addJre(Element element) {
// <fileset dir="${java.home}/lib" includes="*.jar"/>
// <fileset dir="${java.home}/lib/ext" includes="*.jar"/>
Element pathElement = doc.createElement("fileset"); //$NON-NLS-1$
pathElement.setAttribute(IAntCoreConstants.DIR, "${java.home}/lib"); //$NON-NLS-1$
pathElement.setAttribute("includes", "*.jar"); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(pathElement);
pathElement = doc.createElement("fileset"); //$NON-NLS-1$
pathElement.setAttribute(IAntCoreConstants.DIR, "${java.home}/lib/ext"); //$NON-NLS-1$
pathElement.setAttribute("includes", "*.jar"); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(pathElement);
}
private void addToClasspathBlock(Element element) {
// remember node to insert all classpaths at same location
if (classpathNode == null) {
classpathNode = root.appendChild(element);
} else {
classpathNode = classpathNode.getNextSibling();
classpathNode = root.insertBefore(element, classpathNode);
}
}
/**
* Add properties of sub-projects to internal properties map.
*/
public void addSubProperties(IJavaProject subproject, EclipseClasspath classpath) throws JavaModelException {
for (Iterator<IJavaProject> iterator = ExportUtil.getClasspathProjectsRecursive(subproject).iterator(); iterator.hasNext();) {
IJavaProject subProject = iterator.next();
String location = subProject.getProject().getName() + ".location"; //$NON-NLS-1$
// add subproject properties to variable2valueMap
String subProjectRoot = ExportUtil.getProjectRoot(subProject);
String relativePath = ExportUtil.getRelativePath(subProjectRoot, projectRoot);
variable2valueMap.put(location, relativePath);
variable2valueMap.putAll(classpath.variable2valueMap);
}
}
/**
* Create init target. Creates directories and copies resources.
*
* @param srcDirs
* source directories to copy resources from
* @param classDirs
* classes directories to copy resources to
*/
public void createInit(List<String> srcDirs, List<String> classDirs, List<List<String>> inclusionLists, List<List<String>> exclusionLists) {
// <target name="init">
// <mkdir dir="classes"/>
// </target>
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "init"); //$NON-NLS-1$
List<String> classDirsUnique = ExportUtil.removeDuplicates(classDirs);
for (Iterator<String> iterator = classDirsUnique.iterator(); iterator.hasNext();) {
String classDir = iterator.next();
if (!classDir.equals(".") && !EclipseClasspath.isReference(classDir)) { //$NON-NLS-1$
Element pathElement = doc.createElement("mkdir"); //$NON-NLS-1$
pathElement.setAttribute(IAntCoreConstants.DIR, classDir);
element.appendChild(pathElement);
}
}
root.appendChild(element);
createCopyResources(srcDirs, classDirs, element, inclusionLists, exclusionLists);
}
private void createCopyResources(List<String> srcDirs, List<String> classDirs, Element element, List<List<String>> inclusionLists, List<List<String>> exclusionLists) {
// Check filter for copying resources
String filter = project.getOption(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
StringTokenizer tokenizer = new StringTokenizer(filter, ","); //$NON-NLS-1$
ArrayList<String> filters = new ArrayList<>();
while (tokenizer.hasMoreTokens()) {
filters.add(tokenizer.nextToken());
}
filters.add("*.java"); //$NON-NLS-1$
// prefix filters with wildcard
for (int i = 0; i < filters.size(); i++) {
String item = filters.get(i).trim();
if (item.equals("*")) //$NON-NLS-1$
{
// everything is excluded from copying
return;
}
filters.set(i, "**/" + item); //$NON-NLS-1$
}
// <copy todir="classes" includeemptydirs="false">
// <fileset dir="src" excludes="**/*.java"/>
// </copy>
for (int i = 0; i < srcDirs.size(); i++) {
String srcDir = srcDirs.get(i);
String classDir = classDirs.get(i);
if (!EclipseClasspath.isReference(classDir)) {
Element copyElement = doc.createElement("copy"); //$NON-NLS-1$
copyElement.setAttribute("todir", classDir); //$NON-NLS-1$
copyElement.setAttribute("includeemptydirs", "false"); //$NON-NLS-1$ //$NON-NLS-2$
Element filesetElement = doc.createElement("fileset"); //$NON-NLS-1$
filesetElement.setAttribute(IAntCoreConstants.DIR, srcDir);
List<String> inclusions = inclusionLists.get(i);
List<String> exclusions = exclusionLists.get(i);
for (String inclusion : inclusions) {
Element includeElement = doc.createElement("include"); //$NON-NLS-1$
includeElement.setAttribute(IAntCoreConstants.NAME, inclusion);
filesetElement.appendChild(includeElement);
}
for (String exclusion : filters) {
Element excludeElement = doc.createElement("exclude"); //$NON-NLS-1$
excludeElement.setAttribute(IAntCoreConstants.NAME, exclusion);
filesetElement.appendChild(excludeElement);
}
for (String exclusion : exclusions) {
Element excludeElement = doc.createElement("exclude"); //$NON-NLS-1$
excludeElement.setAttribute(IAntCoreConstants.NAME, exclusion);
filesetElement.appendChild(excludeElement);
}
copyElement.appendChild(filesetElement);
element.appendChild(copyElement);
}
}
}
/**
* Create clean target.
*
* @param classDirs
* classes directories to delete
*/
public void createClean(List<String> classDirs) {
// <target name="clean">
// <delete dir="classes"/>
// </target>
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "clean"); //$NON-NLS-1$
List<String> classDirUnique = ExportUtil.removeDuplicates(classDirs);
for (Iterator<String> iterator = classDirUnique.iterator(); iterator.hasNext();) {
String classDir = iterator.next();
if (!classDir.equals(".") && //$NON-NLS-1$
!EclipseClasspath.isReference(classDir)) {
Element deleteElement = doc.createElement("delete"); //$NON-NLS-1$
deleteElement.setAttribute(IAntCoreConstants.DIR, classDir);
element.appendChild(deleteElement);
}
}
root.appendChild(element);
// <target name="clean">
// <delete>
// <fileset dir="." includes="**/*.class"/>
// </delete>
// </target>
if (classDirs.contains(".")) //$NON-NLS-1$
{
Element deleteElement = doc.createElement("delete"); //$NON-NLS-1$
Element filesetElement = doc.createElement("fileset"); //$NON-NLS-1$
filesetElement.setAttribute(IAntCoreConstants.DIR, "."); //$NON-NLS-1$
filesetElement.setAttribute("includes", "**/*.class"); //$NON-NLS-1$ //$NON-NLS-2$
deleteElement.appendChild(filesetElement);
element.appendChild(deleteElement);
}
}
/**
* Create cleanall target.
*/
public void createCleanAll() throws JavaModelException {
// <target name="cleanall" depends="clean">
// <ant antfile="build.xml" dir="${hello.location}" inheritAll="false" target="clean"/>
// </target>
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "cleanall"); //$NON-NLS-1$
element.setAttribute("depends", "clean"); //$NON-NLS-1$ //$NON-NLS-2$
List<IJavaProject> subProjects = ExportUtil.getClasspathProjectsRecursive(project);
for (Iterator<IJavaProject> iterator = subProjects.iterator(); iterator.hasNext();) {
IJavaProject subProject = iterator.next();
Element antElement = doc.createElement("ant"); //$NON-NLS-1$
antElement.setAttribute("antfile", BUILD_XML); //$NON-NLS-1$
antElement.setAttribute(IAntCoreConstants.DIR, "${" + subProject.getProject().getName() + ".location}"); //$NON-NLS-1$ //$NON-NLS-2$
antElement.setAttribute("target", "clean"); //$NON-NLS-1$ //$NON-NLS-2$
antElement.setAttribute("inheritAll", "false"); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(antElement);
}
root.appendChild(element);
}
/**
* Create build target.
*
* @param srcDirs
* source directories of mainproject
* @param classDirs
* class directories of mainproject
* @param inclusionLists
* inclusion filters of mainproject
* @param exclusionLists
* exclusion filters of mainproject
*/
public void createBuild(List<String> srcDirs, List<String> classDirs, List<List<String>> inclusionLists, List<List<String>> exclusionLists) throws JavaModelException {
// <target name="build" depends="build-subprojects,build-project"/>
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "build"); //$NON-NLS-1$
element.setAttribute("depends", "build-subprojects,build-project"); //$NON-NLS-1$ //$NON-NLS-2$
root.appendChild(element);
// <target name="build-subprojects">
// <ant antfile="build.xml" dir="${hello.location}" inheritAll="false" target="build-project"/>
// </target>
element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "build-subprojects"); //$NON-NLS-1$
List<IJavaProject> subProjects = ExportUtil.getClasspathProjectsRecursive(project);
for (Iterator<IJavaProject> iterator = subProjects.iterator(); iterator.hasNext();) {
IJavaProject subProject = iterator.next();
Element antElement = doc.createElement("ant"); //$NON-NLS-1$
antElement.setAttribute("antfile", BUILD_XML); //$NON-NLS-1$
antElement.setAttribute(IAntCoreConstants.DIR, "${" + subProject.getProject().getName() + ".location}"); //$NON-NLS-1$ //$NON-NLS-2$
antElement.setAttribute("target", "build-project"); //$NON-NLS-1$ //$NON-NLS-2$
antElement.setAttribute("inheritAll", "false"); //$NON-NLS-1$ //$NON-NLS-2$
if (CREATE_ECLIPSE_COMPILE_TARGET) {
Element propertysetElement = doc.createElement("propertyset"); //$NON-NLS-1$
Element propertyrefElement = doc.createElement("propertyref"); //$NON-NLS-1$
propertyrefElement.setAttribute(IAntCoreConstants.NAME, "build.compiler"); //$NON-NLS-1$
propertysetElement.appendChild(propertyrefElement);
antElement.appendChild(propertysetElement);
}
element.appendChild(antElement);
}
root.appendChild(element);
// Bug 313386 optimization:
// Source directories with the same classes directory get only one <javac> tag
// Side effect: Eclipse inclusion and exclusion filters apply to the specified source directory.
// Ant inclusion and exclusion filters apply to all source directories.
// This may lead to unexpected behavior.
HashMap<String, List<String>> class2sources = new HashMap<>();
HashMap<String, List<String>> class2includes = new HashMap<>();
HashMap<String, List<String>> class2excludes = new HashMap<>();
for (int i = 0; i < srcDirs.size(); i++) {
String srcDir = srcDirs.get(i);
if (!EclipseClasspath.isReference(srcDir)) {
String classDir = classDirs.get(i);
List<String> inclusions = inclusionLists.get(i);
List<String> exclusions = exclusionLists.get(i);
List<String> list = class2sources.get(classDir);
List<String> list2 = class2includes.get(classDir);
List<String> list3 = class2excludes.get(classDir);
if (list == null) {
list = new ArrayList<>();
list2 = new ArrayList<>();
list3 = new ArrayList<>();
class2sources.put(classDir, list);
class2includes.put(classDir, list2);
class2excludes.put(classDir, list3);
}
list.add(srcDir);
list2.addAll(inclusions);
list3.addAll(exclusions);
}
}
// <target name="build-project" depends="init">
// <echo message="${ant.project.name}: ${ant.file}"/>
// <javac destdir="classes">
// <src path="src"/>
// <include name=""/>
// <exclude name=""/>
// <classpath refid="project.classpath"/>
// </javac>
// </target>
element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "build-project"); //$NON-NLS-1$
element.setAttribute("depends", "init"); //$NON-NLS-1$ //$NON-NLS-2$
Element echoElement = doc.createElement("echo"); //$NON-NLS-1$
echoElement.setAttribute("message", "${ant.project.name}: ${ant.file}"); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(echoElement);
for (int i = 0; i < srcDirs.size(); i++) {
String srcDir = srcDirs.get(i);
if (!EclipseClasspath.isReference(srcDir)) {
String classDir = classDirs.get(i);
List<String> sources = class2sources.get(classDir);
List<String> inclusions = class2includes.get(classDir);
List<String> exclusions = class2excludes.get(classDir);
if (sources != null && sources.size() > 1) {
// remove list to exclude it from the next iteration
class2sources.put(classDir, null);
} else if (sources == null) {
continue;
}
Element javacElement = doc.createElement("javac"); //$NON-NLS-1$
javacElement.setAttribute("includeantruntime", "false"); //$NON-NLS-1$ //$NON-NLS-2$
javacElement.setAttribute("destdir", classDir); //$NON-NLS-1$
javacElement.setAttribute("debug", "true"); //$NON-NLS-1$ //$NON-NLS-2$
javacElement.setAttribute("debuglevel", "${debuglevel}"); //$NON-NLS-1$ //$NON-NLS-2$
javacElement.setAttribute("source", "${source}"); //$NON-NLS-1$ //$NON-NLS-2$
javacElement.setAttribute("target", "${target}"); //$NON-NLS-1$ //$NON-NLS-2$
// Bug 313386: <javac> tag with several source directories
for (String s : sources) {
Element srcElement = doc.createElement("src"); //$NON-NLS-1$
srcElement.setAttribute("path", s); //$NON-NLS-1$
javacElement.appendChild(srcElement);
}
for (String inclusion : inclusions) {
Element includeElement = doc.createElement("include"); //$NON-NLS-1$
includeElement.setAttribute(IAntCoreConstants.NAME, inclusion);
javacElement.appendChild(includeElement);
}
for (String exclusion : exclusions) {
Element excludeElement = doc.createElement("exclude"); //$NON-NLS-1$
excludeElement.setAttribute(IAntCoreConstants.NAME, exclusion);
javacElement.appendChild(excludeElement);
}
Element classpathRefElement = doc.createElement("classpath"); //$NON-NLS-1$
classpathRefElement.setAttribute("refid", projectName + ".classpath"); //$NON-NLS-1$ //$NON-NLS-2$
javacElement.appendChild(classpathRefElement);
element.appendChild(javacElement);
if (!JavaRuntime.isModularProject(project))
addCompilerBootClasspath(srcDirs, javacElement);
}
}
root.appendChild(element);
}
/**
* Create target build-refprojects which compiles projects which reference current project.
*/
private void createBuildRef() throws JavaModelException {
Set<IJavaProject> refProjects = new TreeSet<>(ExportUtil.getJavaProjectComparator());
IJavaProject[] projects = project.getJavaModel().getJavaProjects();
for (int i = 0; i < projects.length; i++) {
List<IJavaProject> subProjects = ExportUtil.getClasspathProjects(projects[i]);
for (Iterator<IJavaProject> iter = subProjects.iterator(); iter.hasNext();) {
IJavaProject p = iter.next();
if (projectName.equals(p.getProject().getName())) {
refProjects.add(projects[i]);
}
}
}
// <target name="build-refprojects">
// <ant antfile="build.xml" dir="${hello.location}" target="clean" inheritAll="false"/>
// <ant antfile="build.xml" dir="${hello.location}" target="build" inheritAll="false"/>
// </target>
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "build-refprojects"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.DESCRIPTION, "Build all projects which " + //$NON-NLS-1$
"reference this project. Useful to propagate changes."); //$NON-NLS-1$
for (Iterator<IJavaProject> iter = refProjects.iterator(); iter.hasNext();) {
IJavaProject p = iter.next();
String location = p.getProject().getName() + ".location"; //$NON-NLS-1$
String refProjectRoot = ExportUtil.getProjectRoot(p);
String relativePath = ExportUtil.getRelativePath(refProjectRoot, projectRoot);
variable2valueMap.put(location, relativePath);
Element antElement = doc.createElement("ant"); //$NON-NLS-1$
antElement.setAttribute("antfile", BUILD_XML); //$NON-NLS-1$
antElement.setAttribute(IAntCoreConstants.DIR, "${" + p.getProject().getName() + ".location}"); //$NON-NLS-1$ //$NON-NLS-2$
antElement.setAttribute("target", "clean"); //$NON-NLS-1$ //$NON-NLS-2$
antElement.setAttribute("inheritAll", "false"); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(antElement);
antElement = doc.createElement("ant"); //$NON-NLS-1$
antElement.setAttribute("antfile", BUILD_XML); //$NON-NLS-1$
antElement.setAttribute(IAntCoreConstants.DIR, "${" + p.getProject().getName() + ".location}"); //$NON-NLS-1$ //$NON-NLS-2$
antElement.setAttribute("target", "build"); //$NON-NLS-1$ //$NON-NLS-2$
antElement.setAttribute("inheritAll", "false"); //$NON-NLS-1$ //$NON-NLS-2$
if (CREATE_ECLIPSE_COMPILE_TARGET) {
Element propertysetElement = doc.createElement("propertyset"); //$NON-NLS-1$
Element propertyrefElement = doc.createElement("propertyref"); //$NON-NLS-1$
propertyrefElement.setAttribute(IAntCoreConstants.NAME, "build.compiler"); //$NON-NLS-1$
propertysetElement.appendChild(propertyrefElement);
antElement.appendChild(propertysetElement);
}
element.appendChild(antElement);
}
root.appendChild(element);
}
/**
* Add target to initialize Eclipse compiler. It copies required jars to ant lib directory.
*/
public void addInitEclipseCompiler() {
// use ECLIPSE_HOME classpath variable
IPath value = JavaCore.getClasspathVariable("ECLIPSE_HOME"); //$NON-NLS-1$
if (value != null) {
variable2valueMap.put("ECLIPSE_HOME", ExportUtil.getRelativePath( //$NON-NLS-1$
value.toString(), projectRoot));
}
// <target name="init-eclipse-compiler" description="copy Eclipse compiler jars to ant lib directory">
// <property name="ECLIPSE_HOME" value="C:/Programme/eclipse-3.1" />
// <copy todir="${ant.library.dir}">
// <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar" />
// </copy>
// <unzip dest="${ant.library.dir}">
// <patternset includes="jdtCompilerAdapter.jar" />
// <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar" />
// </unzip>
// </target>
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "init-eclipse-compiler"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.DESCRIPTION, "copy Eclipse compiler jars to ant lib directory"); //$NON-NLS-1$
Element copyElement = doc.createElement("copy"); //$NON-NLS-1$
copyElement.setAttribute("todir", "${ant.library.dir}"); //$NON-NLS-1$ //$NON-NLS-2$
Element filesetElement = doc.createElement("fileset"); //$NON-NLS-1$
filesetElement.setAttribute(IAntCoreConstants.DIR, "${ECLIPSE_HOME}/plugins"); //$NON-NLS-1$
filesetElement.setAttribute("includes", "org.eclipse.jdt.core_*.jar"); //$NON-NLS-1$ //$NON-NLS-2$
copyElement.appendChild(filesetElement);
element.appendChild(copyElement);
Element unzipElement = doc.createElement("unzip"); //$NON-NLS-1$
unzipElement.setAttribute("dest", "${ant.library.dir}"); //$NON-NLS-1$ //$NON-NLS-2$
Element patternsetElement = doc.createElement("patternset"); //$NON-NLS-1$
patternsetElement.setAttribute("includes", "jdtCompilerAdapter.jar"); //$NON-NLS-1$ //$NON-NLS-2$
unzipElement.appendChild(patternsetElement);
unzipElement.appendChild(filesetElement.cloneNode(false));
element.appendChild(unzipElement);
root.appendChild(element);
}
/**
* Add target to compile project using Eclipse compiler.
*/
public void addBuildEclipse() {
// <target name="build-eclipse-compiler" description="compile project with Eclipse compiler">
// <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />
// <antcall target="build" />
// </target>
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "build-eclipse-compiler"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.DESCRIPTION, "compile project with Eclipse compiler"); //$NON-NLS-1$
Element propertyElement = doc.createElement("property"); //$NON-NLS-1$
propertyElement.setAttribute(IAntCoreConstants.NAME, "build.compiler"); //$NON-NLS-1$
propertyElement.setAttribute(IAntCoreConstants.VALUE, "org.eclipse.jdt.core.JDTCompilerAdapter"); //$NON-NLS-1$
element.appendChild(propertyElement);
Element antcallElement = doc.createElement("antcall"); //$NON-NLS-1$
antcallElement.setAttribute("target", "build"); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(antcallElement);
root.appendChild(element);
}
/**
* Add all bootclasspaths in srcDirs to given javacElement.
*/
private void addCompilerBootClasspath(List<String> srcDirs, Element javacElement) {
// <bootclasspath>
// <path refid="mylib.bootclasspath"/>
// <fileset dir="${java.home}/lib" includes="*.jar"/>
// <fileset dir="${java.home}/lib/ext" includes="*.jar"/>
// </bootclasspath>
Element bootclasspathElement = doc.createElement("bootclasspath"); //$NON-NLS-1$
boolean bootclasspathUsed = false;
for (Iterator<String> iter = srcDirs.iterator(); iter.hasNext();) {
String entry = iter.next();
if (EclipseClasspath.isUserSystemLibraryReference(entry)) {
Element pathElement = doc.createElement("path"); //$NON-NLS-1$
pathElement.setAttribute("refid", ExportUtil.removePrefixAndSuffix(entry, "${", "}")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
bootclasspathElement.appendChild(pathElement);
bootclasspathUsed = true;
} else if (EclipseClasspath.isJreReference(entry)) {
addJre(bootclasspathElement);
}
}
if (bootclasspathUsed) {
javacElement.appendChild(bootclasspathElement);
}
}
/**
* Add run targets.
*
* @throws CoreException
* thrown if problem accessing the launch configuration
* @throws TransformerFactoryConfigurationError
* thrown if applet file could not get created
* @throws UnsupportedEncodingException
* thrown if applet file could not get created
*/
public void createRun() throws CoreException, TransformerFactoryConfigurationError, UnsupportedEncodingException {
// <target name="run">
// <java fork="yes" classname="class" failonerror="true" dir="." newenvironment="true">
// <env key="a" value="b"/>
// <jvmarg value="-Dx=y"/>
// <arg value="arg"/>
// <classpath refid="project.classpath"/>
// </java>
// </target>
ILaunchConfiguration[] confs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations();
boolean junitUsed = false;
for (int i = 0; i < confs.length; i++) {
ILaunchConfiguration conf = confs[i];
if (!projectName.equals(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, IAntCoreConstants.EMPTY_STRING))) {
continue;
}
if (conf.getType().getIdentifier().equals(IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION)) {
addJavaApplication(variable2valueMap, conf);
} else if (conf.getType().getIdentifier().equals(IJavaLaunchConfigurationConstants.ID_JAVA_APPLET)) {
addApplet(variable2valueMap, conf);
} else if (conf.getType().getIdentifier().equals("org.eclipse.jdt.junit.launchconfig" /* JUnitLaunchConfiguration.ID_JUNIT_APPLICATION */)) //$NON-NLS-1$
{
addJUnit(variable2valueMap, conf);
junitUsed = true;
}
}
if (junitUsed) {
addJUnitReport();
}
}
/**
* Convert Java application launch configuration to ant target and add it to a document.
*
* @param variable2value
* adds Eclipse variables to this map, if run configuration makes use of this feature
* @param conf
* Java application launch configuration
*/
public void addJavaApplication(Map<String, String> variable2value, ILaunchConfiguration conf) throws CoreException {
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, conf.getName());
Element javaElement = doc.createElement("java"); //$NON-NLS-1$
javaElement.setAttribute("fork", "yes"); //$NON-NLS-1$ //$NON-NLS-2$
javaElement.setAttribute("classname", conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, IAntCoreConstants.EMPTY_STRING)); //$NON-NLS-1$
javaElement.setAttribute("failonerror", "true"); //$NON-NLS-1$ //$NON-NLS-2$
String dir = conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, IAntCoreConstants.EMPTY_STRING);
ExportUtil.addVariable(variable2value, dir, projectRoot);
if (!dir.equals(IAntCoreConstants.EMPTY_STRING)) {
javaElement.setAttribute(IAntCoreConstants.DIR, ExportUtil.getRelativePath(dir, projectRoot));
}
if (!conf.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true)) {
javaElement.setAttribute("newenvironment", "true"); //$NON-NLS-1$ //$NON-NLS-2$
}
Map<String, String> props = conf.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, new TreeMap<String, String>());
addElements(props, doc, javaElement, "env", "key", IAntCoreConstants.VALUE); //$NON-NLS-1$ //$NON-NLS-2$
addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, javaElement, "jvmarg", "line", variable2value, projectRoot); //$NON-NLS-1$ //$NON-NLS-2$
addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, javaElement, "arg", "line", variable2value, projectRoot); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(javaElement);
addRuntimeClasspath(conf, javaElement);
addRuntimeBootClasspath(conf, javaElement);
root.appendChild(element);
}
/**
* Convert applet launch configuration to Ant target and add it to a document.
*
* @param variable2value
* adds Eclipse variables to this map, if run configuration makes use of this feature
* @param conf
* applet configuration
* @throws CoreException
* thrown if problem dealing with launch configuration or underlying resources
* @throws TransformerFactoryConfigurationError
* thrown if applet file could not get created
* @throws UnsupportedEncodingException
* thrown if applet file could not get created
*/
public void addApplet(Map<String, String> variable2value, ILaunchConfiguration conf) throws CoreException, TransformerFactoryConfigurationError, UnsupportedEncodingException {
String dir = conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, IAntCoreConstants.EMPTY_STRING);
if (dir.equals(IAntCoreConstants.EMPTY_STRING)) {
dir = projectRoot;
}
ExportUtil.addVariable(variable2value, dir, projectRoot);
String value;
try {
value = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(dir);
}
catch (CoreException e) {
// cannot resolve variable
value = null;
}
String htmlfile = ((value != null) ? value : dir) + '/' + conf.getName() + ".html"; //$NON-NLS-1$
// confirm overwrite
if (ExportUtil.existsUserFile(htmlfile)
&& !MessageDialog.openConfirm(shell, DataTransferMessages.AntBuildfileExportPage_4, DataTransferMessages.AntBuildfileExportPage_4
+ ": " + htmlfile)) //$NON-NLS-1$
{
return;
}
IJavaProject javaProject = ExportUtil.getJavaProjectByName(projectName);
IFile file = javaProject.getProject().getFile(conf.getName() + ".html"); //$NON-NLS-1$
if (ExportUtil.validateEdit(shell, file)) // checkout file if required
{
// write build file
String html = AppletUtil.buildHTMLFile(conf);
InputStream is = new ByteArrayInputStream(html.getBytes("UTF-8")); //$NON-NLS-1$
if (file.exists()) {
file.setContents(is, true, true, null);
} else {
file.create(is, true, null);
}
}
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, conf.getName());
Element javaElement = doc.createElement("java"); //$NON-NLS-1$
javaElement.setAttribute("fork", "yes"); //$NON-NLS-1$//$NON-NLS-2$
javaElement.setAttribute("classname", conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_APPLET_APPLETVIEWER_CLASS, "sun.applet.AppletViewer")); //$NON-NLS-1$ //$NON-NLS-2$
javaElement.setAttribute("failonerror", "true"); //$NON-NLS-1$ //$NON-NLS-2$
if (value != null) {
javaElement.setAttribute(IAntCoreConstants.DIR, ExportUtil.getRelativePath(dir, projectRoot));
}
addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, javaElement, "jvmarg", "line", variable2value, projectRoot); //$NON-NLS-1$//$NON-NLS-2$
addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, javaElement, "arg", "line", variable2value, projectRoot); //$NON-NLS-1$//$NON-NLS-2$
addElement(conf.getName() + ".html", doc, javaElement, "arg", "line", variable2value, projectRoot); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
element.appendChild(javaElement);
addRuntimeClasspath(conf, javaElement);
addRuntimeBootClasspath(conf, javaElement);
root.appendChild(element);
}
/**
* Convert JUnit launch configuration to JUnit task and add it to a document.
*
* @param variable2value
* adds Eclipse variables to this map, if run configuration makes use of this feature
* @param conf
* applet configuration
*/
public void addJUnit(Map<String, String> variable2value, ILaunchConfiguration conf) throws CoreException {
// <target name="runtest">
// <mkdir dir="junit"/>
// <junit fork="yes" printsummary="withOutAndErr">
// <formatter type="xml"/>
// <test name="testclass"/>
// <env key="a" value="b"/>
// <jvmarg value="-Dx=y"/>
// <classpath refid="project.classpath"/>
// </junit>
// </target>
String testClass = conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, IAntCoreConstants.EMPTY_STRING);
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, conf.getName());
Element mkdirElement = doc.createElement("mkdir"); //$NON-NLS-1$
mkdirElement.setAttribute(IAntCoreConstants.DIR, "${junit.output.dir}"); //$NON-NLS-1$
element.appendChild(mkdirElement);
Element junitElement = doc.createElement("junit"); //$NON-NLS-1$
junitElement.setAttribute("fork", "yes"); //$NON-NLS-1$ //$NON-NLS-2$
junitElement.setAttribute("printsummary", "withOutAndErr"); //$NON-NLS-1$ //$NON-NLS-2$
String dir = conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, IAntCoreConstants.EMPTY_STRING);
ExportUtil.addVariable(variable2value, dir, projectRoot);
if (!dir.equals(IAntCoreConstants.EMPTY_STRING)) {
junitElement.setAttribute(IAntCoreConstants.DIR, ExportUtil.getRelativePath(dir, projectRoot));
}
if (!conf.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true)) {
junitElement.setAttribute("newenvironment", "true"); //$NON-NLS-1$ //$NON-NLS-2$
}
Element formatterElement = doc.createElement("formatter"); //$NON-NLS-1$
formatterElement.setAttribute("type", "xml"); //$NON-NLS-1$//$NON-NLS-2$
junitElement.appendChild(formatterElement);
if (!testClass.equals(IAntCoreConstants.EMPTY_STRING)) {
// Case 1: Single JUnit class
Element testElement = doc.createElement("test"); //$NON-NLS-1$
testElement.setAttribute(IAntCoreConstants.NAME, testClass);
testElement.setAttribute("todir", "${junit.output.dir}"); //$NON-NLS-1$ //$NON-NLS-2$
junitElement.appendChild(testElement);
} else {
// Case 2: Run all tests in project, package or source folder
String container = conf.getAttribute("org.eclipse.jdt.junit.CONTAINER" /* JUnitBaseLaunchConfiguration.LAUNCH_CONTAINER_ATTR */, IAntCoreConstants.EMPTY_STRING); //$NON-NLS-1$
IType[] types = ExportUtil.findTestsInContainer(container);
Set<IType> sortedTypes = new TreeSet<>(ExportUtil.getITypeComparator());
sortedTypes.addAll(Arrays.asList(types));
for (Iterator<IType> iter = sortedTypes.iterator(); iter.hasNext();) {
IType type = iter.next();
Element testElement = doc.createElement("test"); //$NON-NLS-1$
testElement.setAttribute(IAntCoreConstants.NAME, type.getFullyQualifiedName());
testElement.setAttribute("todir", "${junit.output.dir}"); //$NON-NLS-1$ //$NON-NLS-2$
junitElement.appendChild(testElement);
}
}
Map<String, String> props = conf.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, new TreeMap<String, String>());
addElements(props, doc, junitElement, "env", "key", IAntCoreConstants.VALUE); //$NON-NLS-1$ //$NON-NLS-2$
addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, junitElement, "jvmarg", "line", variable2value, projectRoot); //$NON-NLS-1$ //$NON-NLS-2$
element.appendChild(junitElement);
addRuntimeClasspath(conf, junitElement);
addRuntimeBootClasspath(conf, junitElement);
root.appendChild(element);
}
/**
* Add junitreport target.
*/
public void addJUnitReport() {
variable2valueMap.put("junit.output.dir", JUNIT_OUTPUT_DIR); //$NON-NLS-1$
// <target name="junitreport">
// <junitreport todir="junit">
// <fileset dir="junit">
// <include name="TEST-*.xml"/>
// </fileset>
// <report format="frames" todir="junit"/>
// </junitreport>
// </target>
Element element = doc.createElement("target"); //$NON-NLS-1$
element.setAttribute(IAntCoreConstants.NAME, "junitreport"); //$NON-NLS-1$
Element junitreport = doc.createElement("junitreport"); //$NON-NLS-1$
junitreport.setAttribute("todir", "${junit.output.dir}"); //$NON-NLS-1$ //$NON-NLS-2$
Element fileset = doc.createElement("fileset"); //$NON-NLS-1$
fileset.setAttribute(IAntCoreConstants.DIR, "${junit.output.dir}"); //$NON-NLS-1$
junitreport.appendChild(fileset);
Element include = doc.createElement("include"); //$NON-NLS-1$
include.setAttribute(IAntCoreConstants.NAME, "TEST-*.xml"); //$NON-NLS-1$
fileset.appendChild(include);
Element report = doc.createElement("report"); //$NON-NLS-1$
report.setAttribute("format", "frames"); //$NON-NLS-1$ //$NON-NLS-2$
report.setAttribute("todir", "${junit.output.dir}"); //$NON-NLS-1$ //$NON-NLS-2$
junitreport.appendChild(report);
element.appendChild(junitreport);
root.appendChild(element);
}
/**
* Add classpath tag to given javaElement.
*/
private void addRuntimeClasspath(ILaunchConfiguration conf, Element javaElement) throws CoreException {
// <classpath refid="hello.classpath"/>
Element classpathRefElement = doc.createElement("classpath"); //$NON-NLS-1$
EclipseClasspath runtimeClasspath = new EclipseClasspath(project, conf, false);
if (ExportUtil.isDefaultClasspath(project, runtimeClasspath)) {
classpathRefElement.setAttribute("refid", projectName + ".classpath"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
String pathId = "run." + conf.getName() + ".classpath"; //$NON-NLS-1$ //$NON-NLS-2$
classpathRefElement.setAttribute("refid", pathId); //$NON-NLS-1$
createClasspaths(pathId, project, runtimeClasspath);
}
javaElement.appendChild(classpathRefElement);
}
/**
* Add bootclasspath tag to given javaElement.
*/
private void addRuntimeBootClasspath(ILaunchConfiguration conf, Element javaElement) throws CoreException {
// <bootclasspath>
// <path refid="run.hello.bootclasspath"/>
// </bootclasspath>
if (JavaRuntime.isModularConfiguration(conf)) {
// there is no bootclasspath entry from Java 9 onwards
return;
}
EclipseClasspath bootClasspath = new EclipseClasspath(project, conf, true);
if (bootClasspath.rawClassPathEntries.size() == 1 && EclipseClasspath.isJreReference(bootClasspath.rawClassPathEntries.get(0))) {
// the default boot classpath contains exactly one element (the JRE)
return;
}
String pathId = "run." + conf.getName() + ".bootclasspath"; //$NON-NLS-1$ //$NON-NLS-2$
createClasspaths(pathId, project, bootClasspath);
Element bootclasspath = doc.createElement("bootclasspath"); //$NON-NLS-1$
Element classpathRefElement = doc.createElement("path"); //$NON-NLS-1$
classpathRefElement.setAttribute("refid", pathId); //$NON-NLS-1$
bootclasspath.appendChild(classpathRefElement);
javaElement.appendChild(bootclasspath);
}
/**
* Create child node from <code>cmdLine</code> and add it to <code>element</code> which is part of <code>doc</code>.
*
* @param cmdLineArgs
* command line arguments, separated with spaces or within double quotes, may also contain Eclipse variables
* @param doc
* XML document
* @param element
* node to add child to
* @param elementName
* name of new child node
* @param attributeName
* name of attribute for child node
* @param variable2valueMap
* adds Eclipse variables to this map, if command line makes use of this feature
*/
private static void addElement(String cmdLineArgs, Document doc, Element element, String elementName, String attributeName, Map<String, String> variable2valueMap, String projectRoot) {
if (cmdLineArgs == null || cmdLineArgs.length() == 0) {
return;
}
ExportUtil.addVariable(variable2valueMap, cmdLineArgs, projectRoot);
Element itemElement = doc.createElement(elementName);
itemElement.setAttribute(attributeName, cmdLineArgs);
element.appendChild(itemElement);
}
/**
* Create child nodes from string map and add them to <code>element</code> which is part of <code>doc</code>.
*
* @param map
* key/value string pairs
* @param doc
* XML document
* @param element
* node to add children to
* @param elementName
* name of new child node
* @param keyAttributeName
* name of key attribute
* @param valueAttributeName
* name of value attribute
*/
private static void addElements(Map<String, String> map, Document doc, Element element, String elementName, String keyAttributeName, String valueAttributeName) {
for (Iterator<String> iter = map.keySet().iterator(); iter.hasNext();) {
String key = iter.next();
String value = map.get(key);
Element itemElement = doc.createElement(elementName);
itemElement.setAttribute(keyAttributeName, key);
itemElement.setAttribute(valueAttributeName, value);
element.appendChild(itemElement);
}
}
/**
* Set config options.
*
* @param buildfilename
* name for Ant buildfile
* @param junitdir
* name of JUnit output directory
* @param checkcycles
* check project for Ant compatibility
* @param eclipsecompiler
* generate target for compiling project with Eclipse compiler
*/
public static void setOptions(String buildfilename, String junitdir, boolean checkcycles, boolean eclipsecompiler) {
if (buildfilename.length() > 0) {
BUILD_XML = buildfilename;
}
if (junitdir.length() > 0) {
JUNIT_OUTPUT_DIR = junitdir;
}
CHECK_SOURCE_CYCLES = checkcycles;
CREATE_ECLIPSE_COMPILE_TARGET = eclipsecompiler;
}
}