Skip to content

Instantly share code, notes, and snippets.

@DHosseiny
Last active March 29, 2024 12:32
Show Gist options
  • Save DHosseiny/17a55cab01879bb69ea63ceca8726cc0 to your computer and use it in GitHub Desktop.
Save DHosseiny/17a55cab01879bb69ea63ceca8726cc0 to your computer and use it in GitHub Desktop.
Script to migrate gradle dependencies and plugins to version catalog. This script looks for libs.version.toml file and uses existing added libraries and logs not added libraries(just copy from logs and paste in libraries section)
import java.io.File
val path = "path/to/project/directory" // TODO: change here
println("Processing in folder: $path")
println()
fun writeDependenciesFromVersionCatalog(path: String) {
val rootPath = File(path)
if (File(rootPath.path + "/build.gradle").exists().not()) {
println("Not root of a gradle project")
return
}
val tomlFile = File(rootPath.path + "/gradle/libs.versions.toml")
if (tomlFile.exists().not()) {
println("No libs.versions.toml file in gradle directory")
return
}
val tomlFileText = tomlFile.readText()
val existingLibraries = tomlFileText.substringAfter("[libraries]")
.substringBefore("[plugins]") // TODO: change to bundles if u have bundles section
.lines()
.mapNotNull {
it.takeIf {
it.contains("module = \"") // TODO: replace with "group" and "name" if group and name used
}?.substringBefore(" =")
}.toMutableList()
val librariesToAdd = StringBuilder("")
val gradleFiles = File(path)
.walk()
.maxDepth(4)
.onEnter { it.isDirectory }
.filter { File(it.path + "/build.gradle").exists() }
.map {
val gradleFile = File(it.path + "/build.gradle")
println(gradleFile.path)
gradleFile
}
.toList()
if (gradleFiles.isEmpty()) {
println("No modules found")
return
}
val dependencyWords = arrayOf(
"implementation", "kapt", "ksp", "testImplementation",
"androidTestImplementation", "coreLibraryDesugaring",
"kaptAndroidTest", "androidTestUtil", "debugImplementation",
"qaImplementation", "api", "compileOnly", "runtimeOnly" // TODO: add dependency words base on your buildVariants and flavors
)
val replaceablePlugins = arrayOf(
"com.android.library" to "android.library",
"kotlin-android" to "kotlin.android",
"kotlin-kapt" to "kapt",
"androidx.navigation.safeargs.kotlin" to "navigation.safeargs",
"dagger.hilt.android.plugin" to "hilt",
"com.google.devtools.ksp" to "ksp",
"kotlin-parcelize" to "kotlin.parcelize", // TODO: this part is harcoded from our own toml file. add your own plugins if u have others
)
gradleFiles.forEach { gradleFile ->
println("processing file $gradleFile")
val gradleFileText = gradleFile.readText()
val editedLines = gradleFile
.readLines()
.map { line ->
println("line is: $line")
if (line.isBlank()) { // blank line, ignore
line
} else {
val dependencyWord = dependencyWords.find { dependencyWord ->
line.contains("$dependencyWord \"") || line.contains("$dependencyWord '")
}
if (dependencyWord != null) { // it is a dependency line check it
val substringAfterQuote = line.substringAfter(":")
val tomlDependencyName = substringAfterQuote.substringBefore(
":",
substringAfterQuote.substringBefore(
"\"",
substringAfterQuote.substringBefore("'")
)
).replace("_", "-")
if (existingLibraries.all { it != tomlDependencyName }) { // add to "librariesToAdd" variable to print not added libraries at the end
val moduleWithDependencyWord = line.substringBefore(
":\$library",
line.substringBeforeLast("\"", line.substringBeforeLast("'"))
)
val module = moduleWithDependencyWord.substringAfter(
"\"",
moduleWithDependencyWord.substringAfter("'")
)
val versionText = if (substringAfterQuote.contains(":")) {
", version.ref = \"${
substringAfterQuote.substringAfter(
"\$library.",
substringAfterQuote.substringAfter(":")
).substringBefore(
"\"",
substringAfterQuote.substringBefore("'")
)
}\""
} else {
""
}
val libraryToAdd =
"$tomlDependencyName = { module = \"$module\"$versionText }"
librariesToAdd.append(libraryToAdd)
.appendLine()
existingLibraries.add(tomlDependencyName)
}
val dependencyName = tomlDependencyName
.replace("-", ".")
val changedLine = line.substring(
0,
endIndex = line.indexOf(dependencyWord) + dependencyWord.length + 1
) + "libs." + dependencyName
println("changed to: $changedLine")
changedLine
} else if (line.contains("id '")) { // it is a plugin line check it
val pluginName = line.substringAfter("id '").substringBefore("'")
val newPluginName =
replaceablePlugins.find { it.first == pluginName }?.second
?: return@map line
val changedLine = line.replaceRange(
line.indexOf("id '"),
line.lastIndexOf("'") + 1,
"alias(libs.plugins.$newPluginName)"
)
println("changed to: $changedLine")
changedLine
}/* else if (it.contains("apply plugin: '")) {
val pluginName = it.substringAfter("apply plugin: '").substringBefore("'")
val newPluginName =
replaceablePlugins.find { it.first == pluginName }?.second ?: return@map it
it.replaceRange(
it.indexOf("apply plugin"),
it.lastIndexOf("'") + 1,
"alias(libs.plugins.$newPluginName)"
)
} */ else line // non of the above cases just do not touch the line
}
}
println()
val joinToString = editedLines.joinToString(System.lineSeparator())
println("result:\n$joinToString")
gradleFile.writeText(joinToString)
}
println()
println("librariesToAdd:\n$librariesToAdd") // print libraries to add to toml file
}
writeDependenciesFromVersionCatalog(path)
println()
println("Press Enter to close")
System.`in`.read()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment