-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Option to pack jars as uber JAR, support Proguard for uber JAR (#4136)
## Proposed changes 1. Added support to join JARs to the uber JAR with ProGuard, disabled by default: ``` compose.desktop { application { buildTypes.release.proguard { joinOutputJars.set(true) } } } ``` 2. All 'release' tasks now really depend on ProGuard, as stated in [tutorial](https://github.com/JetBrains/compose-multiplatform/tree/master/tutorials/Native_distributions_and_local_execution#minification--obfuscation). ## Testing - A new auto test - Manual: 1. Test on Windows/macOs/Linux 2. Test the new Gradle parameter `joinOutputJars`: ``` compose.desktop { application { buildTypes.release.proguard { joinOutputJars.set(true) } } } ``` `false` (by default) should generate multiple jars (except for `package*UberJarForCurrentOS`) `true` should generate a single jar in a result distribution 3. Test debug tasks: ``` run runDistributable createDistributable packageUberJarForCurrentOS ``` 4. Test release tasks: ``` runRelease runReleaseDistributable createReleaseDistributable packageReleaseUberJarForCurrentOS ``` The jars should be reduced in size (because Proguard is enabled in the release mode) This should be test by QA. ## Issues fixed Fixes #4129 --------- Co-authored-by: Igor Demin <[email protected]>
- Loading branch information
1 parent
6a481b3
commit 994f0c6
Showing
7 changed files
with
275 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
...ns/compose/src/main/kotlin/org/jetbrains/compose/desktop/tasks/AbstractJarsFlattenTask.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* | ||
* Copyright 2020-2024 JetBrains s.r.o. and respective authors and developers. | ||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. | ||
*/ | ||
|
||
package org.jetbrains.compose.desktop.tasks | ||
|
||
import org.gradle.api.file.ConfigurableFileCollection | ||
import org.gradle.api.file.RegularFileProperty | ||
import org.gradle.api.tasks.InputFiles | ||
import org.gradle.api.tasks.Internal | ||
import org.gradle.api.tasks.OutputFile | ||
import org.gradle.api.tasks.TaskAction | ||
import org.jetbrains.compose.desktop.application.internal.files.copyZipEntry | ||
import org.jetbrains.compose.desktop.application.internal.files.isJarFile | ||
import org.jetbrains.compose.internal.utils.delete | ||
import org.jetbrains.compose.internal.utils.ioFile | ||
import java.io.File | ||
import java.io.FileInputStream | ||
import java.io.FileOutputStream | ||
import java.io.InputStream | ||
import java.util.zip.ZipEntry | ||
import java.util.zip.ZipInputStream | ||
import java.util.zip.ZipOutputStream | ||
|
||
|
||
/** | ||
* This task flattens all jars from the input directory into the single one, | ||
* which is used later as a single source for uberjar. | ||
* | ||
* This task is necessary because the standard Jar/Zip task evaluates own `from()` args eagerly | ||
* [in the configuration phase](https://discuss.gradle.org/t/why-is-the-closure-in-from-method-of-copy-task-evaluated-in-config-phase/23469/4) | ||
* and snapshots an empty list of files in the Proguard destination directory, | ||
* instead of a list of real jars after Proguard task execution. | ||
* | ||
* Also, we use output to the single jar instead of flattening to the directory in the filesystem because: | ||
* - Windows filesystem is case-insensitive and not every jar can be unzipped without losing files | ||
* - it's just faster | ||
*/ | ||
abstract class AbstractJarsFlattenTask : AbstractComposeDesktopTask() { | ||
|
||
@get:InputFiles | ||
val inputFiles: ConfigurableFileCollection = objects.fileCollection() | ||
|
||
@get:OutputFile | ||
val flattenedJar: RegularFileProperty = objects.fileProperty() | ||
|
||
@get:Internal | ||
val seenEntryNames = hashSetOf<String>() | ||
|
||
@TaskAction | ||
fun execute() { | ||
seenEntryNames.clear() | ||
fileOperations.delete(flattenedJar) | ||
|
||
ZipOutputStream(FileOutputStream(flattenedJar.ioFile).buffered()).use { outputStream -> | ||
inputFiles.asFileTree.visit { | ||
when { | ||
!it.isDirectory && it.file.isJarFile -> outputStream.writeJarContent(it.file) | ||
!it.isDirectory -> outputStream.writeFile(it.file) | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun ZipOutputStream.writeJarContent(jarFile: File) = | ||
ZipInputStream(FileInputStream(jarFile)).use { inputStream -> | ||
var inputEntry: ZipEntry? = inputStream.nextEntry | ||
while (inputEntry != null) { | ||
writeEntryIfNotSeen(inputEntry, inputStream) | ||
inputEntry = inputStream.nextEntry | ||
} | ||
} | ||
|
||
private fun ZipOutputStream.writeFile(file: File) = | ||
FileInputStream(file).use { inputStream -> | ||
writeEntryIfNotSeen(ZipEntry(file.name), inputStream) | ||
} | ||
|
||
private fun ZipOutputStream.writeEntryIfNotSeen(entry: ZipEntry, inputStream: InputStream) { | ||
if (entry.name !in seenEntryNames) { | ||
copyZipEntry(entry, inputStream, this) | ||
seenEntryNames += entry.name | ||
} | ||
} | ||
} |
Oops, something went wrong.