/*
* 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.eclipse.core.compiler;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import groovy.lang.GroovySystem;
import org.codehaus.groovy.eclipse.core.GroovyCore;
import org.codehaus.groovy.eclipse.core.GroovyCoreActivator;
import org.codehaus.groovy.frameworkadapter.util.CompilerChooser;
import org.codehaus.groovy.frameworkadapter.util.SpecifiedVersion;
import org.codehaus.jdt.groovy.model.GroovyNature;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.groovy.core.Activator;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;
public class CompilerUtils {
public static String getGroovyVersion() {
return GroovySystem.getVersion();
}
public static boolean isGroovyVersionDisabledOrMissing(SpecifiedVersion version) {
return getActiveGroovyVersion() == version;
}
public static SpecifiedVersion getActiveGroovyVersion() {
return CompilerChooser.getInstance().getActiveSpecifiedVersion();
}
public static Version getBundleVersion(SpecifiedVersion version) {
return CompilerChooser.getInstance().getAssociatedVersion(version);
}
public static Bundle getActiveGroovyBundle() {
return CompilerChooser.getInstance().getActiveBundle();
}
/**
* Swtiches to or from groovy version 1.6.x depending on the boolean passed in.
* A restart is required immediately after or else many exceptions will be thrown.
*
* @return {@link Status.OK_STATUS} if successful or error status that contains the exception thrown otherwise
*/
public static IStatus switchVersions(SpecifiedVersion fromVersion, SpecifiedVersion toVersion) {
try {
// store new version in Eclipse preferences
CompilerChooser.getInstance().storeVersion(toVersion);
return Status.OK_STATUS;
} catch (Exception e) {
GroovyCore.logException(e.getMessage(), e);
return new Status(IStatus.ERROR, GroovyCoreActivator.PLUGIN_ID, e.getMessage() + "\n\nSee the error log for more information.", e);
}
}
public static SortedSet<SpecifiedVersion> getAllGroovyVersions() {
SpecifiedVersion[] versions = CompilerChooser.getInstance().getAllSpecifiedVersions();
// remove dups and sort
SortedSet<SpecifiedVersion> allVersions = new TreeSet<SpecifiedVersion>();
for (SpecifiedVersion version : versions) {
allVersions.add(version);
}
return allVersions;
}
/**
* @return Best guess at the .groovy location (usually in user.home).
* If user.home can't be found, then null is returned
*/
public static String getDotGroovyLocation() {
String home = System.getProperty("user.home");
if (home != null) {
home += "/.groovy";
}
return home;
}
private static String getDotGroovyLibLocation() {
String home = getDotGroovyLocation();
if (home != null) {
home += "/lib";
}
return home;
}
public static SpecifiedVersion getCompilerLevel(IProject project) {
SpecifiedVersion version = SpecifiedVersion.UNSPECIFIED;
if (GroovyNature.hasGroovyNature(project)) {
String groovyCompilerLevelStr = Activator.getDefault().getGroovyCompilerLevel(project);
if (groovyCompilerLevelStr != null) {
version = SpecifiedVersion.findVersionFromString(groovyCompilerLevelStr);
}
}
return version;
}
public static SpecifiedVersion getWorkspaceCompilerLevel() {
String groovyVersion = GroovySystem.getVersion();
// convert from major.minor.micro to major.minor
int dotIndex = groovyVersion.lastIndexOf('.');
if (dotIndex > 0) {
groovyVersion = groovyVersion.substring(0, dotIndex);
}
return SpecifiedVersion.findVersionFromString(groovyVersion);
}
public static void setCompilerLevel(IProject project, SpecifiedVersion projectLevel) {
setCompilerLevel(project, projectLevel, false);
}
public static void setCompilerLevel(IProject project, SpecifiedVersion projectLevel, boolean assertCompatible) {
Activator.getDefault().setGroovyCompilerLevel(project, projectLevel.versionName);
if (assertCompatible) {
if (projectVersionMatchesWorkspaceVersion(projectLevel)) {
removeCompilermMismatchProblem(project);
} else {
addCompilerMismatchError(project, projectLevel);
}
}
}
/**
* Checks that the compiler level of the project matches that of the workspace.
* If a mismatch, then a marker is added to the project.
*/
public static void addCompilerMismatchError(IProject project, SpecifiedVersion projectLevel) {
try {
SpecifiedVersion workspaceLevel = CompilerUtils.getWorkspaceCompilerLevel();
IMarker marker = project.getProject().createMarker(CompilerCheckerParticipant.COMPILER_MISMATCH_PROBLEM);
marker.setAttribute(IMarker.MESSAGE, "Groovy: compiler mismatch Project level is: " +
projectLevel.toReadableVersionString() + " Workspace level is " + workspaceLevel.toReadableVersionString() +
"\nGroovy compiler level expected by the project does not match workspace compiler level. " +
"\nGo to Project properties -> Groovy compiler to set the Groovy compiler level for this project");
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
marker.setAttribute(IMarker.LOCATION, project.getName());
} catch (CoreException e) {
GroovyCore.logException("Error checking Groovy project compiler level compatibility for " + project.getName(), e);
}
}
public static void removeCompilermMismatchProblem(IProject project) {
try {
IMarker[] findMarkers = project.findMarkers(CompilerCheckerParticipant.COMPILER_MISMATCH_PROBLEM, true, IResource.DEPTH_ZERO);
for (IMarker marker : findMarkers) {
marker.delete();
}
} catch (CoreException e) {
GroovyCore.logException("Error checking Groovy project compiler level compatibility for " + project.getName(), e);
}
}
public static void addMultipleCompilersOnClasspathError(IProject project, SpecifiedVersion compiler1, SpecifiedVersion compiler2) {
try {
IMarker marker = project.getProject().createMarker(CompilerCheckerParticipant.COMPILER_MISMATCH_PROBLEM);
marker.setAttribute(IMarker.MESSAGE, "Multiple Groovy compilers found on classpath. Continuing with compilation will produce unpredictible results. " +
"Remove a compiler before continuing.\n" + "Found " + compiler1.toReadableVersionString() + " and " + compiler2.toReadableVersionString());
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
marker.setAttribute(IMarker.LOCATION, project.getName());
} catch (CoreException e) {
GroovyCore.logException("Error checking Groovy project compiler level compatibility for " + project.getName(), e);
}
}
public static boolean projectVersionMatchesWorkspaceVersion(SpecifiedVersion version) {
if (version == SpecifiedVersion.UNSPECIFIED || version == SpecifiedVersion.DONT_CARE) {
return true;
}
return version == getWorkspaceCompilerLevel();
}
/**
* Returns the groovy-all-x.y.z.jar that is used in the Eclipse project.
*/
public static IPath getExportedGroovyAllJar() {
Bundle groovyBundle = CompilerUtils.getActiveGroovyBundle();
for (URL jarUrl : Collections.list(groovyBundle.findEntries("lib", "groovy-all-*.jar", false))) {
if (!jarUrl.getFile().endsWith("-javadoc.jar") && !jarUrl.getFile().endsWith("-sources.jar")) {
return toFilePath(jarUrl);
}
}
throw new RuntimeException("Could not find groovy-all jar");
}
private static boolean includeServlet = true;
static {
try {
if (System.getProperty("greclipse.includeServletInClasspathContainer", "true").equalsIgnoreCase("false")) {
includeServlet = false;
}
} catch (Exception e) {
// likely security related
}
}
/**
* Returns the extra jars that belong inside the Groovy Classpath Container.
*/
public static List<IPath> getExtraJarsForClasspath() {
List<IPath> jarPaths = new ArrayList<IPath>();
Bundle groovyBundle = CompilerUtils.getActiveGroovyBundle();
for (URL jarUrl : Collections.list(groovyBundle.findEntries("lib", "*.jar", false))) {
if (!jarUrl.getFile().startsWith("groovy-all") && (!jarUrl.getFile().startsWith("servlet") || includeServlet) &&
!jarUrl.getFile().endsWith("-javadoc.jar") && !jarUrl.getFile().endsWith("-sources.jar")) {
jarPaths.add(toFilePath(jarUrl));
}
}
return jarPaths;
}
/**
* Finds a specific jar in the groovy lib folder, or null if not found.
*
* @param jarName the name of the jar
* @return the full, resolved url to the jar
*/
public static IPath getJarInGroovyLib(String jarName) {
Bundle groovyBundle = CompilerUtils.getActiveGroovyBundle();
Enumeration<URL> enu = groovyBundle.findEntries("lib", jarName, false);
if (enu != null && enu.hasMoreElements()) {
URL jarUrl = enu.nextElement();
if (jarUrl.getFile().endsWith("-sources.jar") && enu.hasMoreElements()) {
jarUrl = enu.nextElement();
}
return toFilePath(jarUrl);
}
return null;
}
public static IPath findDSLDFolder() {
try {
Bundle groovyBundle = CompilerUtils.getActiveGroovyBundle();
Enumeration<URL> enu = groovyBundle.findEntries(".", "plugin_dsld_support", false);
if (enu != null && enu.hasMoreElements()) {
return toFilePath(enu.nextElement());
}
} catch (Exception e) {
GroovyCore.logException("Failed to resolve DSLD folder", e);
}
return null;
}
public static File[] findJarsInDotGroovyLocation() {
String home = getDotGroovyLibLocation();
if (home != null) {
File libDir = new File(home);
if (libDir.isDirectory()) {
File[] files = libDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return !(new File(dir, name).isDirectory()) && name.endsWith(".jar");
}
});
return files;
}
}
return new File[0];
}
/** Converts "bundleentry:/514.fwk1995952705/lib/groovy-all-x.y.z.jar" to file path. */
private static IPath toFilePath(URL url) {
try {
url = FileLocator.toFileURL(url);
return new Path(url.getPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}