import org.gradle.api.*; import org.gradle.artifacts.*; import org.gradle.process.JavaExecSpec; import org.gradle.api.file.*; import org.gradle.api.tasks.*; import org.gradle.api.internal.file.UnionFileCollection; import groovy.xml.MarkupBuilder; public class WriteEclipseLauncher extends JavaExec { @OutputFile File dest; @Input boolean isRunFave = false; @Input boolean isDbgFave = false; @Input boolean useEclipseDefaultClasspath = false public E one(Collection col) { assert col.size() == 1; return col.iterator().next(); } void walkFileCollection(UnionFileCollection col, Set gathered) { col.sources.each { walkFileCollection(it, gathered); } } void walkFileCollection(ConfigurableFileCollection col, Set gathered) { col.from.each { walkFileCollection(it, gathered); } } void walkFileCollection(SourceSetOutput col, Set gathered) { gathered.add(col); } void walkFileCollection(Configuration col, Set gathered) { col.allDependencies.each { walkDependency(it, gathered) } } void walkDependency(ExternalModuleDependency dep, Set gathered) { gathered.add(dep) } void walkDependency(ProjectDependency dep, Set gathered) { gathered.add(dep) Project project = dep.dependencyProject String confName = dep.targetConfiguration ?: 'default' Configuration configuration = project.configurations."$confName" walkFileCollection(configuration, gathered) } String makeEntryXml(ExternalModuleDependency dep, FileCollection cp) { def writer = new StringWriter(); def xml = new MarkupBuilder(writer); def file = cp.find { it.name.contains(dep.name) } xml.mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8', standalone: 'no') xml.runtimeClasspathEntry( externalArchive: file, path: 5, // TODO: Figure out source jar type: 2 ); return writer } String makeEntryXml(Project proj) { def writer = new StringWriter(); def xml = new MarkupBuilder(writer); xml.mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8', standalone: 'no') xml.runtimeClasspathEntry( path: 5, projectName: proj.eclipse.project.name, type: 1 ) return writer } String makeEntryXml(ProjectDependency dep, FileCollection cp) { return makeEntryXml(dep.dependencyProject); } String makeEntryXml(SourceSetOutput out, FileCollection cp) { Task task = one(out.buildDependencies.getDependencies(null)) return makeEntryXml(task.project) } public File forName(String name) { return project.file(".launch/${name}.launch") } List getJvmArgumentsForEclipse() { List all = allJvmArgs; int index = all.indexOf('-cp'); if (index == -1) { return all; } all.remove(index); all.remove(index); return all; } @TaskAction void exec() { // Override exec. Instead write launcher dest.parentFile.mkdirs(); def launcher = new MarkupBuilder(new FileWriter(dest)); Set gathered = new LinkedHashSet(); if (!useEclipseDefaultClasspath) { walkFileCollection(classpath, gathered); } launcher.mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8', standalone: 'no') launcher.launchConfiguration(type: 'org.eclipse.jdt.launching.localJavaApplication') { listAttribute(key: 'org.eclipse.debug.ui.favoriteGroups') { if (isRunFave) { listEntry(value: 'org.eclipse.debug.ui.launchGroup.run'); } if (isDbgFave) { listEntry(value: 'org.eclipse.debug.ui.launchGroup.debug'); } } if (!useEclipseDefaultClasspath) { listAttribute(key: 'org.eclipse.jdt.launching.CLASSPATH') { gathered.each { listEntry(value: makeEntryXml(it, classpath)) } } } booleanAttribute(key: 'org.eclipse.jdt.launching.DEFAULT_CLASSPATH', value: useEclipseDefaultClasspath); stringAttribute(key: 'org.eclipse.jdt.launching.MAIN_TYPE', value: main); // TODO: Proper escaping of program and JVM arguments. stringAttribute(key: 'org.eclipse.jdt.launching.PROGRAM_ARGUMENTS', value: args.join(' ')); stringAttribute(key: 'org.eclipse.jdt.launching.PROJECT_ATTR', value: project.eclipse.project.name); stringAttribute(key: 'org.eclipse.jdt.launching.VM_ARGUMENTS', value: jvmArgumentsForEclipse.join(' ')); } } } allprojects { ext.WriteEclipseLauncher = WriteEclipseLauncher }