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

com.facebook.mojo.SwiftMojo Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 Facebook, Inc.
 *
 * 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.facebook.mojo;

import com.facebook.swift.generator.SwiftGenerator;
import com.facebook.swift.generator.SwiftGeneratorConfig;
import com.facebook.swift.generator.SwiftGeneratorTweak;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import org.apache.maven.model.FileSet;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.FileUtils;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.List;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
import static java.lang.String.format;

/**
 * Process IDL files and generates source code from the IDL files.
 */
@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class SwiftMojo extends AbstractMojo
{

    private static final Pattern scanRequiredPattern
            = Pattern.compile("^[/\\\\]|[*?]|\\.\\.|[/\\\\]$");

    /**
     * Skip the plugin execution.
     */
    @Parameter(defaultValue = "false")
    private boolean skip = false;

    /**
     * Override java package for the generated classes. If unset, the java namespace from
     * the IDL files is used. If a value is set here, the java package definition from
     * the IDL files is ignored.
     */
    @Parameter
    private String overridePackage = null;

    /**
     * Give a default Java package for generated classes if the IDL files do not contain
     * a java namespace definition. This package is only used if the IDL files do not
     * contain a java namespace definition.
     */
    @Parameter
    private String defaultPackage = null;

    /**
     * IDL files to process.
     */
    @Parameter(required = true)
    private FileSet idlFiles = null;

    /**
     * Set the Output folder for generated code.
     */
    @Parameter(defaultValue = "${project.build.directory}/generated-sources/swift", required = true)
    private File outputFolder = null;

    /**
     * Generate code for included IDL files. If true, generate Java code for all IDL
     * files that are listed in the idlFiles set and all IDL files loaded through include
     * statements. Default is false (generate only code for explicitly listed IDL files).
     */
    @Parameter(defaultValue = "false")
    private boolean generateIncludedCode = false;

    /**
     * Add {@link org.apache.thrift.TException} to each method signature. This exception
     * is thrown when a thrift internal error occurs.
     */
    @Parameter(defaultValue = "true")
    private boolean addThriftExceptions = true;

    /**
     * Have generated services extend {@link Closeable} and a close method.
     */
    @Parameter(defaultValue = "false")
    private boolean addCloseableInterface = false;

    /**
     * Generated exceptions extends {@link RuntimeException}, not {@link Exception}.
     */
    @Parameter(defaultValue = "true")
    private boolean extendRuntimeException = true;

    /**
     * Select the flavor of the generated source code. Default is "java-regular".
     */
    @Parameter(defaultValue = "java-regular")
    private String codeFlavor = "java-regular";

    /**
     * Use the 'java' namespace instead of the 'java.swift' namespace.
     */
    @Parameter(defaultValue = "false")
    private boolean usePlainJavaNamespace = false;

    @Parameter(defaultValue = "${project}", required = true, readonly = true)
    private MavenProject project = null;

    @Override
    public final void execute() throws MojoExecutionException, MojoFailureException
    {
        try
        {
            if (!skip)
            {

                final File inputFolder = new File(idlFiles.getDirectory());

                final List files = getFiles(inputFolder);

                final SwiftGeneratorConfig.Builder configBuilder = SwiftGeneratorConfig.builder()
                    .inputBase(inputFolder.toURI())
                    .outputFolder(outputFolder)
                    .overridePackage(overridePackage)
                    .defaultPackage(defaultPackage)
                    .generateIncludedCode(generateIncludedCode)
                    .codeFlavor(codeFlavor);

                if (usePlainJavaNamespace)
                {
                    configBuilder.addTweak(SwiftGeneratorTweak.USE_PLAIN_JAVA_NAMESPACE);
                }

                if (addThriftExceptions)
                {
                    configBuilder.addTweak(SwiftGeneratorTweak.ADD_THRIFT_EXCEPTION);
                }

                if (addCloseableInterface)
                {
                    configBuilder.addTweak(SwiftGeneratorTweak.ADD_CLOSEABLE_INTERFACE);
                }

                if (extendRuntimeException)
                {
                    configBuilder.addTweak(SwiftGeneratorTweak.EXTEND_RUNTIME_EXCEPTION);
                }

                final SwiftGenerator generator = new SwiftGenerator(configBuilder.build());
                generator.parse(files.stream().map(File::toURI).collect(toList()));

                project.addCompileSourceRoot(outputFolder.getPath());
            }
        } 
        catch (Exception e)
        {
            Throwables.propagateIfInstanceOf(e, MojoExecutionException.class);
            Throwables.propagateIfInstanceOf(e, MojoFailureException.class);

            getLog().error(format("While executing Mojo %s", this.getClass().getSimpleName()), e);
            throw new MojoExecutionException("Failure:", e);
        }
    }

    private static boolean requiresScan(String pattern)
    {
        Matcher matcher = scanRequiredPattern.matcher(pattern);
        return matcher.find();
    }

    @VisibleForTesting
    static boolean canBypassScan(
            List includedFiles,
            List excludedFiles)
    {
        // The directory scan can be bypassed, IFF
        // 1) There are no excludes
        // 2) There is at least one include string
        // 3) In the include strings, the following apply
        //    a) No * or ? in the string
        //    b) Doesn't end in / or \ (as that auto-adds ** to the end)
        //    c) Doesn't start with / or \ (as that has special matching rules)
        //    d) Doesn't have relative paths (
        return excludedFiles.isEmpty()
                && !includedFiles.isEmpty()
                && includedFiles
                .stream()
                .noneMatch(s -> requiresScan(s));
    }

    @SuppressWarnings("unchecked")
    private List getFiles(File inputFolder) throws IOException
    {
        // On large source trees under the input folder, the directory
        // search can take a very long time. 
        if (canBypassScan(
                idlFiles.getIncludes(),
                idlFiles.getExcludes()))
        {
            return idlFiles.getIncludes()
                    .stream()
                    .map(s -> new File(inputFolder, s))
                    .collect(Collectors.toList());
        }

        return FileUtils.getFiles(inputFolder,
                                  Joiner.on(',').join(idlFiles.getIncludes()),
                                  Joiner.on(',').join(idlFiles.getExcludes()));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy