com.palantir.baseline.plugins.BaselineConfig Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-baseline-java Show documentation
Show all versions of gradle-baseline-java Show documentation
A Gradle plugin for applying Baseline-recommended build and IDE settings
/*
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
*
* 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.palantir.baseline.plugins;
import com.palantir.baseline.plugins.BaselineFormat.FormatterState;
import java.io.FileReader;
import java.io.FileWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
/** Extracts Baseline configuration into the configuration directory. */
class BaselineConfig extends AbstractBaselinePlugin {
public void apply(Project rootProject) {
this.project = rootProject;
if (!rootProject.equals(rootProject.getRootProject())) {
throw new IllegalArgumentException(
BaselineConfig.class.getCanonicalName() + " plugin can only be applied to the root project.");
}
Configuration configuration = rootProject.getConfigurations().create("baseline");
// users can still override this default dependency, it just reduces boilerplate
Optional version = Optional.ofNullable(getClass().getPackage().getImplementationVersion());
configuration.defaultDependencies(d -> d.add(rootProject
.getDependencies()
.create(String.format(
"com.palantir.baseline:gradle-baseline-java-config%s@zip",
version.map(v -> ":" + v).orElse("")))));
// Create task for generating configuration.
rootProject.getTasks().register("baselineUpdateConfig", task -> {
task.setGroup("Baseline");
task.setDescription("Installs or updates Baseline configuration files in .baseline/");
task.getInputs().files(configuration);
task.getOutputs().dir(getConfigDir());
task.getOutputs().dir(rootProject.getRootDir().toPath().resolve("project"));
task.doLast(new BaselineUpdateConfigAction(configuration, rootProject));
});
}
private class BaselineUpdateConfigAction implements Action {
private final Configuration configuration;
private final Project rootProject;
BaselineUpdateConfigAction(Configuration configuration, Project rootProject) {
this.configuration = configuration;
this.rootProject = rootProject;
}
@Override
public void execute(Task task) {
if (configuration.getFiles().size() != 1) {
throw new IllegalArgumentException("Expected to find exactly one config dependency in the "
+ "'baseline' configuration, found: "
+ configuration.getFiles());
}
Path configDir = Paths.get(BaselineConfig.this.getConfigDir());
rootProject.copy(copySpec -> {
copySpec.from(rootProject.zipTree(configuration.getSingleFile()));
copySpec.into(configDir);
copySpec.exclude("**/scalastyle_config.xml");
copySpec.setIncludeEmptyDirs(false);
if (!BaselineFormat.eclipseFormattingEnabled(task.getProject())) {
copySpec.exclude("**/spotless/eclipse.xml");
}
});
// Disable some checkstyle rules that clash with PJF
if (BaselineFormat.palantirJavaFormatterState(rootProject) != FormatterState.OFF
|| project.getPluginManager().hasPlugin("com.palantir.java-format-provider")) {
Path checkstyleXml = configDir.resolve("checkstyle/checkstyle.xml");
try {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
InputSource inputSource = new InputSource(new FileReader(checkstyleXml.toFile()));
inputSource.setEncoding("UTF-8");
Document document = builder.parse(inputSource);
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
removeNode(document, xPath, "//module[@name='Indentation']");
removeNode(document, xPath, "//module[@name='ParenPad']");
removeNode(document, xPath, "//module[@name='LeftCurly']");
removeNode(document, xPath, "//module[@name='WhitespaceAround']");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(
OutputKeys.DOCTYPE_PUBLIC, document.getDoctype().getPublicId());
transformer.setOutputProperty(
OutputKeys.DOCTYPE_SYSTEM, document.getDoctype().getSystemId());
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(new FileWriter(checkstyleXml.toFile()));
transformer.transform(source, result);
} catch (Exception e) {
throw new RuntimeException("Unable to patch " + checkstyleXml, e);
}
}
}
private void removeNode(Document document, XPath xPath, String expression) throws XPathExpressionException {
xPath.reset();
Node node = (Node) xPath.compile(expression).evaluate(document, XPathConstants.NODE);
node.getParentNode().removeChild(node);
}
}
}