This is an automated email from the ASF dual-hosted git repository. royteeuwen pushed a commit to branch feature/SLING-12146-windows-build in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-committer-cli.git
commit fece945075abb99e8981160f41795a00df7143f3 Author: Roy Teeuwen <[email protected]> AuthorDate: Thu Aug 20 21:24:52 2026 +0200 SLING-12146 - fix the Windows build Three separate causes behind the nine failures in the log attached to the issue: - No .gitattributes, so Git for Windows' default core.autocrlf=true rewrote the fixtures on checkout. That broke the two tests that hash and PGP-verify a .pom byte-for-byte, and the three that compare generated mail against LF-only text blocks. Reproduced by converting the resources to CRLF locally. - JBakeContentUpdater used Files.write(Path, Iterable), which terminates lines with the platform separator. On Windows that rewrote every line of the LF-only site sources, so update-local-site would have pushed a whole-file diff to the website rather than the intended change. - downloadFileFromRepository never closed the stream it wrote each artifact to, leaking a descriptor per file. On Windows the open handle leaves the directory entry in place after the delete, which is the DirectoryNotEmptyException the issue reports. Also drops the operatingSystems pin added as a workaround in #24, so the Windows build runs again and can confirm the fix. --- .gitattributes | 3 +++ .sling-module.json | 5 +---- .../apache/sling/cli/impl/jbake/JBakeContentUpdater.java | 15 ++++++++++++--- .../apache/sling/cli/impl/nexus/RepositoryService.java | 6 ++++-- .../sling/cli/impl/nexus/RepositoryServiceTest.java | 15 +++++++++------ 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9194060 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Fixtures are hashed and PGP-verified byte-for-byte, and the email templates are compared against +# LF-only text blocks, so no checkout may rewrite line endings (Git for Windows defaults autocrlf on). +* -text diff --git a/.sling-module.json b/.sling-module.json index 5b5a5e5..1adf09b 100644 --- a/.sling-module.json +++ b/.sling-module.json @@ -1,8 +1,5 @@ { "jenkins": { - "jdks": [21], - "operatingSystems": [ - "linux" - ] + "jdks": [21] } } diff --git a/src/main/java/org/apache/sling/cli/impl/jbake/JBakeContentUpdater.java b/src/main/java/org/apache/sling/cli/impl/jbake/JBakeContentUpdater.java index b2f9cc8..401bc52 100644 --- a/src/main/java/org/apache/sling/cli/impl/jbake/JBakeContentUpdater.java +++ b/src/main/java/org/apache/sling/cli/impl/jbake/JBakeContentUpdater.java @@ -65,7 +65,7 @@ public class JBakeContentUpdater { }) .collect(Collectors.toList()); - Files.write(downloadsTemplatePath, updatedLines); + writeLines(downloadsTemplatePath, updatedLines); return new DownloadsUpdate(updated[0], otherMajor[0], alreadyCurrent[0]); } @@ -210,7 +210,7 @@ public class JBakeContentUpdater { if (!changed) releasesLines.add(dateLineIdx + 2, "* " + releaseName + " " + releaseVersion + " (" + date + ")"); - Files.write(releasesPath, releasesLines); + writeLines(releasesPath, releasesLines); } /** @@ -252,7 +252,7 @@ public class JBakeContentUpdater { newsLines.add(firstEntryIdx, entry); } - Files.write(newsPath, newsLines); + writeLines(newsPath, newsLines); return true; } @@ -269,4 +269,13 @@ public class JBakeContentUpdater { return date + "th"; } } + + /** + * Writes {@code lines} with LF terminators. {@link Files#write(Path, Iterable)} would use the platform + * separator, which on Windows rewrites every line of the LF-only site sources and produces a whole-file + * diff instead of the intended change. + */ + private static void writeLines(Path path, List<String> lines) throws IOException { + Files.writeString(path, String.join("\n", lines) + "\n", StandardCharsets.UTF_8); + } } diff --git a/src/main/java/org/apache/sling/cli/impl/nexus/RepositoryService.java b/src/main/java/org/apache/sling/cli/impl/nexus/RepositoryService.java index 80f7fdd..9ee49bf 100644 --- a/src/main/java/org/apache/sling/cli/impl/nexus/RepositoryService.java +++ b/src/main/java/org/apache/sling/cli/impl/nexus/RepositoryService.java @@ -21,6 +21,7 @@ package org.apache.sling.cli.impl.nexus; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -433,8 +434,9 @@ public class RepositoryService { } String fileName = relativeFilePath.substring(relativeFilePath.lastIndexOf('/') + 1); Path filePath = Files.createFile(artifactFolderPath.resolve(fileName)); - try (InputStream content = response.getEntity().getContent()) { - IOUtils.copyLarge(content, Files.newOutputStream(filePath)); + try (InputStream content = response.getEntity().getContent(); + OutputStream target = Files.newOutputStream(filePath)) { + IOUtils.copyLarge(content, target); } return true; } diff --git a/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryServiceTest.java b/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryServiceTest.java index 6c16afa..0234efe 100644 --- a/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryServiceTest.java +++ b/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryServiceTest.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.sling.cli.impl.CredentialsService; @@ -143,17 +144,19 @@ public class RepositoryServiceTest { for (Artifact artifact : localRepository.getArtifacts()) { assertTrue(Files.exists(localRepository.getRootFolder().resolve(artifact.getRepositoryRelativePath()))); } - List<Path> artifactFiles = Files.walk(localRepository.getRootFolder()) - .filter(path -> path.toFile().isFile()) - .collect(Collectors.toList()); + List<Path> artifactFiles; + try (Stream<Path> paths = Files.walk(localRepository.getRootFolder())) { + artifactFiles = paths.filter(Files::isRegularFile).collect(Collectors.toList()); + } LOGGER.debug("Cleaning {}.", localRepository.getRootFolder()); for (Path artifactFile : artifactFiles) { LOGGER.debug("Deleting file {}.", artifactFile.toString()); Files.delete(artifactFile); } - List<Path> emptyDirectories = Files.walk(localRepository.getRootFolder()) - .filter(path -> path.toFile().isDirectory()) - .collect(Collectors.toList()); + List<Path> emptyDirectories; + try (Stream<Path> paths = Files.walk(localRepository.getRootFolder())) { + emptyDirectories = paths.filter(Files::isDirectory).collect(Collectors.toList()); + } Collections.reverse(emptyDirectories); for (Path directory : emptyDirectories) { LOGGER.debug("Deleting empty folder {}.", directory.toString());
