Skip to content

Commit

Permalink
refactor: minimize the 'admin' application, provide only one JAR for …
Browse files Browse the repository at this point in the history
…the sync script to simplify the usage (#15)

* refactor: minimize the 'admin' application

* refactor: obfuscated and minimized JAR files
  • Loading branch information
EchoEllet authored Jul 4, 2024
1 parent de3274a commit 44ca1ec
Show file tree
Hide file tree
Showing 14 changed files with 165 additions and 59 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/runConfigurations/Run_JAR.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/runConfigurations/Run_JAR__Cli_.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/runConfigurations/Run_Minimized_JAR.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/runConfigurations/Run_Minimized_JAR__Cli_.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions .idea/runConfigurations/Run_Obfuscated_JAR.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions .idea/runConfigurations/Run_Obfuscated_JAR__Cli_.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 9 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,17 @@ Use one of the shared run configurations of IntelliJ IDEA in `.idea` which will
If you're not using any of the supported IDEs, text editor or something like `vim` and you want to test the changes,
and you want to test the code changes, you can use the following Gradle tasks:

- `./gradlew build` to build the project, running checks, tests and build JAR files
- `./gradlew minimizedJar` to build the full JAR file to build the minimized one
- `./gradlew build` to build the project, running checks, lints, tests and build JAR files
- `./gradlew run` to run the application
- `./gradlew runJar` to run the application using the JAR file in GUI mode
- `./gradlew runJarCli` to run the application using the JAR file in non-GUI mode
- `./gradlew shadowJar` to build the uber JAR file
- `./gradlew runJar` to run the application using the uber JAR file in GUI mode
- `./gradlew runJarCli` to run the application using the uber JAR file in non-GUI mode
- `./gradlew minimizedJar` to build the minimized JAR file.
- `./gradlew runMinimizedJar` to run the application using the minimized JAR file in GUI mode
- `./gradlew runMinimizedJarCli` to run the application using the minimized JAR file in non-GUI mode
- `./gradlew obfuscatedJar` to build the obfuscated JAR file.
- `./gradlew runObfuscatedJar` to run the application using the obfuscated JAR file in GUI mode
- `./gradlew runObfuscatedJarCli` to run the application using the obfuscated JAR file in non-GUI mode

</details>

Expand Down Expand Up @@ -155,7 +159,7 @@ discussed above
- When doing any code changes, use the Kotlin Run configuration to test them, if possible, also try to run the JAR
using the run configurations that are provided as in `.idea` and as a Gradle task to make it work with other IDEs and
text editor, as a bonus, you could also test the minimized JAR and modify the Proguard rules and configurations if
necessary
necessary.
- Usually when we add a new fields or modify existing ones in the data classes, like, for example, adding `description`
field in the `Mod` data class, we will try to update the [Admin](./admin) module too to convert the new
data from other launchers to make the process easier for administrations
Expand Down
17 changes: 6 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
![Build and test](https://github.com/ellet0/kraft-sync/actions/workflows/build.yml/badge.svg?branch=main)
![GitHub repo size](https://img.shields.io/github/repo-size/ellet0/kraft-sync)
![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/ellet0/kraft-sync)
![JAR Size](https://img.shields.io/badge/JAR_Size-4.60_MB-blue)
![Minimized JAR Size](https://img.shields.io/badge/Minimized_JAR_Size-1.55_MB-blue)
![JAR Size](https://img.shields.io/badge/JAR_Size-2.46_MB-blue)
![Obfuscated JAR Size](https://img.shields.io/badge/Minimized_JAR_Size-1.59_MB-blue)
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/ellet0/kraft-sync/total)
![GitHub Repo stars](https://img.shields.io/github/stars/ellet0/kraft-sync)

Expand Down Expand Up @@ -339,7 +339,7 @@ issues, it's easier to set up and maintain yet less flexible and simpler
</details>

<details>
<summary id="q6">Why is the JAR file size not smaller?</summary>
<summary id="q6">Can the JAR file be smaller?</summary>
Although the script has only one task, the bundle size is not too small. You might wonder why this is the case if
Java is already installed on the system/launcher.

Expand Down Expand Up @@ -371,14 +371,9 @@ There are some technical reasons:
4. **Features**: The script provides some features like dark and light mode support with different themes
which makes the bundle size a little bit larger

We will try to find a good balance between the features and the bundle size, we
use a tool called [Proguard](https://www.guardsquare.com/proguard) which makes it easy to shrink and minimize
the JAR file, sometimes it doesn't if it should keep something or remove it due to reflections and dynamic class
loading, we will try to always test it and make sure the minimized JAR works as expected and will also provide both
the minimized JAR and the full JAR files in the release assets which can be found in the [Releases].

if the JAR file is a priority, use the minimized JAR.
if you would rather not risk getting unexpected errors at runtime, use the normal JAR
We will try to find a good balance between the features and the bundle size.
We use a tool called [Proguard](https://www.guardsquare.com/proguard) to shrink and minimize
the JAR file.

</details>

Expand Down
27 changes: 25 additions & 2 deletions admin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ application {
mainClass = "MainKt"
}

val distDirectory
get() = project.rootDir.resolve("dist")

tasks.shadowJar {
val scriptJarFileNameWithoutExtension = rootProject.name
// If you change the file name or destination directory, also update it from the README.md and other markdown files
archiveFileName.set("$scriptJarFileNameWithoutExtension-admin.jar")
destinationDirectory = project.rootDir.resolve("dist")
description = "A admin utility program for $scriptJarFileNameWithoutExtension script."
minimize {
// Exclude the entire FlatLaf dependency from minimization to fix `no ComponentUI class for: javax.swing.<component>`
Expand All @@ -57,7 +59,28 @@ tasks.shadowJar {
}
}

val minimizedJar =
tasks.register<BuildMinimizedJarTask>("minimizedJar") {
dependsOn(tasks.shadowJar)

val uberJarFile = tasks.shadowJar.flatMap { it.archiveFile }

inputJarFile = uberJarFile
outputJarFile =
distDirectory
.resolve("${uberJarFile.get().asFile.nameWithoutExtension}.jar")

proguardConfigFile = project(projects.common.identityPath.path).file("proguard.pro")
obfuscate = false
compileClasspath = sourceSets.main.get().compileClasspath
additionalJdkModules =
listOf(
// For Java Clipboard
"java.datatransfer",
)
}

tasks.assemble {
// The `assemble` task already depends on `shadowJar`
dependsOn(tasks.shadowJar)
dependsOn(tasks.shadowJar, minimizedJar)
}
32 changes: 20 additions & 12 deletions buildSrc/src/main/kotlin/BuildMinimizedJarTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.logging.LogLevel
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.listProperty
import org.gradle.kotlin.dsl.property
import proguard.gradle.ProGuardTask
import java.io.File
Expand Down Expand Up @@ -36,6 +38,9 @@ open class BuildMinimizedJarTask : DefaultTask() {
@get:InputFiles
val compileClasspath: ConfigurableFileCollection = project.objects.fileCollection()

@get:Input
val additionalJdkModules: ListProperty<String> = project.objects.listProperty()

@TaskAction
fun execute() {
val buildProguardDirectory =
Expand Down Expand Up @@ -78,7 +83,10 @@ open class BuildMinimizedJarTask : DefaultTask() {
}
}

val proguardTask = project.tasks.create<ProGuardTask>("proguard")
val isObfuscatedEnabled = obfuscate.get()

val proguardTask =
project.tasks.create<ProGuardTask>(name = if (isObfuscatedEnabled) "proguardWithObfuscation" else "proguard")
proguardTask.apply {
injars(inputJarFile)
outjars(outputJarFile)
Expand All @@ -100,7 +108,7 @@ open class BuildMinimizedJarTask : DefaultTask() {
)
}

val javaModules =
val javaModules: List<String> =
listOf(
"java.base",
// Needed to support Java Swing/Desktop
Expand All @@ -109,7 +117,7 @@ open class BuildMinimizedJarTask : DefaultTask() {
"java.prefs",
// Needed to support Java logging utils (needed by Okio)
"java.logging",
)
) + additionalJdkModules.get()
javaModules.forEach { includeJavaModuleFromJdk(jModFileNameWithoutExtension = it) }
}

Expand All @@ -125,7 +133,7 @@ open class BuildMinimizedJarTask : DefaultTask() {
.resolve("${outputJarFile.get().asFile.nameWithoutExtension}.map"),
)

if (!obfuscate.get()) {
if (!isObfuscatedEnabled) {
// Disabling obfuscation makes the JAR file size a bit larger, and the debugging process a bit less easy
dontobfuscate()
}
Expand All @@ -152,21 +160,21 @@ open class BuildMinimizedJarTask : DefaultTask() {
proguardTask.actions.forEach { it.execute(proguardTask) }
}

logResultMessage()
logResultMessage(isObfuscatedEnabled = isObfuscatedEnabled)
}

private fun logResultMessage() {
val original = inputJarFile.get().asFile
val minimized = outputJarFile.get().asFile
val minimizedFileSizeInMegabytes = String.format("%.2f", minimized.length().toDouble() / (1024L * 1024L))
private fun logResultMessage(isObfuscatedEnabled: Boolean) {
val originalJarFile = inputJarFile.get().asFile
val minimizedJarFile = outputJarFile.get().asFile
val minimizedFileSizeInMegabytes = String.format("%.2f", minimizedJarFile.length().toDouble() / (1024L * 1024L))

val percentageDifference =
((minimized.length() - original.length()).toDouble() / original.length()) * 100
((minimizedJarFile.length() - originalJarFile.length()).toDouble() / originalJarFile.length()) * 100
val formattedPercentageDifference = String.format("%.2f%%", kotlinMathAbs(percentageDifference))

logger.lifecycle(
"📦 The size of the Proguard minimized JAR file (${minimized.name}) is $minimizedFileSizeInMegabytes MB." +
" The size has been reduced \uD83D\uDCC9 by $formattedPercentageDifference. Location: ${minimized.path}",
"📦 The size of the Proguard ${if (isObfuscatedEnabled) "obfuscated" else "minimized"} JAR file (${minimizedJarFile.name}) is $minimizedFileSizeInMegabytes MB." +
" The size has been reduced \uD83D\uDCC9 by $formattedPercentageDifference. Location: ${minimizedJarFile.path}",
)
}

Expand Down
2 changes: 1 addition & 1 deletion common/src/main/kotlin/constants/ProjectInfoConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ object ProjectInfoConstants {
"https://raw.githubusercontent.com/ellet0/kraft-sync/main/gradle/libs.versions.toml"

// TODO: This will always download the latest pre-release, will need to update the URL later
const val LATEST_SYNC_SCRIPT_JAR_FILE_URL = "https://github.com/ellet0/kraft-sync/releases/download/latest/kraft-sync.min.jar"
const val LATEST_SYNC_SCRIPT_JAR_FILE_URL = "https://github.com/ellet0/kraft-sync/releases/download/latest/kraft-sync.jar"
}
Loading

0 comments on commit 44ca1ec

Please sign in to comment.