/* * Copyright (c) 2017 the original author or authors. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.buildship.kotlin; import java.io.File; import java.io.FileFilter; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.gradle.tooling.GradleConnector; import org.gradle.tooling.ProjectConnection; import org.gradle.tooling.model.build.BuildEnvironment; import org.gradle.tooling.model.build.GradleEnvironment; import org.jetbrains.kotlin.core.model.ScriptTemplateProviderEx; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Lists; import com.google.common.io.Files; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.buildship.core.CorePlugin; import org.eclipse.buildship.core.GradlePluginsRuntimeException; import org.eclipse.buildship.core.configuration.BuildConfiguration; import org.eclipse.buildship.core.configuration.GradleProjectNature; import org.eclipse.buildship.core.util.gradle.GradleDistributionWrapper; /** * Contributes the Gradle Kotlin Script template to the Kotlin Eclipse * integration. * * @author Donat Csikos */ public final class GradleKotlinScriptTemplateProvider implements ScriptTemplateProviderEx { // properties names defined in gradle-script-kotlin private static final String GSK_PROJECT_ROOT = "projectRoot"; private static final String GSK_GRADLE_USER_HOME = "gradleUserHome"; private static final String GSK_JAVA_HOME = "gradleJavaHome"; private static final String GSK_OPTIONS = "gradleOptions"; private static final String GSK_JVM_OPTIONS = "gradleJvmOptions"; private static final String GSK_INSTALLATION_LOCAL = "gradleHome"; private static final String GSK_INSTALLATION_REMOTE = "gradleUri"; private static final String GSK_INSTALLATION_VERSION = "gradleVersion"; @Override public boolean isApplicable(IFile file) { IProject project = file.getProject(); return GradleProjectNature.isPresentOn(project); } @Override public Iterable<String> getTemplateClasspath(Map<String, ? extends Object> environment, IProgressMonitor monitor) { // TODO (donat) the Gradle home should be available in the BuildEnvirontment TAPI model File distroRoot = (File) environment.get(GSK_INSTALLATION_LOCAL); if (distroRoot == null) { BuildEnvironment buildEnvironment = queryBuildEnvironment(environment); GradleEnvironment gradleEnvironment = buildEnvironment.getGradle(); File gradleUserHome = gradleEnvironment.getGradleUserHome(); String gradleVersion = gradleEnvironment.getGradleVersion(); distroRoot = findDistributionRoot(gradleUserHome, gradleVersion); } if (distroRoot == null) { return Collections.emptyList(); } return jarPathsFromDistributionLibDirectory(distroRoot); } @SuppressWarnings("unchecked") private static BuildEnvironment queryBuildEnvironment(Map<String, ? extends Object> environment) { ProjectConnection connection = null; try { GradleConnector connector = GradleConnector.newConnector().forProjectDirectory((File) environment.get(GSK_PROJECT_ROOT)); connector.useGradleUserHomeDir((File) environment.get(GSK_GRADLE_USER_HOME)); applyGradleDistribution(environment, connector); connection = connector.connect(); return connection.model(BuildEnvironment.class) .setJvmArguments((List<String>) environment.get(GSK_JVM_OPTIONS)) .withArguments((List<String>) environment.get(GSK_OPTIONS)) .setJavaHome((File) environment.get(GSK_JAVA_HOME)) .get(); } catch (Exception e) { CorePlugin.logger().warn("Cannot query BuildEnvironment", e); return null; } finally { if (connection != null) { connection.close(); } } } private static void applyGradleDistribution(Map<String, ? extends Object> environment, GradleConnector connector) { File gradleLocal = (File) environment.get(GSK_INSTALLATION_LOCAL); URI gradleRemote = (URI) environment.get(GSK_INSTALLATION_REMOTE); String gradleVersion = (String) environment.get(GSK_INSTALLATION_VERSION); if (gradleLocal != null) { connector.useInstallation(gradleLocal); } else if (gradleRemote != null) { connector.useDistribution(gradleRemote); } else if (gradleVersion != null) { connector.useGradleVersion(gradleVersion); } else { connector.useBuildDistribution(); } } private static File findDistributionRoot(File gradleUserHome, final String version) { File distsDir = new File(gradleUserHome, "wrapper/dists"); List<File> candidates = Arrays.asList(distsDir.listFiles(new FileFilter() { @Override public boolean accept(File path) { String name = path.getName(); return name.contains("gradle") && name.contains(version); } })); if (candidates.isEmpty()) { return null; } else { return candidates.get(candidates.size() - 1); } } private static List<String> jarPathsFromDistributionLibDirectory(File distroRoot) { Optional<File> libFolder = findLibFolder(distroRoot); List<String> result = Lists.newArrayList(); if (libFolder.isPresent()) { for (File jar : libFolder.get().listFiles()) { String name = jar.getName(); if (name.endsWith(".jar")) { result.add(jar.getAbsolutePath()); } } } return result; } private static Optional<File> findLibFolder(File distroRoot) { return Files.fileTreeTraverser().breadthFirstTraversal(distroRoot).firstMatch(new Predicate<File>() { @Override public boolean apply(File f1) { return f1.isDirectory() && f1.getName().equals("lib"); } }); } @Override public Map<String, Object> getEnvironment(IFile file) { HashMap<String, Object> environment = new HashMap<String, Object>(); BuildConfiguration buildConfig = CorePlugin.configurationManager().loadProjectConfiguration(file.getProject()).getBuildConfiguration(); environment.put(GSK_PROJECT_ROOT, buildConfig.getRootProjectDirectory()); environment.put(GSK_GRADLE_USER_HOME, buildConfig.getWorkspaceConfiguration().getGradleUserHome()); environment.put(GSK_JAVA_HOME, null); environment.put(GSK_OPTIONS, Collections.<String>emptyList()); environment.put(GSK_JVM_OPTIONS, Collections.<String>emptyList()); GradleDistributionWrapper gradleDistribution = GradleDistributionWrapper.from(buildConfig.getGradleDistribution()); switch (gradleDistribution.getType()) { case LOCAL_INSTALLATION: environment.put(GSK_INSTALLATION_LOCAL, new File(gradleDistribution.getConfiguration())); break; case REMOTE_DISTRIBUTION: environment.put(GSK_INSTALLATION_REMOTE, createURI(gradleDistribution.getConfiguration())); break; case VERSION: environment.put(GSK_INSTALLATION_VERSION, gradleDistribution.getConfiguration()); break; default: break; } return environment; } @Override public String getTemplateClassName() { return "org.gradle.script.lang.kotlin.KotlinBuildScript"; } private URI createURI(String uri) { try { return new URI(uri); } catch (URISyntaxException e) { throw new GradlePluginsRuntimeException(e); } } }