Package com.comoyo.maven.plugins.protoc

Source Code of com.comoyo.maven.plugins.protoc.ProtocBundledMojo

/**
* Copyright (C) 2013-2014 Telenor Digital AS
*
* 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 com.comoyo.maven.plugins.protoc;

import org.apache.maven.artifact.Artifact;
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.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.List;


/**
* Maven Plugin Mojo for compiling Protobuf schema files.  Protobuf
* compiler binaries for various platforms and protobuf versions are
* bundled with the plugin and used as required.
* <p>
* The included ``protoc'' binary is:
* <pre>
* Copyright 2008, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
*     * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*     * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Code generated by the Protocol Buffer compiler is owned by the owner
* of the input file used when generating it.  This code is not
* standalone and requires a support library to be linked with it.  This
* support library is itself covered by the above license.
* </pre>
*
* @goal run
* @phase generate-sources
* @requiresDependencyResolution
*/

public class ProtocBundledMojo extends AbstractMojo
{
    /**
     * Plugin descriptor.
     *
     * @component role="org.apache.maven.plugin.descriptor.PluginDescriptor"
     * @required
     * @readonly
     */
    private PluginDescriptor pluginDescriptor;

    /**
     * The Maven project.
     *
     * @parameter property="project"
     * @required
     * @readonly
     */
    private MavenProject project;

    /**
     * Used to look up Artifacts in the remote repository.
     *
     * @component role="org.apache.maven.repository.RepositorySystem"
     * @required
     * @readonly
     */
    protected RepositorySystem repositorySystem;

    /**
     * List of Remote Repositories used by the resolver
     *
     * @parameter property="project.remoteArtifactRepositories"
     * @readonly
     * @required
     */
    protected List<ArtifactRepository> remoteRepositories;


    /**
     * Protobuf version to compile schema files for.  If omitted,
     * version is inferred from the project's depended-on
     * com.google.com:protobuf-java artifact, if any.  (If both are
     * present, the version must match.)
     *
     * @parameter property="protobufVersion"
     */
    private String protobufVersion;

    /**
     * Directories containing *.proto files to compile.
     *
     * @parameter
     *     property="inputDirectories"
     */
    private File[] inputDirectories;

    /**
     * Output directory for generated Java class files.
     *
     * @parameter
     *     property="outputDirectory"
     *     default-value="${project.build.directory}/generated-sources/protobuf"
     */
    private File outputDirectory;

    /**
     * Directories containing *.proto files to compile for test.
     *
     * @parameter
     *     property="testInputDirectories"
     */
    private File[] testInputDirectories;

    /**
     * Output directory for generated Java class files.
     *
     * @parameter
     *     property="testOutputDirectory"
     *     default-value="${project.build.directory}/generated-test-sources/protobuf"
     */
    private File testOutputDirectory;

    /**
     * Path to existing protoc to use.  Overrides auto-detection and
     * use of bundled protoc.
     *
     * @parameter property="protocExec"
     */
    private File protocExec;


    private static final Map<String, String> osNamePrefix = new HashMap<String, String>();
    private static final Map<String, String> osArchCanon = new HashMap<String, String>();
    static {
        osNamePrefix.put("linux", "linux");
        osNamePrefix.put("mac os x", "mac_os_x");
        osNamePrefix.put("windows", "win32");

        osArchCanon.put("x86_64", "x86_64");
        osArchCanon.put("amd64", "x86_64");
        osArchCanon.put("x86", "x86");
        osArchCanon.put("i386", "x86");
        osArchCanon.put("i686", "x86");
    }

    /**
     * Dynamically determine name of protoc variant suitable for
     * current system.
     *
     */
    private String determineProtocForSystem()
        throws MojoExecutionException
    {
        final String osName = System.getProperty("os.name");
        if (osName == null) {
            throw new MojoExecutionException("Unable to determine OS platform");
        }

        String os = null;
        for (String prefix : osNamePrefix.keySet()) {
            if (osName.toLowerCase().startsWith(prefix)) {
                os = osNamePrefix.get(prefix);
                break;
            }
        }
        if (os == null) {
            throw new MojoExecutionException("Unable to determine OS class for " + osName);
        }

        final String archName = System.getProperty("os.arch");
        if (archName == null) {
            throw new MojoExecutionException("Unable to determine CPU architecture");
        }

        String arch = osArchCanon.get(archName.toLowerCase());
        if (arch == null) {
            throw new MojoExecutionException("Unable to determine CPU arch id for " + archName);
        }

        // Pre-built protoc binaries for Windows use the same image
        // for 32- and 64-bit systems.
        if ("win32".equals(os) && "x86_64".equals(arch)) {
            arch = "x86";
        }

        return protobufVersion + "-" + os + "-" + arch;
    }

    /**
     * Return reference to suitable protoc binary artifact, download
     * from remote repository if necessary.
     *
     * @param protocName   protoc specifier
     */
    private File resolveProtocArtifact(String protocName)
        throws MojoExecutionException
    {
        Artifact artifact
            = repositorySystem.createArtifactWithClassifier(
                pluginDescriptor.getGroupId(),
                pluginDescriptor.getArtifactId(),
                pluginDescriptor.getVersion(),
                "exe", protocName);

        getLog().info("Using protoc " + artifact);
        ArtifactResolutionRequest request = new ArtifactResolutionRequest()
            .setArtifact(artifact)
            .setRemoteRepositories(remoteRepositories);
        ArtifactResolutionResult result = repositorySystem.resolve(request);
        if (!result.isSuccess()) {
            throw new MojoExecutionException(
                "Unable to resolve dependency on protoc binary artifact, sorry: "
                    + result.toString());
        }

        Set<Artifact> artifacts = result.getArtifacts();
        if (artifacts.size() != 1) {
            throw new MojoExecutionException(
                "Unexpected number of artifacts returned when resolving protoc binary (" + artifacts.size() + ")");
        }
        Artifact protocArtifact = artifacts.iterator().next();
        File file = protocArtifact.getFile();
        file.setExecutable(true, false);
        return file;
    }

    /**
     * Get version of specified artifact from the current project's
     * dependencies, if it exists.
     *
     * @param groupId
     * @param artifactId
     */
    private String getArtifactVersion(String groupId, String artifactId)
        throws MojoExecutionException
    {
        Set<Artifact> artifacts = project.getArtifacts();
        for (Artifact artifact : artifacts) {
            if (groupId.equals(artifact.getGroupId())
                && artifactId.equals(artifact.getArtifactId()))
            {
                return artifact.getVersion();
            }
        }
        return null;
    }

    /**
     * Ensure we have a suitable protoc binary available.  If
     * protocExec is explicitly given, use that.  Otherwise find and
     * extract suitable protoc from plugin bundle.
     *
     */
    private void ensureProtocBinaryPresent()
        throws MojoExecutionException
    {
        if (protocExec != null) {
            return;
        }

        final String protobufArtifactVersion
            = getArtifactVersion("com.google.protobuf", "protobuf-java");

        if (protobufVersion == null) {
            if (protobufArtifactVersion == null) {
                throw new MojoExecutionException(
                    "protobufVersion not specified and unable to derive version "
                        + "from protobuf-java dependency");
            }
            protobufVersion = protobufArtifactVersion;
        }
        else {
            if (protobufArtifactVersion != null
                && !protobufVersion.equals(protobufArtifactVersion))
            {
                getLog().warn("Project includes protobuf-java artifact of version "
                              + protobufArtifactVersion
                              + " while protoc is set to compile for version "
                              + protobufVersion);
            }
        }

        final String protocName = determineProtocForSystem();
        protocExec = resolveProtocArtifact(protocName);
    }

    /**
     * Compile single protobuf schema file.
     *
     * @param dir   base dir for input file, used to resolve includes
     * @param input   input file to compile
     */
    private void compileFile(File inputDir, File input, File outputDir)
        throws MojoExecutionException
    {
        try {
            final Process proc
                = new ProcessBuilder(protocExec.toString(),
                                     "--proto_path=" + inputDir.getAbsolutePath(),
                                     "--java_out=" + outputDir,
                                     input.getAbsolutePath())
                .redirectErrorStream(true)
                .start();
            final BufferedReader procOut
                = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            while (true) {
                final String line = procOut.readLine();
                if (line == null) {
                    break;
                }
                getLog().info("[protoc] " + line);
            }
            final int status = proc.waitFor();
            procOut.close();
            if (status != 0) {
                throw new MojoExecutionException(
                    "Compilation failure signalled by protoc exit status: " + status);
            }
        }
        catch (Exception e) {
            throw new MojoExecutionException("Unable to compile " + input.toString(), e);
        }
    }

    /**
     * Compile all *.proto files found under inputDirectories.
     *
     */
    private boolean compileAllFiles(String tag, File[] inputDirs, File outputDir)
        throws MojoExecutionException
    {
        final IOFileFilter filter = new SuffixFileFilter(".proto");

        boolean seen = false;
        for (File inputDir : inputDirs) {
            if (!inputDir.exists()) {
                continue;
            }
            if (!outputDir.exists()) {
                outputDir.mkdirs();
            }
            getLog().info("Compiling " + inputDir + " to " + outputDir + " [" + tag + "]");
            Iterator<File> files
                = FileUtils.iterateFiles(inputDir, filter, TrueFileFilter.INSTANCE);
            while (files.hasNext()) {
                final File input = files.next();
                compileFile(inputDir, input, outputDir);
                seen = true;
            }
        }
        return seen;
    }

    /**
     * Plugin invocation point.
     *
     */
    @Override
    public void execute()
        throws MojoExecutionException
    {
        ensureProtocBinaryPresent();

        if (inputDirectories.length == 0) {
            inputDirectories = new File[]{new File(project.getBasedir(), "src/main/protobuf")};
        }
        if (compileAllFiles("main", inputDirectories, outputDirectory)) {
            project.addCompileSourceRoot(outputDirectory.getAbsolutePath());
        }

        if (testInputDirectories.length == 0) {
            testInputDirectories = new File[]{new File(project.getBasedir(), "src/test/protobuf")};
        }
        if (compileAllFiles("test", testInputDirectories, testOutputDirectory)) {
            project.addTestCompileSourceRoot(testOutputDirectory.getAbsolutePath());
        }
    }
}
TOP

Related Classes of com.comoyo.maven.plugins.protoc.ProtocBundledMojo

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.