Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ jobs:
JDK21_HOME: ${{ steps.jdk21.outputs.path }}

# The binary itself on a file that needs formatting, a formatted one and one that does not parse.
# For the Windows binary this is the only check.
- name: Smoke-test the binary
run: |
binary="$PWD/$(ls open-java-format-native/build/native/nativeCompile/open-java-format-* | grep -v '\.txt$')"
Expand All @@ -102,9 +101,7 @@ jobs:
set +e; "$binary" B.java; status=$?; set -e
test "$status" -eq 2

# The Gradle plugin does not run a native image on Windows, and its tests have never run there.
- name: Test the plugins against the image
if: runner.os != 'Windows'
run: ./gradlew -PnativeImage=true :open-java-format-jdk-bootstrap:test :gradle-open-java-format:test
env:
JDK21_HOME: ${{ steps.jdk21.outputs.path }}
Expand Down
4 changes: 3 additions & 1 deletion gradle-open-java-format/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ dependencies {

tasks.register("copyNativeImage", Copy.class) {
from(configurations.formatterNativeImage)
// Named like the published artifact, whose extension is its artifact type: bin, and exe on Windows.
// The plugin's ExecutableTransform starts from that type, so a Windows binary must keep .exe.
rename { fileName ->
String.format("%s.bin", fileName)
fileName.endsWith('.exe') ? fileName : String.format("%s.bin", fileName)
}
into("$buildDir/nativeImage")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ public abstract class ExecutableTransform implements TransformAction<TransformPa
@Override
public void transform(TransformOutputs outputs) {
File inputFile = getInputArtifact().get().getAsFile();
File outputFile = outputs.file(inputFile.getName() + ".executable");
// The Windows binary keeps its name, so that it still ends in .exe like any Windows program.
String name = inputFile.getName().endsWith(".exe") ? inputFile.getName() : inputFile.getName() + ".executable";
File outputFile = outputs.file(name);
try {
Files.copy(inputFile.toPath(), outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
makeFileExecutable(outputFile.toPath());
Expand All @@ -67,6 +69,10 @@ public void transform(TransformOutputs outputs) {
}

private static void makeFileExecutable(Path pathToExe) {
// Windows file systems have no POSIX permissions, and an .exe needs none to run.
if (!pathToExe.getFileSystem().supportedFileAttributeViews().contains("posix")) {
return;
}
try {
Set<PosixFilePermission> existingPermissions = Files.getPosixFilePermissions(pathToExe);
Files.setPosixFilePermissions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.palantir.javaformat.gradle;

import com.palantir.platform.Architecture;
import com.palantir.platform.GradleOperatingSystem;
import com.palantir.platform.OperatingSystem;
import javax.inject.Inject;
Expand All @@ -37,14 +38,14 @@ public boolean isNativeImageConfigured() {
/**
* The platforms a native image is published for, and therefore the only ones where it can be
* resolved. macOS is supported on both architectures: the x86-64 image used to be excluded
* because nobody built it, and .github/workflows/ci.yml now does. musl is still absent for the
* same reason — no job produces it. Windows x86-64 is built and published, but not used here yet:
* {@link ExecutableTransform} sets POSIX permissions, which NTFS does not have, and the tests of
* this plugin have never run on Windows.
* because nobody built it, and .github/workflows/ci.yml now does. Windows has an image for
* x86-64 only, and musl none: no job produces them.
*/
private boolean isNativeImageSupported() {
return getOs().getOperatingSystem()
.map(os -> os.equals(OperatingSystem.LINUX_GLIBC) || os.equals(OperatingSystem.MACOS))
.map(os -> os.equals(OperatingSystem.LINUX_GLIBC)
|| os.equals(OperatingSystem.MACOS)
|| (os.equals(OperatingSystem.WINDOWS) && Architecture.get() == Architecture.X86_64))
.get();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -50,17 +51,20 @@ class FormatDiffTest {

@Test
void parsing_git_diff_output_works() throws IOException {
// A Windows checkout gives the fixture CRLF line endings, while git prints a diff with LF.
String example1 = Files.readString(
Paths.get("src/test/resources/com/palantir/javaformat/java/FormatDiffCliTest/example1.patch"));
Paths.get("src/test/resources/com/palantir/javaformat/java/FormatDiffCliTest/example1.patch"))
.replace("\r\n", "\n");

List<String> strings = FormatDiff.parseGitDiffOutput(example1)
.map(FormatDiff.SingleFileDiff::toString)
.collect(Collectors.toList());
assertThat(strings)
.containsExactly(
"SingleFileDiff{path=build.gradle, lineRanges=[[24..25), [29..30)]}",
"SingleFileDiff{path=tracing/src/test/java/com/palantir/tracing/TracersTest.java, "
+ "lineRanges=[[659..660), [675..676)]}");
// The path is a Path, which prints with backslashes on Windows.
"SingleFileDiff{path=" + Path.of("tracing/src/test/java/com/palantir/tracing/TracersTest.java")
+ ", lineRanges=[[659..660), [675..676)]}");
}

@ParameterizedTest
Expand Down Expand Up @@ -112,7 +116,7 @@ private static Stream<FormatterService> getFormatters() throws IOException {
}

private static List<Path> getClasspath() throws IOException {
return Splitter.on(':')
return Splitter.on(File.pathSeparatorChar)
.trimResults()
.omitEmptyStrings()
.splitToStream(Files.readString(CLASSPATH_FILE.toPath()))
Expand All @@ -122,6 +126,10 @@ private static List<Path> getClasspath() throws IOException {

private static Path javaBinPath() {
String javaHome = Preconditions.checkNotNull(System.getProperty("java.home"), "java.home property not set");
return Path.of(javaHome).resolve("bin").resolve("java");
return Path.of(javaHome).resolve("bin").resolve("java" + (isWindows() ? ".exe" : ""));
}

private static boolean isWindows() {
return System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("windows");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@

class PalantirJavaFormatIdeaPluginTest {

private static final String NATIVE_IMAGE_FILE = new File("build/nativeImage.path").getAbsolutePath();
// Forward slashes: the path goes into a Groovy string, where a Windows backslash would start an escape.
private static final String NATIVE_IMAGE_FILE =
new File("build/nativeImage.path").getAbsolutePath().replace('\\', '/');

private static final String NATIVE_CONFIG =
"palantirJavaFormatNative files(file(\"" + NATIVE_IMAGE_FILE + "\").text)";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@
class PalantirJavaFormatPluginTest {

/** ./gradlew writeImplClasspath generates this file. */
private static final String CLASSPATH_FILE = new File("build/impl.classpath").getAbsolutePath();
// Forward slashes: the path goes into a Groovy string, where a Windows backslash would start an escape.
private static final String CLASSPATH_FILE =
new File("build/impl.classpath").getAbsolutePath().replace('\\', '/');

private static final String NATIVE_IMAGE_FILE = new File("build/nativeImage.path").getAbsolutePath();
private static final String NATIVE_IMAGE_FILE =
new File("build/nativeImage.path").getAbsolutePath().replace('\\', '/');

private static final String NATIVE_CONFIG =
"palantirJavaFormatNative files(file(\"" + NATIVE_IMAGE_FILE + "\").text)";
Expand Down Expand Up @@ -59,7 +62,7 @@ void formatDiff_updates_only_lines_changed_in_git_diff(String extraGradlePropert
.buildGradle(
"""
dependencies {
palantirJavaFormat files(file("%s").text.split(':'))
palantirJavaFormat files(file("%s").text.split(File.pathSeparator))
%s
}
""",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@
class PalantirJavaFormatSpotlessPluginTest {

/** ./gradlew writeImplClasspath generates this file. */
private static final String CLASSPATH_FILE = new File("build/impl.classpath").getAbsolutePath();
// Forward slashes: the path goes into a Groovy string, where a Windows backslash would start an escape.
private static final String CLASSPATH_FILE =
new File("build/impl.classpath").getAbsolutePath().replace('\\', '/');

private static final String NATIVE_IMAGE_FILE = new File("build/nativeImage.path").getAbsolutePath();
private static final String NATIVE_IMAGE_FILE =
new File("build/nativeImage.path").getAbsolutePath().replace('\\', '/');

private static final String NATIVE_CONFIG =
"palantirJavaFormatNative files(file(\"" + NATIVE_IMAGE_FILE + "\").text)";
Expand Down Expand Up @@ -78,7 +81,7 @@ void formats_with_spotless_when_spotless_is_applied(
.buildGradle(
"""
dependencies {
palantirJavaFormat files(file("%s").text.split(':'))
palantirJavaFormat files(file("%s").text.split(File.pathSeparator))
%s
}
""",
Expand All @@ -87,7 +90,8 @@ palantirJavaFormat files(file("%s").text.split(':'))

BuildResult result = project.succeeds("spotlessApply", "--info");

assertThat(project.readFile(MAIN_JAVA)).isEqualTo(validJavaFile());
// Spotless writes the platform's line endings, CRLF on Windows.
assertThat(project.readFile(MAIN_JAVA)).isEqualToNormalizingNewlines(validJavaFile());
assertThat(result.getOutput()).contains(expectedOutput);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@

class SpotlessExcludesTest {

private static final String CLASSPATH_FILE = new File("build/impl.classpath").getAbsolutePath();
// Forward slashes: the path goes into a Groovy string, where a Windows backslash would start an escape.
private static final String CLASSPATH_FILE =
new File("build/impl.classpath").getAbsolutePath().replace('\\', '/');

private static final String SOURCE_FILE =
"""
Expand All @@ -51,7 +53,7 @@ void setup() {
.buildGradle(
"""
dependencies {
palantirJavaFormat files(file("%s").text.split(':'))
palantirJavaFormat files(file("%s").text.split(File.pathSeparator))
}
""",
CLASSPATH_FILE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
*/
class SupportsCurrentSpotlessTest {

private static final String CLASSPATH_FILE = new File("build/impl.classpath").getAbsolutePath();
// Forward slashes: the path goes into a Groovy string, where a Windows backslash would start an escape.
private static final String CLASSPATH_FILE =
new File("build/impl.classpath").getAbsolutePath().replace('\\', '/');

@TempDir
private Path projectDir;
Expand All @@ -47,7 +49,7 @@ void palantirjavaformatplugin_works_with_current_spotless() {
.buildGradle(
"""
dependencies {
palantirJavaFormat files(file("%s").text.split(':'))
palantirJavaFormat files(file("%s").text.split(File.pathSeparator))
}

// Forces realization of the spotlessJava task, creating the spotless steps. Any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.palantir.javaformat.java.FormatterException;
import com.palantir.javaformat.java.FormatterService;
import com.palantir.javaformat.java.Replacement;
import java.io.File;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -116,7 +117,7 @@ private String getTestResourceContent(String resourceName) {

private static List<Path> getClasspath() {
String classpath = System.getProperty("java.class.path");
return Splitter.on(':')
return Splitter.on(File.pathSeparatorChar)
.trimResults()
.omitEmptyStrings()
.splitToStream(classpath)
Expand Down
Loading