Package org.eclipse.tycho.p2.resolver

Source Code of org.eclipse.tycho.p2.resolver.P2TargetPlatformResolver

/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.tycho.p2.resolver;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.maven.ProjectDependenciesResolver;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.Authentication;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.Server;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.core.TargetEnvironment;
import org.eclipse.tycho.core.TargetPlatform;
import org.eclipse.tycho.core.TargetPlatformConfiguration;
import org.eclipse.tycho.core.TargetPlatformResolver;
import org.eclipse.tycho.core.TychoConstants;
import org.eclipse.tycho.core.facade.MavenLogger;
import org.eclipse.tycho.core.maven.MavenDependencyInjector;
import org.eclipse.tycho.core.osgitools.AbstractTychoProject;
import org.eclipse.tycho.core.osgitools.BundleReader;
import org.eclipse.tycho.core.osgitools.DebugUtils;
import org.eclipse.tycho.core.osgitools.DefaultArtifactKey;
import org.eclipse.tycho.core.osgitools.targetplatform.AbstractTargetPlatformResolver;
import org.eclipse.tycho.core.osgitools.targetplatform.DefaultTargetPlatform;
import org.eclipse.tycho.core.osgitools.targetplatform.MultiEnvironmentTargetPlatform;
import org.eclipse.tycho.core.p2.P2ArtifactRepositoryLayout;
import org.eclipse.tycho.core.utils.ExecutionEnvironmentUtils;
import org.eclipse.tycho.core.utils.PlatformPropertiesUtils;
import org.eclipse.tycho.equinox.EquinoxServiceFactory;
import org.eclipse.tycho.osgi.adapters.MavenLoggerAdapter;
import org.eclipse.tycho.p2.facade.internal.ReactorArtifactFacade;
import org.eclipse.tycho.p2.metadata.DependencyMetadataGenerator;
import org.eclipse.tycho.p2.resolver.facade.P2ResolutionResult;
import org.eclipse.tycho.p2.resolver.facade.P2Resolver;
import org.eclipse.tycho.p2.resolver.facade.P2ResolverFactory;
import org.eclipse.tycho.p2.resolver.facade.ResolutionContext;
import org.eclipse.tycho.p2.target.facade.TargetDefinition;
import org.eclipse.tycho.p2.target.facade.TargetDefinition.InstallableUnitLocation;
import org.eclipse.tycho.p2.target.facade.TargetDefinition.Location;
import org.eclipse.tycho.p2.target.facade.TargetDefinitionResolutionException;
import org.eclipse.tycho.p2.target.facade.TargetDefinitionSyntaxException;

@Component(role = TargetPlatformResolver.class, hint = P2TargetPlatformResolver.ROLE_HINT, instantiationStrategy = "per-lookup")
public class P2TargetPlatformResolver extends AbstractTargetPlatformResolver implements TargetPlatformResolver,
        Initializable {

    public static final String ROLE_HINT = "p2";

    @Requirement
    private EquinoxServiceFactory equinox;

    @Requirement
    private BundleReader bundleReader;

    @Requirement
    private RepositorySystem repositorySystem;

    @Requirement(hint = "p2")
    private ArtifactRepositoryLayout p2layout;

    @Requirement
    private ProjectDependenciesResolver projectDependenciesResolver;

    private P2ResolverFactory resolverFactory;

    private DependencyMetadataGenerator generator;

    private DependencyMetadataGenerator sourcesGenerator;

    private static final ArtifactRepositoryPolicy P2_REPOSITORY_POLICY = new ArtifactRepositoryPolicy(true,
            ArtifactRepositoryPolicy.UPDATE_POLICY_NEVER, ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);

    public void setupProjects(MavenSession session, MavenProject project, ReactorProject reactorProject) {
        TargetPlatformConfiguration configuration = (TargetPlatformConfiguration) project
                .getContextValue(TychoConstants.CTX_TARGET_PLATFORM_CONFIGURATION);
        List<Map<String, String>> environments = getEnvironments(configuration);
        Set<Object> metadata = generator
                .generateMetadata(new ReactorArtifactFacade(reactorProject, null), environments);
        reactorProject.setDependencyMetadata(null, metadata);

        // TODO this should be moved to osgi-sources-plugin somehow
        if (isBundleProject(project) && hasSourceBundle(project)) {
            ReactorArtifactFacade sourcesArtifact = new ReactorArtifactFacade(reactorProject, "sources");
            Set<Object> sourcesMetadata = sourcesGenerator.generateMetadata(sourcesArtifact, environments);
            reactorProject.setDependencyMetadata(sourcesArtifact.getClassidier(), sourcesMetadata);
        }
    }

    private static boolean isBundleProject(MavenProject project) {
        String type = project.getPackaging();
        return ArtifactKey.TYPE_ECLIPSE_PLUGIN.equals(type) || ArtifactKey.TYPE_ECLIPSE_TEST_PLUGIN.equals(type);
    }

    private static boolean hasSourceBundle(MavenProject project) {
        // TODO this is a fragile way of checking whether we generate a source bundle
        // should we rather use MavenSession to get the actual configured mojo instance?
        for (Plugin plugin : project.getBuildPlugins()) {
            if ("org.eclipse.tycho:tycho-source-plugin".equals(plugin.getKey())) {
                return true;
            }
        }
        return false;
    }

    public TargetPlatform resolvePlatform(final MavenSession session, final MavenProject project,
            List<ReactorProject> reactorProjects, List<Dependency> dependencies) {

        MavenLogger loggerForOsgiImpl = new MavenLoggerAdapter(getLogger(), DebugUtils.isDebugEnabled(session, project));

        File localRepositoryRoot = new File(session.getLocalRepository().getBasedir());

        TargetPlatformConfiguration configuration = (TargetPlatformConfiguration) project
                .getContextValue(TychoConstants.CTX_TARGET_PLATFORM_CONFIGURATION);

        ResolutionContext resolutionContext = resolverFactory.createResolutionContext(localRepositoryRoot,
                session.isOffline(), configuration.isDisableP2Mirrors(), loggerForOsgiImpl);

        P2Resolver osgiResolverImpl = resolverFactory.createResolver(loggerForOsgiImpl);

        try {
            return doResolvePlatform(session, project, reactorProjects, dependencies, resolutionContext,
                    osgiResolverImpl, configuration);
        } finally {
            resolutionContext.stop();
        }
    }

    protected TargetPlatform doResolvePlatform(final MavenSession session, final MavenProject project,
            List<ReactorProject> reactorProjects, List<Dependency> dependencies, ResolutionContext resolutionContext,
            P2Resolver resolver, TargetPlatformConfiguration configuration) {

        Map<File, ReactorProject> projects = new HashMap<File, ReactorProject>();

        resolver.setEnvironments(getEnvironments(configuration));

        for (ReactorProject otherProject : reactorProjects) {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("P2resolver.addMavenProject " + otherProject.getId());
            }
            projects.put(otherProject.getBasedir(), otherProject);
            resolutionContext.addReactorArtifact(new ReactorArtifactFacade(otherProject, null));

            Map<String, Set<Object>> dependencyMetadata = otherProject.getDependencyMetadata();
            if (dependencyMetadata != null) {
                for (String classifier : dependencyMetadata.keySet()) {
                    resolutionContext.addReactorArtifact(new ReactorArtifactFacade(otherProject, classifier));
                }
            }
        }

        if (dependencies != null) {
            for (Dependency dependency : dependencies) {
                resolver.addDependency(dependency.getType(), dependency.getArtifactId(), dependency.getVersion());
            }
        }

        if (TargetPlatformConfiguration.POM_DEPENDENCIES_CONSIDER.equals(configuration.getPomDependencies())) {
            Set<String> projectIds = new HashSet<String>();
            for (ReactorProject p : reactorProjects) {
                String key = ArtifactUtils.key(p.getGroupId(), p.getArtifactId(), p.getVersion());
                projectIds.add(key);
            }

            ArrayList<String> scopes = new ArrayList<String>();
            scopes.add(Artifact.SCOPE_COMPILE);
            Collection<Artifact> artifacts;
            try {
                artifacts = projectDependenciesResolver.resolve(project, scopes, session);
            } catch (MultipleArtifactsNotFoundException e) {
                Collection<Artifact> missing = new HashSet<Artifact>(e.getMissingArtifacts());

                for (Iterator<Artifact> it = missing.iterator(); it.hasNext();) {
                    Artifact a = it.next();
                    String key = ArtifactUtils.key(a.getGroupId(), a.getArtifactId(), a.getBaseVersion());
                    if (projectIds.contains(key)) {
                        it.remove();
                    }
                }

                if (!missing.isEmpty()) {
                    throw new RuntimeException("Could not resolve project dependencies", e);
                }

                artifacts = e.getResolvedArtifacts();
                artifacts.removeAll(e.getMissingArtifacts());
            } catch (AbstractArtifactResolutionException e) {
                throw new RuntimeException("Could not resolve project dependencies", e);
            }
            List<Artifact> externalArtifacts = new ArrayList<Artifact>(artifacts.size());
            for (Artifact artifact : artifacts) {
                String key = ArtifactUtils.key(artifact.getGroupId(), artifact.getArtifactId(),
                        artifact.getBaseVersion());
                if (projectIds.contains(key)) {
                    // resolved to an older snapshot from the repo, we only want the current project in the reactor
                    continue;
                }
                externalArtifacts.add(artifact);
            }
            List<Artifact> explicitArtifacts = MavenDependencyInjector.filterInjectedDependencies(externalArtifacts); // needed when the resolution is done again for the test runtime
            PomDependencyProcessor pomDependencyProcessor = new PomDependencyProcessor(session, repositorySystem,
                    getLogger());
            pomDependencyProcessor.addPomDependenciesToResolutionContext(project, explicitArtifacts, resolutionContext);
        }

        for (ArtifactRepository repository : project.getRemoteArtifactRepositories()) {
            try {
                URI uri = new URL(repository.getUrl()).toURI();

                if (repository.getLayout() instanceof P2ArtifactRepositoryLayout) {
                    if (session.isOffline()) {
                        getLogger().debug(
                                "Offline mode, using local cache only for repository " + repository.getId() + " ("
                                        + repository.getUrl() + ")");
                    }

                    try {
                        Authentication auth = repository.getAuthentication();
                        if (auth != null) {
                            resolutionContext.setCredentials(uri, auth.getUsername(), auth.getPassword());
                        }

                        resolutionContext.addP2Repository(uri);

                        getLogger().debug(
                                "Added p2 repository " + repository.getId() + " (" + repository.getUrl() + ")");
                    } catch (Exception e) {
                        String msg = "Failed to access p2 repository " + repository.getId() + " ("
                                + repository.getUrl() + "), will try to use local cache. Reason: " + e.getMessage();
                        if (getLogger().isDebugEnabled()) {
                            getLogger().warn(msg, e);
                        } else {
                            getLogger().warn(msg);
                        }
                    }
                }
            } catch (MalformedURLException e) {
                getLogger().warn("Could not parse repository URL", e);
            } catch (URISyntaxException e) {
                getLogger().warn("Could not parse repository URL", e);
            }
        }

        if (configuration.getTarget() != null) {
            final TargetDefinitionFile target;
            try {
                target = TargetDefinitionFile.read(configuration.getTarget());
            } catch (TargetDefinitionSyntaxException e) {
                throw new RuntimeException("Invalid syntax in target definition " + configuration.getTarget() + ": "
                        + e.getMessage(), e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            Set<URI> uris = new HashSet<URI>();

            for (Location location : target.getLocations()) {
                if (!(location instanceof InstallableUnitLocation)) {
                    continue;
                }
                for (TargetDefinition.Repository repository : ((InstallableUnitLocation) location).getRepositories()) {

                    try {
                        URI uri = getMirror(repository, session.getRequest().getMirrors());
                        if (uris.add(uri)) {
                            if (!session.isOffline()) {
                                String id = repository.getId();
                                if (id != null) {
                                    Server server = session.getSettings().getServer(id);

                                    if (server != null) {
                                        // TODO don't do this via magic side-effects, but when loading repositories
                                        resolutionContext.setCredentials(uri, server.getUsername(),
                                                server.getPassword());
                                    } else {
                                        getLogger().info(
                                                "Unknown server id=" + id + " for repository location="
                                                        + repository.getLocation());
                                    }
                                }

                                // TODO mirrors are no longer considered -> lookup mirrors when loading p2 repositories
                            }
                        }
                    } catch (URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                }

                try {
                    resolutionContext.addTargetDefinition(target, getEnvironments(configuration));
                } catch (TargetDefinitionSyntaxException e) {
                    throw new RuntimeException("Invalid syntax in target definition " + configuration.getTarget()
                            + ": " + e.getMessage(), e);
                } catch (TargetDefinitionResolutionException e) {
                    throw new RuntimeException("Failed to resolve target definition " + configuration.getTarget(), e);
                }
            }
        }

        if (!isAllowConflictingDependencies(project, configuration)) {
            List<P2ResolutionResult> results = resolver.resolveProject(resolutionContext, project.getBasedir());

            MultiEnvironmentTargetPlatform multiPlatform = new MultiEnvironmentTargetPlatform();

            // FIXME this is just wrong
            for (int i = 0; i < configuration.getEnvironments().size(); i++) {
                TargetEnvironment environment = configuration.getEnvironments().get(i);
                P2ResolutionResult result = results.get(i);

                DefaultTargetPlatform platform = newDefaultTargetPlatform(session, projects, result);

                // addProjects( session, platform );

                multiPlatform.addPlatform(environment, platform);
            }

            return multiPlatform;
        } else {
            P2ResolutionResult result = resolver.collectProjectDependencies(resolutionContext, project.getBasedir());

            return newDefaultTargetPlatform(session, projects, result);
        }
    }

    private boolean isAllowConflictingDependencies(MavenProject project, TargetPlatformConfiguration configuration) {
        String packaging = project.getPackaging();

        if (org.eclipse.tycho.ArtifactKey.TYPE_ECLIPSE_UPDATE_SITE.equals(packaging)
                || org.eclipse.tycho.ArtifactKey.TYPE_ECLIPSE_FEATURE.equals(packaging)) {
            Boolean allow = configuration.getAllowConflictingDependencies();
            if (allow != null) {
                return allow.booleanValue();
            }
        }

        // conflicting dependencies do not make sense for products and bundles
        return false;
    }

    protected DefaultTargetPlatform newDefaultTargetPlatform(MavenSession session, Map<File, ReactorProject> projects,
            P2ResolutionResult result) {
        DefaultTargetPlatform platform = new DefaultTargetPlatform();

        platform.addSite(new File(session.getLocalRepository().getBasedir()));

        platform.addNonReactorUnits(result.getNonReactorUnits());

        for (P2ResolutionResult.Entry entry : result.getArtifacts()) {
            ArtifactKey key = new DefaultArtifactKey(entry.getType(), entry.getId(), entry.getVersion());
            ReactorProject otherProject = projects.get(entry.getLocation());
            if (otherProject != null) {
                platform.addReactorArtifact(key, otherProject, entry.getClassifier(), entry.getInstallableUnits());
            } else {
                platform.addArtifactFile(key, entry.getLocation(), entry.getInstallableUnits());
            }
        }
        return platform;
    }

    private List<Map<String, String>> getEnvironments(TargetPlatformConfiguration configuration) {
        ArrayList<Map<String, String>> environments = new ArrayList<Map<String, String>>();

        for (TargetEnvironment environment : configuration.getEnvironments()) {
            Properties properties = new Properties();
            properties.put(PlatformPropertiesUtils.OSGI_OS, environment.getOs());
            properties.put(PlatformPropertiesUtils.OSGI_WS, environment.getWs());
            properties.put(PlatformPropertiesUtils.OSGI_ARCH, environment.getArch());
            ExecutionEnvironmentUtils.loadVMProfile(properties);

            // TODO does not belong here
            properties.put("org.eclipse.update.install.features", "true");

            Map<String, String> map = new LinkedHashMap<String, String>();
            for (Object key : properties.keySet()) {
                map.put(key.toString(), properties.getProperty(key.toString()));
            }
            environments.add(map);
        }

        return environments;
    }

    private URI getMirror(TargetDefinition.Repository location, List<Mirror> mirrors) throws URISyntaxException {
        URI p2RepositoryLocation = location.getLocation();
        String id = location.getId();
        if (id == null) {
            id = p2RepositoryLocation.toString();
        }

        ArtifactRepository repository = repositorySystem.createArtifactRepository(id, p2RepositoryLocation.toString(),
                p2layout, P2_REPOSITORY_POLICY, P2_REPOSITORY_POLICY);

        Mirror mirror = repositorySystem.getMirror(repository, mirrors);

        return mirror != null ? new URI(mirror.getUrl()) : p2RepositoryLocation;
    }

    public void initialize() throws InitializationException {
        this.resolverFactory = equinox.getService(P2ResolverFactory.class);
        this.generator = equinox.getService(DependencyMetadataGenerator.class, "(role-hint=dependency-only)");
        this.sourcesGenerator = equinox.getService(DependencyMetadataGenerator.class, "(role-hint=source-bundle)");
    }

    public void injectDependenciesIntoMavenModel(MavenProject project, AbstractTychoProject projectType,
            TargetPlatform targetPlatform, Logger logger) {
        MavenDependencyInjector.injectMavenDependencies(project, targetPlatform, bundleReader, logger);
    }
}
TOP

Related Classes of org.eclipse.tycho.p2.resolver.P2TargetPlatformResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.