blob: 3cba46624feaf77136954946af59d0d10cd31430 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2015 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
* Bachmann electronic GmbH - Bug 457314 - handle null as tycho version
*******************************************************************************/
package org.eclipse.tycho.core.maven;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.MavenExecutionException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Plugin;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.core.osgitools.BundleReader;
import org.eclipse.tycho.core.osgitools.DefaultBundleReader;
import org.eclipse.tycho.core.osgitools.DefaultReactorProject;
import org.eclipse.tycho.core.shared.BuildFailureException;
import org.eclipse.tycho.core.utils.TychoVersion;
import org.eclipse.tycho.resolver.TychoResolver;
@Component(role = AbstractMavenLifecycleParticipant.class, hint = "TychoMavenLifecycleListener")
public class TychoMavenLifecycleParticipant extends AbstractMavenLifecycleParticipant {
private static final String TYCHO_GROUPID = "org.eclipse.tycho";
private static final Set<String> TYCHO_PLUGIN_IDS = new HashSet<>(Arrays.asList("tycho-maven-plugin",
"tycho-p2-director-plugin", "tycho-p2-plugin", "tycho-p2-publisher-plugin", "tycho-p2-repository-plugin",
"tycho-packaging-plugin", "tycho-pomgenerator-plugin", "tycho-source-plugin", "tycho-surefire-plugin",
"tycho-versions-plugin", "tycho-compiler-plugin"));
private static final String P2_USER_AGENT_KEY = "p2.userAgent";
private static final String P2_USER_AGENT_VALUE = "tycho/";
@Requirement
private BundleReader bundleReader;
@Requirement
private TychoResolver resolver;
@Requirement
private PlexusContainer plexus;
@Requirement
private Logger log;
public TychoMavenLifecycleParticipant() {
// needed for plexus
}
// needed for unit tests
protected TychoMavenLifecycleParticipant(Logger log) {
this.log = log;
}
@Override
public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
try {
if (disableLifecycleParticipation(session)) {
return;
}
List<MavenProject> projects = session.getProjects();
validate(projects);
// setting this system property to let EF figure out where the traffic
// is coming from (#467418)
System.setProperty(P2_USER_AGENT_KEY, P2_USER_AGENT_VALUE + TychoVersion.getTychoVersion());
configureComponents(session);
for (MavenProject project : projects) {
resolver.setupProject(session, project, DefaultReactorProject.adapt(project));
}
List<ReactorProject> reactorProjects = DefaultReactorProject.adapt(session);
for (MavenProject project : projects) {
resolver.resolveProject(session, project, reactorProjects);
}
} catch (BuildFailureException e) {
// build failure is not an internal (unexpected) error, so avoid printing a stack
// trace by wrapping it in MavenExecutionException
throw new MavenExecutionException(e.getMessage(), e);
}
}
private void validate(List<MavenProject> projects) throws MavenExecutionException {
validateConsistentTychoVersion(projects);
validateUniqueBaseDirs(projects);
}
protected void validateConsistentTychoVersion(List<MavenProject> projects) throws MavenExecutionException {
Map<String, Set<MavenProject>> versionToProjectsMap = new HashMap<>();
for (MavenProject project : projects) {
for (Plugin plugin : project.getBuild().getPlugins()) {
if (TYCHO_GROUPID.equals(plugin.getGroupId()) && TYCHO_PLUGIN_IDS.contains(plugin.getArtifactId())) {
String version = plugin.getVersion();
// Skip checking plug ins that do not have a version
if (version == null) {
continue;
}
log.debug(TYCHO_GROUPID + ":" + plugin.getArtifactId() + ":" + version + " configured in "
+ project);
Set<MavenProject> projectSet = versionToProjectsMap.get(version);
if (projectSet == null) {
projectSet = new LinkedHashSet<>();
versionToProjectsMap.put(version, projectSet);
}
projectSet.add(project);
}
}
}
if (versionToProjectsMap.size() > 1) {
List<String> versions = new ArrayList<>(versionToProjectsMap.keySet());
Collections.sort(versions);
log.error("Several versions of tycho plugins are configured " + versions + ":");
for (String version : versions) {
log.error(version + ":");
for (MavenProject project : versionToProjectsMap.get(version)) {
log.error("\t" + project.toString());
}
}
throw new MavenExecutionException("All tycho plugins configured in one reactor must use the same version",
projects.get(0).getFile());
}
}
private void validateUniqueBaseDirs(List<MavenProject> projects) throws MavenExecutionException {
// we store intermediate build results in the target/ folder and use the baseDir as unique key
// so multiple modules in the same baseDir would lead to irreproducible/unexpected results
// e.g. with mvn clean. This should really not be supported by maven core
Set<File> baseDirs = new HashSet<>();
for (MavenProject project : projects) {
File basedir = project.getBasedir();
if (baseDirs.contains(basedir)) {
throw new MavenExecutionException("Multiple modules within the same basedir are not supported: "
+ basedir, project.getFile());
} else {
baseDirs.add(basedir);
}
}
}
private boolean disableLifecycleParticipation(MavenSession session) {
// command line property to disable Tycho lifecycle participant
if ("maven".equals(session.getUserProperties().get("tycho.mode"))) {
return true;
}
if (session.getUserProperties().containsKey("m2e.version")) {
return true;
}
return false;
}
private void configureComponents(MavenSession session) {
// TODO why does the bundle reader need to cache stuff in the local maven repository?
File localRepository = new File(session.getLocalRepository().getBasedir());
((DefaultBundleReader) bundleReader).setLocationRepository(localRepository);
}
}