blob: 859728d4eec15626dde469d9d2365e59a9f966e3 [file] [log] [blame]
/**
* Copyright (c) 2015 Montages AG
*
* 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
*
* Inspired by org.eclipse.tycho.surefire.TestMojo
*/
package org.eclipse.gmf.tooling.codegen.maven;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
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.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
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.apache.maven.toolchain.ToolchainManager;
import org.eclipse.gmf.tooling.codegen.launcher.GMFLauncherConstants;
import org.eclipse.sisu.equinox.launching.BundleStartLevel;
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.ArtifactDescriptor;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.artifacts.DependencyArtifacts;
import org.eclipse.tycho.core.DependencyResolver;
import org.eclipse.tycho.core.DependencyResolverConfiguration;
import org.eclipse.tycho.core.TargetPlatformConfiguration;
import org.eclipse.tycho.core.TychoConstants;
import org.eclipse.tycho.core.maven.ToolchainProvider;
import org.eclipse.tycho.core.maven.ToolchainProvider.JDKUsage;
import org.eclipse.tycho.core.osgitools.DefaultReactorProject;
import org.eclipse.tycho.core.resolver.DefaultDependencyResolverFactory;
import org.eclipse.tycho.core.resolver.shared.OptionalResolutionAction;
import org.eclipse.tycho.core.resolver.shared.PlatformPropertiesUtils;
import org.eclipse.tycho.core.utils.TychoProjectUtils;
@Mojo(name = "generate", defaultPhase=LifecyclePhase.GENERATE_SOURCES, requiresProject=true)
public class MavenGenerator extends AbstractMojo {
public static final String SEPARATOR = File.separator;
@Parameter(property = "session", readonly = true, required = true)
private MavenSession session;
@Parameter(defaultValue = "SYSTEM")
private JDKUsage useJDK;
@Parameter
private BundleStartLevel defaultStartLevel;
@Parameter(required = true)
private String gmfgen;
@Parameter(defaultValue = "${basedir}")
private String output;
@Parameter
private File[] relatedProjects;
@Parameter
private File formatter;
@Parameter
private String customEmitter;
@Parameter
private String customEmitterBundle;
@Parameter(property = "project", readonly = true)
private MavenProject project;
@Parameter(defaultValue = "${basedir}/../target/work")
private File work;
@Parameter(defaultValue = "${basedir}/../target/osgi/")
private File osgiDataDirectory;
@Component
private ToolchainManager toolchainManager;
@Component
private ToolchainProvider toolchainProvider;
@Component
private EquinoxInstallationFactory installationFactory;
@Component
private DefaultDependencyResolverFactory dependencyResolverLocator;
@Parameter
private Dependency[] dependencies;
@Component
private EquinoxLauncher launcher;
public void execute() throws MojoExecutionException {
checkOverlapPath(work, project.getBasedir(), "Work dir", "Project dir");
checkOverlapPath(osgiDataDirectory, project.getBasedir(), "OSGi dir", "Project dir");
checkOverlapPath(work, output, "Work dir", "Path to generated plugin");
checkOverlapPath(osgiDataDirectory, output, "OSGi dir", "Path to generated plugin");
EquinoxInstallation gmfGenerationInstallation = createGMFGenerationIntallation();
EquinoxLaunchConfiguration cli = new EquinoxLaunchConfiguration(gmfGenerationInstallation);
String executable = null;
Toolchain tc = getToolchain();
if (tc != null) {
executable = tc.findTool("java");
}
cli.setJvmExecutable(executable);
cli.setWorkingDirectory(project.getBasedir());
Properties properties = (Properties) project.getContextValue(TychoConstants.CTX_MERGED_PROPERTIES);
cli.addVMArguments("-Dosgi.os=" + PlatformPropertiesUtils.getOS(properties), //
"-Dosgi.ws=" + PlatformPropertiesUtils.getWS(properties), //
"-Dosgi.arch=" + PlatformPropertiesUtils.getArch(properties));
cli.addProgramArguments("-data", osgiDataDirectory.getAbsolutePath(), //
"-install", gmfGenerationInstallation.getLocation().getAbsolutePath(), //
"-application", "org.eclipse.gmf.tooling.codegen.launcher.GMFGenerateApplication",
"-configuration", gmfGenerationInstallation.getConfigurationLocation().getAbsolutePath());
String workDirPath = work.getAbsolutePath();
StringBuilder tempFile = new StringBuilder(workDirPath);
if (!workDirPath.endsWith(SEPARATOR)) {
tempFile.append(SEPARATOR);
}
tempFile.append("gmflauncher.properties");
String tempFilePath = tempFile.toString();
prepareGeneratePropertyFile(tempFilePath);
cli.addProgramArguments(GMFLauncherConstants.KEY_GENERATION_PROPERTIES, tempFilePath);
int result = launcher.execute(cli, 0);
if (result != 0) {
throw new MojoExecutionException("Generation error");
}
}
protected Toolchain getToolchain() throws MojoExecutionException {
if (JDKUsage.SYSTEM.equals(useJDK)) {
if (toolchainManager != null) {
return toolchainManager.getToolchainFromBuildContext("jdk", session);
}
return null;
}
String profileName = TychoProjectUtils.getExecutionEnvironmentConfiguration(project).getProfileName();
Toolchain toolChain = toolchainProvider.findMatchingJavaToolChain(session, profileName);
if (toolChain == null) {
throw new MojoExecutionException("useJDK = BREE configured, but no toolchain of type 'jdk' with id '"
+ profileName + "' found. See http://maven.apache.org/guides/mini/guide-using-toolchains.html");
}
return toolChain;
}
EquinoxInstallation createGMFGenerationIntallation() throws MojoExecutionException {
DependencyResolver platformResolver = dependencyResolverLocator.lookupDependencyResolver(project);
final List<Dependency> extraDependencies = getExtraDependencies();
List<ReactorProject> reactorProjects = getReactorProjects();
final DependencyResolverConfiguration resolverConfiguration = new DependencyResolverConfiguration() {
@Override
public OptionalResolutionAction getOptionalResolutionAction() {
return OptionalResolutionAction.IGNORE;
}
@Override
public List<Dependency> getExtraRequirements() {
return extraDependencies;
}
};
DependencyArtifacts generateRuntimeArtifacts = platformResolver.resolveDependencies(session, project, null,
reactorProjects, resolverConfiguration);
if (generateRuntimeArtifacts == null) {
throw new MojoExecutionException("Cannot determinate build target platform location -- code not generated");
}
work.mkdirs();
EquinoxInstallationDescription generateAppDescr = new DefaultEquinoxInstallationDescription();
generateAppDescr.setDefaultBundleStartLevel(defaultStartLevel);
generateAppDescr.addBundlesToExplode(new LinkedList<String>());
generateAppDescr.addFrameworkExtensions(new LinkedList<File>());
for (ArtifactDescriptor artifact : generateRuntimeArtifacts.getArtifacts(ArtifactType.TYPE_ECLIPSE_PLUGIN)) {
ReactorProject otherProject = artifact.getMavenProject();
if (otherProject != null) {
if (otherProject.sameProject(project)) {
generateAppDescr.addBundle(artifact.getKey(), project.getBasedir());
continue;
}
File file = otherProject.getArtifact(artifact.getClassifier());
if (file != null) {
generateAppDescr.addBundle(artifact.getKey(), file);
continue;
}
}
generateAppDescr.addBundle(artifact);
}
return installationFactory.createInstallation(generateAppDescr, work);
}
private List<Dependency> getExtraDependencies() {
final List<Dependency> dependencies = new ArrayList<Dependency>();
if (this.dependencies != null) {
dependencies.addAll(Arrays.asList(this.dependencies));
}
TargetPlatformConfiguration configuration = TychoProjectUtils.getTargetPlatformConfiguration(project);
dependencies.addAll(configuration.getDependencyResolverConfiguration().getExtraRequirements());
dependencies.add(newBundleDependency("org.eclipse.osgi"));
dependencies.add(newBundleDependency(EquinoxInstallationDescription.EQUINOX_LAUNCHER));
dependencies.add(newBundleDependency("org.eclipse.core.runtime"));
dependencies.add(newBundleDependency("org.eclipse.gmf.tooling.codegen.launcher"));
return dependencies;
}
protected Dependency newBundleDependency(String bundleId) {
Dependency ideapp = new Dependency();
ideapp.setArtifactId(bundleId);
ideapp.setType(ArtifactType.TYPE_ECLIPSE_PLUGIN);
return ideapp;
}
private List<ReactorProject> getReactorProjects() {
return DefaultReactorProject.adapt(session);
}
private void checkOverlapPath(File containerDir, File overlapDir, String containerName, String overlapDirName) throws MojoExecutionException {
checkOverlapPath(containerDir, overlapDir.getAbsolutePath(), containerName, overlapDirName);
}
private void checkOverlapPath(File containerDir, String overlapDirPath, String containerName, String overlapDirName) throws MojoExecutionException {
String containerDirPath = containerDir.getAbsolutePath();
if (containerDirPath.startsWith(overlapDirPath)) {
throw new MojoExecutionException(containerDir + ":" + containerDir + " cannot be located in:" + overlapDirName +":"+ overlapDirPath);
}
}
public void prepareGeneratePropertyFile(String tempFile) throws MojoExecutionException {
Properties prop = new Properties();
OutputStream outputStrem = null;
try {
File outputFile = new File(tempFile);
outputStrem = new FileOutputStream(outputFile);
// set the properties value
prop.setProperty(GMFLauncherConstants.PROPERTY_GMFGEN_MODEL, gmfgen);
prop.setProperty(GMFLauncherConstants.PROPERTY_GENERATE_PROJECT_LOCATION, output);
prop.setProperty(GMFLauncherConstants.PROPERTY_GMFGEN_PROJECT_LOCATION, project.getBasedir().getAbsolutePath());
if (relatedProjects != null && relatedProjects.length > 0) {
StringBuilder sb = new StringBuilder(relatedProjects[0].getAbsolutePath());
for (int i = 1; i < relatedProjects.length; i++) {
sb.append(',');
sb.append(relatedProjects[i].getAbsolutePath());
}
prop.setProperty(GMFLauncherConstants.PROPERTY_RELATED_PROJECTS, sb.toString());
}
if (formatter.exists()) {
prop.setProperty(GMFLauncherConstants.PROPERTY_FORMATTER, formatter.getAbsolutePath());
}
if (customEmitterBundle != null && !customEmitterBundle.isEmpty()
&& customEmitter != null && !customEmitter.isEmpty()) {
prop.setProperty(GMFLauncherConstants.PROPERTY_CUSTOM_EMITTER, customEmitter);
prop.setProperty(GMFLauncherConstants.PROPERTY_CUSTOM_EMITTER_BUNDLE, customEmitterBundle);
}
prop.setProperty(GMFLauncherConstants.PROPERTY_TRACE, new Boolean(getLog().isDebugEnabled()).toString());
prop.store(outputStrem, null);
} catch (FileNotFoundException e) {
throw new MojoExecutionException(e.getMessage());
} catch (IOException e) {
throw new MojoExecutionException(e.getMessage());
} finally {
if (outputStrem != null) {
try {
outputStrem.close();
} catch (IOException e) {
throw new MojoExecutionException(e.getMessage());
}
}
}
}
}