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
The newest version!
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.googlejavaformat.java.Formatter;
import com.google.googlejavaformat.java.JavaFormatterOptions;
import org.apache.maven.execution.MavenSession;
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.nio.file.Files;
import java.nio.file.StandardOpenOption;
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.Style;
import static com.theoryinpractise.googleformatter.Constants.DIRECTORY_MISSING;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
/** Reformat all source files using the Google Code Formatter */
@Mojo(name = "format", defaultPhase = LifecyclePhase.PROCESS_SOURCES)
public class GoogleFormatterMojo extends AbstractMojo {
public static final SuffixMapping SOURCE_MAPPING = new SuffixMapping(".java", new HashSet<>(Arrays.asList(".java", ".class")));
@Component ScmManager scmManager;
@Parameter(required = true, readonly = true, property = "session")
protected MavenSession session;
@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 = "GOOGLE")
protected Style style;
@Parameter(defaultValue = "false", property = "formatter.skip")
protected boolean skip;
@Parameter(defaultValue = "true", property = "formatter.main")
protected boolean formatMain;
@Parameter(defaultValue = "true", property = "formatter.test")
protected boolean formatTest;
@Parameter(defaultValue = "false", property = "formatter.modified")
protected boolean filterModified;
@Parameter(defaultValue = "false", property = "formatter.fixImports")
protected boolean fixImports;
@Parameter(defaultValue = "100", property = "formatter.maxLineLength")
protected int maxLineLength;
@Override
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<>();
if (formatMain) {
sourceFiles.addAll(findFilesToReformat(sourceDirectory, outputDirectory));
}
if (formatTest) {
sourceFiles.addAll(findFilesToReformat(testSourceDirectory, testOutputDirectory));
}
Set sourceFilesToProcess = filterModified ? filterUnchangedFiles(sourceFiles) : sourceFiles;
JavaFormatterOptions options = getJavaFormatterOptions();
for (File file : sourceFilesToProcess) {
String source = CharStreams.toString(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
Formatter formatter = new Formatter(options);
String formattedSource = fixImports ? formatter.formatSourceAndFixImports(source) : formatter.formatSource(source);
HashCode sourceHash = Hashing.sha256().hashString(source, StandardCharsets.UTF_8);
HashCode formattedHash = Hashing.sha256().hashString(formattedSource, StandardCharsets.UTF_8);
if (!formattedHash.equals(sourceHash)) {
// overwrite existing file
Files.write(file.toPath(), formattedSource.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
getLog().info(String.format("Reformatted file %s", file.getPath()));
}
}
} catch (Exception e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
private JavaFormatterOptions getJavaFormatterOptions() {
JavaFormatterOptions options = spy(JavaFormatterOptions.builder().style(style).build());
doReturn(maxLineLength).when(options).maxLineLength();
return options;
}
private Set filterUnchangedFiles(Set originalFiles) throws MojoExecutionException {
MavenProject topLevelProject = session.getTopLevelProject();
try {
if (topLevelProject.getScm().getConnection() == null && topLevelProject.getScm().getDeveloperConnection() == null) {
throw new MojoExecutionException(
"You must supply at least one of scm.connection or scm.developerConnection in your POM file if you " +
"specify the filterModified or filter.modified option.");
}
String connectionUrl = MoreObjects.firstNonNull(topLevelProject.getScm().getConnection(), topLevelProject.getScm().getDeveloperConnection());
ScmRepository repository = scmManager.makeScmRepository(connectionUrl);
ScmFileSet scmFileSet = new ScmFileSet(topLevelProject.getBasedir());
String basePath = topLevelProject.getBasedir().getAbsoluteFile().getPath();
List changedFiles =
scmManager.status(repository, scmFileSet).getChangedFiles().stream()
.map(f -> new File(basePath, f.getPath()).toString())
.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(SOURCE_MAPPING);
Set sourceFiles = scanner.getIncludedSources(sourceDirectory, outputDirectory);
getLog().info(String.format(Constants.FOUND_UNCOMPILED, sourceFiles.size(), sourceDirectory.getPath()));
return sourceFiles;
} catch (InclusionScanException e) {
throw new MojoExecutionException(String.format(Constants.ERROR_SCANNING_PATH, sourceDirectory.getPath()), e);
}
} else {
getLog().info(String.format(DIRECTORY_MISSING, sourceDirectory.getPath()));
return Collections.emptySet();
}
}
protected SourceInclusionScanner getSourceInclusionScanner(boolean includeStale) {
return includeStale ? new SimpleSourceInclusionScanner(Collections.singleton("**/*"), Collections.emptySet()) : new StaleSourceScanner(1024);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy