com.diffplug.spotless.maven.AbstractSpotlessMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spotless-maven-plugin Show documentation
Show all versions of spotless-maven-plugin Show documentation
Spotless - keep your code spotless with Gradle
/*
* Copyright 2016-2020 DiffPlug
*
* 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.diffplug.spotless.maven;
import static java.util.stream.Collectors.toList;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
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.Parameter;
import org.codehaus.plexus.resource.ResourceManager;
import org.codehaus.plexus.resource.loader.FileResourceLoader;
import org.codehaus.plexus.util.FileUtils;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.RemoteRepository;
import com.diffplug.common.collect.Iterables;
import com.diffplug.spotless.Formatter;
import com.diffplug.spotless.LineEnding;
import com.diffplug.spotless.Provisioner;
import com.diffplug.spotless.generic.LicenseHeaderStep;
import com.diffplug.spotless.maven.antlr4.Antlr4;
import com.diffplug.spotless.maven.cpp.Cpp;
import com.diffplug.spotless.maven.generic.Format;
import com.diffplug.spotless.maven.generic.LicenseHeader;
import com.diffplug.spotless.maven.java.Java;
import com.diffplug.spotless.maven.kotlin.Kotlin;
import com.diffplug.spotless.maven.scala.Scala;
import com.diffplug.spotless.maven.typescript.Typescript;
public abstract class AbstractSpotlessMojo extends AbstractMojo {
private static final String DEFAULT_ENCODING = "UTF-8";
private static final String DEFAULT_LINE_ENDINGS = "GIT_ATTRIBUTES";
@Component
private RepositorySystem repositorySystem;
@Component
private ResourceManager resourceManager;
@Parameter(defaultValue = "${repositorySystemSession}", required = true, readonly = true)
private RepositorySystemSession repositorySystemSession;
@Parameter(defaultValue = "${project.remotePluginRepositories}", required = true, readonly = true)
private List repositories;
@Parameter(defaultValue = "${project.basedir}", required = true, readonly = true)
private File baseDir;
@Parameter(defaultValue = "${project.build.directory}", required = true, readonly = true)
private File buildDir;
@Parameter(defaultValue = DEFAULT_ENCODING)
private String encoding;
@Parameter(defaultValue = DEFAULT_LINE_ENDINGS)
private LineEnding lineEndings;
@Parameter
private String ratchetFrom;
@Parameter
private LicenseHeader licenseHeader;
@Parameter
private List formats = Collections.emptyList();
@Parameter
private Java java;
@Parameter
private Scala scala;
@Parameter
private Kotlin kotlin;
@Parameter
private Cpp cpp;
@Parameter
private Typescript typescript;
@Parameter
private Antlr4 antlr4;
@Parameter(property = "spotlessFiles")
private String filePatterns;
@Parameter(property = LicenseHeaderStep.spotlessSetLicenseHeaderYearsFromGitHistory)
private String setLicenseHeaderYearsFromGitHistory;
protected abstract void process(Iterable files, Formatter formatter) throws MojoExecutionException;
@Override
public final void execute() throws MojoExecutionException {
List formatterFactories = getFormatterFactories();
for (FormatterFactory formatterFactory : formatterFactories) {
execute(formatterFactory);
}
}
private void execute(FormatterFactory formatterFactory) throws MojoExecutionException {
List files = collectFiles(formatterFactory);
FormatterConfig config = getFormatterConfig();
Optional ratchetFrom = formatterFactory.ratchetFrom(config);
Iterable toFormat;
if (!ratchetFrom.isPresent()) {
toFormat = files;
} else {
toFormat = Iterables.filter(files, GitRatchetMaven.instance().isGitDirty(baseDir, ratchetFrom.get()));
}
try (Formatter formatter = formatterFactory.newFormatter(files, config)) {
process(toFormat, formatter);
}
}
private List collectFiles(FormatterFactory formatterFactory) throws MojoExecutionException {
Set configuredIncludes = formatterFactory.includes();
Set configuredExcludes = formatterFactory.excludes();
Set includes = configuredIncludes.isEmpty() ? formatterFactory.defaultIncludes() : configuredIncludes;
if (includes.isEmpty()) {
throw new MojoExecutionException("You must specify some files to include, such as 'src/** '");
}
Set excludes = new HashSet<>(FileUtils.getDefaultExcludesAsList());
excludes.add(withTrailingSeparator(buildDir.toString()));
excludes.addAll(configuredExcludes);
String includesString = String.join(",", includes);
String excludesString = String.join(",", excludes);
try {
final List files = FileUtils.getFiles(baseDir, includesString, excludesString);
if (filePatterns == null || filePatterns.isEmpty()) {
return files;
}
final String[] includePatterns = this.filePatterns.split(",");
final List compiledIncludePatterns = Arrays.stream(includePatterns)
.map(Pattern::compile)
.collect(Collectors.toList());
final Predicate shouldInclude = file -> compiledIncludePatterns
.stream()
.anyMatch(filePattern -> filePattern.matcher(file.getAbsolutePath())
.matches());
return files
.stream()
.filter(shouldInclude)
.collect(toList());
} catch (IOException e) {
throw new MojoExecutionException("Unable to scan file tree rooted at " + baseDir, e);
}
}
private static String withTrailingSeparator(String path) {
return path.endsWith(File.separator) ? path : path + File.separator;
}
private FormatterConfig getFormatterConfig() {
ArtifactResolver resolver = new ArtifactResolver(repositorySystem, repositorySystemSession, repositories, getLog());
Provisioner provisioner = MavenProvisioner.create(resolver);
List formatterStepFactories = getFormatterStepFactories();
FileLocator fileLocator = getFileLocator();
return new FormatterConfig(baseDir, encoding, lineEndings, Optional.ofNullable(ratchetFrom), provisioner, fileLocator, formatterStepFactories, Optional.ofNullable(setLicenseHeaderYearsFromGitHistory));
}
private FileLocator getFileLocator() {
resourceManager.addSearchPath(FileResourceLoader.ID, baseDir.getAbsolutePath());
resourceManager.addSearchPath("url", "");
resourceManager.setOutputDirectory(buildDir);
return new FileLocator(resourceManager, baseDir, buildDir);
}
private List getFormatterFactories() {
return Stream.concat(formats.stream(), Stream.of(java, scala, kotlin, cpp, typescript, antlr4))
.filter(Objects::nonNull)
.collect(toList());
}
private List getFormatterStepFactories() {
return Stream.of(licenseHeader)
.filter(Objects::nonNull)
.collect(toList());
}
}