All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.oneandone.maven.plugins.application.UploadMojo Maven / Gradle / Ivy

/**
 * 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.application;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;

import com.jcraft.jsch.JSchException;
import net.oneandone.sushi.fs.Node;
import net.oneandone.sushi.fs.NodeInstantiationException;
import net.oneandone.sushi.fs.OnShutdown;
import net.oneandone.sushi.fs.World;
import net.oneandone.sushi.fs.file.FileNode;
import net.oneandone.sushi.fs.ssh.SshNode;
import net.oneandone.sushi.util.Strings;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

/**
 * Copies an application to some target directory and creates/updates a symlink pointing to it.
 * The symlink is mandatory, because it allows version updates without breaking running applications.
 * So it's not possible to only install the application file with this plugin.
 */
@Mojo(name = "upload")
public class UploadMojo extends BaseMojo {
    /**
     * Symlink pointing to the application. A local file or an ssh location
     */
    @Parameter(required = true)
    private String symlink;

    /**
     * Directory where to store application. A local directory or an ssh location.
     * Optional, when not specified, the directory containing the symlink will be used.
     * The name of the application in the target file is 
     *   artifactId + "-" + Strings.removeRightOpt(version, "-SNAPSHOT") + "-" + classifier + "." + type);artifactId
     * . Note that snapshot suffixes are stripped, i.e. updating an snapshot overwrites
     * the previous snapshots.
     */
    @Parameter
    private String target;

    /**
     * Version of the application artifact to resolve from Maven repositories.
     * When not specified, the artifact is picked from the build directory. This is useful to
     * test local builds.
     */
    @Parameter(property = "resolve")
    private String resolve;

    @Parameter(property = "project", required = true, readonly = true)
    private MavenProject project;

    @Parameter(property = "localRepository", readonly = true)
    private ArtifactRepository localRepository;

    @Parameter(property = "project.remoteArtifactRepositories", readonly = true)
    private List remoteRepositories;

    @Component
    private ArtifactFactory artifactFactory;

    @Component
    private ArtifactResolver resolver;

    public UploadMojo() {
        this(new World());
    }

    public UploadMojo(World world) {
        super(world);
    }

    public void execute() throws MojoExecutionException {
        try {
            doExecute();
        } catch (MojoExecutionException | RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new MojoExecutionException("cannot deploy application: " + e.getMessage(), e);
        } finally {
            // Shutdown here, because otherwise Plexus might remove classes, that are needed for the shutdown hook
            // TODO: what if the plugin is executed twice?
            OnShutdown shutdown;

            shutdown = OnShutdown.get();
            Runtime.getRuntime().removeShutdownHook(shutdown);
            shutdown.run();
        }
    }

    public void doExecute()
            throws IOException, MojoExecutionException, ArtifactNotFoundException, ArtifactResolutionException, URISyntaxException, JSchException {
        String version;
        FileNode src;
        Node dest;
        Node link;
        String relative;

        if (resolve == null) {
            version = project.getVersion();
            src = getFile();
        } else {
            version = resolve;
            src = resolve(artifactFactory.createArtifactWithClassifier(
                    project.getGroupId(), project.getArtifactId(), version, type, classifier));
        }
        src.checkFile();
        link = node(symlink);
        dest = (target != null ? node(target) : link.getParent()).join(project.getArtifactId() + "-"
                + Strings.removeRightOpt(version, "-SNAPSHOT") + "-" + classifier + "." + type);
        if (dest.exists()) {
            dest.deleteFile();
            getLog().info("U " + dest.getURI());
        } else {
            getLog().info("A " + dest.getURI());
        }
        src.copyFile(dest);
        dest.setPermissions(permissions);
        if (link.exists()) {
            if (link.resolveLink().equals(dest)) {
                // the link is re-created to point to the same file, so from the user's perspective, it is not updated.
            } else {
                getLog().info("U " + link.getURI());
            }
            link.deleteFile();
        } else {
            getLog().info("A " + link.getURI());
        }
        relative = dest.getRelative(link.getParent());
        // TODO: sushi
        if (link instanceof SshNode) {
            ((SshNode) link).getRoot().exec(false, "cd", "/" + link.getParent().getPath(), "&&", "ln", "-s", relative, link.getName());
        } else {
            link.mklink(relative);
        }
    }

    private Node node(String str) throws URISyntaxException, NodeInstantiationException {
        if (str.startsWith("ssh:")) {
            return world.node(str);
        } else {
            return world.file(str);
        }
    }

    private FileNode resolve(Artifact artifact) throws ArtifactNotFoundException, ArtifactResolutionException {
        resolver.resolve(artifact, remoteRepositories, localRepository);
        return world.file(artifact.getFile());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy