2
0

ProjectExt.kt 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * Copyright (c) Milan Jurkulák 2024.
  3. * Contact:
  4. * e: mimoccc@gmail.com
  5. * e: mj@mjdev.org
  6. * w: https://mjdev.org
  7. */
  8. @file:Suppress("unused", "DEPRECATION", "RedundantRunCatching")
  9. package org.mjdev.gradle.extensions
  10. import com.android.build.api.dsl.ApplicationExtension
  11. import com.android.build.api.variant.AndroidComponentsExtension
  12. import com.android.build.gradle.AppExtension
  13. import com.android.build.gradle.api.ApplicationVariant
  14. import com.android.build.gradle.api.BaseVariant
  15. import io.gitlab.arturbosch.detekt.Detekt
  16. import org.gradle.TaskExecutionRequest
  17. import org.gradle.accessors.dm.LibrariesForLibs
  18. import org.gradle.api.Plugin
  19. import org.gradle.api.Project
  20. import org.gradle.api.Task
  21. import org.gradle.api.logging.Logger
  22. import org.gradle.api.logging.Logging
  23. import org.gradle.api.tasks.SourceSet
  24. import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
  25. import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME
  26. import org.gradle.api.tasks.SourceSetContainer
  27. import org.gradle.api.tasks.TaskProvider
  28. import org.gradle.kotlin.dsl.extra
  29. import org.gradle.kotlin.dsl.findByType
  30. import org.gradle.kotlin.dsl.the
  31. import org.gradle.kotlin.dsl.withType
  32. import org.jetbrains.dokka.gradle.DokkaTask
  33. import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
  34. import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
  35. import org.mjdev.gradle.plugin.config.base.BuildConfigs
  36. //import org.kordamp.gradle.plugin.markdown.tasks.MarkdownToHtmlTask
  37. import java.io.File
  38. import java.io.FileInputStream
  39. import java.util.Properties
  40. import kotlin.reflect.KClass
  41. private const val VERSION_TAG_MAJOR = "majorVersion"
  42. private const val VERSION_TAG_MINOR = "minorVersion"
  43. private const val VERSION_TAG_PATCH = "patchVersion"
  44. val Project.versionCode
  45. get(): Int {
  46. val major = runCatching {
  47. rootProject.extra.get(VERSION_TAG_MAJOR)?.toString()?.toInt()
  48. }.getOrNull() ?: 1
  49. val minor = runCatching {
  50. rootProject.extra.get(VERSION_TAG_MINOR)?.toString()?.toInt()
  51. }.getOrNull() ?: 0
  52. val patch = runCatching {
  53. rootProject.extra.get(VERSION_TAG_PATCH)?.toString()?.toInt()
  54. }.getOrNull() ?: 0
  55. return major * 10000 + minor * 100 + patch
  56. }
  57. val Project.versionName: String
  58. get() {
  59. val major = runCatching {
  60. rootProject.extra.get(VERSION_TAG_MAJOR)?.toString()?.toInt()
  61. }.getOrNull() ?: 1
  62. val minor = runCatching {
  63. rootProject.extra.get(VERSION_TAG_MINOR)?.toString()?.toInt()
  64. }.getOrNull() ?: 0
  65. val patch = runCatching {
  66. rootProject.extra.get(VERSION_TAG_PATCH)?.toString()?.toInt()
  67. }.getOrNull() ?: 0
  68. return "${major}.${minor}.${patch}"
  69. }
  70. val Project.taskRequest: List<TaskExecutionRequest>
  71. get() = gradle.startParameter.taskRequests
  72. val Project.taskRequestsArgs: List<String>
  73. get() = ArrayList<String>().also { argsList ->
  74. taskRequest.map { tr ->
  75. tr.args
  76. }.let { list ->
  77. list.forEach { argsList.addAll(it) }
  78. }
  79. }
  80. val Project.taskRequestAssembleTasks
  81. get() = taskRequestsArgs.filter { arg -> arg.startsWith("assemble") }
  82. val Project.taskRequestBundleTasks
  83. get() = taskRequestsArgs.filter { arg -> arg.startsWith("bundle") }
  84. val Project.taskRequestHasAssembles
  85. get() = taskRequestAssembleTasks.isNotEmpty()
  86. val Project.taskRequestHasBundles
  87. get() = taskRequestBundleTasks.isNotEmpty()
  88. //val Project.currentFlavor: String
  89. // get() {
  90. // val buildTypes = arrayOf("Release", "Debug", "Mock")
  91. // val str: String = when {
  92. // taskRequestHasAssembles -> taskRequestAssembleTasks.joinToString { "," }
  93. // taskRequestHasBundles -> taskRequestBundleTasks.joinToString { "," }
  94. // else -> ""
  95. // }
  96. // return when {
  97. // taskRequestHasAssembles -> Pattern
  98. // .compile("assemble(\\w+)(${buildTypes.joinToString { "|" }})")
  99. // .matcher(str)
  100. // .let { matcher ->
  101. // if (matcher.find()) matcher.group(1).lowercase()
  102. // else ""
  103. // }
  104. //
  105. // taskRequestHasBundles -> Pattern
  106. // .compile("bundle(\\w+)(${buildTypes.joinToString { "|" }})")
  107. // .matcher(str)
  108. // .let { matcher ->
  109. // if (matcher.find()) matcher.group(1).lowercase()
  110. // else ""
  111. // }
  112. //
  113. // else -> "-"
  114. // }
  115. // }
  116. val Project.android: ApplicationExtension
  117. get() = extensions.getByType(ApplicationExtension::class.java)
  118. val Project.isAndroid: Boolean
  119. get() = extensions.findByType<ApplicationExtension>() != null
  120. val Project.packageName: String
  121. get() = applicationId
  122. val Project.applicationId: String
  123. get() = if (isAndroid) android.defaultConfig.applicationId ?: "" else ""
  124. val Project.androidComponents: AndroidComponentsExtension<*, *, *>
  125. get() = extensions.getByType(AndroidComponentsExtension::class.java)
  126. val Project.buildDirectory: File
  127. get() = layout.buildDirectory.asFile.get()
  128. val Project.sourceSets
  129. get() = properties["sourceSets"] as SourceSetContainer
  130. val Project.mainSourceSet: SourceSet?
  131. get() = sourceSets.findByName(MAIN_SOURCE_SET_NAME)
  132. val Project.testSourceSet: SourceSet?
  133. get() = sourceSets.findByName(TEST_SOURCE_SET_NAME)
  134. val Project.androidExtension: AppExtension
  135. get() = extensions.getByType(AppExtension::class.java)
  136. val Project.kotlinExtension: KotlinProjectExtension
  137. get() = extensions.getByName("kotlin") as KotlinProjectExtension
  138. //val Project.assembleTasks: List<Task>
  139. // get() = mutableListOf<Task>().apply {
  140. // androidExtension.apply {
  141. // applicationVariants.all { variant ->
  142. // val task = project.tasks.getByName("assemble${variant.name.capitalize()}")
  143. // add(task)
  144. // }
  145. // }
  146. // }
  147. val Project.variants: List<ApplicationVariant>
  148. get() = androidExtension.applicationVariants.toList()
  149. val Project.unitTestDir: File
  150. get() = file("src").file("test").file("java")
  151. val Project.assembleTasks
  152. get() = tasks.filter { t -> t.name.startsWith("assemble") }
  153. val Project.libs
  154. get() = the<LibrariesForLibs>()
  155. val Project.log: Logger
  156. get() = Logging.getLogger(this::class.java)
  157. //inline fun <reified T : Task> Project.registerTask(
  158. // name: String,
  159. // configurationAction: Action<T> = Action<T> {}
  160. //): List<T> = if (T::class.isSubclassOf(BaseTask::class)) {
  161. // mutableListOf<T>().apply {
  162. // variants.forEach { variant ->
  163. // registerTask<T>(
  164. // "$name${variant.name.capitalize()}"
  165. // ).apply {
  166. // (this.get() as BaseTask).variant = variant
  167. // }.get().also { task ->
  168. // task.apply {
  169. // configurationAction.execute(this)
  170. // add(this)
  171. // }
  172. // }
  173. // }
  174. // }
  175. //} else {
  176. // listOf(registerTask<T>(name).get().apply {
  177. // configurationAction.execute(this)
  178. // })
  179. //}
  180. fun Project.loadPropertiesFile(path:String) {
  181. val propertiesFile = project.rootDir.resolve(path)
  182. val props = Properties()
  183. props.load(FileInputStream(propertiesFile))
  184. props.forEach { prop ->
  185. project.rootProject.extra.set(
  186. prop.key.toString(),
  187. prop.value.toString()
  188. )
  189. }
  190. }
  191. inline fun <reified T> Project.extension(name: String? = null): T = runCatching {
  192. var cfg: T? = project.extensions.findByType(T::class.java)
  193. if (cfg == null && name != null) {
  194. project.extensions.add(name, T::class.java)
  195. }
  196. cfg = project.extensions.findByType(T::class.java)
  197. cfg!!
  198. }.getOrThrow()
  199. inline fun <reified T : Any> Project.extension(): T = runCatching {
  200. extensions.getByType(T::class.java)
  201. }.onFailure {
  202. println("Config missing.")
  203. }.getOrThrow()
  204. inline fun <reified T : Task> Project.registerTask(
  205. name: String? = null,
  206. fn: T.() -> Unit = {}
  207. ): T {
  208. val taskName = name
  209. ?: T::class.java.simpleName.replace("Task", "").unCapitalize()
  210. tasks.register(taskName, T::class.java)
  211. return tasks.findByName(taskName).let { task ->
  212. task as T
  213. }.apply {
  214. fn(this)
  215. }
  216. }
  217. fun <T : Plugin<*>> Project.apply(type: KClass<T>): T = plugins.apply(type.java)
  218. fun Project.apply(id: String): Plugin<*> = plugins.apply(id)
  219. fun Project.kotlinCompileOptions(scoped: KotlinCompile.() -> Unit) {
  220. tasks.withType<KotlinCompile>().first().also { t -> scoped(t) }
  221. }
  222. fun Project.detektTask(scoped: Detekt.() -> Unit) {
  223. tasks.withType<Detekt>().first().also { t -> scoped(t) }
  224. }
  225. fun Project.dokkaTask(scoped: DokkaTask.() -> Unit) {
  226. tasks.withType<DokkaTask>().first().also { t -> scoped(t) }
  227. }
  228. //fun Project.markDownToHtmlTask(scoped: MarkdownToHtmlTask.() -> Unit) {
  229. // tasks.withType<MarkdownToHtmlTask>().first().also { t -> scoped(t) }
  230. //}
  231. fun Project.registerSources(outDir: File, variant: BaseVariant) {
  232. if (outDir.absolutePath.contains("generated/source")) {
  233. project.kotlinExtension.sourceSets.findByName(variant.name)?.apply {
  234. kotlin.srcDirs(outDir)
  235. }
  236. project.androidExtension.sourceSets.findByName(variant.name)?.apply {
  237. kotlin.srcDirs(outDir)
  238. }
  239. } else if (outDir.absolutePath.contains("generated/res")) {
  240. project.androidExtension.sourceSets.findByName(variant.name)?.apply {
  241. res.srcDirs(outDir)
  242. }
  243. // variant.mergeResourcesProvider.configure {
  244. // it.dependsOn(task)
  245. // }
  246. }
  247. }
  248. @Suppress("UNCHECKED_CAST")
  249. fun <T> Project.extension(
  250. name: String,
  251. cls: Class<T>,
  252. canCreate: Boolean = true
  253. ): T? = extensions.findByName(name) as? T ?: if (canCreate) extensions.create(
  254. name,
  255. cls
  256. ) else null
  257. fun Project.propOrDefault(propertyName: String, defaultValue: Any): Any = project
  258. .properties[propertyName] ?: (System.getenv(propertyName) ?: defaultValue)
  259. fun Project.propertyOrEmpty(name: String): String = findProperty(name) as String? ?: ""
  260. fun Project.fileTree(directory: File, inc: String, exc: String): List<File> {
  261. return project.fileTree(directory) {
  262. setExcludes(listOf(exc))
  263. setIncludes(listOf(inc))
  264. }.toList()
  265. }
  266. fun Project.fileTree(directory: String, inc: String, exc: String): List<File> {
  267. return project.fileTree(directory) {
  268. setExcludes(listOf(exc))
  269. setIncludes(listOf(inc))
  270. }.toList()
  271. }
  272. inline fun <reified T> Project.runConfigured(crossinline function: T.() -> Unit) {
  273. afterEvaluate {
  274. val config = project.extension<T>()
  275. if (config is BuildConfigs) {
  276. // project.androidExtension.buildTypes.forEach { bt ->
  277. // println("> Configuring build : ${bt.name}")
  278. // val btConfig = config.buildTypes[bt.name.lowercase()]
  279. // println ("> Config: $btConfig")
  280. // btConfig?.invoke(bt)
  281. // }
  282. }
  283. function(config)
  284. }
  285. }
  286. fun Project.androidComponents(
  287. block: AndroidComponentsExtension<*, *, *>.() -> Unit
  288. ) {
  289. block.invoke(androidComponents)
  290. }