From 8d0b036759fe8d3ab67b8e6cca1818a153183fd9 Mon Sep 17 00:00:00 2001 From: overpas Date: Sat, 10 Jun 2023 19:49:59 +0400 Subject: [PATCH] Add --replace-usages flag --- README.md | 1 + depstoml/build.gradle.kts | 2 +- .../depstoml/ConvertDependenciesToToml.kt | 38 ++++++--- .../by/overpass/depstoml/DepsTreeNode.kt | 21 ++++- .../kotlin/by/overpass/depstoml/ReplaceAll.kt | 15 ++++ .../{DepstomlTest.kt => ConversionTest.kt} | 2 +- .../by/overpass/depstoml/ReplacementTest.kt | 85 +++++++++++++++++++ .../gradle/dependencies/build.gradle.kts | 11 +++ .../build.gradle.kts | 11 +++ 9 files changed, 173 insertions(+), 13 deletions(-) create mode 100644 depstoml/src/main/kotlin/by/overpass/depstoml/ReplaceAll.kt rename depstoml/src/test/kotlin/by/overpass/depstoml/{DepstomlTest.kt => ConversionTest.kt} (99%) create mode 100644 depstoml/src/test/kotlin/by/overpass/depstoml/ReplacementTest.kt create mode 100644 depstoml/src/test/resources/gradle/dependencies/build.gradle.kts create mode 100644 depstoml/src/test/resources/gradle/versions-and-dependencies/build.gradle.kts diff --git a/README.md b/README.md index 84529d7..7fad360 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Sample toml value: `gradle/libs.versions.toml` #### Options - `-o`, `--order-lexicographically` - if you want to sort the dependencies lexicographically +- `-r`, `--replace-usages` - if you want to replace usages of old dependencies with new ones in build.gradle.kts files #### Arguments - `deps` - path to Kotlin dependencies file diff --git a/depstoml/build.gradle.kts b/depstoml/build.gradle.kts index 3b0b379..5c88703 100644 --- a/depstoml/build.gradle.kts +++ b/depstoml/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "by.overpass" -version = "0.1" +version = "0.2" application { mainClass.set("by.overpass.depstoml.MainKt") diff --git a/depstoml/src/main/kotlin/by/overpass/depstoml/ConvertDependenciesToToml.kt b/depstoml/src/main/kotlin/by/overpass/depstoml/ConvertDependenciesToToml.kt index 46566b9..5513912 100644 --- a/depstoml/src/main/kotlin/by/overpass/depstoml/ConvertDependenciesToToml.kt +++ b/depstoml/src/main/kotlin/by/overpass/depstoml/ConvertDependenciesToToml.kt @@ -7,6 +7,9 @@ import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file import java.io.File +import java.nio.file.Files +import kotlin.io.path.Path +import kotlin.io.path.extension class ConvertDependenciesToToml : CliktCommand( name = "depstoml", @@ -29,20 +32,35 @@ class ConvertDependenciesToToml : CliktCommand( help = "order libraries lexicographically", ).flag(default = false) + private val replaceUsages by option( + names = arrayOf("-r", "--replace-usages"), + help = "replace artifact usages with new identifiers" + ).flag(default = false) + override fun run() { dependenciesFile.asKotlinFile() ?.extractDepsTree() - ?.createTomlConfig( - orderLexicographically = orderLexicographically, - ) - ?.writeTo( - tomlFile.apply { - if (!exists()) { - parentFile?.mkdirs() - createNewFile() + ?.apply { + createTomlConfig(orderLexicographically) + .writeTo( + tomlFile.apply { + if (!exists()) { + parentFile?.mkdirs() + createNewFile() + } + }, + ) + if (replaceUsages) { + val replacements = findReplacements() + Files.find( + Path(""), + Int.MAX_VALUE, + { path, _ -> path.extension == "kts" }, + ).forEach { path -> + path.replaceAll(replacements) } - }, - ) + } + } ?: System.err.println("Kotlin Dependencies object not found in file: ${dependenciesFile.path}") } } diff --git a/depstoml/src/main/kotlin/by/overpass/depstoml/DepsTreeNode.kt b/depstoml/src/main/kotlin/by/overpass/depstoml/DepsTreeNode.kt index 0b4c666..d7e94fd 100644 --- a/depstoml/src/main/kotlin/by/overpass/depstoml/DepsTreeNode.kt +++ b/depstoml/src/main/kotlin/by/overpass/depstoml/DepsTreeNode.kt @@ -96,7 +96,7 @@ private fun MutableList>.format(orderLexicographically: Bool if (path.matches(libraryRegex) || path.matches(pluginRegex)) { formattedList += path } else { - formattedList += separateIds(this[i][j]) + formattedList += separateIds(path) } } this[i] = formattedList @@ -106,6 +106,25 @@ private fun MutableList>.format(orderLexicographically: Bool } } +fun DepsTreeNode.findReplacements(): Map = getAllLeafPaths() + .findReplacements() + +private fun List>.findReplacements(): Map { + val map = mutableMapOf() + for (path in this) { + val oldIdentifier = path + .subList(1, path.size - 1) + .joinToString(".") + val newPath = mutableListOf("libs") + for (j in 2 until path.size - 1) { + newPath += separateIds(path[j]) + } + val newIdentifier = newPath.joinToString(".") + map += oldIdentifier to newIdentifier + } + return map +} + private fun createVersion(path: List): Version { return Version( key = path.subList(0, path.size - 1).joinToString("-"), diff --git a/depstoml/src/main/kotlin/by/overpass/depstoml/ReplaceAll.kt b/depstoml/src/main/kotlin/by/overpass/depstoml/ReplaceAll.kt new file mode 100644 index 0000000..816cb6c --- /dev/null +++ b/depstoml/src/main/kotlin/by/overpass/depstoml/ReplaceAll.kt @@ -0,0 +1,15 @@ +package by.overpass.depstoml + +import java.nio.file.Files +import java.nio.file.Path + +fun Path.replaceAll(replacements: Map) { + var fileString = Files.readString(this) + if (replacements.keys.none(fileString::contains)) { + return + } + for ((old, new) in replacements) { + fileString = fileString.replace(old, new) + } + Files.writeString(this, fileString) +} diff --git a/depstoml/src/test/kotlin/by/overpass/depstoml/DepstomlTest.kt b/depstoml/src/test/kotlin/by/overpass/depstoml/ConversionTest.kt similarity index 99% rename from depstoml/src/test/kotlin/by/overpass/depstoml/DepstomlTest.kt rename to depstoml/src/test/kotlin/by/overpass/depstoml/ConversionTest.kt index 9ea48c0..3aafddf 100644 --- a/depstoml/src/test/kotlin/by/overpass/depstoml/DepstomlTest.kt +++ b/depstoml/src/test/kotlin/by/overpass/depstoml/ConversionTest.kt @@ -10,7 +10,7 @@ import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals -class DepstomlTest { +class ConversionTest { private val tomlPath = "build/generated/main/kotlin/by/overpass/depstoml/libs.versions.toml" diff --git a/depstoml/src/test/kotlin/by/overpass/depstoml/ReplacementTest.kt b/depstoml/src/test/kotlin/by/overpass/depstoml/ReplacementTest.kt new file mode 100644 index 0000000..c254a44 --- /dev/null +++ b/depstoml/src/test/kotlin/by/overpass/depstoml/ReplacementTest.kt @@ -0,0 +1,85 @@ +package by.overpass.depstoml + +import java.io.File +import java.nio.file.Files +import kotlin.io.path.Path +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertEquals +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +@RunWith(Parameterized::class) +class ReplacementTest( + private val dependenciesFilePath: String, + buildGradlePath: String, + private val expected: String, +) { + + companion object { + + @JvmStatic + @Parameterized.Parameters + fun data(): Collection> = listOf( + arrayOf( + "src/test/resources/DependenciesFile.kt", + "src/test/resources/gradle/dependencies/build.gradle.kts", + """ |plugins { + | alias(libs.plugins.ksp) + |} + | + |dependencies { + | implementation(libs.kotlin.gradle.plugin) + | implementation(libs.kotlin.date.time) + | implementation(libs.kotlin.coroutines.core) + | implementation(libs.log.napier) + | testImplementation(libs.kotlin.coroutines.test) + |} + |""".trimMargin(), + ), + arrayOf( + "src/test/resources/VersionsAndDependenciesFile.kt", + "src/test/resources/gradle/versions-and-dependencies/build.gradle.kts", + """ |plugins { + | alias(libs.plugins.ksp) + |} + | + |dependencies { + | implementation(libs.kotlin.gradle.plugin) + | implementation(libs.kotlin.date.time) + | implementation(libs.kotlin.coroutines.core) + | implementation(libs.log.napier) + | testImplementation(libs.kotlin.coroutines.test) + |} + |""".trimMargin(), + ), + ) + } + + private val tomlPath = "build/generated/main/kotlin/by/overpass/depstoml/libs.versions.toml" + private val buildGradlePath = Path(buildGradlePath) + private val initialBuildGradleText = Files.readString(this.buildGradlePath) + + private val depstomlCommand = ConvertDependenciesToToml() + + @Test + fun `usages are replaced in build gradle kts`() { + depstomlCommand.main( + arrayOf( + dependenciesFilePath, + "-r", + tomlPath, + ), + ) + + val actual = Files.readString(buildGradlePath) + + assertEquals(expected, actual) + } + + @AfterTest + fun teardown() { + File(tomlPath).delete() + Files.writeString(buildGradlePath, initialBuildGradleText) + } +} diff --git a/depstoml/src/test/resources/gradle/dependencies/build.gradle.kts b/depstoml/src/test/resources/gradle/dependencies/build.gradle.kts new file mode 100644 index 0000000..2ef1459 --- /dev/null +++ b/depstoml/src/test/resources/gradle/dependencies/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + alias(Dependencies.Plugins.ksp) +} + +dependencies { + implementation(Dependencies.Kotlin.gradlePlugin) + implementation(Dependencies.Kotlin.dateTime) + implementation(Dependencies.Kotlin.Coroutines.core) + implementation(Dependencies.Log.napier) + testImplementation(Dependencies.Kotlin.Coroutines.test) +} diff --git a/depstoml/src/test/resources/gradle/versions-and-dependencies/build.gradle.kts b/depstoml/src/test/resources/gradle/versions-and-dependencies/build.gradle.kts new file mode 100644 index 0000000..215300a --- /dev/null +++ b/depstoml/src/test/resources/gradle/versions-and-dependencies/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + alias(Deps.Plugins.ksp) +} + +dependencies { + implementation(Deps.Kotlin.gradlePlugin) + implementation(Deps.Kotlin.dateTime) + implementation(Deps.Kotlin.Coroutines.core) + implementation(Deps.Log.napier) + testImplementation(Deps.Kotlin.Coroutines.test) +}