/* * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.groovy.m2eclipse; import java.util.HashSet; import java.util.Set; import org.apache.maven.model.Dependency; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; import org.apache.maven.project.MavenProject; import org.codehaus.groovy.eclipse.core.model.GroovyRuntime; import org.codehaus.jdt.groovy.model.GroovyNature; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; 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.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest; import org.eclipse.m2e.jdt.IClasspathDescriptor; import org.eclipse.m2e.jdt.IJavaProjectConfigurator; import org.eclipse.m2e.jdt.internal.AbstractJavaProjectConfigurator; public class GroovyProjectConfigurator extends AbstractJavaProjectConfigurator implements IJavaProjectConfigurator { private static final String SRC_MAIN_GROOVY = "src/main/groovy"; private static final String SRC_TEST_GROOVY = "src/test/groovy"; private static final String COMPILE = "compile"; private static final String TEST_COMPILE = "testCompile"; private enum SourceType { MAIN, TEST, BOTH, NONE } @Override public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException { super.configure(request, monitor); IProject project = request.getProject(); if (getSourceType(request.getMavenProjectFacade()) != null) { if (!project.hasNature(GroovyNature.GROOVY_NATURE)) { if (!project.hasNature(JavaCore.NATURE_ID)) { addJavaNature(project); } GroovyRuntime.addGroovyNature(project); } // add dsl support if not already there IJavaProject javaProject = JavaCore.create(project); if (!GroovyRuntime.hasClasspathContainer(javaProject, GroovyRuntime.DSLD_CONTAINER_ID)) { GroovyRuntime.addLibraryToClasspath(javaProject, GroovyRuntime.DSLD_CONTAINER_ID, false); } } else { GroovyRuntime.removeGroovyNature(project); } } public void configureClasspath(IMavenProjectFacade facade, IClasspathDescriptor classpath, IProgressMonitor monitor) throws CoreException { SourceType sourceType = getSourceType(facade); if (sourceType != null) { // add source folders IJavaProject javaProject = JavaCore.create(facade.getProject()); IPath projectPath = facade.getFullPath(); Set<IPath> toRemove = new HashSet<IPath>(); IFolder testFolder = javaProject.getProject().getFolder(SRC_TEST_GROOVY); IPath testPath = testFolder.getFullPath(); //$NON-NLS-1$ if (testFolder.exists() && (sourceType == SourceType.TEST || sourceType == SourceType.BOTH)) { IPath testOutPath = projectPath.append("target/test-classes"); //$NON-NLS-1$ if (!hasEntry(javaProject, testPath)) { GroovyRuntime.addClassPathEntryToFront(javaProject, JavaCore.newSourceEntry(testPath, new Path[0], testOutPath)); } } else { toRemove.add(testPath); } IFolder sourceFolder = javaProject.getProject().getFolder(SRC_MAIN_GROOVY); IPath sourcePath = sourceFolder.getFullPath(); if (sourceFolder.exists() && (sourceType == SourceType.MAIN || sourceType == SourceType.BOTH)) { IPath sourceOutPath = projectPath.append("target/classes"); //$NON-NLS-1$ if (!hasEntry(javaProject, sourcePath)) { GroovyRuntime.addClassPathEntryToFront(javaProject, JavaCore.newSourceEntry(sourcePath, new Path[0], sourceOutPath)); } } else { toRemove.add(sourcePath); } // We should remove the generated sources from the classpath if it exists toRemove.add(projectPath.append("target/generated-sources/groovy-stubs/main")); // Also remove stuff that was there already which we control, but that shouldn't be there according to the gmaven conf IClasspathEntry[] allEntries = javaProject.getRawClasspath(); for (IClasspathEntry entry : allEntries) { if (toRemove.contains(entry.getPath())) { GroovyRuntime.removeClassPathEntry(javaProject, entry); } } } } private boolean hasEntry(IJavaProject javaProject, IPath path) throws JavaModelException { IClasspathEntry[] entries = javaProject.getRawClasspath(); for (IClasspathEntry entry : entries) { if (entry.getPath().equals(path)) { return true; } } return false; } public void configureRawClasspath(ProjectConfigurationRequest request, IClasspathDescriptor classpath, IProgressMonitor monitor) throws CoreException { } /** * Determine if this maven project uses src/main/groovy and/or src/test/groovy. Only * applicable for gmaven. With groovy-eclipse-compiler, this is configured by the build-helper-maven-plugin * @param mavenProject * @return */ private SourceType getSourceType(IMavenProjectFacade facade) { MavenProject mavenProject = facade.getMavenProject(); Plugin plugin = getGMavenPlugin(mavenProject); if (plugin != null) { return getSourceTypeInGMavenProject(plugin); } // Recognize gmaven-plus Plugin gmavenPlusPlugin = mavenProject.getPlugin("org.codehaus.gmavenplus:gmavenplus-plugin"); //$NON-NLS-1$ if (gmavenPlusPlugin != null) { return getSourceTypeInGMavenProject(gmavenPlusPlugin); } // look to see if there is the maven-compiler-plugin // with a compilerId of the groovy eclipse compiler if (compilerPluginUsesGroovyEclipseAdapter(mavenProject, "org.apache.maven.plugins", "maven-compiler-plugin")) { return getSourceTypeInGECProject(facade); } // For eclipse plugins written in groovy : // look to see if there is the tycho-compiler-plugin // with a compilerId of the groovy eclipse compiler // /!\ Requires m2e-tycho >= 0.6.0.201210231015 if (compilerPluginUsesGroovyEclipseAdapter(mavenProject, "org.eclipse.tycho", "tycho-compiler-plugin")) { //Assume configuration is controlled in the MANIFEST.MF, hence returning SourceType.NONE here return SourceType.NONE; } // not a groovy project return null; } private SourceType getSourceTypeInGMavenProject(Plugin plugin) { SourceType result = SourceType.NONE; if (plugin != null && plugin.getExecutions() != null && !plugin.getExecutions().isEmpty()) { for (PluginExecution execution : plugin.getExecutions()) { if (execution.getGoals().contains(COMPILE)) { switch (result) { case NONE: result = SourceType.MAIN; break; case TEST: result = SourceType.BOTH; break; } } if (execution.getGoals().contains(TEST_COMPILE)) { switch (result) { case NONE: result = SourceType.TEST; break; case MAIN: result = SourceType.BOTH; break; } } } } return result; } /** * in this case, look to see if the folders exist. * if so, they are automatically added */ private SourceType getSourceTypeInGECProject(IMavenProjectFacade facade) { IProject project = facade.getProject(); boolean srcMainGroovy = project.getFolder(SRC_MAIN_GROOVY).exists(); boolean srcTestGroovy = project.getFolder(SRC_TEST_GROOVY).exists(); if (srcMainGroovy) { if (srcTestGroovy) { return SourceType.BOTH; } else { return SourceType.MAIN; } } else if (srcTestGroovy) { return SourceType.TEST; } else { return SourceType.NONE; } } private Plugin getGMavenPlugin(MavenProject mavenProject) { Plugin p = mavenProject.getPlugin("org.codehaus.gmaven:gmaven-plugin"); //$NON-NLS-1$ if (p == null) { // try the old (pre-1.1) version of the plugin p = mavenProject.getPlugin("org.codehaus.groovy.maven:gmaven-plugin"); //$NON-NLS-1$ } return p; } private boolean compilerPluginUsesGroovyEclipseAdapter(MavenProject mavenProject, String pluginGroupId, String pluginArtifactId) { for (Plugin buildPlugin : mavenProject.getBuildPlugins()) { if (pluginArtifactId.equals(buildPlugin.getArtifactId()) && pluginGroupId.equals(buildPlugin.getGroupId())) { for (Dependency dependency : buildPlugin.getDependencies()) { if ("groovy-eclipse-compiler".equals(dependency.getArtifactId()) && "org.codehaus.groovy".equals(dependency.getGroupId())) { return true; } } } } return false; } public static void addJavaNature(final IProject project) throws CoreException { final IProjectDescription description = project.getDescription(); final String[] ids = description.getNatureIds(); // add groovy nature at the start so that its image will be shown final String[] newIds = new String[ids == null ? 1 : ids.length + 1]; newIds[0] = JavaCore.NATURE_ID; if (ids != null) { for (int i = 1; i < newIds.length; i++) { newIds[i] = ids[i - 1]; } } description.setNatureIds(newIds); project.setDescription(description, null); } }