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

org.robovm.maven.plugin.AbstractRoboVMMojo Maven / Gradle / Ivy

Go to download

The RoboVM Maven Plugin provides a way to build RoboVM based distribution bundles.

There is a newer version: 2.3.21
Show newest version
/*
 * Copyright (C) 2013 RoboVM AB.
 *
 * 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 org.robovm.maven.plugin;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collection;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
import org.codehaus.plexus.util.xml.XMLWriter;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.Xpp3DomWriter;
import org.robovm.compiler.AppCompiler;
import org.robovm.compiler.Version;
import org.robovm.compiler.config.Arch;
import org.robovm.compiler.config.Config;
import org.robovm.compiler.config.Config.Home;
import org.robovm.compiler.config.OS;
import org.robovm.compiler.log.Logger;
import org.robovm.compiler.target.ios.ProvisioningProfile;
import org.robovm.compiler.target.ios.SigningIdentity;

/**
 */
public abstract class AbstractRoboVMMojo extends AbstractMojo {

    @Component
    protected MavenProject project;

    @Component
    private ArchiverManager archiverManager;

    @Component
    private ArtifactResolver artifactResolver;

    @Parameter(defaultValue="${localRepository}")
    private ArtifactRepository localRepository;

    /**
     * Base directory to extract RoboVM native distribution files into. The
     * robovm-dist bundle will be downloaded from Maven and extracted into this
     * directory. Note that each release of RoboVM is placed in a separate
     * sub-directory with the version number as suffix.
     *
     * If not set, then the tar file is extracted into the local Maven
     * repository where the tar file is downloaded to.
     */
    @Parameter
    protected File home;

    /**
     * The path to a {@code robovm.properties} file which contains info for your app.
     */
    @Parameter(property="robovm.propertiesFile")
    protected File propertiesFile;

    /**
     * The path to a {@code robovm.xml} file which configures the RoboVM compiler.
     */
    @Parameter(property="robovm.configFile")
    protected File configFile;

    /**
     * The identity to sign the app as when building an iOS bundle for the app.
     * Default is to look for an identity starting with 'iPhone Developer' or
     * 'iOS Development'. Enclose in '/' to search by regexp, e.g. '/foo|bar/'.
     */
    @Parameter(property="robovm.iosSignIdentity")
    protected String iosSignIdentity;

    /**
     * The provisioning profile to use when building for device.
     */
    @Parameter(property="robovm.iosProvisioningProfile")
    protected String iosProvisioningProfile;

    /**
     * Whether the app should be signed or not. Unsigned apps can only be run on jailbroken
     * devices.
     */
    @Parameter(property="robovm.iosSkipSigning")
    protected boolean iosSkipSigning = false;

    /**
     * The directory into which the RoboVM distributable for the project will be built.
     */
    @Parameter(property="robovm.installDir", defaultValue="${project.build.directory}/robovm")
    protected File installDir;

    /**
     * Overrides the arch used when running the app. One of x86, x86_64, thumbv7, arm64.
     * Will be ignored if the specified value isn't supported by the executed goal.
     */
    @Parameter(property="robovm.arch")
    protected String arch;

    /**
     * Overrides the os used when running the app. One of macosx, linux, ios.
     * Will be ignored if the specified value isn't supported by the executed goal.
     */
    @Parameter(property="robovm.os")
    protected String os;

    /**
     * If set to {@code true} the app will be launched in debug mode. The app
     * will suspend before the main method is called and will wait for a
     * debugger to connect. If set to {@code "clientmode"} then the application
     * will connect back to the local host to attach to already started
     * debugging server which is waiting for connection on robovm.debugPort.
     */
    @Parameter(property="robovm.debug")
    protected String debug;

    /**
     * The port to listen for debugger connections on when launching in debug
     * mode using {@code debug=true}. If not set a default port will be used.
     * The port actually used will be written to the console before the app is
     * launched.
     */
    @Parameter(property="robovm.debugPort")
    protected int debugPort = -1;

    private Logger roboVMLogger;

    protected Config.Builder configure(Config.Builder builder) throws MojoExecutionException {
        builder.logger(getRoboVMLogger());

        // load config base file if it exists (and properties)

        if (propertiesFile != null) {
            if (!propertiesFile.exists()) {
                throw new MojoExecutionException(
                        "Invalid 'propertiesFile' specified for RoboVM compile: "
                                + propertiesFile);
            }
            try {
                getLog().debug(
                        "Including properties file in RoboVM compiler config: "
                                + propertiesFile.getAbsolutePath());
                builder.addProperties(propertiesFile);
            } catch (IOException e) {
                throw new MojoExecutionException(
                        "Failed to add properties file to RoboVM config: "
                                + propertiesFile);
            }
        } else {
            try {
                builder.readProjectProperties(project.getBasedir(), false);
            } catch (IOException e) {
                throw new MojoExecutionException(
                        "Failed to read RoboVM project properties file(s) in "
                                + project.getBasedir().getAbsolutePath(), e);
            }
        }

        if (configFile != null) {
            if (!configFile.exists()) {
                throw new MojoExecutionException(
                        "Invalid 'configFile' specified for RoboVM compile: "
                                + configFile);
            }
            try {
                getLog().debug(
                        "Loading config file for RoboVM compiler: "
                                + configFile.getAbsolutePath());
                builder.read(configFile);
            } catch (Exception e) {
                throw new MojoExecutionException(
                        "Failed to read RoboVM config file: " + configFile);
            }
        } else {
            try {
                builder.readProjectConfig(project.getBasedir(), false);
            } catch (Exception e) {
                throw new MojoExecutionException(
                        "Failed to read project RoboVM config file in "
                                + project.getBasedir().getAbsolutePath(), e);
            }
        }

        // Read embedded RoboVM  if there is one
        Plugin plugin = project.getPlugin("com.mobidevelop.robovm:robovm-maven-plugin");
        MavenProject p = project;
        while (p != null && plugin == null) {
            plugin = p.getPluginManagement().getPluginsAsMap().get("com.mobidevelop.robovm:robovm-maven-plugin");
            if (plugin == null) p = p.getParent();
        }
        if (plugin != null) {
            getLog().debug("Reading RoboVM plugin configuration from " + p.getFile().getAbsolutePath());
            Xpp3Dom configDom = (Xpp3Dom) plugin.getConfiguration();
            if (configDom != null && configDom.getChild("config") != null) {
                StringWriter sw = new StringWriter();
                XMLWriter xmlWriter = new PrettyPrintXMLWriter(sw, "UTF-8", null);
                Xpp3DomWriter.write(xmlWriter, configDom.getChild("config"));
                try {
                    builder.read(new StringReader(sw.toString()),
                            project.getBasedir());
                } catch (Exception e) {
                    throw new MojoExecutionException(
                            "Failed to read RoboVM config embedded in POM", e);
                }
            }
        }

        File tmpDir = new File(project.getBuild().getDirectory(), "robovm.tmp");
        try {
            FileUtils.deleteDirectory(tmpDir);
        } catch (IOException e) {
            throw new MojoExecutionException(
                    "Failed to clean output dir " + tmpDir, e);
        }
        tmpDir.mkdirs();

        Home home = null;
        try {
            home = Home.find();
        } catch (Throwable t) {}
        if (home == null || !home.isDev()) {
            home = new Config.Home(unpackRoboVMDist());
        }
        builder.home(home)
                .tmpDir(tmpDir)
                .skipInstall(true)
                .installDir(installDir);
        if (home.isDev()) {
            builder.useDebugLibs(Boolean.getBoolean("robovm.useDebugLibs"));
            builder.dumpIntermediates(true);
        }

        if (debug != null && !debug.equals("false")) {
            builder.debug(true);
            if (debugPort != -1) {
                builder.addPluginArgument("debug:jdwpport=" + debugPort);
            }
            if ("clientmode".equals(debug)) {
                builder.addPluginArgument("debug:clientmode=true");
            }
        }

        if (iosSkipSigning) {
            builder.iosSkipSigning(true);
        } else {
            if (iosSignIdentity != null) {
                getLog().debug(
                        "Using explicit iOS Signing identity: " + iosSignIdentity);
                builder.iosSignIdentity(SigningIdentity.find(
                        SigningIdentity.list(), iosSignIdentity));
            }

            if (iosProvisioningProfile != null) {
                getLog().debug(
                        "Using explicit iOS provisioning profile: "
                                + iosProvisioningProfile);
                builder.iosProvisioningProfile(ProvisioningProfile.find(
                        ProvisioningProfile.list(), iosProvisioningProfile));
            }
        }

        builder.clearClasspathEntries();

        // configure the runtime classpath

        try {
            for (Object object : project.getRuntimeClasspathElements()) {
                String path = (String) object;
                if (getLog().isDebugEnabled()) {
                    getLog().debug(
                            "Including classpath element for RoboVM app: "
                                    + path);
                }
                builder.addClasspathEntry(new File(path));
            }
        } catch (DependencyResolutionRequiredException e) {
            throw new MojoExecutionException(
                    "Error resolving application classpath for RoboVM build", e);
        }

        return builder;
    }

    protected AppCompiler build(OS os, Arch arch, String targetType)
            throws MojoExecutionException, MojoFailureException {

        getLog().info("Building RoboVM app for: " + os + " (" + arch + ")");

        Config.Builder builder;
        try {
            builder = new Config.Builder();
        } catch (IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }

        configure(builder).os(os).arch(arch).targetType(targetType);

        // execute the RoboVM build

        try {

            getLog().info(
                    "Compiling RoboVM app, this could take a while, especially the first time round");
            AppCompiler compiler = new AppCompiler(builder.build());
            compiler.build();

            return compiler;

        } catch (IOException e) {
            throw new MojoExecutionException(
                    "Error building RoboVM executable for app", e);
        }
    }

    protected String getRoboVMVersion() {
        return Version.getVersion();
    }

    protected File unpackRoboVMDist() throws MojoExecutionException {

        Artifact distTarArtifact = resolveRoboVMDistArtifact();
        File distTarFile = distTarArtifact.getFile();
        File unpackBaseDir;
        if (home != null) {
            unpackBaseDir = home;
        } else {
            // by default unpack into the local repo directory
            unpackBaseDir = new File(distTarFile.getParent(), "unpacked");
        }
        if (unpackBaseDir.exists() && distTarArtifact.isSnapshot()) {
            getLog().debug("Deleting directory for unpacked snapshots: " + unpackBaseDir);
            try {
                FileUtils.deleteDirectory(unpackBaseDir);
            } catch (IOException e) {
                throw new MojoExecutionException(
                        "Failed to delete " + unpackBaseDir, e);
            }
        }
        unpack(distTarFile, unpackBaseDir);
        File unpackedDir = new File(unpackBaseDir, "robovm-" + getRoboVMVersion());
        return unpackedDir;
    }

    protected Artifact resolveRoboVMDistArtifact() throws MojoExecutionException {

        MavenArtifactHandler handler = new MavenArtifactHandler("tar.gz");
        Artifact artifact = new DefaultArtifact("com.mobidevelop.robovm", "robovm-dist",
                getRoboVMVersion(), "", "tar.gz", "nocompiler", handler);
        return resolveArtifact(artifact);
    }

    protected Artifact resolveArtifact(Artifact artifact)
            throws MojoExecutionException {

        ArtifactResolutionRequest request = new ArtifactResolutionRequest();
        request.setArtifact(artifact);
        request.setLocalRepository(localRepository);
        final List remoteRepositories = project
                .getRemoteArtifactRepositories();
        request.setRemoteRepositories(remoteRepositories);

        getLog().debug("Resolving artifact " + artifact);

        ArtifactResolutionResult result = artifactResolver.resolve(request);
        if (!result.isSuccess()) {
            throw new MojoExecutionException("Unable to resolve artifact: "
                    + artifact);
        }
        Collection resolvedArtifacts = result.getArtifacts();
        artifact = (Artifact) resolvedArtifacts.iterator().next();
        return artifact;
    }

    protected void unpack(File archive, File targetDirectory)
            throws MojoExecutionException {

        if (!targetDirectory.exists()) {

            getLog().info("Extracting '" + archive + "' to: " + targetDirectory);
            if (!targetDirectory.mkdirs()) {
                throw new MojoExecutionException(
                        "Unable to create base directory to unpack into: "
                                + targetDirectory);
            }

            try {
                UnArchiver unArchiver = archiverManager.getUnArchiver(archive);
                unArchiver.setSourceFile(archive);
                unArchiver.setDestDirectory(targetDirectory);
                unArchiver.extract();
            } catch (NoSuchArchiverException e) {
                throw new MojoExecutionException("Unable to unpack archive "
                        + archive + " to " + targetDirectory, e);
            }
            getLog().debug(
                    "Archive '" + archive + "' unpacked to: " + targetDirectory);

        } else {
            getLog().debug(
                    "Archive '" + archive + "' was already unpacked in: "
                            + targetDirectory);
        }
    }

    protected Logger getRoboVMLogger() {

        if (roboVMLogger == null) {
            roboVMLogger = new Logger() {
                public void debug(String s, Object... objects) {
                    getLog().debug(String.format(s, objects));
                }

                public void info(String s, Object... objects) {
                    getLog().info(String.format(s, objects));
                }

                public void warn(String s, Object... objects) {
                    getLog().warn(String.format(s, objects));
                }

                public void error(String s, Object... objects) {
                    getLog().error(String.format(s, objects));
                }
            };
        }
        return roboVMLogger;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy