blob: b93e6517fe70b565ebb7030cb47d23e287f30cee [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2016 Sonatype Inc. and others.
* 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
*
* Contributors:
* Sonatype Inc. - initial API and implementation
* Marc-Andre Laperle - EclipseRunMojo inspired by TestMojo
*******************************************************************************/
package org.eclipse.tycho.extras.eclipserun;
import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.toolchain.Toolchain;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.eclipse.sisu.equinox.EquinoxServiceFactory;
import org.eclipse.sisu.equinox.launching.DefaultEquinoxInstallationDescription;
import org.eclipse.sisu.equinox.launching.EquinoxInstallation;
import org.eclipse.sisu.equinox.launching.EquinoxInstallationDescription;
import org.eclipse.sisu.equinox.launching.EquinoxInstallationFactory;
import org.eclipse.sisu.equinox.launching.EquinoxLauncher;
import org.eclipse.sisu.equinox.launching.internal.EquinoxLaunchConfiguration;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.DefaultArtifactKey;
import org.eclipse.tycho.artifacts.IllegalArtifactReferenceException;
import org.eclipse.tycho.artifacts.TargetPlatform;
import org.eclipse.tycho.core.ee.shared.ExecutionEnvironmentConfigurationStub;
import org.eclipse.tycho.core.maven.ToolchainProvider;
import org.eclipse.tycho.core.resolver.shared.MavenRepositoryLocation;
import org.eclipse.tycho.launching.LaunchConfiguration;
import org.eclipse.tycho.osgi.adapters.MavenLoggerAdapter;
import org.eclipse.tycho.p2.resolver.facade.P2ResolutionResult;
import org.eclipse.tycho.p2.resolver.facade.P2ResolutionResult.Entry;
import org.eclipse.tycho.p2.resolver.facade.P2Resolver;
import org.eclipse.tycho.p2.resolver.facade.P2ResolverFactory;
import org.eclipse.tycho.p2.target.facade.TargetPlatformConfigurationStub;
import org.eclipse.tycho.plugins.p2.extras.Repository;
/**
* Launch an eclipse process with arbitrary commandline arguments. The eclipse installation is
* defined by the dependencies to bundles specified.
*/
@Mojo(name = "eclipse-run")
public class EclipseRunMojo extends AbstractMojo {
@Parameter(defaultValue = "${project.build.directory}/eclipserun-work")
private File work;
@Parameter(property = "project")
private MavenProject project;
/**
* Dependencies which will be resolved transitively to make up the eclipse runtime. Example:
*
* <pre>
* &lt;dependencies&gt;
* &lt;dependency&gt;
* &lt;artifactId&gt;org.eclipse.ant.core&lt;/artifactId&gt;
* &lt;type&gt;eclipse-plugin&lt;/type&gt;
* &lt;/dependency&gt;
* &lt;/dependencies&gt;
* </pre>
*/
@Parameter
private List<Dependency> dependencies = new ArrayList<>();
/**
* Whether to add default dependencies to bundles org.eclipse.equinox.launcher, org.eclipse.osgi
* and org.eclipse.core.runtime.
*/
@Parameter(defaultValue = "true")
private boolean addDefaultDependencies;
/**
* Execution environment profile name used to resolve dependencies.
*/
@Parameter(defaultValue = "JavaSE-1.7")
private String executionEnvironment;
/**
* p2 repositories which will be used to resolve dependencies. Example:
*
* <pre>
* &lt;repositories&gt;
* &lt;repository&gt;
* &lt;id&gt;juno&lt;/id&gt;
* &lt;layout&gt;p2&lt;/layout&gt;
* &lt;url&gt;http://download.eclipse.org/releases/juno&lt;/url&gt;
* &lt;/repository&gt;
* &lt;/repositories&gt;
* </pre>
*/
@Parameter(required = true)
private List<Repository> repositories;
@Parameter(property = "session", readonly = true, required = true)
private MavenSession session;
/**
* Arbitrary JVM options to set on the command line.
*
* @deprecated use {@link #jvmArgs} instead.
*/
@Parameter
private String argLine;
/**
* List of JVM arguments set on the command line. Example:
*
* <pre>
* &lt;jvmArgs&gt;
* &lt;args&gt;-Xdebug&lt;/args&gt;
* &lt;args&gt;-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044&lt;/args&gt;
* &lt;/jvmArgs&gt;
* </pre>
*
* @since 0.25.0
*/
@Parameter
private List<String> jvmArgs;
/**
* Whether to skip mojo execution.
*/
@Parameter(property = "eclipserun.skip", defaultValue = "false")
private boolean skip;
/**
* Arbitrary applications arguments to set on the command line.
*
* @deprecated use {@link #applicationsArgs} instead.
*/
@Parameter
private String appArgLine;
/**
* List of applications arguments set on the command line. Example:
*
* <pre>
* &lt;applicationsArgs&gt;
* &lt;args&gt;-buildfile&lt;/args&gt;
* &lt;args&gt;build-test.xml&lt;/args&gt;
* &lt;/applicationsArgs&gt;
* </pre>
*
* @since 0.24.0
*/
@Parameter
private List<String> applicationsArgs;
/**
* Kill the forked process after a certain number of seconds. If set to 0, wait forever for the
* process, never timing out.
*/
@Parameter(property = "eclipserun.timeout")
private int forkedProcessTimeoutInSeconds;
/**
* Additional environments to set for the forked JVM.
*/
@Parameter
private Map<String, String> environmentVariables;
@Component
private EquinoxInstallationFactory installationFactory;
@Component
private EquinoxLauncher launcher;
@Component
private ToolchainProvider toolchainProvider;
@Component
private EquinoxServiceFactory equinox;
@Component
private Logger logger;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (skip) {
getLog().debug("skipping mojo execution");
return;
}
EquinoxInstallation installation = createEclipseInstallation();
runEclipse(installation);
}
private void addDefaultDependency(P2Resolver resolver, String bundleId) {
try {
resolver.addDependency(ArtifactType.TYPE_ECLIPSE_PLUGIN, bundleId, null);
} catch (IllegalArtifactReferenceException e) {
// shouldn't happen for the constant type and version
throw new RuntimeException(e);
}
}
private void addDefaultDependencies(P2Resolver resolver) {
if (addDefaultDependencies) {
addDefaultDependency(resolver, "org.eclipse.osgi");
addDefaultDependency(resolver, EquinoxInstallationDescription.EQUINOX_LAUNCHER);
addDefaultDependency(resolver, "org.eclipse.core.runtime");
}
}
private EquinoxInstallation createEclipseInstallation() throws MojoFailureException {
P2ResolverFactory resolverFactory = equinox.getService(P2ResolverFactory.class);
TargetPlatformConfigurationStub tpConfiguration = new TargetPlatformConfigurationStub();
// we want to resolve from remote repos only
tpConfiguration.setForceIgnoreLocalArtifacts(true);
for (Repository repository : repositories) {
tpConfiguration.addP2Repository(new MavenRepositoryLocation(repository.getId(), repository.getLocation()));
}
TargetPlatform targetPlatform = resolverFactory.getTargetPlatformFactory().createTargetPlatform(tpConfiguration,
new ExecutionEnvironmentConfigurationStub(executionEnvironment), null, null);
P2Resolver resolver = resolverFactory.createResolver(new MavenLoggerAdapter(logger, false));
for (Dependency dependency : dependencies) {
try {
resolver.addDependency(dependency.getType(), dependency.getArtifactId(), dependency.getVersion());
} catch (IllegalArtifactReferenceException e) {
throw new MojoFailureException("Invalid dependency " + dependency.getType() + ":"
+ dependency.getArtifactId() + ":" + dependency.getVersion() + ": " + e.getMessage(), e);
}
}
addDefaultDependencies(resolver);
EquinoxInstallationDescription installationDesc = new DefaultEquinoxInstallationDescription();
for (P2ResolutionResult result : resolver.resolveDependencies(targetPlatform, null)) {
for (Entry entry : result.getArtifacts()) {
if (ArtifactType.TYPE_ECLIPSE_PLUGIN.equals(entry.getType())) {
installationDesc.addBundle(
new DefaultArtifactKey(ArtifactType.TYPE_ECLIPSE_PLUGIN, entry.getId(), entry.getVersion()),
entry.getLocation());
}
}
}
return installationFactory.createInstallation(installationDesc, work);
}
private void runEclipse(EquinoxInstallation runtime) throws MojoExecutionException, MojoFailureException {
try {
File workspace = new File(work, "data").getAbsoluteFile();
FileUtils.deleteDirectory(workspace);
LaunchConfiguration cli = createCommandLine(runtime);
getLog().info("Expected eclipse log file: " + new File(workspace, ".metadata/.log").getCanonicalPath());
int returnCode = launcher.execute(cli, forkedProcessTimeoutInSeconds);
if (returnCode != 0) {
throw new MojoExecutionException("Error while executing platform (return code: " + returnCode + ")");
}
} catch (Exception e) {
throw new MojoExecutionException("Error while executing platform", e);
}
}
LaunchConfiguration createCommandLine(EquinoxInstallation runtime)
throws MalformedURLException, MojoExecutionException {
EquinoxLaunchConfiguration cli = new EquinoxLaunchConfiguration(runtime);
String executable = null;
Toolchain tc = getToolchain();
if (tc != null) {
getLog().info("Toolchain in tycho-eclipserun-plugin: " + tc);
executable = tc.findTool("java");
}
cli.setJvmExecutable(executable);
cli.setWorkingDirectory(project.getBasedir());
cli.addVMArguments(splitArgLine(argLine));
if (jvmArgs != null) {
cli.addVMArguments(jvmArgs.toArray(new String[jvmArgs.size()]));
}
addProgramArgs(cli, "-install", runtime.getLocation().getAbsolutePath(), "-configuration",
new File(work, "configuration").getAbsolutePath());
cli.addProgramArguments(splitArgLine(appArgLine));
if (applicationsArgs != null) {
for (String args : applicationsArgs) {
cli.addProgramArguments(splitArgLine(args));
}
}
if (environmentVariables != null) {
cli.addEnvironmentVariables(environmentVariables);
}
return cli;
}
private String[] splitArgLine(String argumentLine) throws MojoExecutionException {
try {
return CommandLineUtils.translateCommandline(argumentLine);
} catch (Exception e) {
throw new MojoExecutionException("Error parsing commandline: " + e.getMessage(), e);
}
}
private void addProgramArgs(EquinoxLaunchConfiguration cli, String... arguments) {
if (arguments != null) {
for (String argument : arguments) {
if (argument != null) {
cli.addProgramArguments(argument);
}
}
}
}
private Toolchain getToolchain() throws MojoExecutionException {
return toolchainProvider.findMatchingJavaToolChain(session, executionEnvironment);
}
}