Skip to content

Commit

Permalink
Minimize the "ktlint" ShadowJar
Browse files Browse the repository at this point in the history
When creating a shadow jar of a specific ktlint ruleset all transitive dependencies are included in that jar. Combining the individual ruleset shadow jars in the plugin-jar blows up the size of the plugin jar as the same dependencies are included multiple times. By first combining the ruleset shadow jars into another shadowed jar the duplicate dependencies are pruned.

Closes #498
  • Loading branch information
paul-dingemans committed Apr 10, 2024
1 parent 773b912 commit c5ed7ee
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 36 deletions.
6 changes: 5 additions & 1 deletion ktlint-lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ The Ktlint RuleEngine core module requires certain elements of the kotlin compil

## Ruleset

Each ruleset library transforms the StandardRuleSetProvider of that version to a unique class name so that multiple versions of the Standard rule sets can be supported by the plugin. The plugin allows the user to configure one of the supported ktlint versios. In this way, the user can keep the configuration of the ktlint intellij plugin in sync with other plugins like the ktlint gradle plugin or kotlinter.
Each ruleset library transforms the StandardRuleSetProvider of that version to a unique class name so that multiple versions of the Standard rule sets can be supported by the plugin. The plugin allows the user to configure one of the supported ktlint versions. In this way, the user can keep the configuration of the ktlint intellij plugin in sync with other plugins like the ktlint gradle plugin or kotlinter.

# ktlint-lib

The ktlint-lib module itself contains the `KtlintRulesetVersion` class which contains the references to the distinct versions of the rulesets. Also, it contains the `ShadowJarMinimizeHelper` class containing references to classes which are also used in the `plugin` module to prevent that those classes are removed by the minimize process of the Shadow Jar.
64 changes: 64 additions & 0 deletions ktlint-lib/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("java") // Java support
alias(libs.plugins.kotlin) // Kotlin support
alias(libs.plugins.shadow)
}

repositories {
mavenCentral()
}

dependencies {
compileOnly(project(":ktlint-lib:core")) // Required for IDE
implementation(project(":ktlint-lib:core", "shadow"))

compileOnly(project(":ktlint-lib:ruleset-0-50-0")) // Required for IDE
implementation(project(":ktlint-lib:ruleset-0-50-0", "shadow"))

compileOnly(project(":ktlint-lib:ruleset-1-0-1")) // Required for IDE
implementation(project(":ktlint-lib:ruleset-1-0-1", "shadow"))

compileOnly(project(":ktlint-lib:ruleset-1-1-1")) // Required for IDE
implementation(project(":ktlint-lib:ruleset-1-1-1", "shadow"))

compileOnly(project(":ktlint-lib:ruleset-1-2-1")) // Required for IDE
implementation(project(":ktlint-lib:ruleset-1-2-1", "shadow"))

implementation("com.rollbar:rollbar-java:1.10.0") {
exclude(group = "org.slf4j") // Duplicated in IDE environment
}

// Tests:
testImplementation(project(":ktlint-lib:core"))
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
testImplementation("org.junit.platform:junit-platform-launcher:1.10.2")
testImplementation("io.mockk:mockk:1.13.10")
}

tasks {
// Set the compatibility versions to 11
withType<JavaCompile> {
sourceCompatibility = "11"
targetCompatibility = "11"
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}

withType<ShadowJar> {
val api = project.configurations.api.get()
val impl = project.configurations.implementation.get()

configurations = listOf(api, impl).map { it.apply { isCanBeResolved = true } }

// Expose all ruleset implementations:
mergeServiceFiles()

// Remove all classes which are not referenced. Note that classes that are reference inside the "plugin" module might need to be
// added to ShadowJarMinimizeHelper to prevent that they are removed.
minimize()
}
}
6 changes: 3 additions & 3 deletions ktlint-lib/ruleset-0-50-0/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ tasks {

relocate(
"com.pinterest.ktlint.logger",
"shadow.com.pinterest.ktlint-0-50-0.logger",
"com.pinterest.ktlint-0-50-0.logger",
)
relocate(
"com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider",
"shadow.com.pinterest.ktlint.ruleset.standard.StandardRuleSetProviderV0_50_0",
"com.pinterest.ktlint.ruleset.standard",
"com.pinterest.ktlint.ruleset.standard.V0_50_0",
)
}
}
4 changes: 2 additions & 2 deletions ktlint-lib/ruleset-1-0-1/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ tasks {
configurations = listOf(api, impl).map { it.apply { isCanBeResolved = true } }

relocate(
"com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider",
"shadow.com.pinterest.ktlint.ruleset.standard.StandardRuleSetProviderV1_00_1",
"com.pinterest.ktlint.ruleset.standard",
"com.pinterest.ktlint.ruleset.standard.V1_00_1",
)
}
}
4 changes: 2 additions & 2 deletions ktlint-lib/ruleset-1-1-1/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ tasks {
configurations = listOf(api, impl).map { it.apply { isCanBeResolved = true } }

relocate(
"com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider",
"shadow.com.pinterest.ktlint.ruleset.standard.StandardRuleSetProviderV1_01_1",
"com.pinterest.ktlint.ruleset.standard",
"com.pinterest.ktlint.ruleset.standard.V1_01_1",
)
}
}
4 changes: 2 additions & 2 deletions ktlint-lib/ruleset-1-2-1/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ tasks {
configurations = listOf(api, impl).map { it.apply { isCanBeResolved = true } }

relocate(
"com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider",
"shadow.com.pinterest.ktlint.ruleset.standard.StandardRuleSetProviderV1_02_1",
"com.pinterest.ktlint.ruleset.standard",
"com.pinterest.ktlint.ruleset.standard.V1_02_1",
)
}
}
28 changes: 28 additions & 0 deletions ktlint-lib/src/main/kotlin/ShadowJarMinimizeHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@file:Suppress("unused")

import com.pinterest.ktlint.cli.reporter.baseline.BaselineErrorHandling
import com.pinterest.ktlint.cli.reporter.baseline.BaselineLoaderException
import com.pinterest.ktlint.cli.reporter.baseline.loadBaseline
import com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError
import com.pinterest.ktlint.rule.engine.api.Code
import com.pinterest.ktlint.rule.engine.api.EditorConfigOverride
import com.pinterest.ktlint.rule.engine.api.KtLintParseException
import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine
import com.pinterest.ktlint.rule.engine.api.KtlintSuppressionAtOffset
import com.pinterest.ktlint.rule.engine.api.LintError
import com.pinterest.ktlint.rule.engine.api.insertSuppression
import com.pinterest.ktlint.rule.engine.core.api.RuleId

// When the Shadow jar is created, it is also minimized. This means that all unreferenced classes are removed. In this class we define
// reference to objects that are used by the plugin so that they will not be removed when minimizing the jar.
private class ShadowJarMinimizeHelper {
val lintError: LintError? = null
val xxx = loadBaseline("xxx", BaselineErrorHandling.EXCEPTION)
val baselineLoaderException: BaselineLoaderException? = null
val ktlintCliError: KtlintCliError? = null
val xx = EditorConfigOverride.EMPTY_EDITOR_CONFIG_OVERRIDE
val ktLintRuleEngine: KtLintRuleEngine? = null
val ktLintParseException: KtLintParseException? = null
val ktlintSuppressionAtOffset: KtlintSuppressionAtOffset? = null
val code = ktLintRuleEngine?.insertSuppression(Code.fromSnippet("", true), KtlintSuppressionAtOffset(1, 1, RuleId("xxx")))
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.nbadal.ktlint
package com.pinterest.ktlint.ruleset.standard

import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3
import shadow.com.pinterest.ktlint.ruleset.standard.StandardRuleSetProviderV0_50_0
import shadow.com.pinterest.ktlint.ruleset.standard.StandardRuleSetProviderV1_00_1
import shadow.com.pinterest.ktlint.ruleset.standard.StandardRuleSetProviderV1_01_1
import shadow.com.pinterest.ktlint.ruleset.standard.StandardRuleSetProviderV1_02_1
import com.pinterest.ktlint.ruleset.standard.V0_50_0.StandardRuleSetProvider as StandardRuleSetProviderV0_50_0
import com.pinterest.ktlint.ruleset.standard.V1_00_1.StandardRuleSetProvider as StandardRuleSetProviderV1_00_1
import com.pinterest.ktlint.ruleset.standard.V1_01_1.StandardRuleSetProvider as StandardRuleSetProviderV1_01_1
import com.pinterest.ktlint.ruleset.standard.V1_02_1.StandardRuleSetProvider as StandardRuleSetProviderV1_02_1

/**
* Policies for supporting rulesets from older versions:
* * Only support for RuleSetProviderV3
* * Only latest patch version of a minor release is supported
*/
enum class KtlintRulesetVersion(
/**
* Label should match with the dropdown values of the ktlint version field in the configuration panel "KtlintConfigForm".
*/
val label: String,
private val ruleSetProvider: RuleSetProviderV3?,
) {
Expand All @@ -24,9 +27,6 @@ enum class KtlintRulesetVersion(
// Older versions are not compatible with the plugin and are therefore not supported.
// * V49 is incompatible as the RuleSet class was defined as value/data class which can not be used from Java environment
// * V48 and before use the RulesetProviderV2 instead of RulesetProviderV3

// User must at least import one custom ruleset as ktlint plugin otherwise will throw errors
NONE("none", null),
;

fun ruleProviders() =
Expand Down
19 changes: 2 additions & 17 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,8 @@ repositories {

// Dependencies are managed with Gradle version catalog - read more: https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog
dependencies {
// implementation(libs.annotations)

// Shadow lib (see: ../ktlint-lib/README.md)
compileOnly(project(":ktlint-lib:core")) // Required for IDE
implementation(project(":ktlint-lib:core", "shadow"))

compileOnly(project(":ktlint-lib:ruleset-0-50-0")) // Required for IDE
implementation(project(":ktlint-lib:ruleset-0-50-0", "shadow"))

compileOnly(project(":ktlint-lib:ruleset-1-0-1")) // Required for IDE
implementation(project(":ktlint-lib:ruleset-1-0-1", "shadow"))

compileOnly(project(":ktlint-lib:ruleset-1-1-1")) // Required for IDE
implementation(project(":ktlint-lib:ruleset-1-1-1", "shadow"))

compileOnly(project(":ktlint-lib:ruleset-1-2-1")) // Required for IDE
implementation(project(":ktlint-lib:ruleset-1-2-1", "shadow"))
compileOnly(project(":ktlint-lib")) // Required for IDE
implementation(project(":ktlint-lib", "shadow"))

implementation("com.rollbar:rollbar-java:1.10.0") {
exclude(group = "org.slf4j") // Duplicated in IDE environment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.nbadal.ktlint.KtlintMode.DISABLED
import com.nbadal.ktlint.KtlintMode.DISTRACT_FREE
import com.nbadal.ktlint.KtlintMode.MANUAL
import com.nbadal.ktlint.KtlintMode.NOT_INITIALIZED
import com.pinterest.ktlint.ruleset.standard.KtlintRulesetVersion
import java.awt.Desktop
import java.net.URI
import java.util.Objects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.pinterest.ktlint.cli.reporter.baseline.loadBaseline
import com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError
import com.pinterest.ktlint.rule.engine.api.EditorConfigOverride
import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine
import com.pinterest.ktlint.ruleset.standard.KtlintRulesetVersion
import java.io.File

private val logger = KtlintLogger(KtlintConfigStorage::class.qualifiedName)
Expand All @@ -34,7 +35,7 @@ class KtlintConfigStorage : PersistentStateComponent<KtlintConfigStorage> {
var ktlintMode: KtlintMode = NOT_INITIALIZED

@Tag
var ktlintRulesetVersion: KtlintRulesetVersion = KtlintRulesetVersion.DEFAULT
var ktlintRulesetVersion: KtlintRulesetVersion = KtlintRulesetVersion.findByLabelOrDefault("")

@Tag
var formatOnSave: Boolean = true
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
rootProject.name = "ktlint-intellij-plugin"

include(
"ktlint-lib",
"ktlint-lib:core",
"ktlint-lib:ruleset-0-50-0",
"ktlint-lib:ruleset-1-0-1",
Expand Down

0 comments on commit c5ed7ee

Please sign in to comment.