All Downloads are FREE. Search and download functionalities are using the official Maven repository.

name.remal.gradle_plugins.dsl.extensions.org.gradle.api.Project.kt Maven / Gradle / Ivy

There is a newer version: 1.9.2
Show newest version
package name.remal.gradle_plugins.dsl.extensions

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.gradle_plugins.dsl.utils.getPluginIdForLogging
import name.remal.gradle_plugins.dsl.utils.isPluginDisabledBySystemProperty
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.nio.file.Path
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
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_BUILD_TEMP_DIR_NAME = "tmp"
val Project.buildTempDir get() = File(buildDir, PROJECT_BUILD_TEMP_DIR_NAME)

val Project.ext: ExtraPropertiesExtension get() = project.extensions.extraProperties


fun Project.newTempDir(prefix: String = ""): File {
    return newTempDir(prefix, false, buildTempDir.createDirectories()).also { file ->
        gradle.buildFinished { file.deleteRecursively() }
    }
}

fun Project.newTempFile(prefix: String = "", suffix: String = ".tmp"): File {
    return newTempFile(prefix, suffix, false, buildTempDir.createDirectories()).also { file ->
        gradle.buildFinished { file.delete() }
    }
}


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.randomizeFileCollection(fileCollection: FileCollection, random: Random = Random()): FileCollection {
    return files(provider { fileCollection.files.shuffled(random) })
}

fun Project.randomizeFileTree(fileCollection: FileCollection, random: Random = Random()): FileTree {
    val fileTree = fileCollection.asFileTree

    val paths = mutableListOf().apply {
        fileTree.visit { if (it.isFile) add(it.file.toPath()) }
        if (isEmpty()) return emptyFileTree()
        if (size == 1) return fileTree
        shuffle(random)
    }

    var result = emptyFileTree()
    paths.forEach { path ->
        result += fileTree.matching {
            it.include {
                return@include path.startsWith(it.file.path)
            }
        }
    }

    return result
}


private fun Project.afterEvaluateOrNowImpl(superOrder: Int, order: Int, action: (project: Project) -> Unit) {
    if (state.executed) {
        action(this)

    } else {
        registerOrderedAction(
            "afterEvaluate",
            { execute -> afterEvaluate { execute() } },
            superOrder,
            order,
            action
        )
    }
}

fun Project.afterEvaluateOrNow(action: (project: Project) -> Unit) = afterEvaluateOrNow(DEFAULT_ACTIONS_ORDER, action)
fun Project.afterEvaluateOrNow(order: Int, action: (project: Project) -> Unit) = afterEvaluateOrNowImpl(0, order, action)

fun Project.setupTasksAfterEvaluateOrNow(action: (project: Project) -> Unit) = setupTasksAfterEvaluateOrNow(DEFAULT_ACTIONS_ORDER, action)
fun Project.setupTasksAfterEvaluateOrNow(order: Int, action: (project: Project) -> Unit) = afterEvaluateOrNowImpl(1, order, action)

fun Project.setupTasksDependenciesAfterEvaluateOrNow(action: (project: Project) -> Unit) = setupTasksDependenciesAfterEvaluateOrNow(DEFAULT_ACTIONS_ORDER, action)
fun Project.setupTasksDependenciesAfterEvaluateOrNow(order: Int, action: (project: Project) -> Unit) = afterEvaluateOrNowImpl(2, order, action)

fun Project.atTheEndOfAfterEvaluationOrNow(action: (project: Project) -> Unit) = atTheEndOfAfterEvaluationOrNow(DEFAULT_ACTIONS_ORDER, action)
fun Project.atTheEndOfAfterEvaluationOrNow(order: Int, action: (project: Project) -> Unit) = afterEvaluateOrNowImpl(3, order, action)


private fun Project.afterEvaluateAllProjectsOrNowDelegate(impl: Project.(Int, (Project) -> Unit) -> Unit, order: Int, action: (project: Project) -> Unit) {
    val project = this
    val allprojects = allprojects.toList()
    val projectsLeft = AtomicInteger(allprojects.size)
    allprojects.forEach {
        it.impl(order) {
            if (projectsLeft.decrementAndGet() == 0) {
                action(project)
            }
        }
    }
}

fun Project.afterEvaluateAllProjectsOrNow(action: (project: Project) -> Unit) = afterEvaluateAllProjectsOrNow(DEFAULT_ACTIONS_ORDER, action)
fun Project.afterEvaluateAllProjectsOrNow(order: Int, action: (project: Project) -> Unit) = afterEvaluateAllProjectsOrNowDelegate(Project::afterEvaluateOrNow, order, action)

fun Project.setupTasksAfterEvaluateAllProjectsOrNow(action: (project: Project) -> Unit) = setupTasksAfterEvaluateAllProjectsOrNow(DEFAULT_ACTIONS_ORDER, action)
fun Project.setupTasksAfterEvaluateAllProjectsOrNow(order: Int, action: (project: Project) -> Unit) = afterEvaluateAllProjectsOrNowDelegate(Project::setupTasksAfterEvaluateOrNow, order, action)

fun Project.setupTasksDependenciesAfterEvaluateAllProjectsOrNow(action: (project: Project) -> Unit) = setupTasksDependenciesAfterEvaluateAllProjectsOrNow(DEFAULT_ACTIONS_ORDER, action)
fun Project.setupTasksDependenciesAfterEvaluateAllProjectsOrNow(order: Int, action: (project: Project) -> Unit) = afterEvaluateAllProjectsOrNowDelegate(Project::setupTasksDependenciesAfterEvaluateOrNow, order, action)

fun Project.atTheEndOfAfterEvaluationAllProjectsOrNow(action: (project: Project) -> Unit) = atTheEndOfAfterEvaluationAllProjectsOrNow(DEFAULT_ACTIONS_ORDER, action)
fun Project.atTheEndOfAfterEvaluationAllProjectsOrNow(order: Int, 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
        }
    }
}

fun Project.isPluginDisabledByProperty(pluginId: PluginId): Boolean {
    return isPluginDisabledBySystemProperty(pluginId) || pluginId.allIds.any {
        findProperty("plugin-disabled.$it").unwrapProviders()?.toString()?.toBoolean() == true
    }
}

fun Project.isPluginDisabledByProperty(pluginId: String) = isPluginDisabledByProperty(PluginId(pluginId))

fun Project.isPluginDisabledByProperty(pluginClass: ProjectPluginClass) = isPluginDisabledByProperty(getPluginIdForLogging(pluginClass))




© 2015 - 2024 Weber Informatics LLC | Privacy Policy