name.remal.gradle_plugins.dsl.extensions.org.gradle.api.Project.kt Maven / Gradle / Ivy
package name.remal.gradle_plugins.dsl.extensions
import com.google.common.annotations.VisibleForTesting
import groovy.lang.Closure
import name.remal.*
import name.remal.gradle_plugins.dsl.PluginId
import name.remal.gradle_plugins.dsl.ProjectPluginClass
import name.remal.gradle_plugins.dsl.SNAPSHOT_REGEX
import name.remal.gradle_plugins.dsl.utils.ClassLoaderProvider
import name.remal.proxy.CompositeInvocationHandler
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.Project.DEFAULT_VERSION
import org.gradle.api.file.FileCollection
import org.gradle.api.file.FileTree
import org.gradle.api.internal.NamedDomainObjectContainerConfigureDelegate
import org.gradle.api.plugins.AppliedPlugin
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.reporting.ReportingExtension
import org.gradle.api.reporting.ReportingExtension.DEFAULT_REPORTS_DIR_NAME
import org.gradle.initialization.DefaultSettings.DEFAULT_BUILD_SRC_DIR
import org.gradle.util.ConfigureUtil.configureSelf
import java.io.File
import java.lang.reflect.Proxy
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
import kotlin.text.isNotEmpty
val Project.id: String
get() {
return "$group.$name".splitToSequence('.', ':')
.filter(CharSequence::isNotEmpty)
.joinToString(".")
}
val Project.parents: Set
get() = buildSet {
var proj: Project? = project.parent
while (null != proj) {
add(proj)
proj = proj.parent
}
}
val Project.isRootProject: Boolean get() = this.parent == null
private val Project.defaultGroup: String
get() {
val parent = this.parent ?: return ""
return rootProject.name + if (parent === rootProject) "" else "." + parent.path.substring(1).replace(':', '.')
}
val Project.isGroupSet: Boolean get() = !isGroupNotSet
val Project.isGroupNotSet: Boolean
get() = group.toString().run {
if (isEmpty()) return@run true
if (defaultGroup == this) return true
return@run false
}
val Project.isVersionSet: Boolean get() = !isVersionNotSet
val Project.isVersionNotSet: Boolean
get() = version.toString().run {
if (isEmpty()) return@run true
if (DEFAULT_VERSION == this) return@run true
return@run false
}
val Project.isBuildSrcProject get() = DEFAULT_BUILD_SRC_DIR == rootProject.projectDir.name
val Project.isSnapshotVersion get() = SNAPSHOT_REGEX.containsMatchIn(version.toString())
val Project.isNotSnapshotVersion get() = !isSnapshotVersion
val Project.reportsDir: File get() = (extensions.findByType(ReportingExtension::class.java)?.baseDir ?: File(buildDir, DEFAULT_REPORTS_DIR_NAME)).absoluteFile
val PROJECT_GENERATED_SOURCES_DIR_NAME = "generated"
val Project.generatedSourcesDir get() = File(buildDir, PROJECT_GENERATED_SOURCES_DIR_NAME)
val Project.ext: ExtraPropertiesExtension get() = project.extensions.extraProperties
fun Project.findAndUnwrapProperties(propertyNameMask: String) = buildMap {
if (propertyNameMask.contains('*')) {
val regex = Regex(propertyNameMask.split('*').joinToString(".*", transform = ::escapeRegex))
properties.forEach { name, value ->
if (name.matches(regex)) {
put(name, value?.unwrapProviders()?.toStringSmart() ?: return@forEach)
}
}
} else {
findProperty(propertyNameMask)?.let { value ->
put(propertyNameMask, value.unwrapProviders()?.toStringSmart() ?: return@let)
}
}
}
fun Project.isPluginApplied(pluginId: String) = pluginManager.hasPlugin(pluginId)
fun Project.isPluginApplied(pluginId: PluginId) = pluginManager.hasPlugin(pluginId)
fun Project.isPluginApplied(pluginClass: ProjectPluginClass) = plugins.hasPlugin(pluginClass)
fun Project.withPlugin(pluginId: String, action: (appliedPlugin: AppliedPlugin) -> Unit) = pluginManager.withPlugin(pluginId, action)
fun Project.withPlugin(pluginId: PluginId, action: (appliedPlugin: AppliedPlugin) -> Unit) = pluginManager.withPlugin(pluginId, action)
fun Project.withOneOfPlugin(pluginIds: Collection, action: (appliedPlugin: AppliedPlugin) -> Unit) = pluginManager.withOneOfPlugin(pluginIds, action)
fun Project.withOneOfPlugin(vararg pluginIds: String, action: (appliedPlugin: AppliedPlugin) -> Unit) = pluginManager.withOneOfPlugin(ids = *pluginIds, action = action)
fun Project.withPlugins(pluginIds: Collection, action: () -> Unit) = pluginManager.withPlugins(pluginIds, action)
@JvmName("withPluginIds")
fun Project.withPlugins(pluginIds: Collection, action: () -> Unit) = pluginManager.withPlugins(pluginIds, action)
fun Project.applyPlugin(pluginClass: ProjectPluginClass) = pluginManager.apply(pluginClass)
fun Project.applyPlugin(pluginId: String) = pluginManager.apply(pluginId)
fun Project.applyPlugin(pluginId: PluginId) = pluginManager.apply(pluginId)
fun Project.applyFirstAvailable(pluginIds: Collection) = pluginManager.applyFirstAvailable(pluginIds)
fun Project.applyFirstAvailable(vararg pluginIds: String) = pluginManager.applyFirstAvailable(*pluginIds)
fun Project.tryApplyPlugin(pluginId: String) = pluginManager.tryApply(pluginId)
fun Project.tryApplyPlugin(pluginId: PluginId) = pluginManager.tryApply(pluginId)
fun Project.containerWithFactory(type: Class, factory: (name: String) -> T): NamedDomainObjectContainer {
val container: NamedDomainObjectContainer = container(type)
return Proxy.newProxyInstance(
ClassLoaderProvider::class.java.classLoader,
arrayOf(NamedDomainObjectContainer::class.java),
CompositeInvocationHandler()
.appendToStringHandler { container.toString() }
.appendMethodHandler("create", String::class.java, Action::class.java) handler@{ proxy, _, args ->
val name: String = args[0]!!.uncheckedCast()
val configureAction: Action = args[1]!!.uncheckedCast()
val element = factory(name)
configureAction.execute(element)
proxy.uncheckedCast>().add(element)
return@handler element
}
.appendMethodHandler("create", String::class.java) handler@{ proxy, _, args ->
val name: String = args[0]!!.uncheckedCast()
return@handler proxy.uncheckedCast>().create(name, {})
}
.appendMethodHandler("create", String::class.java, Closure::class.java) handler@{ proxy, _, args ->
val name: String = args[0]!!.uncheckedCast()
val configureClosure: Closure<*> = args[1]!!.uncheckedCast()
return@handler proxy.uncheckedCast>().create(name, configureClosure.toConfigureAction())
}
.appendMethodHandler("maybeCreate", String::class.java) handler@{ proxy, _, args ->
val name: String = args[0]!!.uncheckedCast()
proxy.uncheckedCast>().let {
it.findByName(name)?.let { return@handler it }
return@handler it.create(name)
}
}
.appendMethodHandler("configure", Closure::class.java) handler@{ proxy, _, args ->
val configureClosure: Closure<*> = args[0]!!.uncheckedCast()
proxy.uncheckedCast>().let {
val delegate = NamedDomainObjectContainerConfigureDelegate(configureClosure, it)
return@handler configureSelf(configureClosure, it, delegate)
}
}
.appendMethodHandler({ it.declaringClass.isAssignableFrom(NamedDomainObjectContainer::class.java) }) handler@{ _, method, args ->
return@handler method.invoke(container, *(args ?: emptyArray()))
}
).uncheckedCast()
}
fun Project.emptyFileCollection(): FileCollection = files()
fun Project.emptyFileTree(): FileTree = emptyFileCollection().asFileTree
fun Project.autoFileTree(baseFile: File): FileTree {
if (baseFile.isDirectory) {
return fileTree(baseFile)
} else if (baseFile.isFile) {
return when {
this.name.endsWith(".pom") -> emptyFileTree()
this.name.endsWith(".tar") -> tarTree(baseFile)
this.name.endsWith(".tar.gz") -> tarTree(resources.gzip(baseFile))
this.name.endsWith(".tar.bz2") -> tarTree(resources.bzip2(baseFile))
else -> zipTree(baseFile)
}
} else {
return emptyFileTree()
}
}
fun Project.afterEvaluateOrNow(order: Int = 0, action: (project: Project) -> Unit) = afterEvaluateOrNowImpl(ProjectSetupActionsContainer::afterEvaluateActions, order, action)
fun Project.setupTasksAfterEvaluateOrNow(order: Int = 0, action: (project: Project) -> Unit) = afterEvaluateOrNowImpl(ProjectSetupActionsContainer::tasksActions, order, action)
fun Project.setupTasksDependenciesAfterEvaluateOrNow(order: Int = 0, action: (project: Project) -> Unit) = afterEvaluateOrNowImpl(ProjectSetupActionsContainer::taskDependenciesActions, order, action)
fun Project.atTheEndOfAfterEvaluationOrNow(order: Int = 0, action: (project: Project) -> Unit) = afterEvaluateOrNowImpl(ProjectSetupActionsContainer::beforeExecutionActions, order, action)
@VisibleForTesting
internal fun Project.executeSetupActions() {
val actionsContainer = this.extensions.findByType(ProjectSetupActionsContainer::class.java) ?: return
actionsContainer.afterEvaluateActions.sorted().forEach { it.setup(this) }
actionsContainer.tasksActions.sorted().forEach { it.setup(this) }
actionsContainer.taskDependenciesActions.sorted().forEach { it.setup(this) }
actionsContainer.beforeExecutionActions.sorted().forEach { it.setup(this) }
}
private fun Project.afterEvaluateOrNowImpl(containerGetter: ProjectSetupActionsContainer.() -> MutableList, order: Int = 0, action: (project: Project) -> Unit) {
if (state.executed) {
action(this)
} else {
val actionsContainerTask: ProjectSetupActionsContainer = this.extensions.getOrCreateWithAutoName(
ProjectSetupActionsContainer::class.java,
{ afterEvaluate { it.executeSetupActions() } }
)
val container = containerGetter(actionsContainerTask)
container.add(object : ProjectSetupAction() {
override fun getOrder() = order
override fun setupImpl(project: Project) = action(project)
})
}
}
private abstract class ProjectSetupAction : Ordered {
companion object {
private val setupActionNextIndex = AtomicLong(Long.MIN_VALUE)
}
abstract fun setupImpl(project: Project)
@Volatile
var wasExecuted: Boolean = false
fun setup(project: Project) {
if (!wasExecuted) {
synchronized(this) {
if (!wasExecuted) {
wasExecuted = true
setupImpl(project)
}
}
}
}
private val actionIndex = setupActionNextIndex.getAndIncrement()
override fun compareTo(other: ProjectSetupAction): Int {
super.compareTo(other).let { if (it != 0) return it }
return actionIndex.compareTo(other.actionIndex)
}
}
@KotlinAllOpen
private class ProjectSetupActionsContainer {
val afterEvaluateActions = copyOnWriteListOf()
val tasksActions = copyOnWriteListOf()
val taskDependenciesActions = copyOnWriteListOf()
val beforeExecutionActions = copyOnWriteListOf()
}
private fun Project.afterEvaluateAllProjectsOrNowDelegate(impl: Project.(Int, (Project) -> Unit) -> Unit, order: Int, action: (project: Project) -> Unit) {
val allprojects = allprojects.toList()
val projectsLeft = AtomicInteger(allprojects.size)
allprojects.forEach {
it.impl(order) {
if (projectsLeft.decrementAndGet() == 0) {
action(this)
}
}
}
}
fun Project.afterEvaluateAllProjectsOrNow(order: Int = 0, action: (project: Project) -> Unit) = afterEvaluateAllProjectsOrNowDelegate(Project::afterEvaluateOrNow, order, action)
fun Project.setupTasksAfterEvaluateAllProjectsOrNow(order: Int = 0, action: (project: Project) -> Unit) = afterEvaluateAllProjectsOrNowDelegate(Project::setupTasksAfterEvaluateOrNow, order, action)
fun Project.setupTasksDependenciesAfterEvaluateAllProjectsOrNow(order: Int = 0, action: (project: Project) -> Unit) = afterEvaluateAllProjectsOrNowDelegate(Project::setupTasksDependenciesAfterEvaluateOrNow, order, action)
fun Project.atTheEndOfAfterEvaluationAllProjectsOrNow(order: Int = 0, action: (project: Project) -> Unit) = afterEvaluateAllProjectsOrNowDelegate(Project::atTheEndOfAfterEvaluationOrNow, order, action)
@KotlinAllOpen
private class AllprojectsInfo {
var group: String? = null
var version: String? = null
}
fun Project.setAllprojectsGroup(newGroup: String) {
val currentGroup = group.toString()
allprojects { proj ->
val projGroup = proj.group.toString()
val info = proj.extensions.getOrCreateWithAutoName(AllprojectsInfo::class.java)
val infoGroup = info.group
/*
* Set if:
* 1. proj.isGroupNotSet
* 2. projGroup == currentGroup
* 3. projGroup == infoGroup
*/
if (proj.isGroupNotSet
|| projGroup == currentGroup
|| projGroup == infoGroup
) {
proj.group = newGroup
info.group = newGroup
}
}
}
fun Project.setAllprojectsVersion(newVersion: String) {
val currentVersion = version.toString()
allprojects { proj ->
val projVersion = proj.version.toString()
val info = proj.extensions.getOrCreateWithAutoName(AllprojectsInfo::class.java)
val infoVersion = info.version
/*
* Set if:
* 1. proj.isVersionNotSet
* 2. projVersion == currentVersion
* 3. projVersion == infoVersion
*/
if (proj.isVersionNotSet
|| projVersion == currentVersion
|| projVersion == infoVersion
) {
proj.version = newVersion
info.version = newVersion
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy