
com.theoryinpractise.googleformatter.GoogleFormatterMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of googleformatter-maven-plugin Show documentation
Show all versions of googleformatter-maven-plugin Show documentation
Apache Maven Mojo for reformatting code using the Google Code Formatter
package com.theoryinpractise.googleformatter;
import com.google.common.base.MoreObjects;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.common.io.CharStreams;
import com.google.common.io.Files;
import com.google.googlejavaformat.java.Formatter;
import com.google.googlejavaformat.java.JavaFormatterOptions;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
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.apache.maven.scm.ScmException;
import org.apache.maven.scm.ScmFileSet;
import org.apache.maven.scm.manager.ScmManager;
import org.apache.maven.scm.repository.ScmRepository;
import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.googlejavaformat.java.JavaFormatterOptions.JavadocFormatter;
import static com.google.googlejavaformat.java.JavaFormatterOptions.SortImports;
import static com.google.googlejavaformat.java.JavaFormatterOptions.Style;
/**
* Reformat all source files using the Google Code Formatter
*/
@Mojo(name = "format", defaultPhase = LifecyclePhase.PROCESS_SOURCES)
public class GoogleFormatterMojo extends AbstractMojo {
@Component ScmManager scmManager;
@Parameter(required = true, readonly = true, property = "project")
protected MavenProject project;
@Parameter(required = true, readonly = true, property = "project.build.sourceDirectory")
protected File sourceDirectory;
@Parameter(required = true, readonly = true, property = "project.build.testSourceDirectory")
protected File testSourceDirectory;
@Parameter(required = true, readonly = true, property = "project.build.outputDirectory")
protected File outputDirectory;
@Parameter(required = true, readonly = true, property = "project.build.testOutputDirectory")
protected File testOutputDirectory;
@Parameter(defaultValue = "false")
protected boolean includeStale;
@Parameter(defaultValue = "ALSO")
protected SortImports sortImports;
@Parameter(defaultValue = "NONE")
protected JavadocFormatter javadocFormatter;
@Parameter(defaultValue = "GOOGLE")
protected Style style;
@Parameter(defaultValue = "100", property = "formatter.length")
protected int maxWidth;
@Parameter(defaultValue = "false", property = "formatter.skip")
protected boolean skip;
@Parameter(defaultValue = "false", property = "formatter.modified")
protected boolean filterModified;
public static class JavaFormatterOptionsWithCustomLength extends JavaFormatterOptions {
int maxLineLength;
public JavaFormatterOptionsWithCustomLength(JavadocFormatter javadocFormatter, Style style, SortImports sortImports, int maxLineLength) {
super(javadocFormatter, style, sortImports);
this.maxLineLength = maxLineLength;
}
@Override
public int maxLineLength() {
return maxLineLength;
}
}
public void execute() throws MojoExecutionException {
if ("pom".equals(project.getPackaging())) {
getLog().info("Project packaging is POM, skipping...");
return;
}
if (skip) {
getLog().info("Skipping source reformatting due to plugin configuration.");
return;
}
try {
Set sourceFiles = new HashSet<>();
sourceFiles.addAll(findFilesToReformat(sourceDirectory, outputDirectory));
sourceFiles.addAll(findFilesToReformat(testSourceDirectory, testOutputDirectory));
Set sourceFilesToProcess = filterModified ? filterUnchangedFiles(sourceFiles) : sourceFiles;
for (File file : sourceFilesToProcess) {
String source = CharStreams.toString(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
JavaFormatterOptions options = new JavaFormatterOptionsWithCustomLength(javadocFormatter, style, sortImports, maxWidth);
Formatter formatter = new Formatter(options);
String formattedSource = formatter.formatSource(source);
HashCode sourceHash = Hashing.sha1().hashString(source, StandardCharsets.UTF_8);
HashCode formattedHash = Hashing.sha1().hashString(formattedSource, StandardCharsets.UTF_8);
if (!formattedHash.equals(sourceHash)) {
// overwrite existing file
Files.write(formattedSource, file, StandardCharsets.UTF_8);
getLog().info("Reformatted file " + file.getPath());
}
}
} catch (Exception e) {
throw new MojoExecutionException(e.getMessage());
}
}
private Set filterUnchangedFiles(Set originalFiles) throws MojoExecutionException {
try {
String connectionUrl = MoreObjects.firstNonNull(project.getScm().getConnection(), project.getScm().getDeveloperConnection());
ScmRepository repository = scmManager.makeScmRepository(connectionUrl);
ScmFileSet scmFileSet = new ScmFileSet(project.getBasedir());
final List changedFiles =
scmManager
.status(repository, scmFileSet)
.getChangedFiles()
.stream()
.map(f -> String.format("%s/%s", project.getBasedir().getAbsoluteFile().getPath(), f.getPath()))
.collect(Collectors.toList());
return originalFiles.stream().filter(f -> changedFiles.contains(f.getPath())).collect(Collectors.toSet());
} catch (ScmException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
private Set findFilesToReformat(File sourceDirectory, File outputDirectory) throws MojoExecutionException {
if (sourceDirectory.exists()) {
try {
SourceInclusionScanner scanner = getSourceInclusionScanner(includeStale);
scanner.addSourceMapping(new SuffixMapping(".java", new HashSet(Arrays.asList(".java", ".class"))));
Set sourceFiles = scanner.getIncludedSources(sourceDirectory, outputDirectory);
getLog().info("Found " + sourceFiles.size() + " uncompiled/modified files in " + sourceDirectory.getPath() + " to reformat.");
return sourceFiles;
} catch (InclusionScanException e) {
throw new MojoExecutionException("Error scanning source path: \'" + sourceDirectory.getPath() + "\' " + "for files to reformat.", e);
}
} else {
getLog().info(String.format("Directory %s does not exist, skipping file collection.", sourceDirectory.getPath()));
return Collections.emptySet();
}
}
protected SourceInclusionScanner getSourceInclusionScanner(boolean includeStale) {
return includeStale ? new SimpleSourceInclusionScanner(Collections.singleton("**/*"), Collections.EMPTY_SET) : new StaleSourceScanner(1024);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy