| /******************************************************************************* |
| * Copyright (c) 2008, 2011 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 |
| * SAP AG - inject nested class path elements into maven model (TYCHO-483) |
| *******************************************************************************/ |
| package org.eclipse.tycho.core.maven; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.apache.maven.artifact.Artifact; |
| import org.apache.maven.model.Dependency; |
| import org.apache.maven.model.Model; |
| import org.apache.maven.project.MavenProject; |
| import org.codehaus.plexus.logging.Logger; |
| import org.eclipse.tycho.ArtifactDescriptor; |
| import org.eclipse.tycho.ArtifactKey; |
| import org.eclipse.tycho.ArtifactType; |
| import org.eclipse.tycho.PackagingType; |
| import org.eclipse.tycho.ReactorProject; |
| import org.eclipse.tycho.artifacts.DependencyArtifacts; |
| import org.eclipse.tycho.core.osgitools.BundleReader; |
| |
| public final class MavenDependencyInjector { |
| |
| /* see RepositoryLayoutHelper#getP2Gav */ |
| private static final String P2_GROUPID_PREFIX = "p2."; |
| |
| /** |
| * Injects the dependencies of a project (as determined by the p2 dependency resolver) back into |
| * the Maven model. |
| * |
| * @param project |
| * A project |
| * @param dependencies |
| * The p2-resolved dependencies of the project. |
| */ |
| public static void injectMavenDependencies(MavenProject project, DependencyArtifacts dependencies, |
| BundleReader bundleReader, Logger logger) { |
| MavenDependencyInjector generator = new MavenDependencyInjector(project, bundleReader, logger); |
| for (ArtifactDescriptor artifact : dependencies.getArtifacts()) { |
| generator.addDependency(artifact); |
| } |
| } |
| |
| private static final List<Dependency> NO_DEPENDENCIES = Collections.emptyList(); |
| |
| private final BundleReader bundleReader; |
| private final Logger logger; |
| |
| private final MavenProject project; |
| |
| MavenDependencyInjector(MavenProject project, BundleReader bundleReader, Logger logger) { |
| this.project = project; |
| this.bundleReader = bundleReader; |
| this.logger = logger; |
| } |
| |
| void addDependency(ArtifactDescriptor artifact) { |
| List<Dependency> dependencyList = new ArrayList<>(); |
| if (artifact.getMavenProject() != null) { |
| dependencyList.addAll(newProjectDependencies(artifact)); |
| } else { |
| dependencyList.addAll(newExternalDependencies(artifact)); |
| } |
| Model model = project.getModel(); |
| for (Dependency dependency : dependencyList) { |
| model.addDependency(dependency); |
| } |
| } |
| |
| private List<Dependency> newExternalDependencies(ArtifactDescriptor artifact) { |
| File location = artifact.getLocation(); |
| if (!location.isFile() || !location.canRead()) { |
| logger.debug("Dependency at location " + location |
| + " can not be represented in Maven model and will not be visible to non-OSGi aware Maven plugins"); |
| return NO_DEPENDENCIES; |
| } |
| List<Dependency> result = new ArrayList<>(); |
| if (ArtifactType.TYPE_ECLIPSE_PLUGIN.equals(artifact.getKey().getType())) { |
| for (String classpathElement : getClasspathElements(location)) { |
| if (".".equals(classpathElement)) { |
| result.add(createSystemScopeDependency(artifact.getKey(), location)); |
| } else { |
| File nestedJarOrDir = bundleReader.getEntry(location, classpathElement); |
| if (nestedJarOrDir != null) { |
| if (nestedJarOrDir.isFile()) { |
| Dependency nestedJarDependency = createSystemScopeDependency(artifact.getKey(), |
| nestedJarOrDir); |
| nestedJarDependency.setClassifier(classpathElement); |
| result.add(nestedJarDependency); |
| } else if (nestedJarOrDir.isDirectory()) { |
| // system-scoped dependencies on directories are not supported |
| logger.debug("Dependency from " |
| + project.getBasedir() |
| + " to nested directory classpath entry " |
| + nestedJarOrDir |
| + " can not be represented in Maven model and will not be visible to non-OSGi aware Maven plugins"); |
| } |
| } |
| } |
| } |
| } else { |
| result.add(createSystemScopeDependency(artifact.getKey(), location)); |
| } |
| return result; |
| } |
| |
| private String[] getClasspathElements(File bundleLocation) { |
| return bundleReader.loadManifest(bundleLocation).getBundleClasspath(); |
| } |
| |
| private Dependency createSystemScopeDependency(ArtifactKey artifactKey, File location) { |
| return createSystemScopeDependency(artifactKey, P2_GROUPID_PREFIX + artifactKey.getType(), location); |
| } |
| |
| private Dependency createSystemScopeDependency(ArtifactKey artifactKey, String groupId, File location) { |
| Dependency dependency = new Dependency(); |
| dependency.setGroupId(groupId); |
| dependency.setArtifactId(artifactKey.getId()); |
| dependency.setVersion(artifactKey.getVersion()); |
| dependency.setScope(Artifact.SCOPE_SYSTEM); |
| dependency.setSystemPath(location.getAbsolutePath()); |
| return dependency; |
| } |
| |
| private List<Dependency> newProjectDependencies(ArtifactDescriptor artifact) { |
| ReactorProject dependentMavenProjectProxy = artifact.getMavenProject(); |
| List<Dependency> result = new ArrayList<>(); |
| if (!artifact.getMavenProject().sameProject(project)) { |
| result.add(createProvidedScopeDependency(dependentMavenProjectProxy)); |
| } |
| // TODO treat eclipse-test-plugins in the same way? |
| if (PackagingType.TYPE_ECLIPSE_PLUGIN.equals(dependentMavenProjectProxy.getPackaging())) { |
| for (String classpathElement : getClasspathElements(dependentMavenProjectProxy.getBasedir())) { |
| if (".".equals(classpathElement)) { |
| // covered by provided-scope dependency above |
| continue; |
| } else /* nested classpath entry */ |
| { |
| File jar = new File(dependentMavenProjectProxy.getBasedir(), classpathElement); |
| // we can only add a system scope dependency for an existing (checked-in) jar file |
| // otherwise maven will throw a DependencyResolutionException |
| if (jar.isFile()) { |
| Dependency systemScopeDependency = createSystemScopeDependency(artifact.getKey(), artifact |
| .getMavenProject().getGroupId(), jar); |
| systemScopeDependency.setClassifier(classpathElement); |
| result.add(systemScopeDependency); |
| } else { |
| logger.debug("Dependency from " |
| + project.getBasedir() |
| + " to nested classpath entry " |
| + jar.getAbsolutePath() |
| + " can not be represented in Maven model and will not be visible to non-OSGi aware Maven plugins"); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| private Dependency createProvidedScopeDependency(ReactorProject dependentReactorProject) { |
| Dependency dependency = new Dependency(); |
| dependency.setArtifactId(dependentReactorProject.getArtifactId()); |
| dependency.setGroupId(dependentReactorProject.getGroupId()); |
| dependency.setVersion(dependentReactorProject.getVersion()); |
| dependency.setType(dependentReactorProject.getPackaging()); |
| dependency.setScope(Artifact.SCOPE_PROVIDED); |
| return dependency; |
| } |
| } |