/
ktsify.kts
executable file
·162 lines (141 loc) · 5 KB
/
ktsify.kts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env kscript
import java.io.File
import java.lang.Exception
import kotlin.system.exitProcess
if (args.size == 0 || args.size > 1) {
println("""
ktsify.kts: convert from build.gradle to build.gradle.kts
ktsify helps you convert your gradle files to kotlin. As Groovy and Kotlin are
quite different languages, it will miss some details but it can still save you
time for the most frequent transformations.
ktsify.kts [file]: converts the given file.
ktsify.kts [directory]: converts all settings.gradle and build.gradle recursively
in directory.
""".trimIndent())
exitProcess(1)
}
fun traverse(file: File) {
when {
file.isDirectory -> {
file.listFiles()?.forEach {
traverse(it)
}
}
!file.isFile -> Unit
file.name == "build.gradle" || file.name == "build.gradle.old" || file.name == "settings.gradle" || file.name == "settings.gradle.old" -> {
convert(file)
}
}
}
fun String.isExtra() = when {
startsWith("dep") -> true
startsWith("androidConfig") -> true
this == "isCi" -> true
else -> false
}
fun String.escapeExtra() = when {
isExtra() -> "groovy.util.Eval.x(project, \"x.$this\")"
else -> this
}
class Replacement(val from: String, val to: (List<String>) -> String, val import: String? = null, val escapeExtra: Boolean = false)
class Processor {
private val replacements = mutableListOf<Replacement>()
fun replace(from: String, import: String? = null, to: (List<String>) -> String): Processor {
replacements.add(Replacement(from, to, import))
return this
}
fun replaceCheckExtra(from: String, import: String? = null, to: (List<String>) -> String): Processor {
replacements.add(Replacement(from, to, null, true))
return this
}
fun process(text: String): String {
return replacements.fold(text) { t, replacement ->
var replaced = false
val newText = t.replace(Regex(replacement.from)) {
replaced = true
replacement.to(it.groupValues.map {
if (replacement.escapeExtra) {
it.escapeExtra()
} else {
it
}
})
}
if (replaced && replacement.import != null) {
"import ${replacement.import}\n$newText"
} else {
newText
}
}
}
}
val processor = Processor()
.replace("'") {
"\""
}
.replace("android \\{", "com.android.build.gradle.BaseExtension") {
"extensions.findByType(BaseExtension::class.java)!!.apply {"
}
.replace("apply from\\: (.*)") {
"""
apply {
from(${it[1]})
}
""".trimIndent()
}
.replaceCheckExtra("classpath (.*)") {
"classpath(${it[1]})"
}
.replaceCheckExtra("apply plugin\\: *\"(.*)\"") {
"apply(plugin = \"${it[1]}\")"
}
.replaceCheckExtra("compileSdkVersion (.*)") {
"compileSdkVersion(${it[1]}.toString().toInt())"
}
.replaceCheckExtra("minSdkVersion (.*)") {
"minSdkVersion(${it[1]}.toString())"
}
.replaceCheckExtra("targetSdkVersion (.*)") {
"targetSdkVersion(${it[1]}.toString())"
}
.replaceCheckExtra("sourceCompatibility ([^=]+)") {
"sourceCompatibility = ${it[1]}"
}
.replaceCheckExtra("targetCompatibility ([^=]+)") {
"targetCompatibility = ${it[1]}"
}
.replaceCheckExtra("testInstrumentationRunner ([^=]+)") {
"testInstrumentationRunner = ${it[1]}"
}
.replaceCheckExtra("preDexLibraries = (.*)") {
"preDexLibraries = ${it[1]} as Boolean"
}
.replace("([^ ]*(?:ompileOnly|ompile|mplementation|api|rovided)) (.*)") {
"add(\"${it[1]}\", ${it[2].escapeExtra()})"
}
fun convert(file: File) {
val ktsFile: File
val oldFile: File?
if (file.name == "build.gradle" || file.name == "settings.gradle") {
ktsFile = File(file.parentFile, "${file.name}.kts")
oldFile = File(file.parentFile, "${file.name}.old")
} else if (file.name == "build.gradle.old" || file.name == "settings.gradle.old") {
ktsFile = File(file.parentFile, "${file.name.substringBeforeLast(".")}.kts")
oldFile = null
} else {
throw Exception("cannot convert from ${file.name}")
}
println("Converting ${file.path} to ${ktsFile.path}")
val ktsText = processor.process(file.readText())
ktsFile.writeText(ktsText)
if (oldFile != null) {
oldFile.writeText(file.readText())
file.delete()
}
}
val file = File(args[0])
if (!file.exists()) {
println("${file.absolutePath} does not exist")
exitProcess(1)
}
traverse(file)