From 4d556b4b45289757fc4079cb348e3b3d0168659d Mon Sep 17 00:00:00 2001 From: paul-dingemans Date: Wed, 28 Dec 2022 21:49:09 +0100 Subject: [PATCH 1/2] * Inline variables based on PicoCli Options. PicoCli Options will only be fully initialized once PicoCli has parsed the arguments (see class Main). As of that, such variables can not be declared as class variables. Added as CLI Test to verify that a custom rule set based on RuleSetProviderV2 is actually loaded. * Add an '.editorconfig' override for each custom rule set that is loaded via a rule set JAR. * Fix sorting of Rule Runners. A rule can only be unblocked, if all run after rules which refer to a rule which is actually loaded, are added to the list of rules. The 'removeRunAfterRules' in the RuleRunner now actually modifies the list of RunAfterRules which have to be respected. * Allow urls in the About information to contain up to 120 characters and print stacktrace in case a rule set JAR can not be loaded. --- CHANGELOG.md | 1 + .../ktlint/core/RuleSetProviderV2.kt | 8 +-- .../ktlint/core/internal/RuleRunner.kt | 2 +- .../ktlint/core/internal/RuleRunnerSorter.kt | 20 ++---- .../core/internal/RuleRunnerSorterTest.kt | 31 ++++---- .../GenerateEditorConfigSubCommand.kt | 9 ++- .../ktlint/internal/KtlintCommandLine.kt | 61 +++++++++++----- .../ktlint/internal/LoadRuleProviders.kt | 66 ++++++++++-------- .../pinterest/ktlint/RuleSetsLoaderCLITest.kt | 22 ++++++ .../ktlint-ruleset-template.jar | Bin 4039 -> 27445 bytes 10 files changed, 137 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52dd9acaba..ec59b3aa93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Add API so that KtLint API consumer is able to process a Kotlin script snippet without having to specify a file path ([#1738](https://github.com/pinterest/ktlint/issues/1738)) * Disable the `standard:filename` rule whenever Ktlint CLI is run with option `--stdin` ([#1742](https://github.com/pinterest/ktlint/issues/1742)) * Fix initialization of the logger when `--log-level` is specified. Throw exception when an invalid value is passed. ([#1749](https://github.com/pinterest/ktlint/issues/1749)) +* Fix loading of custom rule set JARs ### Changed diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/RuleSetProviderV2.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/RuleSetProviderV2.kt index 6df0f88bd9..2513afd037 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/RuleSetProviderV2.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/RuleSetProviderV2.kt @@ -65,13 +65,13 @@ public abstract class RuleSetProviderV2( require(description == null || description.length <= 400) { "Length of description should be 400 characters or less" } - require(license == null || license.length <= 80) { - "Length of license should be 80 characters or less" + require(license == null || license.length <= 120) { + "Length of license url should be 80 characters or less" } - require(repositoryUrl == null || repositoryUrl.length <= 80) { + require(repositoryUrl == null || repositoryUrl.length <= 120) { "Length of repository url should be 80 characters or less" } - require(issueTrackerUrl == null || issueTrackerUrl.length <= 80) { + require(issueTrackerUrl == null || issueTrackerUrl.length <= 120) { "Length of repository url should be 80 characters or less" } } diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/RuleRunner.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/RuleRunner.kt index a5de66c34b..ca54d7c8df 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/RuleRunner.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/RuleRunner.kt @@ -51,6 +51,6 @@ internal class RuleRunner(private val provider: RuleProvider) { require(!rule.isUsedForTraversalOfAST()) { "RunAfterRules can not be removed when RuleRunner has already been used for traversal of the AST" } - this.runAfterRules - runAfterRules + this.runAfterRules = this.runAfterRules - runAfterRules } } diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/RuleRunnerSorter.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/RuleRunnerSorter.kt index 6955f5d7d6..c80286637a 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/RuleRunnerSorter.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/RuleRunnerSorter.kt @@ -93,8 +93,10 @@ internal class RuleRunnerSorter { do { if (newRuleRunnersAdded) { newRuleRunnersAdded = false + // All rule runners which were (previously) blocked can now be checked again ruleRunnersIterator = blockedRuleRunners + .canRunWith(newRuleRunners) .toSet() .iterator() blockedRuleRunners.clear() @@ -157,13 +159,6 @@ internal class RuleRunnerSorter { // already added to the new list of rule which will be loaded before the current rule. newRuleRunners.add(currentRuleRunner) newRuleRunnersAdded = true - // All rule runners which were (recursively) blocked because they need to be run after the newly added rule - // runner can now be added to the new list of rule runners as well. - val ruleReferencesToUnblock = blockedRuleRunners.canRunWith(newRuleRunners) - if (ruleReferencesToUnblock.isNotEmpty()) { - newRuleRunners.addAll(ruleReferencesToUnblock) - blockedRuleRunners.removeAll(ruleReferencesToUnblock.toSet()) - } } BLOCK_UNTIL_RUN_AFTER_RULE_IS_LOADED -> { @@ -200,9 +195,9 @@ internal class RuleRunnerSorter { .sorted() val prefix = if (customRuleSetIds.isEmpty()) { - "Found cyclic dependencies between rules that should run after another rule:" + "Found cyclic dependencies between required rules that should run after another rule:" } else { - "Found cyclic dependencies between rules that should run after another rule. Please contact " + + "Found cyclic dependencies between required rules that should run after another rule. Please contact " + "the maintainer(s) of the custom rule set(s) [${customRuleSetIds.joinToString()}] before " + "creating an issue in the KtLint project. Dependencies:" } @@ -217,13 +212,6 @@ internal class RuleRunnerSorter { return newRuleRunners } - private fun Set.findRuleRunnersBlockedBy(qualifiedRuleId: String): List { - return this - .filter { it.runAfterRules.any { it.ruleId == qualifiedRuleId } } - .map { listOf(it) + this.findRuleRunnersBlockedBy(it.qualifiedRuleId) } - .flatten() - } - private fun Set.canRunWith(loadedRuleRunners: List): List = canRunWithRuleIds(loadedRuleRunners.map { it.qualifiedRuleId }) diff --git a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/RuleRunnerSorterTest.kt b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/RuleRunnerSorterTest.kt index cbb4440dd7..df7a33bd1e 100644 --- a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/RuleRunnerSorterTest.kt +++ b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/RuleRunnerSorterTest.kt @@ -222,10 +222,11 @@ class RuleRunnerSorterTest { assertThat(actual).containsExactly( "$STANDARD:$RULE_B", "$STANDARD:$RULE_C", - "$STANDARD:$RULE_A", - // Although RULE_D like RULE_C depends on RULE_B it still comes after RULE_A because that rules according to - // the default sort order comes before rule D "$STANDARD:$RULE_D", + // RULE_D is ordered before RULE_A because rules are evaluated in order of the initial sorting (A, B, C, D). In the first + // iteration of the rules, RULE_A is blocked because rule C is not yet added. RULE_B, RULE_C and RULE_D can be added during the + // first iteration as the rules are not blocked when they are evaluated. In the second iteration, RULE_A can be added as well. + "$STANDARD:$RULE_A", ) } @@ -492,7 +493,7 @@ class RuleRunnerSorterTest { ) }.withMessage( """ - Found cyclic dependencies between rules that should run after another rule: + Found cyclic dependencies between required rules that should run after another rule: - Rule with id '$STANDARD:$RULE_A' should run after rule(s) with id '$STANDARD:$RULE_B' - Rule with id '$STANDARD:$RULE_B' should run after rule(s) with id '$EXPERIMENTAL:$RULE_C' - Rule with id '$EXPERIMENTAL:$RULE_C' should run after rule(s) with id '$STANDARD:$RULE_A' @@ -509,7 +510,7 @@ class RuleRunnerSorterTest { object : R( id = RULE_A, visitorModifiers = setOf( - VisitorModifier.RunAfterRule("$EXPERIMENTAL:$RULE_B"), + VisitorModifier.RunAfterRule("$CUSTOM_RULE_SET_A:$RULE_B"), VisitorModifier.RunAfterRule(RULE_B), ), ) {}, @@ -517,21 +518,21 @@ class RuleRunnerSorterTest { id = RULE_B, visitorModifiers = setOf( VisitorModifier.RunAfterRule(RULE_C), - VisitorModifier.RunAfterRule("$EXPERIMENTAL:$RULE_C"), + VisitorModifier.RunAfterRule("$CUSTOM_RULE_SET_A:$RULE_C"), ), ) {}, object : R( - id = "$EXPERIMENTAL:$RULE_C", + id = "$CUSTOM_RULE_SET_A:$RULE_C", visitorModifier = VisitorModifier.RunAfterRule(RULE_A), ) {}, ), ) }.withMessage( """ - Found cyclic dependencies between rules that should run after another rule: - - Rule with id '$STANDARD:$RULE_A' should run after rule(s) with id '$EXPERIMENTAL:$RULE_B, $STANDARD:$RULE_B' - - Rule with id '$STANDARD:$RULE_B' should run after rule(s) with id '$STANDARD:$RULE_C, $EXPERIMENTAL:$RULE_C' - - Rule with id '$EXPERIMENTAL:$RULE_C' should run after rule(s) with id '$STANDARD:$RULE_A' + Found cyclic dependencies between required rules that should run after another rule. Please contact the maintainer(s) of the custom rule set(s) [custom-rule-set-a] before creating an issue in the KtLint project. Dependencies: + - Rule with id '$STANDARD:$RULE_A' should run after rule(s) with id '$STANDARD:$RULE_B' + - Rule with id '$STANDARD:$RULE_B' should run after rule(s) with id '$CUSTOM_RULE_SET_A:$RULE_C' + - Rule with id '$CUSTOM_RULE_SET_A:$RULE_C' should run after rule(s) with id '$STANDARD:$RULE_A' """.trimIndent(), ) } @@ -561,7 +562,7 @@ class RuleRunnerSorterTest { ) }.withMessage( """ - Found cyclic dependencies between rules that should run after another rule. Please contact the maintainer(s) of the custom rule set(s) [$CUSTOM_RULE_SET_A, $CUSTOM_RULE_SET_B] before creating an issue in the KtLint project. Dependencies: + Found cyclic dependencies between required rules that should run after another rule. Please contact the maintainer(s) of the custom rule set(s) [$CUSTOM_RULE_SET_A, $CUSTOM_RULE_SET_B] before creating an issue in the KtLint project. Dependencies: - Rule with id '$STANDARD:$RULE_C' should run after rule(s) with id '$CUSTOM_RULE_SET_B:$RULE_B' - Rule with id '$CUSTOM_RULE_SET_A:$RULE_A' should run after rule(s) with id '$STANDARD:$RULE_C' - Rule with id '$CUSTOM_RULE_SET_B:$RULE_B' should run after rule(s) with id '$CUSTOM_RULE_SET_A:$RULE_A' @@ -597,10 +598,10 @@ class RuleRunnerSorterTest { ) }.withMessage( """ - Found cyclic dependencies between rules that should run after another rule. Please contact the maintainer(s) of the custom rule set(s) [$CUSTOM_RULE_SET_A, $CUSTOM_RULE_SET_B] before creating an issue in the KtLint project. Dependencies: - - Rule with id '$STANDARD:$RULE_C' should run after rule(s) with id '$CUSTOM_RULE_SET_B:$RULE_B, $STANDARD:$RULE_B' + Found cyclic dependencies between required rules that should run after another rule. Please contact the maintainer(s) of the custom rule set(s) [$CUSTOM_RULE_SET_A, $CUSTOM_RULE_SET_B] before creating an issue in the KtLint project. Dependencies: + - Rule with id '$STANDARD:$RULE_C' should run after rule(s) with id '$CUSTOM_RULE_SET_B:$RULE_B' - Rule with id '$CUSTOM_RULE_SET_A:$RULE_A' should run after rule(s) with id '$STANDARD:$RULE_C' - - Rule with id '$CUSTOM_RULE_SET_B:$RULE_B' should run after rule(s) with id '$STANDARD:$RULE_A, $CUSTOM_RULE_SET_A:$RULE_A' + - Rule with id '$CUSTOM_RULE_SET_B:$RULE_B' should run after rule(s) with id '$CUSTOM_RULE_SET_A:$RULE_A' """.trimIndent(), ) } diff --git a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GenerateEditorConfigSubCommand.kt b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GenerateEditorConfigSubCommand.kt index 32001dfd95..62ac0b0476 100644 --- a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GenerateEditorConfigSubCommand.kt +++ b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GenerateEditorConfigSubCommand.kt @@ -29,8 +29,15 @@ internal class GenerateEditorConfigSubCommand : Runnable { override fun run() { commandSpec.commandLine().printCommandLineHelpOrVersionUsage() + val ruleProviders = + ktlintCommand + .ruleProvidersByRuleSetId() + .values + .flatten() + .toSet() + val ktLintRuleEngine = KtLintRuleEngine( - ruleProviders = ktlintCommand.ruleProviders(), + ruleProviders = ruleProviders, editorConfigOverride = EditorConfigOverride.from(CODE_STYLE_PROPERTY to codeStyle()), isInvokedFromCli = true, ) diff --git a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt index 00539d0aa0..a0b72cbc7c 100644 --- a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt +++ b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt @@ -6,6 +6,7 @@ import com.pinterest.ktlint.core.KtLintRuleEngine import com.pinterest.ktlint.core.LintError import com.pinterest.ktlint.core.Reporter import com.pinterest.ktlint.core.ReporterProvider +import com.pinterest.ktlint.core.RuleProvider import com.pinterest.ktlint.core.api.Baseline.Status.INVALID import com.pinterest.ktlint.core.api.Baseline.Status.NOT_FOUND import com.pinterest.ktlint.core.api.EditorConfigDefaults @@ -251,20 +252,6 @@ internal class KtlintCommandLine { ?.let { path -> Paths.get(path) }, ) - private val editorConfigOverride: EditorConfigOverride - get() = - EditorConfigOverride - .EMPTY_EDITOR_CONFIG_OVERRIDE - .applyIf(experimental) { - plus(createRuleSetExecutionEditorConfigProperty("experimental:all") to RuleExecution.enabled) - }.applyIf(disabledRules.isNotBlank()) { - plus(*disabledRulesEditorConfigOverrides()) - }.applyIf(android) { - plus(CODE_STYLE_PROPERTY to CodeStyleValue.android) - }.applyIf(stdin) { - plus(createRuleExecutionEditorConfigProperty("standard:filename") to RuleExecution.disabled) - } - private fun disabledRulesEditorConfigOverrides() = disabledRules .split(",") @@ -283,6 +270,37 @@ internal class KtlintCommandLine { exitKtLintProcess(1) } + val ruleProvidersByRuleSetId = ruleProvidersByRuleSetId() + val customRuleSetIds = + ruleProvidersByRuleSetId + .filterKeys { + // Exclude the standard and experimental rule sets from Ktlint itself + it != "standard" && it != "experimental" + }.map { it.key } + + val editorConfigOverride = EditorConfigOverride + .EMPTY_EDITOR_CONFIG_OVERRIDE + .applyIf(experimental) { + logger.debug { "Add editor config override to allow the experimental rule set" } + plus(createRuleSetExecutionEditorConfigProperty("experimental:all") to RuleExecution.enabled) + }.applyIf(disabledRules.isNotBlank()) { + logger.debug { "Add editor config override to disable rules: '$disabledRules'" } + plus(*disabledRulesEditorConfigOverrides()) + }.applyIf(android) { + logger.debug { "Add editor config override to set code style to 'android'" } + plus(CODE_STYLE_PROPERTY to CodeStyleValue.android) + }.applyIf(stdin) { + logger.debug { "Add editor config override to disable 'filename' rule which can not be used in combination with reading from " } + plus(createRuleExecutionEditorConfigProperty("standard:filename") to RuleExecution.disabled) + }.applyIf (customRuleSetIds.isNotEmpty()) { + logger.debug { "Add editor config override to enable rule set(s) '$customRuleSetIds' from custom rule set JAR('s): '$rulesetJarPaths'" } + val ruleSetExecutionEditorConfigProperties = + customRuleSetIds + .map { createRuleSetExecutionEditorConfigProperty("$it:all") to RuleExecution.enabled } + .toTypedArray() + plus(*ruleSetExecutionEditorConfigProperties) + } + assertStdinAndPatternsFromStdinOptionsMutuallyExclusive() val stdinPatterns: Set = readPatternsFromStdin() @@ -299,8 +317,14 @@ internal class KtlintCommandLine { var reporter = loadReporter() + val ruleProviders = + ruleProvidersByRuleSetId + .values + .flatten() + .toSet() + val ktLintRuleEngine = KtLintRuleEngine( - ruleProviders = ruleProviders(), + ruleProviders = ruleProviders, editorConfigDefaults = editorConfigDefaults, editorConfigOverride = editorConfigOverride, isInvokedFromCli = true, @@ -347,11 +371,13 @@ internal class KtlintCommandLine { } } - internal fun ruleProviders() = + // Do not convert to "val" as the function depends on PicoCli options which are not fully instantiated until the "run" method is started + internal fun ruleProvidersByRuleSetId(): Map> = rulesetJarPaths .toFilesURIList() - .loadRuleProviders(debug) + .loadRuleProvidersByRuleSetId(debug) + // Do not convert to "val" as the function depends on PicoCli options which are not fully instantiated until the "run" method is started private fun List.toFilesURIList() = map { val jarFile = File(it.expandTildeToFullPath()) @@ -362,6 +388,7 @@ internal class KtlintCommandLine { jarFile.toURI().toURL() } + // Do not convert to "val" as the function depends on PicoCli options which are not fully instantiated until the "run" method is started internal fun configureLogger() { logger = KotlinLogging .logger {} diff --git a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt index 58c824582b..ca45f1dbeb 100644 --- a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt +++ b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt @@ -14,40 +14,51 @@ private val LOGGER = KotlinLogging.logger {}.initKtLintKLogger() /** * Loads given list of paths to jar files. For files containing a [RuleSetProviderV2] class, get all [RuleProvider]s. */ -internal fun List.loadRuleProviders(debug: Boolean): Set = - this +internal fun List.loadRuleProvidersByRuleSetId(debug: Boolean): Map> = + getKtlintRulesets() .plus( - // Ensure that always at least one element exists in this list so that the rule sets provided by the KtLint - // CLI module itself will be found even in case no JAR files are specified - null, + getRuleProvidersFromCustomRuleSetJars(debug) ) + +private fun getKtlintRulesets(): Map> { + return loadRulesetsFrom() +} + + +private fun loadRulesetsFrom(url: URL? = null): Map> = + try { + ServiceLoader + .load( + RuleSetProviderV2::class.java, + URLClassLoader(listOfNotNull(url).toTypedArray()), + ).associate { ruleSetProviderV2 -> ruleSetProviderV2.id to ruleSetProviderV2.getRuleProviders() } + } catch (e: ServiceConfigurationError) { + LOGGER.warn { "Error while loading rule set JAR '$url':\n${e.printStackTrace()}" } + emptyMap() + } + +private fun List.getRuleProvidersFromCustomRuleSetJars(debug: Boolean): Map> = + this // Remove JAR files which were provided multiple times .distinct() - .flatMap { getRuleProvidersFromJar(it, debug).values } - .flatten() - .toSet() + .flatMap { getRuleProvidersFromCustomRuleSetJar(it, debug).entries } + .associate { it.key to it.value } -private fun getRuleProvidersFromJar( - url: URL?, +private fun getRuleProvidersFromCustomRuleSetJar( + url: URL, debug: Boolean, ): Map> { - if (url != null && debug) { + if (debug) { LOGGER.debug { "JAR ruleset provided with path \"${url.path}\"" } } - return try { - ServiceLoader - .load( - RuleSetProviderV2::class.java, - URLClassLoader(listOfNotNull(url).toTypedArray()), - ).filter { - // The KtLint-root (CLI) module includes the standard and experimental rule sets. When those rule sets - // are also included in the specified JAR (url != null) then ignore them. - url == null || it.id !in KTLINT_RULE_SETS - }.associate { ruleSetProviderV2 -> ruleSetProviderV2.id to ruleSetProviderV2.getRuleProviders() } - .also { ruleSetIdMap -> - if (url != null && ruleSetIdMap.isEmpty()) { - LOGGER.warn { - """ + return loadRulesetsFrom(url) + .filterKeys { + // Ignore the Ktlint rule sets when they are included in the custom rule set. + it !in KTLINT_RULE_SETS + }.also { ruleSetIdMap -> + if (ruleSetIdMap.isEmpty()) { + LOGGER.warn { + """ JAR ${url.path}, provided as command line argument, does not contain a custom ruleset provider. Check following: - Does the jar contain an implementation of the RuleSetProviderV2 interface? @@ -55,12 +66,9 @@ private fun getRuleProvidersFromJar( - Is the resource file located in directory "src/main/resources/META-INF/services"? - Does the resource file contain the fully qualified class name of the class implementing the RuleSetProviderV2 interface? """.trimIndent() - } } } - } catch (e: ServiceConfigurationError) { - emptyMap() - } + } } private val KTLINT_RULE_SETS = listOf("standard", "experimental") diff --git a/ktlint/src/test/kotlin/com/pinterest/ktlint/RuleSetsLoaderCLITest.kt b/ktlint/src/test/kotlin/com/pinterest/ktlint/RuleSetsLoaderCLITest.kt index 0cbf56b715..e270c7ebea 100644 --- a/ktlint/src/test/kotlin/com/pinterest/ktlint/RuleSetsLoaderCLITest.kt +++ b/ktlint/src/test/kotlin/com/pinterest/ktlint/RuleSetsLoaderCLITest.kt @@ -23,4 +23,26 @@ class RuleSetsLoaderCLITest { }.assertAll() } } + + @Test + fun `Given a custom rule set with RulesetProviderV2 defined`( + @TempDir + tempDir: Path, + ) { + val jarWithRulesetProviderV2 = "custom-ruleset/rule-set-provider-v2/ktlint-ruleset-template.jar" + CommandLineTestRunner(tempDir) + .run( + "custom-ruleset", + listOf("-R", "$tempDir/$jarWithRulesetProviderV2"), + ) { + SoftAssertions().apply { + assertNormalExitCode() + // JAR ruleset provided with path "/var/folders/24/wtp_g21953x22nr8z86gvltc0000gp/T/junit920502858262478102/custom-ruleset/rule-set-provider-v2/ktlint-ruleset-template.jar + // Add editor config override to enable rule set(s) '[indent-string-template-ruleset]' from custom rule set JAR('s): '[/var/folders/24/wtp_g21953x22nr8z86gvltc0000gp/T/junit920502858262478102/custom-ruleset/rule-set-provider-v2/ktlint-ruleset-template.jar]' + assertThat(normalOutput) + .containsLineMatching(Regex(".* JAR ruleset provided with path .*$jarWithRulesetProviderV2.*")) + .containsLineMatching(Regex(".* Add editor config override to enable rule set\\(s\\) '\\[indent-string-template-ruleset]' from custom rule set JAR\\('s\\): .*$jarWithRulesetProviderV2.*")) + }.assertAll() + } + } } diff --git a/ktlint/src/test/resources/cli/custom-ruleset/rule-set-provider-v2/ktlint-ruleset-template.jar b/ktlint/src/test/resources/cli/custom-ruleset/rule-set-provider-v2/ktlint-ruleset-template.jar index 603ea1256e2fd5fa58eb0b16108e44be54d21b6d..77d30a35d4e08b83cc1f8a5889cc7ac85ac7a8aa 100644 GIT binary patch literal 27445 zcmb@rV~}UT_vTq$c6HfRUAAr8wr$(`mTlYWvTfV8ZEyc~W_I_tGcPt`CnNH{xbb9W z+=x7%^PF?#r9eQTfq)<(fig3*RDk{s;QxC38&LnIjEJ%TjfAWy9SD&8|0Pr`$W*EK z1HQ)oC&2tSQU0Go839=dQ4u9&S{cy?naK%hDH_^2I4K&+>B*S}Mfydi-J|^@;Qz;F z;rW^WaVqG)&1_Aa|Kq^_w+8;dYm6;y%}ksvO`QHio$~+s4&?tyZExUW{XZ@FrL_oM z2?7Kp1px%4@V{OnVQXw+>#XGL`0re06B~PL17{Ori~rS2dq)#f3wLP~TQg^KVkTN6 zYXc{zYGoZcY%vrbBkbC)*1lFKQ1gY7{60VmNt|!SY#_`On$bK40csB53CO6{?Cg5A z!0t2UJ5V$kYf%#Q+{jmXvEu@6Zy@}AHZ(h($LWUWWt)SEPWStb%|CS2P+d(>3$7eK z*fyeXvJr*$9NKJ#1`SL5ZP#8B2I)4pcyHvClL(eDXbt`*68)5+fJGz#z+EN2iH#xx}rq z0=Z$pU{oh4MH?6tnU5qGFV4of-UUIvIS>NuS#>eoB7&Vewh*ztP$cfl_JAMLhsVln z4)_52pDZ!1U&`B^aSccHTv+L|2Y%m^BE1I3?4I_SL^#b%795B=!l0(WO^q=ct(u!r!?ebe+!Cm~ohMjBPGM_5+?sD}5pSuZ!JpX!fmnq^65HTS*t3XLf`euAaE)b} zk(m=>wluJ|c{q~$uSI$5^@L88Gj8G}X$m zbqp~Kg*f2Y+&b<)^r~5fh5+POC>JbS+(7Y(lIFN3rPvr$*1!@AOw`t54;(ISJ#09Q zQJYbbd`3(J@z37ORybH{y0M(fgah5<)EMji0)RrnKL*$ui5Ft404so#+GNNX3fcZe~l zxn`J~e)pE9a@dCxc}>R;QB$wa$b;yja$>Ck1^E%&EjUg7#LVP~^a8P3FppK4*<;HU z&{pp=_(q*3xMNMRo-4@0<|eM7cZjdQ&JU}xc8jhJ6XLC@_p^2A|LPvPr=9<$3aku_ zQs6+&|E>3bv+loOG9}&W*8GnQCjZ;X!06>)b??ymsC!Q{H%s;x@@>w}Rd2erMfNXicMYl!@(QQLb!zN6Us= zlVOTb?k?~!>Vn&+;!r$F|8(<5Vi4oH6PG+3RH%SBd65cs&f6fAAf*MG3$sWcBg`lm z<(>Z>R_o}eP9(`wu%gC`9K-Y>=m-t4IAPy%=_%7d;=FZ`aK0hG1=EO?fY zlPjec5%}oU#JT7$?TXa1|38RxKueIK4!!aS>^}D zUs%GS(E+f(NGDs96&dt)I_t}(P*f^bSF0{BGquKASt#=6QR*Sgq|A2qu^`lRZbi=% zH|R@%!eFc#{1HC8RR^CZlz@Y7w|7lonU;+bcP(nsVInLSf4(%PtRGE5UW2@vD;>_| zBQY#jXT@`;VTwv>bzF+IX*pOZl7C(MVTY68Hf?3FCdPPvP=nm6opkkza=}?Uf3j%O ztZap22u8E>le|WE14*#mg&G+A`-lb~?qA0efvX*5m9T=V0D}gYt5+_Vw^#{T zS=sd6R?ut?DQ=%nEzCn<$<36WCuj^SO1fLYzxW9B6kd$GYUd&qYVp`(!=6=G zQ`T_d5n!pb9IP1%f!`+j_-FsJr$!RmcV>G8GGfew)$xkrHAJ!KCb0letMezctx6f| z1`Dqhu`Dd?XV02Z=TR5rk03{2I=Dt4$T55{l@pPN#ysZi)zUAz z&vfEb#yO5Iys7TkMmmRxa`?`l8>D``1$|H`jR)eQM!P@R=td_cP54jO&qs$C!39?Lv?=juK zdm|{o=&8T{%ZuciVM z1OgKN|7#!qI~R&oFO;xVP=2#;4?(m!t_x!v))B@S=Q2|US zk~Hd$y5&{&GU2wJrKMDZl|_ya+lbHMLa7)mUI?d0dNH~uRy+)O2s3N% z(d-hh+iQqgCuz+vhktm2F$iH-^zcMs6#%CRG&W6>zh%vuF$gWF8j^)^00F#@$O5>l zyaU;vKLb$((d+d`%b-HEK69T;JV5%bcY&C+#g*<{V}X^>G9v`#an<`6oN&WX>M4s3 z@2+dHd(Z<*_W|T9ob8#L2QC7Euu5k&K&-Bn1y$`kMcLM>AZ$^HAZiTb^j>v1Mi^$T z(x=Bb3S>Z1vDlz0tl1n8s&G53$z;J6E)-^o?x-v83;`Fgm^3?(^Jv|SR_g#lq8xgT zt&T-Q_iO@N)QIBbe#;mGQa@Xj`&Uw1;#+W1Oj-p>?98_Ql^1;5Bu9zOL6#tPCF3kF z!WWrDuAgwL(1bNv!XS(23)q3(bj7eeT!4BcmrPyV2z}P}wF;d?S{f65qz9la67A2x z6kfjRbV33K|2RM7jp7l@=+dkPW}trgC8$j)7ft>U-~6hM?5st&;-{By70eKowu8>_ zlWN*A`ht`)oxVPc4H_!Rst!@q3UBvvKf#{^H%9yLk+auoA)g zz)RFlcdY1symIccrv9nk{(N%mh3!JA1OIX9^x8ecA!g0vxfh@d=H-2@+w+ZCXVUg! zm`Xp$ph(TVfkni~I@$VS#eQOQZ9iwq4Od|vW`KV?rC_$|2D(-#-F-G`yaq<9*?Na` zew?o`#Nb}!daQ_@B&D$kWxHa)M{m~U57|V_g_8bb1%zz~fkNX8iJD9-HC_yJXt3kKTz<{4N2UfcjjP` zeZI?4xcP1oy{IO-a@2c|O5~%fn3=)HNe0rK{jLRG`*E@TK{4Q)1CafZyFH11q5#<0 z9~i;d9D)yITRtdApVvUupuu(E!dFIqE8I+XlvWrcuGJeOvas-PthnV7E=a9bBZHxS zohr>&P!1TYS7(UH5gv7}u=m%=krQ5kH}yNlZTvgTe=_BK$7ciLUpYqqk1M?Y-8F4 zttFDuAxT1qgO%pUBQ=*UgLP!SkYq95o9ua%V!kMbte~hAIF@5v_*^$rlN-4`-9JFL zkZzcGq1qYUkRRIc?uI#@7W$g`GeT<#48=OUoN(M@nHIfT+IS;#>aX0sH0XU8_aJtc z=>h1^Q*2wmZWL6_RtXp<%Gq#Q792BE9x4u4V`8p^TIMXeo3OK02d>mz0Q=WDJ_5I; zJ4yf>u85Cg{|Vd6aC(L=`luo@5#erR2{Jg~iVEElA%h%0Fz}R=Jc1E@?h7zNlzWb# z?hdzpdBlY!tFgvrQnQH_!*$-h`CiI_cAhBWzDXilo}ENIxWedRPKxoxcohhYRe269 zoo@8;4YCEUl!>|8BQ>Xte6`58hlcv*nQa-~MKb&b@U3JfK*|bPZarp*$0*9y zv^-0)pIG^qpCZ63)x8TsXzcHtv=D{pCiDm);+8+Y?&)Nl2jbgcvuR`;*IC(w(Mll} zK$}YP0MCy?Sw6!dYm#BtpLkk2gq&(<%$CAol$KIMz8_cw%T}pTLgUG#+wkoH#mP*y za@x-UT-83rJEUS#eyx9#mSA7M3XF($gFP-A^`>w+ zT*_<}whc8gJ(4x)_!w#H6ZU^zF>N+~hJ=6Di}ZiHw`Kev-d0BmM+Ak32j+vJ%0L4d zQrL(X)K!3qzd(V2T!5Zvg7ipHnL@6sVak@SfroveA;j*D<{MZ^H9bjHBMBkpD7L!$7H`Rx0lHrEf#9$yZ#IeAu9s-k&T2T@&&+nGkIDR>_43b~WY zQ;hbXy)6k4>t>G|VaZ=_XKKg-F*09<=ed$JarxkpqNMR2(y1KwnnKg#=y3Z@DJCTc zwyavOsafsfk*h_kW@FXc=!mJIWsvsn7J~!8u0iS_#Xq&ViI|nNzl zgDl#m*Z-XD3BwTm_qcuGz!%_^6=fWeqf;bULh+x|C6@kM?bJFZ|0ptZ5h?1`XFH|Q7^09MgHtZv6c#_Al;*stj6@fs zmY4rd?~%*XvAe8UVPlQ_YhTR2OE|E~_hKMszP+CzcCvb5cIsGfJ}L_G&&4*5&K}oA zsUBK3hJ8oxo;}6(cO}~q_VM(C4+v{| zx*@RWEW<_MW`~~GyTyJau<6uc!@(A^lne7*vV`RRVe5uYPT?`A?EY8UUewm03``Df zEnquNSDF7SZQ)WO0`hj|WR6;O`NQW7TszT(@(DH~E@sI@8}>rFiJFat`O<%1>JW|) zLK&q^19B9lMJ4kW@Csssg-6kGt2wQ_heF7g`ptpVyrR0qC(l`IB zZmsq0ahqBtE|gDYrBelXa@g*Ik0FfPq;+4OVB5{{Z0rza0R~|2^#}uQ_7>7Xa2rB&n%%ks$h!;?1G( zHW(_S`qI*1<4vGDKK*kw3!69R%SKoh6hqkjVDx}gsA=)Y(PMArP~3|8)KkRI3_RPm zUb47Owm1B~zcy}wSpUx43PRbi6k9@Vp#``Md)1g!mdL;Je;D(kY%!%;Da0j4nRT6hS)#heDCKVQ!0$Z_ZR@*GEch1nH zR;I8RSLimZf-WQZx>Sz;{rn-O7{tWu%peaT7IIXgEN{WcL9tS*kf*_o&*e=PFi6g4 zZqh;{HD#oaGYLb#npZ%x*kq0GrN$KG26S1>l}La|BvHKfBi7S-Lu*uYuOPz4Mjjxg zlA2H6{yl!9sibipI7w(cko3qvaH;ZY-*(bzHxbVso-f;0d;3FA2w8+&WFKqL$AKzK zcK?;}(Mjcuu_-S75#4O>>>`*{wC2-kYKU2zIFqDVd<#B+d(BP=Nw@_-Vz8FUeS(@> z)#waqk?9N%g>^ClF1dvls+ifzS>-cOFUpdW=ZG93&u|Y$67tOo-kSrpkUSs-Y|5OV zY)={D!H}Y6i+FHqVHdaFXMMDgy#yc2)Oe&V+46}ZfWm|tv-=0Q^ovBn>y6usJlQcr zIUn6~o9X6ciqi6A*=CBakLu*mVOLu7q%)bv@UZ>7@?y%3IEBwzWgD0#Qpx$OJbC_N z`O`NeM`;O2+>d6A3Uui-$Zo5#M({KL*!_FWLUwe%6g$0e-eO>3bKnFhmRQp}Ge4ih z?T1Hw#JR?E(7Ojv!4Cu&G?ONmy|lyaiKTq(JSL^+{Gaik-uz>Q2k4(#sMN)1OKD0* z`i}Xp)|TsY`hT^yddU?^brZ2Z`I}Kzc>cAvKx$984AlUSFNA@G431Tb9K_--+)6c{QCdf@wWD9`G2uiKRjT?MSY;s&#@?v5gYjR03#Z&J)p~j(BlvTNyMR$vyC+1`FGX0dpf{LB z2u7j9ul&Y>+QO1t0aR$lr$O&hj72j zsvMDpb!=k>ikI-;XDH zzc%~f2LMPpa|!4C?lyZ^Vw)|nN=?D{mN`Q9I?l1w*Wq9s(Au#<4BlF2t2rdebJs3# z<=lJZwwS2fHjVCkoz^>QGIHzVEY0AhO@>3R@KMdTSn#RD80KtO-!dsA8-Ssu0ELRB zN>?cqN}KHipVJx}t-#8D(Ex+%T%jtsgF!^2Fx29NZEzvtR5Hr~4yK+&QQ-C% zh9byY_~Hrs()%CwLUSXPG;6#FQ#1V!f38j{@puCUH(LKIQ7z`K2bME3Ey%FU{>B)IN%|^n z+7b3+jQv4d9qxOKn#216_<48K+G6_HN?2*RT{r-!oA8@euGSCMA<)=O$sJk^m;f!k zH0&MLh)YD_2#ucg4U_bdt5|%lD7*)5q`IMcmo*D!O)Mk}A8av0OcXpEmGW>Q3*hoE zyn?*7rU3$kO(yK39g?}K)sv!2L)LJIJBP%sSJIW9lZT#r=MWEGqgV@izFPp8)W4q2 zrfZ;3aB!@#y=Jjezm4cZQ*a6gPtJnsnkRMP99~=L&$AA7Mwsa^ zaHR`CIi5<(XQ9a_bvUXql@ld7^%uLB)b;c4E2k-*}S*LuQrs8GAsy?~;{XwS!G|Ci|yr*e_N zNEzF6g8{n{Hkn5f-vxyLm6Ik8945n<;vMvC#Gr7qlx0ioPSKnRv5}fEKSTlz>nd?# zO-+`*;}cnztYn+JZ-Y$zI|mf2BA=ow`jx5Ey26gWm73keA?R=eqzh^te-_>BD_1)F zvx_P0_PJNj(c%r|fv>;y6y)_FEA}uwmYAeR^d5A1CLtT%#eb1*w%apMi*NU9gn%AE zXTBs+T}vMnN}!ax&$KA$hPXKJ<>ZYyJb3#{!>2VgEId{kMH&irrreaaikTY2f}hl7nN zeQe^lpdj$TG2|~n)dYTje{o0wA_;%u-@xKH2@;HPlY<_}Xw?y|%6-dCnpNw|>+`A` z5h=uBT`&?uQK9wtjoyTcv8v?*o1EBJ{Jzc6#X0 zt{;L1J#ubw*%S`xe7gvAW|E^hE%6rf@Hez}2BmDXy5@fy>PL3g&S5yn$3);AEsGQw zk8utNi4&i?>5n&$Ad*=OAfk;jqBklm)l`;QnOE2rRhD$;H{~@NYT7&V>)ULFTuhvN zOoW`4C`-cE9x6ib8x}$? zTv&+ttR1h5B&4V9XImFUY&ptBmC{mTY7(oWeRU)|NLSD89zFy$TzCTRSz%dGSfedE z@t(moyYf|?EXk(yHF3?rGTGErZeS(fL%3XBP%9`vwx|15x>+H)VSNJ6a?m)^*&2~y zGFucV#|r11+vCP;wl|P2FCUwNzc6$mO->bI8qzM?={lREEmSWjty*q+XTvT%`@dy9 zV2D{WkIj=roYL#}?KzEG`$o8}q8jL9imzSd@fI?e{upW&{7~v~ zJ379B$$Lj3s@l|8>#DW5>X_&VAuEARUgKy0dXJUjMMIP)ok<4?WgAS~G`r3)F`!zdQe(N)tF zLw8&ls>KNfj-;FIL-CD{RbmkZQ~Ki=NO^-9icJs>;w={bPMe%m%$aaZq|!p1X)N{0 zd+ovNxqFRXgbH^B@Y7$i6lr0@t~@)t8ZN$Gb+g9lULlfH+T+lRKn{k}8oEZp3xbw=O#R=Pcz|{2ylIG_3tkx_X+orMa zUEk<`6Hved5B4dsKWS=~D$rD$WiZuq!_i>vJIV9ddxw3qdUARFNm$M&3 zs+q)7F~2|E*fygf^2&0Lmk8EfW$g0l#Om z__c%AfDMjL=X_lxdj`;vra%K50#Q0ED?_hbP~R3{65n$CrbSr+&~G!qx019wU+|_Ah_&JS_kHMm9Ha#QnDpIWHy}}^vuW+NML_-QN;AKJB%?F`~iYdTAryNz`3CKc*7Co{a7DKLFd zq-899_1yf&jlK8qe&p|95|8MfEYNwRLz%U|K}~M~-pOju?p$(_&+(%Ooo~cGk_BG|#!z|PvJivR7!CgPn}?|0 zz5re-k_YmAW$H9SXs{(os+Y#sBsq>#C&-;&+INj*v*&BqLQ)7`{Q`1-FhJd{jXIR1Lxvl0 z2t@nE)-JWyFd{*jZ=;2w%PTkz^U}Pr3(Sm4;ip z*+BS!m32rBv!rX9nyO7j9{kX9iqM%qa{DBgGXQMl{!T5B3_*T-=ft_SjFe4rXZuzS zZJf<<1@dH9<5}Py&+}{q?ZG45a%$zC2sj)muty=2`PlppA}wP-y-28@df4BMHonNj z@(Jo@VXuq;v4Vex_a4AsMcst*(PJeY!D1N0%WCqD)s-!|nSV)F&2Bs15BY|F&sRQ* zmG8xjFRugHuS#{)EH9YQ4>GpoI`BAH3@Hs~%`86nO7kV;_@I~v^2@UB6RE`l@vSko zF=m6>LW)MqNe*I|;#)}WYwF_J(-)yf3H1DZ%~sgWxwTI}lP*{s$!KoN+cAP3o#aI9npaAXb-q(Sp=iky$8}6wtS{*R{1Xs~6Xl&~>lFC-dvU1#pQi{r)~C=5GHIb8eku*7CG=Rt)uU zM6TlFIIJq}4IpHyymW3D(qWBJVI%hBJ1o?ypp(%+jhuY*)OfZO!Q?dr$~A7f^b<$f z;PJc*`01c8XZI&f6F#s*sbg>2q$40sfGxTfCHcM~N6jGRScOl(v;7EUxPEdZx?{Qa zIH7zLLy^8(%Zm0S63Q;k`R2-R96>Te!Mui~R1zmlJz}LSQ_>yvy_d%`ZB?q^YltKf z7_|q%_#m~itJ}Kk8q5v&PQ?Sqnm8&^!EOC(PcfhKvsDt&#&&07KCXrD3Pd}0xUksE zjvz<;n!}}e7&-wAvEL)GNBMDXbg*Pz+bPiKYIi1B8y;}`iI1|eYA@o1U-)m zlhJDrS=s~4EUsKM8G2<`IOy0~CY|sH`__Y$oX~yeyO@YBlGxjdh$9_X?m@#(oeYKv z=bFw;D}9-NF>vLt_oqfD+QM7%qQ>vdJR0shJ_DL;tb`KAJ{y|Ys;Z}YM(ney2=g3K z6K{id90K~(_akt}m_3MvOvYK`?5Ufi#`QheTazsgID%BOrc~SdtP%-^$F6$!Pu+`Y zjckju6ALnu5HObksv@7pj@o?X3Fdzjxr*UjB`TS+Y0K{5uSFTToQ|c*K+tvgKX++& zI7x&`j)-_IFs~^cu6QST7%i{*QMQ+t5#uZyB42KGEtu3aa28)013=JwX8zd2VI;?X z;rQxMV6*ZV#w9;K-#y(oe@Tm!zMUX6Jn8^JxGz6KWsi{0fZ>C~{L3NB)N7`_r%h5l^@B8gLQdD%UGM&pm8vofQp5 z=9hF<05>Yy&Hz`>PP7xY>5s$pM@(-G8TP}uZ2~cNa3sCNL@nz5HiIueemIu@hG&cO z-ZeS75*Hy^e))AVvDis93uU47mA(Szo0$=>?L<@G|G;c7P?u-_-af4LFB@F}-WCoy zK3^vJ-u}p|6A}X7OrvR4xI*Vv073p(Uo6v7RNFi*h=|6)J+g#%aBi@vsCInBkr+V< zhTcXJPXwr}US14o7w`2-Yiew^+8HX>>+4&xZe7B5II(X=uE1|#!}iyrzW3B=stXeM z@B25CF5$XwZzR7ExokC6boSRuX%8d0xoG1(E3BSTy1rgxUUbIZYGY=Q$dEYmC*X}Y za6cu=T`h7$RMiv+O|_4gJkaF4+TX_20m>Js@@=nNmOs%wk!h=hxx69XzeeAwk^at6 zzngq_3uoZ}x#A$x00H(LY~0_Z?z?@*C%dEiOms4V)O~7jG99%q$|bw2{ER%!i%+7SIG zcJ8Yut*V#|)QP#&>Aokc5rIOns3J`DZ)#N9-W>I`Z zttXg;fQNX#=wdV2k4xbDkf@M2x-W8aM<{F?p(CnG@o1xEq_w^cui;I#=#VuA?jTpF zPJH(0L5e-Wc`K|C>GMUwl(aE7dgU{lv#?yx5f`qa9Zlx1ln{T( zQaDaVRJH_*1MTQEPUz7w;_((P!mUU4jd=L@Un)R^iG3_NbQoh;O(;bWr) zA=pmkht)Q}6-v`0P)Dm9`nc9QX1vKhKCMk6&kVr@{agLV7SKGLEZw;o<3zPb8y(F} zuakp#_F~-InlGah?IJbAQ%0WCh7k(M7lU~6(Q@xz^~PzA*P_#^!#N!JxZoZZ-}D7& zx<&n33k9xZZ6iJ+&N(Knd34a%4Dn3SfWFELN2AY->F) zQHEHyDO1URhxB?d;OpWm%}=>R7?N!TgWA@VlGKZl7i~Mlp(*IA3kNiY1@<+cqC^6*_DwHCuA18;!oc@@{y?nEJV^07g`%(D zNmE8NU$p=E(qz0YN=|i?86<6M#mYt zEl_{D@(|g^jiE_YC1$FF$8t!Jn0Hgb_*4J5^8=~;YNOHzm1x7XA5%}qk8Y0`SJ`JA zyTM}5Hqnmn(xotbqn?1Kr&X{5&1>=(M)l|H3fiCX1nRm>Fmn)WhkAUHMkTWD6PLDQ zu*C$Kw*%shVa&d>p4azIOskqxm;(hrs;I!Cycn+x^{JBA*pOd2MACw#T7#CRzlXKc zzk%cseSG@UHfM23Z`jy05Y{|SILR|5P>VdqCRoh7xIkC8_1h-$&UU$?>91;TpIGJ{ zqq>NPi;L4yiHl3})02vol}^Dx>t!mJ?y{HgzqDjXwlD;Kz=&D)Vt12-FBtXL-<^(V ztO=tdfdTZ;h{K3(SzT(9WXZ-h%=KM#6&lx|!mz{wac>YCsNd|Y3_hQ%fz)YF80xa# zIiBkYm9|dmGDYqAPi%w_EKQe&?FVF=-StXghdu2buP;BcTBKE)WVA^Jfn>2u;ZZI_ ztUBc)*Kq4pBP7L+I-@jZ$sa?`rPVPa0eGeFvm(3+k-8=w?$^Gv;?nBVeQvGrpGFdr zb*%$9H}*jq$IMZD{dzOCu@lmLfA+F)ts$HHu_(1}Qx>-G%K?19FocK=6VM)zeEFL- z+undp#2CJJT8EaZkZS`j0RoiAL9|2s~vxvveq}KbAZZC5`?| zrE^QGkOJX}qOGJy`!m+th8rNN4)U5u~t;Fu)-pVPU_#nT< zI(>_D;7a7Et;n%+CTRE&@HMg?R*2x>7_Iv3l(Ee|x^z?C((0h!S8(?cp9-GWkhD0} z$#0fg(D#)xUW?c#nTI?FQBI`d!X3Ja1?8#v%u3QWJB0qexud7^dT#Uab07ncrx)z_ z4fYY2@O`IhJ-+GQQ2mI2`}nRLBgKZ(iR-y%odFM^i`Gphr3iqgPlsT?rmA(VvY~9O zM15fnTC~_BQq)J$eI(QicBAF`rGC~^Z)LgLfB*f|KF(GP=``1nDt%jXoKtUES|W<` z_tp^QuFg@p|MH zU`b=R@gjR|wKQmq_~o!qwq(?dJS)o(ThC{8%Z?*=E#y|uIl8S}>cPS!*~c!++cwis zrao!*8OEsFIRCvl5KhRl$0&E+N@3_L>0nx6BdM7|BQv?Oc(eF+;1)(js-5AHPRAk> zEiNrH;y@UK$!>~PE0N87l+gIt2=%a)cjPE5;lx>5vX(V{X;GnuJkCQ5CxgdE43}nen}Q#x%}>ntox1{bwHoWMP&f>e4#w3t zxY(Y!rg+r)dVBxR`;(qPvPE<+SWK~crR_%pq8f|s`6nq4RM*nD=B~9hEQ^LwbQa; zH+eSAw6D`iNHfc-zBRuzs$D~U0N;xkQW6TVf^G|=hk^XD~*GKA&@!oyrd2Q~a46hDa-D6$syI{@?VGl#z0k78;k{z7>A*=bsGJ8q* zTu(PwnRb}ZcpqJov*=1nXT|LCv^aOj*iLd45EQf|e3_f{9ltKz#QA_4ubq}TElqgW z*5ae7nYk)G60Hh>?1PwAD|aqRP*n=tuahSwV_$db7N^2*A(c?helW6a#%9A7ERX`H$t;hcWrF&K z>tdXOIw?_kQQC5_G#~H7LVKAnNo>?$l~Q)HqSKiZqhayrTJ#OG7IU0kbw~nc56;Qs znd)+u=`$lih~T9VFx@4iBD-oYY~&-m8ZLbN9$@AryHa)W{9URj4z(}yDNDM+rF@zP zxJ)u`%2ULG7)FZ+e>0v%8ns0%YDSsY2FKKnYCvraSDk02Zor*CE07W|ok#-WR-e_b z$lo{xiHQD7A-2|@#tUhKEvP}{8(J7dQ@$zdhM~A;JxYh@!**D*1y_Dp>I2#16gwxD zmXjCzGEemNcqX(MlQWW*p_`X9eDL^I(m3*QI%Xy}KgXyQv#~5T0^gTnd~hbz$V}D} zD~ne^@zx6E;lS6G_Kb9SyfJbL!D`7(NY|riIy2_7@lg6SH$xb$Cmh0@gX9d+^#)Jl zJUi#NU`$fRC>b!kvH)8VRCb=f0^Z1)za*?>!35eE(tOYvL`%k}Bd~Q?+;zGp$4gRm zq;AHheV%HM%|)&)+EcKyo1)%9(u{pd>#1Y$1nwE+TOI5PvL)2>%LqVzqg;TKs~?dt zX_WCvz3^C5Dxi$De!fX|TAlcK;`^SPu?dR(ve5I8#GL4K|9;9BYEg6MbBXpYiplYd)3LK*}y_s(oM%L&~3&{<;MFtL&_J zX^dqrzT(n{#q|U3E{dL19v|<$hQEqAIzb`RJi~3H(3iF!45A^vqH*9Oq22Q=aUXx1p_$O!Yv0Fbm)(>y)9cY^@9T-bnVD; z^A9qmUa__$?ecGEvVPLxDUny9k91|jy*ccJyf>sJ zHen~^1|bV)pfp8uLAX16)kfW+$CEFImOy76?pzy*VLOd5=eafwF%mwp-~%84NxR@G zX%ubFY+WUxB`c?7$yc-`&TEVie|2tTZ+b`7qAj|+?~=595jQ^J zO*&qknVub7h?eO6F1C|bYee0{zQ%tI&tew*%mlw9x11y#nf#?GG#%D871B24VxMT> z5_yk4rIQD1$2E^D7?l}Lt|sjUe0EcS)g9yAi6H96Q?n_OyZ`k_{*G7LaVF6npu3NK z#^#Ou6?AQizB7sZ3O-%rwK{b(f@Hh*Wd8A{3ct%O?k0X(7j$L~!MWAn(m!i_0fY}az9i4IQ!;4}=kW&8N=fg>=qEq-Q7Ll6 zhSrrz?Wxyv>a$evQY3OC9*p}!INm!}L z=rax|%JcqL3?tuPonQRYC$Vc)D0}p%hpks(;U42XfEaIf*P<(Nz}0UVmyId)jEbjw zvWKYIwV7PZ1oz~A+v7QA6Ou{`U|+tl#|whsu~@-W{6daLhYT?UCEjVNGsLRLMD>eO zb6lW`9A24d_MSjI5z{*l{#A4!Td}H5L!AE0oj(Ye^tBCnhn!S}t+FO~f=$Yz`I?Lq zf76jV(UH7a2>XIFe`y>Lj9JmJdoV+j%@;?FUW5rG`F{5!e~P3#-YUu6HdNegB7X+X zIc4ctkDndXVsCwYUJ=xlpm1pD`U0wBdr~)M_`C!Cu<{?J3KamL?I;Ep7(KS`f6o@_ zCQ_WwiCY=B)JjN_NIO`RZc52D?&wPO?W-8`LLE0X@qdng%WzKHv9__W01MQ_{@ACH z9;M-`-)pHm0=i;;uSJm2tDuJvqVYUK*d_8 zMsBli`D&q~!raV;1_UHeaH0vpnFu3euXBRi**N%Ib)YC zR`Wpp%Az_$?@iWoME#1OD_m*K&^^KO3|iS=2mf=y`c5-@BJ(_d zcIFWeEiDC1*h4^C=Df@LUM-G%b~}a3tpMiT@kj>KQxpA4sz*hN)g8{ez&3}qpLzcP zg}enlS#hR+&A=dnRgnfxB`xkx1dU)lyX`(Wijj;OnGQG@$1p1~4wbh|FEfP?f}(Us z)=+RyoCPQ5rZ|QbVOv_GI>zE(p>o771aJmeXBrSO`W1et-flE*Q!Tj_?LGd8%#%;X4$_ufBpz-E1-`nWR zXH2@O$z+5j$l;jvE8Va~iSTgnUIk)PAQmwi|D%(H(KP=N9bg!sL0ufFD1^fREG>*= zdwvRrRg3iFT&HgGog)8G%x!Z=+?HbvqTWJu9zN`M_R9LUaohE49M1zbudi&T-C?bo zIUdA|BnMK#Se~^$>M5)i+rAqN@dY|Z(97VWWzQXAMt;6$F)oqhfh&1RDt(6{C5^F1 zNy9$SGI=bTz$J7sNT;a?4{0j8$osU9Agct=kzR0q=R}tIk$&p$K&0WIIiE1iT&G%< z{2yO~nxy=+g`#)L`}}U+y7!{iMm1%8Ui3Pvq+8bNE&VYm)$hTFKeaf!{Itb{9cf_? z6t@E~t#J|VyflY|75xr0bpB7YMU@VnF{y*2cDW=yJ}Fbz$SnL|`I?AtR}F_PauQQD znu-aCZ!{sF2{ixy?=fYAsNZrPUArK`M4ht1LSs#XLbJvIgE2t<&U}Ck3M`4w^PjMw ztSu6Gr8t1rgvQW=z^FZ0S`2%bcvD=5XSajM+6g|W*0vJpQ|1>agaU)0uEYB~=-C?> z2!e)!gOPInSOBji!pX(ZPcgBusaw}Zab>GA@h!iEB3fgRm>fLLLTO?Zpb$5qO*A(u zPQB2noqkN5UR0LUKguR8fq;Xrh#*Jy(Q(KsbkU(~Ai9G3DJRKXxr#aO9w%z09U9!3 zLwakY98nm{$8V!;hpA3s5@|zunIvE1I4e9}NJ2@zmLCRJpiz8$P_CdIkVmY{ffujS zaa+)xtc5P8p*Y8&iFF;VP>w-}SPc-DRVd#uMbUgN16^0qMXsZ1`bdDz$7IVlJy;J` z)ao9eIOL(EQ)0W8FBqR>BPQcCA{JAKry;r08CT|j+`|#NKn1mR*0C?rLgt=sSOdZE%1yu(zXC~CAOVGZgs>XvFL8X%46BDt73q?5) zM!qYG$cXai$1W0&8yJN7tFXB;2!uq}1;i8yLYRncOlfM^@C*-Tht*JR8ZIvjqH6fg}O$QtPr zmm?ZE_#{aQuSxk#b+&d!=n&M3Xr&j;Wvi%0b%=XTS!6I~9n^|xOKb8>_T3N;kfW$5 zt1R&uOd9-3il0_G+U|WM-R)`<0S-@DlXt}E0F^BJtq(Xb7Xj^9jl9(u!yFkY$ZyK8?WE)tfyB@sJy(7rG@wp{f#F*m=(Ux?r z*$oF_o)f=Zn?_mkC#wj6Is$;R4z!2)FoR%TYWo7szWvdOcqa9QjC%vBFO5~Aa*M-X zvx#$?r8RExn%$131Le+~ub4-5tApJs~((0f0Bg+J+QE7*>;K zdT)ziqs;^@$YkFDRZji;$n1eYmSi7&YR zS^bD?N#~dK7ca7GXP@DYV~~PlgELGTdWvGA&)0$Y+nHk+!-})iy+3Q(Lb_B_E`m-J zk1%Xzgttghx`+(cRPbBYC9<$!Wl?Cdzce2QZ&IRvHzbnRYVWHg0v8Y=aG&NrPOJew zO>7tLSnG9X6hsc4SdgD69BEh}F-H-jC5KE_sS&O{G89gFjZBt{qQ_C-X}$mQssq9Q z+Qpe0l{LVQ#}F%*IZ~T8fV8>Ot$@(fl;tT`)TBA_gyJEJ#W$SV%U`&Jp30)&S_HbA{LW( zf9Ju@))vnho)Ct6Y8k&Qi~#XvMs4>wjcK!UcERS8N7Um4af-QjlU zDp5&fT~oG6mAR6<*4RNo15tCxgd{SusUQR5z3Z^R@Xcy$x?&_#*AiCE9%*BmO4WvLrt?;-`Ap1 zM;T|S%ahu#86jEX{| zV7<7$D^Iuy{e(tTOR=xuUa~16#1R%P#8tMqB2ie{8#$ZgQAWfm!0^=#j(-CcvMR2Kb$TLL}yT)BL~GTU`rX}xqohErv% zx%1se=aav5!=+uSbj8I}D7sAyoljZKuP9Q@`OZk^Qy86ZDMSdJr9G`Ik}YKg`;NHrxa~4>Qx4!nVN;H3dU*g>>-IP)6 zJTnE_{&1yD0f%c?3dgvr7T2eF7D}{vPA*eps6Eemai0&DV}CTJFw!oyN$vo(OTTe8 zEl3=9#}Fy;5xW$`>#GPUT_JulB>BXp;AL{GCI7l2k>U%Od)`lrHS^7xG_B>haDYA4 zg*Hp1_lsIer()An3O6vUYBUEK=Djy%rXrz{Kb56Lg89$(SsfN|&>^;4Cn!!k7 zW>AaAEoT@20DHpTpcmqGDB=kXQeu+UgbGaC(?3Le7ZGiB_saex#O$&+V zPH_%C;Md`-2Jvm}!`IcqJ1ATS4*Jqj*I+yl9rI>SxlsCOv8ttC0UkHi=scFXwaUV@a^%BO zhO};b;64^_LRjTebbH#V4zF!nLIB69P_e6S=ih{C5 zwZ>RZbSU+53CA$|3kloU)h@(1o_^*ZCoFD)+io7Q$KF`N7#U>d3=F~dP16k z$)yKGJJfkTg#IchE`3ctM4H{PE2yu01G4uV9^BU!Po&2VsqVTe)Kq>j@G0IQ!i%lD ziE%i3p1d$Dt2i}#)b#mWqJ~|##jxZ=)J>)u+{>2UB8B7&>c^u&tNTES!Gm+eSmw+| zuT63Jxk^%Qs{xHqt2#&=RC(=n$hw7Ai`ztco=-ZWKje7H;M9GBiF|yuozHpfpUBaJ z!BvmNLK9?0Da}sRyA+YwfWTCotl4AMF7{Q}eXzVCrHb}@@4e|WrXX3h@#E?GWPoLdmaf$uLG9%JjsC?dSg$Wq}2R$rwMH8i!=kdyrP1J-DC9o)7GCJJkX!wddP^{VGTUWfy zqeV5Km3Vw;Pq&nTaE=J#rb2qiw~G3Vj3&-}C6eXEY$@vtEl+ok8Kp}7>cYOOMIpw8 zs~Z1g&z$R=Yo*JZ8#l=`_2p6N;!CF1x*pb)y6pPr0dcDoAOZ3^)-n1;J0#E53u1oG zR^jn9W1dQ~O4g@Wk3!YP9$`?o+68v|+fSD|d`>b}iFjCAC=ZV4o7RFu4x=2`$>gf20fk zkk7}ByCt&O&faTkTVDAQxsAS*ny{nm;H(RQkTgL#Q-eFX`=Xp{MvDd56AKX^i;iwe z$LP>-#h&@f72xC}aVs`xGAngW^Qm!VO<1viQPPE-oj0;_|A_|(DDczDNL$obqd?^W+y(Ais{y;gt-9~(s`2G9(pXVog-)3aByc(Hq6&PXo zrgdJPh`aU3KJvIK>N?GxAI-`Cy`lPRJo&v&_?uQHGjHe1!L}{Lvl|;JbjFY3xE~z` zeMr9f>sjPZ@m__l9`HI>^65&6B*Qyd6d;9GsbuxTD$a$vMn&7sQ5$^jS(>KYV4Lr$ za`QcD`aBJzRe8oZjz)gW<3Wae+7xVSSDPMhK;h}Df%&<4pXK0c-l4@g^$5FOib6HUuI%iVIT)(Z*NY(!D= z%x)8L@$%M~z3gtTlu-H{}dZ-a2GW~S2UMMoRE`}+napwBgNG@`E z``JMFY08#xUI(K3Rro7;j@srGirEI(H^gQ6_DtckbG5)L^k$_+jI%|&2Z*)%`Ah{a zORE4xM6xOSz17=$|GbZW;Z_A!5JF&82;qRx`u#ZmTM8)%iPewaQ=0)D96?$ZKoCI9 z&d3BH4=^%QvQaa#2FL?#0Mvid#c1ehL1-av`l+c+W#q(qM#tnnP%9I)SdJRT<%vs6 zzEgllu@s?3B;*vpF;~>yCbzWFZ&j^6?(o6m=;_BP^Jq$3b?poG)e76$nc1z0 z!^?-Fx5#tE{H@juu^LWGdCHTN<-`r^x-})pg|gjr_BtaZtXjr?sJaJHXq^}%-SOE{ zg`b$R9-Vb$G4I#W^Q(r*w?o!inMQ<{1&6-R6zWB&e@>XHMs8>_Se|ID3(qT|?~L*0 z8Go$Mhb#PM_&dJk^eQ^T_c6ROye_9S>z-wY;bfM$Py-E9lu3`kS}8se2;Y>MttnB! z&0~N5EYyS>fpC6f)DJ{Y1velkaMENje%llYK?HXD;_#X-?gT-@pv4Jb@jj zJLwX98T*)sGb|5-rX1YF!nm<#Wf>Jcs(+F>+jbw7T|V`F2Y&!zKTgIgt&!lt178G{ zI0bXXPa0Hq%*!Z76M?Cf&l-F}pA&Y_1ccSt`T;`4ba==lRWM&@r|tw!Ex3kf4ztF0 zSGMb?8#UNjYDsv&CE&P{QN35yT-kQGF#rO26OHQ(6K_jD3MN3#ntx{z%V@+Xo#>v=$PLgLds|8SwcCFNTWgc+|0N7n6g5 z4Xy02#?S#^2MLCx#VqQ&C{Cj}Ps=`pdTS*y8GYe7E zaBO!Wirx;tw`A5ta|cT6m(cINK>Idkpd7fO1%Y9ThJQUc|yqlKCV#t*6vybv0R z49vdh@gpYV{;zw!)?UjdbBQ^$YmYA0$Nj{o@s7;0kCgM@nkFeynSKI2411D6c}~CO zkEa{M!qD&kSfmaQ3rWOs$!PGkQ^RSl2x^3AYcXo%{t8acsogP!Tc_Fzmprj+kn0hm z6qUQ{>Cx5l2- zMBk1AI4mboK*3`^%&P#GY2VUv-|^9wu0%ma|A{erzsr$xHH zy7U*PC41g_^i;aW^(c%Ba86EzdvgfC6nK6-SViOV@$H6pm5i2NM9-+>&hZ4{XVkB+ zhIyA^CHeU@%w0XIr>r;w2wUNhhmUeA46M|x^pcx~3gX83m~wSLemM5bohpd8LbDDw zqUO_>;EO;V<=l$+E}1T8j2R5S0RE)h(8ftCtI(N!#Yd!?(x#srXw9T~Z7Yts*B=6kd<{?J4N(Kla zMl?Tix-BT)adR%Ny;yG245CoFj4i&Z)w(?!g{M_9B;0kcCGA=8e335wM$rtO*K&SHU)akisIJ)&M;7EVS*7j8mcfEdPq`c7(XnnffP{y*RZ~93Orq3|Dij#0{ zdxFA4K*K|wH*Dxn{0aolnlY_=VX~;TfFqe0Slf6V`7bEWi3_*o1!KCxOe>N;;7mRK zls4;w8NS4gP3`H@JTUbxQY*SDg<9U-z~phbIcci1@W3a;&@VbnH5toi;0DDNjM0GKHubc7|HuFT9^-=ij0^4AsOja<(_mR+#q=8j|1~&v5Qx{Qs z3ttUcp5eqZB$=P~6RP6GMV)@CwCM5L-YOS=>!1?zW)=;Y?FiwGZedSR*Xp3J0Regd zVTFHDM%C9DB<{_)?qa#zIqxB?mD)5< z`uVyoD|1F|IK#GH0;bbg#)&{{Yts|N&Sn!-r<3(nF-|XgNhMvx*TkBw5$vU?8eKuQ z1UJ?tM7``s?oI(%L@Mdrz@3GD@l`eokX~gUV(9#CxX^m( zF|}l)0%xsNdoXqWzz)Wf?_rbMVLNR6*Ty7pLj0HMrRez4@SDWn5Wh|bfQL^`?lsE6 z^L?Xj*~b4mA#jbrh)3P`U|<#@T}trpcPDBs3xJJ+k)0icnAY*ffSjf>X#-(<60xGQH--f()6Wk% zaBw3Lz!kMgVyOm&n0{ppQeUP}(ldX?r&C7dPBvEwgGAwXanA$SxCS>Ek=!d`B58ul ze5Kdp@@5&c1!0HtrG-(}hY=j3ysV&=26dH^PKlJvE`~;?p^ppFer4!>GxLW6%g7jE z6p07-BXP%LEXqakg7@b*M;_A2S_0GA!Q1`ht*z8@R7ISW1pdKh0Zj_ArXTrth6j$U z1d!hFc;@>dMrPK`72)1*&2~1gy56NuQQ)4tELen>bUMo#pQWt6eG0nF9#@tR?-Ra(Y1X6ud?eFOT z=KzbRgpXGOY_X}IgF)nG3Vp=vy)8n%PK&&5GU{w5+inXye8EJxM6KCcVO9>)sErau5 z2U(BUd5_;mP9G8zo(|oxVle)qpiSF@H^0P+@5o3iuk^iyA*~}8;<)ks8!bfA*4oa< z254*Zqj|)s4*W2zwN-%k$|1<@v&gWt02DV#h4QS49I=;HJoAI{lUVuFX*Bg}S+yO$ zZ-VH`Qsspc^Pb+)FQ(*fwEOCtHJvt|Hu9a%T%Db73wZ@<1HP$C)ITqb@Y@OgCb9xI zd#tVnVIju)iiSmcsUNy5OGxTSBN=zk6@=YK|Gq-k}*Kzb-<8LAL)$2Phl+3l!q9h3nt-!!-;@lb}7swaX zcPSI0p+r<$2xz|M29=cD!0*UQ*?)v0)<;MFCYu147hy~#qzzI{Q9tuZ3ai|Xl;_dG#ku?+ zs&nX?I7@C;5jes9?APXKs3^BZ-`A{kZD_VsS0{?pjo)BaJsFv^&PbHt*|KZyq5>`; zB^}0MtF*7$Gq1_4QlUo0J~jvXsut%i1C3RodU1$K~5N5TeSam7}C zkdKN9vYDfeFONoT@OKA^(!P$jJPa%s>3v1-n%GI>12J0z{*vW{q4eaGWUav;a7pZV z?v1~OGFcA@ZLLQjjd2sQfMNA-G)NO$8;}vu#!&(23NZZ<{xAYT+NY$2k%N&52;ksI zZ3=V*0c}kF2#);nhd=o-)#V%^gd;a*EOPObofY<^q7n~+WsYPjYH$pqIOu6<wb6zf!SsV1ec?Ma^9SAHT90=K;IB{FL*3YSV0wsfIgEetPuA z#;9;;iEIZ!e{|ZwIMCiUEk1w!_Y=}{N&7cYSc z@1$aI$IW7FQd~?kf}1K)sDBJACB1@P_d?LSmWcHnZGQK}laGELaYlpWRJs=>L)Pff9Z0Ay9vt$OvwAm2Qy0>(t;3!DOcI!sU3l1v~nrZFB ztpK;%8Hq)Sr5pJzly%GCteCRCx%dFYwHNY--C>tcQ;>mWZEaiUCbUUcY2;!jcwIwmt=JGd4nCP;giFYRs$^r@0TYtnx!_SfjlbRZ(=$KTzl=#nP+x)umKd{CnA=cmnEABZB9j&PvS_aMV5Ty=#yu42(5kRzi5;39a^o91RY6nf_fp~uXPGFRqmF{GNuNmZ zWtwMdQ)td(o8ULeI02vax0>g19BOvDB=#{+Uo7}861JSe5q439Q9o{bn)9#&Ax*W) zvF>#EEM$xj4IF4bEhAaryqxfj`rM0Il(r0UlJG$JpnORMxrh95yE%EcD;O>BgU>)M zN6Eg7iH1pOz2YqtJDFOdPqY!lr~n~fcOilUD z6V8zcp#@GX%5y>KoK@i+@#be)>xN`U#hDT7a@1s8$6GtmYvzb9$E*O?seVpp&OFhv ztDGkc2TZF%8m{xd%#4Ddk{V$DT69N%gEPh2T96_ui8UlxRo4){CIfWVH$|Mma)RqS{9 zA?|LzyK=l4Am9HI`z2e%uNt5eKHMdR_;K9$f zKjt~VR_4yCKyS7AsoGicx2pfu#+zRi-x(0-wZET=AItq#@oziezqt|!T?pui{?9^e zLxOXE^T9!NivRr_@2U$O_xp*&q5hvD{mUpIbTy%)BtOBuAj__Qvzot&nLy(}&$WNz zWa<2U9H^N$Gzj$k=_d%6{@(}rf0#`{7Yy3>`dP5IhQAEq|A8m=E7I>=r5{Ll1GgN+ r`TNUR_{(vEmWOtnewNhpxAOmn8>K9FAK^|N0px`N8Okt??|%9p=D7PV literal 4039 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 Date: Wed, 28 Dec 2022 21:52:53 +0100 Subject: [PATCH 2/2] Fix lint violations --- .../ktlint/internal/KtlintCommandLine.kt | 2 +- .../ktlint/internal/LoadRuleProviders.kt | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt index a0b72cbc7c..59bcbd04dd 100644 --- a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt +++ b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt @@ -292,7 +292,7 @@ internal class KtlintCommandLine { }.applyIf(stdin) { logger.debug { "Add editor config override to disable 'filename' rule which can not be used in combination with reading from " } plus(createRuleExecutionEditorConfigProperty("standard:filename") to RuleExecution.disabled) - }.applyIf (customRuleSetIds.isNotEmpty()) { + }.applyIf(customRuleSetIds.isNotEmpty()) { logger.debug { "Add editor config override to enable rule set(s) '$customRuleSetIds' from custom rule set JAR('s): '$rulesetJarPaths'" } val ruleSetExecutionEditorConfigProperties = customRuleSetIds diff --git a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt index ca45f1dbeb..3655c6df18 100644 --- a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt +++ b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt @@ -17,14 +17,13 @@ private val LOGGER = KotlinLogging.logger {}.initKtLintKLogger() internal fun List.loadRuleProvidersByRuleSetId(debug: Boolean): Map> = getKtlintRulesets() .plus( - getRuleProvidersFromCustomRuleSetJars(debug) + getRuleProvidersFromCustomRuleSetJars(debug), ) private fun getKtlintRulesets(): Map> { return loadRulesetsFrom() } - private fun loadRulesetsFrom(url: URL? = null): Map> = try { ServiceLoader @@ -59,13 +58,13 @@ private fun getRuleProvidersFromCustomRuleSetJar( if (ruleSetIdMap.isEmpty()) { LOGGER.warn { """ - JAR ${url.path}, provided as command line argument, does not contain a custom ruleset provider. - Check following: - - Does the jar contain an implementation of the RuleSetProviderV2 interface? - - Does the jar contain a resource file with name "com.pinterest.ktlint.core.RuleSetProviderV2"? - - Is the resource file located in directory "src/main/resources/META-INF/services"? - - Does the resource file contain the fully qualified class name of the class implementing the RuleSetProviderV2 interface? - """.trimIndent() + JAR ${url.path}, provided as command line argument, does not contain a custom ruleset provider. + Check following: + - Does the jar contain an implementation of the RuleSetProviderV2 interface? + - Does the jar contain a resource file with name "com.pinterest.ktlint.core.RuleSetProviderV2"? + - Is the resource file located in directory "src/main/resources/META-INF/services"? + - Does the resource file contain the fully qualified class name of the class implementing the RuleSetProviderV2 interface? + """.trimIndent() } } }