|
1 | 1 | package io.quarkus.gradle.tasks; |
2 | 2 |
|
3 | 3 | import java.io.File; |
| 4 | +import java.io.IOException; |
| 5 | +import java.nio.file.Files; |
4 | 6 | import java.nio.file.Path; |
5 | 7 | import java.util.Map; |
6 | 8 | import java.util.stream.Collectors; |
7 | 9 |
|
8 | 10 | import javax.inject.Inject; |
9 | 11 |
|
| 12 | +import org.gradle.api.Action; |
10 | 13 | import org.gradle.api.GradleException; |
11 | 14 | import org.gradle.api.file.FileCollection; |
| 15 | +import org.gradle.api.file.FileCopyDetails; |
12 | 16 | import org.gradle.api.file.FileSystemOperations; |
13 | 17 | import org.gradle.api.logging.LogLevel; |
14 | 18 | import org.gradle.api.tasks.Classpath; |
@@ -168,6 +172,9 @@ void generateBuild() { |
168 | 172 | PackageConfig.BuiltInType packageType = packageType(); |
169 | 173 | getLogger().info("Building Quarkus app for package type {} in {}", packageType, genDir); |
170 | 174 |
|
| 175 | + // Need to delete app-cds.jsa specially, because it's usually read-only and Gradle's delete file-system |
| 176 | + // operation doesn't delete "read only" files :( |
| 177 | + deleteFileIfExists(genDir.resolve(outputDirectory()).resolve("app-cds.jsa")); |
171 | 178 | getFileSystemOperations().delete(delete -> { |
172 | 179 | // Caching and "up-to-date" checks depend on the inputs, this 'delete()' should ensure that the up-to-date |
173 | 180 | // checks work against "clean" outputs, considering that the outputs depend on the package-type. |
@@ -223,6 +230,7 @@ void generateBuild() { |
223 | 230 | getFileSystemOperations().copy(copy -> { |
224 | 231 | copy.from(buildDir); |
225 | 232 | copy.into(genDir); |
| 233 | + copy.eachFile(new CopyActionDeleteNonWriteableTarget(genDir)); |
226 | 234 | switch (packageType) { |
227 | 235 | case NATIVE: |
228 | 236 | copy.include(nativeRunnerFileName()); |
@@ -261,4 +269,32 @@ void abort(String message, Object... args) { |
261 | 269 | }); |
262 | 270 | throw new StopExecutionException(); |
263 | 271 | } |
| 272 | + |
| 273 | + public static final class CopyActionDeleteNonWriteableTarget implements Action<FileCopyDetails> { |
| 274 | + private final Path destDir; |
| 275 | + |
| 276 | + public CopyActionDeleteNonWriteableTarget(Path destDir) { |
| 277 | + this.destDir = destDir; |
| 278 | + } |
| 279 | + |
| 280 | + @Override |
| 281 | + public void execute(FileCopyDetails details) { |
| 282 | + // Delete a pre-existing non-writeable file, otherwise a copy or sync operation would fail. |
| 283 | + // This situation happens for 'app-cds.jsa' files, which are created as "read only" files, |
| 284 | + // prefer to keep those files read-only. |
| 285 | + |
| 286 | + Path destFile = destDir.resolve(details.getPath()); |
| 287 | + if (Files.exists(destFile) && !Files.isWritable(destFile)) { |
| 288 | + deleteFileIfExists(destFile); |
| 289 | + } |
| 290 | + } |
| 291 | + } |
| 292 | + |
| 293 | + protected static void deleteFileIfExists(Path file) { |
| 294 | + try { |
| 295 | + Files.deleteIfExists(file); |
| 296 | + } catch (IOException e) { |
| 297 | + throw new RuntimeException(e); |
| 298 | + } |
| 299 | + } |
264 | 300 | } |
0 commit comments