net.oneandone.maven.plugins.prerelease.util.Maven.java Source code

Java tutorial

Introduction

Here is the source code for net.oneandone.maven.plugins.prerelease.util.Maven.java

Source

/**
 * Copyright 1&1 Internet AG, https://github.com/1and1/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.oneandone.maven.plugins.prerelease.util;

import net.oneandone.maven.plugins.prerelease.core.Prerelease;
import net.oneandone.sushi.fs.World;
import net.oneandone.sushi.fs.file.FileNode;
import net.oneandone.sushi.util.Separator;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.ExecutionListener;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.project.ProjectBuildingResult;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class Maven {
    private final World world;
    private final Log log;
    private final MavenSession parentSession;
    private final ArtifactRepository localRepository;
    private final ExecutionListener executionListener;
    private final MavenProjectHelper projectHelper;
    private final List<ArtifactRepository> remoteRepositories;
    private final ProjectBuilder builder;

    public Maven(World world, Log log, MavenSession parentSession, ArtifactRepository localRepository,
            ExecutionListener executionListener, MavenProjectHelper projectHelper, ProjectBuilder builder,
            List<ArtifactRepository> remoteRepositories) {
        this.world = world;
        this.log = log;
        this.parentSession = parentSession;
        this.localRepository = localRepository;
        this.executionListener = executionListener;
        this.projectHelper = projectHelper;
        this.builder = builder;
        this.remoteRepositories = remoteRepositories;
    }

    public FileNode getLocalRepositoryDir() {
        return world.file(localRepository.getBasedir());
    }

    public ExecutionListener getExecutionListener() {
        return executionListener;
    }

    public void build(FileNode basedir, Map<String, String> userProperties, FilteringMojoExecutor.Filter filter,
            String... goals) throws Exception {
        build(basedir, userProperties, executionListener, filter, goals);
    }

    /**
     * Creates an DefaultMaven instance, initializes it form parentRequest (in Maven, this is done by MavenCli - also by
     * loading settings).
     */
    public void build(FileNode basedir, Map<String, String> userProperties, ExecutionListener theExecutionListener,
            FilteringMojoExecutor.Filter filter, String... goals) throws BuildException {
        DefaultPlexusContainer container;
        org.apache.maven.Maven maven;
        MavenExecutionRequest request;
        MavenExecutionResult result;
        BuildException exception;
        FilteringMojoExecutor mojoExecutor;

        request = DefaultMavenExecutionRequest.copy(parentSession.getRequest());
        container = (DefaultPlexusContainer) parentSession.getContainer();
        try {
            maven = container.lookup(org.apache.maven.Maven.class);
        } catch (ComponentLookupException e) {
            throw new IllegalStateException(e);
        }
        request.setPom(basedir.join("pom.xml").toPath().toFile());
        request.setProjectPresent(true);
        request.setGoals(Arrays.asList(goals));
        request.setBaseDirectory(basedir.toPath().toFile());
        request.setUserProperties(merged(request.getUserProperties(), userProperties));
        request.setExecutionListener(theExecutionListener);

        mojoExecutor = FilteringMojoExecutor.install(container, filter);
        log.info("[" + basedir + " " + filter + "] mvn " + props(request.getUserProperties())
                + Separator.SPACE.join(goals));
        nestedOutputOn();
        try {
            result = maven.execute(request);
        } finally {
            nestedOutputOff();
            mojoExecutor.uninstall();
        }
        exception = null;
        for (Throwable e : result.getExceptions()) {
            if (exception == null) {
                exception = new BuildException("build failed: " + e, e);
            } else {
                exception.addSuppressed(e);
            }
        }
        if (exception != null) {
            throw exception;
        }
    }

    //--

    /** @return with tailing space */
    private static String props(Properties props) {
        StringBuilder builder;

        builder = new StringBuilder();
        for (Map.Entry<Object, Object> entry : props.entrySet()) {
            builder.append("-D").append(entry.getKey());
            if (!((String) entry.getValue()).isEmpty()) {
                builder.append('=').append(entry.getValue());
            }
            builder.append(' ');
        }
        return builder.toString();
    }

    //--

    private static Properties merged(Properties left, Map<String, String> right) {
        Properties result;

        result = new Properties(left);
        result.putAll(right);
        return result;
    }

    /** Executes the deploy phase only, with the prerelease pom */
    public void deployPrerelease(Log log, Map<String, String> propertyArgs, Prerelease prerelease)
            throws Exception {
        PromoteExecutionListener listener;

        listener = new PromoteExecutionListener(prerelease, projectHelper, executionListener);
        try {
            build(prerelease.checkout, prerelease.descriptor.releaseProps(propertyArgs), listener,
                    FilteringMojoExecutor.DEPLOY, "deploy");
        } catch (BuildException e) {
            if (listener.isDeploySuccess()) {
                log.warn("Promote succeeded: your artifacts have been deployed, and your svn tag was created. ");
                log.warn("However, some optional deploy goals failed with this exception:");
                log.warn(e);
                log.warn("Thus, you can use your release, but someone should have a look at this exception.");
            } else {
                throw e;
            }
        }
    }

    /** executes the deploy phase only - with the snapshot pom */
    public void deploySnapshot(FileNode directory, Log log, Map<String, String> propertyArgs, Prerelease prerelease)
            throws Exception {
        PromoteExecutionListener listener;

        listener = new PromoteExecutionListener(prerelease, projectHelper, executionListener);
        try {
            build(directory, propertyArgs, listener, FilteringMojoExecutor.DEPLOY, "deploy");
        } catch (BuildException e) {
            if (listener.isDeploySuccess()) {
                log.warn("Snapshot deployment succeeded.");
                log.warn("However, some optional deploy goals failed with this exception:");
                log.warn(e);
                log.warn("Thus, you can use your snapshots, but someone should have a look at this exception.");
            } else {
                throw e;
            }
        }
    }

    public List<FileNode> files(List<Artifact> artifacts) {
        List<FileNode> result;

        result = new ArrayList<>();
        for (Artifact a : artifacts) {
            result.add(file(a));
        }
        return result;
    }

    public FileNode file(Artifact artifact) {
        return world.file(artifact.getFile());
    }

    //-- load poms -- for testing only

    public MavenProject loadPom(FileNode file) throws ProjectBuildingException {
        ProjectBuildingRequest request;
        ProjectBuildingResult result;

        // session initializes the repository session in the build request
        request = new DefaultProjectBuildingRequest(parentSession.getProjectBuildingRequest());
        request.setRemoteRepositories(remoteRepositories);
        request.setProcessPlugins(false);
        request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
        request.setSystemProperties(System.getProperties());
        //If you don't turn this into RepositoryMerging.REQUEST_DOMINANT the dependencies will be resolved against Maven Central
        //and not against the configured repositories. The default of the DefaultProjectBuildingRequest is
        // RepositoryMerging.POM_DOMINANT.
        request.setRepositoryMerging(ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT);
        request.setResolveDependencies(false);
        result = builder.build(file.toPath().toFile(), request);
        return result.getProject();
    }

    //--

    // Marks nested output. I'd love to just indent it by 4 spaces, but there's no single place to do this.
    // * it's too late to configure a LoggerFactory because Maven has already setup most of the components,
    //   and they'll be re-used by the build command
    // * every component has it's own Logger instance, that holds the target output stream; there's no
    //   way to get hold of all these loggers
    // * System.setOut does not affect the output streams already stored in the component loggers

    private void nestedOutputOn() {
        log.info("\033[2m");
    }

    private void nestedOutputOff() {
        log.info("\033[0m");
    }

}