Skip to content

Commit 48ad48f

Browse files
ADFA-4636: Fix three correctness issues in stripJar
- Use removeSuffix(".jar") instead of replace(".jar", ...) so only the trailing extension is affected, not any earlier occurrence in the name - Add a .prefixes companion file alongside the stripped JAR so changes to excludeEntryPrefixes invalidate the cached output even when the source JAR mtime is unchanged - Write to a .tmp file and atomically rename to dest on success; delete the temp file on any failure to prevent partial output from being treated as valid on subsequent builds Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
1 parent d557b26 commit 48ad48f

1 file changed

Lines changed: 33 additions & 12 deletions

File tree

composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/ExternalAssetsPlugin.kt

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import org.gradle.api.provider.Provider
2020
import org.gradle.kotlin.dsl.dependencies
2121
import org.gradle.kotlin.dsl.newInstance
2222
import java.io.File
23+
import java.nio.file.AtomicMoveNotSupportedException
24+
import java.nio.file.Files
25+
import java.nio.file.StandardCopyOption
2326
import java.util.zip.ZipEntry
2427
import java.util.zip.ZipInputStream
2528
import java.util.zip.ZipOutputStream
@@ -85,7 +88,7 @@ abstract class ExternalAssetsExtension @Inject constructor(
8588
config.jarName
8689
} else {
8790
val original = cacheDir.resolve(config.jarName)
88-
val stripped = cacheDir.resolve(config.jarName.replace(".jar", "-stripped.jar"))
91+
val stripped = cacheDir.resolve("${config.jarName.removeSuffix(".jar")}-stripped.jar")
8992
stripJar(original, stripped, config.excludeEntryPrefixes, project.logger)
9093
stripped.name
9194
}
@@ -101,24 +104,42 @@ abstract class ExternalAssetsExtension @Inject constructor(
101104
}
102105

103106
private fun stripJar(source: File, dest: File, excludePrefixes: List<String>, logger: Logger) {
104-
if (dest.exists() && dest.lastModified() >= source.lastModified()) {
107+
val prefixesFile = File(dest.parentFile, "${dest.name}.prefixes")
108+
val currentPrefixContent = excludePrefixes.sorted().joinToString("\n")
109+
val upToDate = dest.exists()
110+
&& dest.lastModified() >= source.lastModified()
111+
&& prefixesFile.exists()
112+
&& prefixesFile.readText() == currentPrefixContent
113+
if (upToDate) {
105114
logger.lifecycle("Skipping strip of ${source.name}: stripped copy is up-to-date")
106115
return
107116
}
108117
logger.lifecycle("Stripping ${excludePrefixes.size} prefix(es) from ${source.name}")
109-
ZipInputStream(source.inputStream().buffered()).use { zin ->
110-
ZipOutputStream(dest.outputStream().buffered()).use { zout ->
111-
var entry: ZipEntry? = zin.nextEntry
112-
while (entry != null) {
113-
if (excludePrefixes.none { entry!!.name.startsWith(it) }) {
114-
zout.putNextEntry(ZipEntry(entry.name))
115-
zin.copyTo(zout)
116-
zout.closeEntry()
118+
val tmp = File(dest.parentFile, "${dest.name}.tmp")
119+
try {
120+
ZipInputStream(source.inputStream().buffered()).use { zin ->
121+
ZipOutputStream(tmp.outputStream().buffered()).use { zout ->
122+
var entry: ZipEntry? = zin.nextEntry
123+
while (entry != null) {
124+
if (excludePrefixes.none { entry!!.name.startsWith(it) }) {
125+
zout.putNextEntry(ZipEntry(entry.name))
126+
zin.copyTo(zout)
127+
zout.closeEntry()
128+
}
129+
zin.closeEntry()
130+
entry = zin.nextEntry
117131
}
118-
zin.closeEntry()
119-
entry = zin.nextEntry
120132
}
121133
}
134+
try {
135+
Files.move(tmp.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE)
136+
} catch (_: AtomicMoveNotSupportedException) {
137+
Files.move(tmp.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING)
138+
}
139+
prefixesFile.writeText(currentPrefixContent)
140+
} catch (e: Exception) {
141+
tmp.delete()
142+
throw e
122143
}
123144
val savedKb = (source.length() - dest.length()) / 1024
124145
logger.lifecycle("Stripped ${source.name}: saved ${savedKb} KB (${source.length()}${dest.length()} bytes)")

0 commit comments

Comments
 (0)