package org.netbeans.gradle.model.java; import java.io.File; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.file.SourceDirectorySet; import org.gradle.api.plugins.GroovyPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.plugins.scala.ScalaPlugin; import org.gradle.api.specs.Specs; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.SourceSetOutput; import org.netbeans.gradle.model.api.ProjectInfoBuilder2; import org.netbeans.gradle.model.util.BuilderUtils; import org.netbeans.gradle.model.util.Exceptions; /** * Defines a {@code ProjectInfoBuilder2} which is able to extract * {@link JavaSourcesModel} from a Gradle project. * <P> * This builder has only two instances {@link #ONLY_COMPILE} and * {@link #COMPLETE}. */ enum JavaSourcesModelBuilder implements ProjectInfoBuilder2<JavaSourcesModel> { /** * The builder instance which will not attempt to query runtime dependencies. */ ONLY_COMPILE(false), /** * The builder instance which will request both runtime and compile time * dependencies. */ COMPLETE(true); private final boolean needRuntime; private JavaSourcesModelBuilder(boolean needRuntime) { this.needRuntime = needRuntime; } /** *Extracts and returns the {@code JavaSourcesModel} from the given * project or returns {@code null} if the project does not uses the 'java' * plugin. * * @param project the project from which the information is to be extracted. * This argument cannot be {@code null}. * * @return the {@code JavaSourcesModel} extracted from the given * project or {@code null} if the project does not applies the "java" * plugin */ public JavaSourcesModel getProjectInfo(Object project) { return getProjectInfo((Project)project); } private JavaSourcesModel getProjectInfo(Project project) { JavaPluginConvention javaPlugin = project.getConvention().findPlugin(JavaPluginConvention.class); if (javaPlugin == null) { return null; } try { return new Builder(project, javaPlugin, needRuntime).getProjectInfo(); } catch (Exception ex) { throw Exceptions.throwUnchecked(ex); } } /** {@inheritDoc } */ public String getName() { return BuilderUtils.getNameForEnumBuilder(this); } private static final class Builder { private final Project project; private final JavaPluginConvention javaPlugin; private final boolean needRuntime; public Builder(Project project, JavaPluginConvention javaPlugin, boolean needRuntime) throws Exception { this.project = project; this.javaPlugin = javaPlugin; this.needRuntime = needRuntime; } public JavaSourcesModel getProjectInfo() throws Exception { List<JavaSourceSet> result = new LinkedList<JavaSourceSet>(); SourceSetContainer sourceSets = javaPlugin.getSourceSets(); for (SourceSet sourceSet: sourceSets) { result.add(parseSourceSet(sourceSet)); } return new JavaSourcesModel(result); } private Collection<File> addSourceGroup( JavaSourceGroupName name, SourceDirectorySet sourceGroup, JavaSourceSet.Builder result) throws Exception { JavaSourceGroup parsedGroup = parseSourceGroup(name, sourceGroup); result.addSourceGroup(parsedGroup); return parsedGroup.getSourceRoots(); } private JavaSourceSet parseSourceSet(SourceSet sourceSet) throws Exception { JavaOutputDirs outputDirs = parseOutputDirs(sourceSet.getOutput()); JavaSourceSet.Builder result = new JavaSourceSet.Builder( sourceSet.getName(), outputDirs); SourceDirectorySet allSourceGroup = sourceSet.getAllSource(); Set<File> others = new HashSet<File>(allSourceGroup.getSrcDirs()); others.removeAll(addSourceGroup(JavaSourceGroupName.JAVA, sourceSet.getJava(), result)); if (project.getPlugins().hasPlugin(GroovyPlugin.class)) { others.removeAll(addSourceGroup(JavaSourceGroupName.GROOVY, JavaSourcesUtils.getGroovySources(sourceSet), result)); } if (project.getPlugins().hasPlugin(ScalaPlugin.class)) { others.removeAll(addSourceGroup(JavaSourceGroupName.SCALA, JavaSourcesUtils.getScalaSources(sourceSet), result)); } others.removeAll(addSourceGroup(JavaSourceGroupName.RESOURCES, sourceSet.getResources(), result)); result.addSourceGroup(new JavaSourceGroup(JavaSourceGroupName.OTHER, others)); parseClassPaths(sourceSet, result); return result.create(); } private Set<File> getLenientClasspath(String configName, Throwable baseError) { try { Configuration config = project.getConfigurations().findByName(configName); if (config != null) { return config.getResolvedConfiguration().getLenientConfiguration().getFiles(Specs.SATISFIES_ALL); } } catch (Throwable ex) { Exceptions.tryAddSuppressedException(baseError, ex); } return Collections.emptySet(); } private void parseClassPaths(SourceSet sourceSet, JavaSourceSet.Builder result) { Set<File> compile; boolean compileResolved = false; try { compile = sourceSet.getCompileClasspath().getFiles(); compileResolved = true; } catch (Throwable ex) { result.setCompileClassPathProblem(ex); compile = getLenientClasspath(sourceSet.getCompileConfigurationName(), ex); } if (!needRuntime) { result.setClasspaths(new JavaClassPaths(compile)); return; } Set<File> runtime = compile; try { runtime = sourceSet.getRuntimeClasspath().getFiles(); if (!compileResolved) { compile = runtime; } } catch (Throwable ex) { result.setRuntimeClassPathProblem(ex); } result.setClasspaths(new JavaClassPaths(compile, runtime)); } private JavaSourceGroup parseSourceGroup(JavaSourceGroupName name, SourceDirectorySet sourceGroup) throws Exception { Set<File> srcDirs = sourceGroup.getSrcDirs(); Set<String> excludes = sourceGroup.getExcludes(); Set<String> includes = sourceGroup.getIncludes(); SourceIncludePatterns patterns = SourceIncludePatterns.create(excludes, includes); return new JavaSourceGroup(name, srcDirs, patterns); } private JavaOutputDirs parseOutputDirs(SourceSetOutput outputDirs) throws Exception { File classesDir = outputDirs.getClassesDir(); File resourcesDir = outputDirs.getResourcesDir(); Set<File> otherDirs = outputDirs.getDirs().getFiles(); return new JavaOutputDirs(classesDir, resourcesDir, otherDirs); } } }