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

com.spotify.fmt.AbstractFMT Maven / Gradle / Ivy

/*-
 * -\-\-
 * com.spotify.fmt:fmt-maven-plugin
 * --
 * Copyright (C) 2016 - 2023 Spotify AB
 * --
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * -/-/-
 */

package com.spotify.fmt;

import com.google.common.annotations.VisibleForTesting;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;

public abstract class AbstractFMT extends AbstractMojo {

  @Parameter(
      defaultValue = "${project.build.sourceDirectory}",
      property = "sourceDirectory",
      required = true)
  private File sourceDirectory;

  @Parameter(
      defaultValue = "${project.build.testSourceDirectory}",
      property = "testSourceDirectory",
      required = true)
  private File testSourceDirectory;

  @Parameter(defaultValue = "${project.packaging}", required = true)
  private String packaging;

  @Parameter(property = "additionalSourceDirectories")
  private File[] additionalSourceDirectories;

  @Parameter(defaultValue = "false", property = "verbose")
  private boolean verbose;

  @Parameter(defaultValue = "false", property = "failOnUnknownFolder")
  private boolean failOnUnknownFolder;

  @Parameter(defaultValue = ".*\\.java", property = "filesNamePattern")
  private String filesNamePattern;

  @Parameter(defaultValue = ".*", property = "filesPathPattern")
  private String filesPathPattern;

  @Parameter(defaultValue = "false", property = "fmt.skip")
  private boolean skip = false;

  @Parameter(defaultValue = "false", property = "skipSourceDirectory")
  private boolean skipSourceDirectory = false;

  @Parameter(defaultValue = "false", property = "skipTestSourceDirectory")
  private boolean skipTestSourceDirectory = false;

  @Parameter(defaultValue = "false", property = "skipSortingImports")
  private boolean skipSortingImports = false;

  @Parameter(defaultValue = "google", property = "style")
  private String style;

  /**
   * Option to specify whether to run google-java-format in a fork or in-process. Can be {@code
   * default}, {@code never} and {@code always}. Also adds JVM arguments when needed.
   *
   * 

Specifying {@code default} (which is the default) will fork when JDK 16+ is detected. * Specifying {@code never} will never fork and instead run in-process, regardless of JDK version. * Specifying {@code always} will always fork, regardless of JDK version.
*/ @Parameter(defaultValue = "default", property = "fmt.forkMode") private String forkMode; @Parameter(property = "plugin.artifactMap", required = true, readonly = true) private Map pluginArtifactMap; /** * Whether to use the classpath from the java.class.path property when forking. Only intended for * use by unit tests. */ @VisibleForTesting boolean useDefaultClasspathWhenForking; private FormattingResult result; /** execute. */ @Override public void execute() throws MojoFailureException { if (skip) { getLog().info("Skipping format check"); return; } if ("pom".equals(packaging)) { getLog().info("Skipping format check: project uses 'pom' packaging"); return; } if (skipSortingImports) { getLog().info("Skipping sorting imports"); } List directoriesToFormat = new ArrayList<>(); if (sourceDirectory.exists() && !skipSourceDirectory) { directoriesToFormat.add(sourceDirectory); } else { handleMissingDirectory("Source", sourceDirectory); } if (testSourceDirectory.exists() && !skipTestSourceDirectory) { directoriesToFormat.add(testSourceDirectory); } else { handleMissingDirectory("Test source", testSourceDirectory); } for (File additionalSourceDirectory : additionalSourceDirectories) { if (additionalSourceDirectory.exists()) { directoriesToFormat.add(additionalSourceDirectory); } else { handleMissingDirectory("Additional source", additionalSourceDirectory); } } FormattingConfiguration configuration = FormattingConfiguration.builder() .debug(getLog().isDebugEnabled()) .directoriesToFormat(directoriesToFormat) .style(style) .filesNamePattern(filesNamePattern) .filesPathPattern(filesPathPattern) .verbose(verbose) .skipSortingImports(skipSortingImports) .writeReformattedFiles(shouldWriteReformattedFiles()) .processingLabel(getProcessingLabel()) .build(); FormattingCallable formattingCallable = new FormattingCallable(configuration); try { if (shouldFork()) { final List classpath = pluginArtifactMap.values().stream() .map(a -> a.getFile().getAbsolutePath()) .collect(Collectors.toList()); try (ForkingExecutor executor = new ForkingExecutor(getLog()) .javaArgs(javaArgs()) .classpath(classpath) .withDefaultClasspath(useDefaultClasspathWhenForking)) { result = executor.execute(formattingCallable); } } else { result = formattingCallable.call(); } } catch (Exception e) { throw new MojoFailureException(e); } postExecute(result); } @VisibleForTesting boolean shouldFork() { switch (forkMode) { case "default": case "always": return true; case "never": return false; default: throw new IllegalArgumentException( "Invalid forkMode: " + forkMode + ", must be `default`, `never` or `always`"); } } /** * Post Execute action. It is called at the end of the execute method. Subclasses can add extra * checks. * * @param result The formatting result */ protected void postExecute(FormattingResult result) throws MojoFailureException {} public FormattingResult getResult() { return result; } private void handleMissingDirectory(String directoryDisplayName, File directory) throws MojoFailureException { if (failOnUnknownFolder) { String message = directoryDisplayName + " directory '" + directory + "' does not exist, failing build (failOnUnknownFolder is true)."; getLog().error(message); throw new MojoFailureException(message); } else { getLog() .warn(directoryDisplayName + " directory '" + directory + "' does not exist, ignoring."); } } /** Whether to write reformatted files to disk. */ protected abstract boolean shouldWriteReformattedFiles(); /** * Provides the name of the label used when a non-formatted file is found. * * @return the label to use in the log */ protected abstract String getProcessingLabel(); private List javaArgs() { // https://github.com/google/google-java-format/blame/13ca73ebbfa86f6aca5f86be16e6829de6d5014c/pom.xml#L238 return Arrays.asList( "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", "--add-opens", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", "--add-opens", "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED"); } private static class FormattingCallable implements SerializableCallable { private final FormattingConfiguration configuration; FormattingCallable(FormattingConfiguration configuration) { this.configuration = configuration; } @Override public FormattingResult call() { Logging.configure(configuration.debug()); Formatter formatter = new Formatter(configuration); return formatter.format(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy