blob: 29ffd15124143f90535d9743f716df0a6aaff45c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2012 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
*******************************************************************************/
package org.eclipse.tycho.core.osgitools;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import org.eclipse.tycho.ArtifactDescriptor;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.artifacts.DependencyArtifacts;
import org.eclipse.tycho.core.ArtifactDependencyVisitor;
import org.eclipse.tycho.core.ArtifactDependencyWalker;
import org.eclipse.tycho.core.PluginDescription;
import org.eclipse.tycho.core.resolver.shared.PlatformPropertiesUtils;
import org.eclipse.tycho.core.shared.TargetEnvironment;
import org.eclipse.tycho.model.Feature;
import org.eclipse.tycho.model.FeatureRef;
import org.eclipse.tycho.model.PluginRef;
import org.eclipse.tycho.model.ProductConfiguration;
import org.eclipse.tycho.model.UpdateSite;
public abstract class AbstractArtifactDependencyWalker implements ArtifactDependencyWalker {
private final DependencyArtifacts artifacts;
private final TargetEnvironment[] environments;
public AbstractArtifactDependencyWalker(DependencyArtifacts artifacts) {
this(artifacts, null);
}
public AbstractArtifactDependencyWalker(DependencyArtifacts artifacts, TargetEnvironment[] environments) {
this.artifacts = artifacts;
this.environments = environments;
}
@Override
public void traverseUpdateSite(UpdateSite site, ArtifactDependencyVisitor visitor) {
WalkbackPath visited = new WalkbackPath();
for (FeatureRef ref : site.getFeatures()) {
traverseFeature(ref, visitor, visited);
}
}
@Override
public void traverseFeature(File location, Feature feature, ArtifactDependencyVisitor visitor) {
traverseFeature(location, feature, null, visitor, new WalkbackPath());
}
protected void traverseFeature(File location, Feature feature, FeatureRef featureRef,
ArtifactDependencyVisitor visitor, WalkbackPath visited) {
ArtifactDescriptor artifact = getArtifact(location, feature.getId());
if (artifact == null) {
// ah?
throw new IllegalStateException("Feature " + location + " with id " + feature.getId()
+ " is not part of the project build target platform");
}
ArtifactKey key = artifact.getKey();
ReactorProject project = artifact.getMavenProject();
String classifier = artifact.getClassifier();
Set<Object> installableUnits = artifact.getInstallableUnits();
DefaultFeatureDescription description = new DefaultFeatureDescription(key, location, project, classifier,
feature, featureRef, installableUnits);
if (visitor.visitFeature(description)) {
for (PluginRef ref : feature.getPlugins()) {
traversePlugin(ref, visitor, visited);
}
for (FeatureRef ref : feature.getIncludedFeatures()) {
traverseFeature(ref, visitor, visited);
}
}
}
protected ArtifactDescriptor getArtifact(File location, String id) {
Map<String, ArtifactDescriptor> artifacts = this.artifacts.getArtifact(location);
if (artifacts != null) {
for (ArtifactDescriptor artifact : artifacts.values()) {
if (id.equals(artifact.getKey().getId())) {
return artifact;
}
}
}
return null;
}
@Override
public void traverseProduct(ProductConfiguration product, ArtifactDependencyVisitor visitor) {
traverseProduct(product, visitor, new WalkbackPath());
}
protected void traverseProduct(ProductConfiguration product, ArtifactDependencyVisitor visitor, WalkbackPath visited) {
if (product.useFeatures()) {
for (FeatureRef ref : product.getFeatures()) {
traverseFeature(ref, visitor, visited);
}
} else {
for (PluginRef ref : product.getPlugins()) {
traversePlugin(ref, visitor, visited);
}
}
Set<String> bundles = new HashSet<>();
for (ArtifactDescriptor artifact : visited.getVisited()) {
ArtifactKey key = artifact.getKey();
if (ArtifactType.TYPE_ECLIPSE_PLUGIN.equals(key.getType())) {
bundles.add(key.getId());
}
}
if (environments != null && product.includeLaunchers()) {
for (TargetEnvironment environment : environments) {
String os = environment.getOs();
String ws = environment.getWs();
String arch = environment.getArch();
String id;
// for Mac OS X there is no org.eclipse.equinox.launcher.carbon.macosx.x86 or org.eclipse.equinox.launcher.carbon.macosx.ppc folder,
// only a org.eclipse.equinox.launcher.carbon.macosx folder.
// see http://jira.codehaus.org/browse/MNGECLIPSE-1075
if (PlatformPropertiesUtils.OS_MACOSX.equals(os)
&& (PlatformPropertiesUtils.ARCH_X86.equals(arch) || PlatformPropertiesUtils.ARCH_PPC
.equals(arch))) {
id = "org.eclipse.equinox.launcher." + ws + "." + os;
} else {
id = "org.eclipse.equinox.launcher." + ws + "." + os + "." + arch;
}
if (!bundles.contains(id)) {
PluginRef ref = new PluginRef("plugin");
ref.setId(id);
ref.setOs(os);
ref.setWs(ws);
ref.setArch(arch);
ref.setUnpack(true);
traversePlugin(ref, visitor, visited);
}
}
}
}
protected void traverseFeature(FeatureRef ref, ArtifactDependencyVisitor visitor, WalkbackPath visited) {
ArtifactDescriptor artifact = artifacts.getArtifact(ArtifactType.TYPE_ECLIPSE_FEATURE, ref.getId(),
ref.getVersion());
if (artifact != null) {
if (visited.visited(artifact.getKey())) {
return;
}
visited.enter(artifact);
try {
File location = artifact.getLocation();
Feature feature = Feature.loadFeature(location);
traverseFeature(location, feature, ref, visitor, visited);
} finally {
visited.leave(artifact);
}
} else {
visitor.missingFeature(ref, visited.getWalkback());
}
}
private void traversePlugin(PluginRef ref, ArtifactDependencyVisitor visitor, WalkbackPath visited) {
if (!matchTargetEnvironment(ref)) {
return;
}
ArtifactDescriptor artifact = artifacts.getArtifact(ArtifactType.TYPE_ECLIPSE_PLUGIN, ref.getId(),
ref.getVersion());
if (artifact != null) {
ArtifactKey key = artifact.getKey();
if (visited.visited(key)) {
return;
}
File location = artifact.getLocation();
ReactorProject project = artifact.getMavenProject();
String classifier = artifact.getClassifier();
Set<Object> installableUnits = artifact.getInstallableUnits();
PluginDescription description = new DefaultPluginDescription(key, location, project, classifier, ref,
installableUnits);
visited.enter(description);
try {
visitor.visitPlugin(description);
} finally {
visited.leave(description);
}
} else {
visitor.missingPlugin(ref, visited.getWalkback());
}
}
private boolean matchTargetEnvironment(PluginRef pluginRef) {
String pluginOs = pluginRef.getOs();
String pluginWs = pluginRef.getWs();
String pluginArch = pluginRef.getArch();
if (environments == null) {
// match all environments be default
return true;
// no target environments, only include environment independent plugins
// return pluginOs == null && pluginWs == null && pluginArch == null;
}
for (TargetEnvironment environment : environments) {
if (environment.match(pluginOs, pluginWs, pluginArch)) {
return true;
}
}
return false;
}
protected static class WalkbackPath {
private Map<ArtifactKey, ArtifactDescriptor> visited = new HashMap<>();
private Stack<ArtifactDescriptor> walkback = new Stack<>();
boolean visited(ArtifactKey key) {
return visited.containsKey(key);
}
public List<ArtifactDescriptor> getWalkback() {
return new ArrayList<>(walkback);
}
void enter(ArtifactDescriptor artifact) {
visited.put(artifact.getKey(), artifact);
walkback.push(artifact);
}
void leave(ArtifactDescriptor artifact) {
walkback.pop();
}
Collection<ArtifactDescriptor> getVisited() {
return visited.values();
}
}
}