foundry.gradle.properties.PropertyResolver.kt Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2024 Slack Technologies, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package foundry.gradle.properties
import java.util.concurrent.Callable
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
/**
* A property resolver that handles multiple property sources in a hierarchical fashion for
* [providerFor].
*
* This checks in the following order of priority
* - project-local `local.properties`
* - project-local `gradle.properties`
* - root-project `local.properties`
* - root-project/global `gradle.properties`
*
* @property startParameterProperty A provider of a property _only_ contained in the project's start
* parameters.
* @property globalLocalProperty A provider of a property _only_ contained in the root project's
* `local.properties`.
*/
public class PropertyResolver(
private val providers: SimpleProviderFactory,
private val localPropertyProvider: (String) -> Provider,
private val localGradlePropertyProvider: (String) -> Provider,
private val startParameterProperty: (String) -> Provider,
private val globalLocalProperty: (String) -> Provider,
private val globalGradleLocalProperty: (String) -> Provider,
) {
public interface SimpleProviderFactory {
public fun provider(callable: Callable): Provider
}
/**
* Returns a "safe" property [Provider] mechanism that handles multiple property sources in a
* hierarchical fashion.
*
* This checks in the following order of priority
* - project-local `local.properties`
* - project-local `gradle.properties`
* - root-project `local.properties`
* - root-project/global `gradle.properties`
*/
public fun providerFor(key: String): Provider =
startParameterProperty(key) // start parameters
.orElse(localPropertyProvider(key)) // project-local `local.properties`
.orElse(localGradlePropertyProvider(key)) // project-local `gradle.properties`
.orElse(globalLocalProperty(key)) // root-project `local.properties`
.orElse(globalGradleLocalProperty(key)) // root-project/global `gradle.properties`
public fun booleanValue(key: String, defaultValue: Boolean = false): Boolean {
return booleanProvider(key, defaultValue).get()
}
public fun booleanValue(key: String, defaultValue: Provider): Boolean {
return booleanProvider(key, defaultValue).get()
}
public fun booleanProvider(key: String, defaultValue: Boolean = false): Provider {
return booleanProvider(key, providers.provider { defaultValue })
}
public fun booleanProvider(key: String, defaultValue: Provider): Provider {
return booleanProvider(key).orElse(defaultValue)
}
public fun booleanProvider(key: String): Provider {
return providerFor(key).mapToBoolean()
}
public fun intValue(key: String, defaultValue: Int = -1): Int {
return intProvider(key, defaultValue).get()
}
public fun intValue(key: String, defaultValue: Provider): Int {
return intProvider(key, defaultValue).get()
}
public fun intProvider(key: String, defaultValue: Int = -1): Provider {
return intProvider(key, providers.provider { defaultValue })
}
public fun intProvider(key: String, defaultValue: Provider): Provider {
return providerFor(key).mapToInt().orElse(defaultValue)
}
public fun stringValue(key: String): String {
return optionalStringValue(key)
?: error("No property for '$key' found and no default value was provided.")
}
public fun stringValue(key: String, defaultValue: String): String {
return optionalStringValue(key, defaultValue)
?: error("No property for '$key' found and no default value was provided.")
}
public fun requiredStringProvider(key: String): Provider {
return optionalStringProvider(key)
.orElse(
providers.provider {
error("No property for '$key' found and no default value was provided.")
}
)
}
public fun optionalStringValue(key: String, defaultValue: String? = null): String? {
return providerFor(key).orNull ?: defaultValue
}
public fun optionalStringProvider(
key: String,
blankBehavior: BlankBehavior = BlankBehavior.ERROR,
): Provider {
return optionalStringProvider(key, null, blankBehavior)
}
public fun optionalStringProvider(
key: String,
defaultValue: String? = null,
blankBehavior: BlankBehavior = BlankBehavior.ERROR,
): Provider {
return providerFor(key)
.let { defaultValue?.let { providers.provider { defaultValue } } ?: it }
.filter {
when (blankBehavior) {
BlankBehavior.FILTER -> {
it.isNotBlank()
}
BlankBehavior.ERROR -> {
it.ifBlank { error("Unexpected blank value for property '$key'") }
true
}
BlankBehavior.NONE -> {
true
}
}
}
}
public enum class BlankBehavior {
FILTER,
ERROR,
NONE,
}
public companion object {
/** @property project The project to resolve properties for. */
public operator fun invoke(
project: Project,
startParameterProperty: (String) -> Provider =
project.providers.emptyStringProvider(),
globalLocalProperty: (String) -> Provider = project.providers.emptyStringProvider(),
localPropertyProvider: (String) -> Provider = project::localProperty,
localGradlePropertyProvider: (String) -> Provider = project::localGradleProperty,
globalGradleLocalProperty: (String) -> Provider = project.providers::gradleProperty,
): PropertyResolver =
PropertyResolver(
providers =
object : SimpleProviderFactory {
override fun provider(callable: Callable): Provider {
return project.providers.provider(callable)
}
},
startParameterProperty = startParameterProperty,
globalLocalProperty = globalLocalProperty,
localPropertyProvider = localPropertyProvider,
localGradlePropertyProvider = localGradlePropertyProvider,
globalGradleLocalProperty = globalGradleLocalProperty,
)
/** @property project The project to resolve properties for. */
public operator fun invoke(
project: Project,
globalResolver: PropertyResolver,
localPropertyProvider: (String) -> Provider = project::localProperty,
localGradlePropertyProvider: (String) -> Provider = project::localGradleProperty,
): PropertyResolver =
PropertyResolver(
providers =
object : SimpleProviderFactory {
override fun provider(callable: Callable): Provider {
return project.providers.provider(callable)
}
},
startParameterProperty = globalResolver.startParameterProperty,
globalLocalProperty = globalResolver.globalLocalProperty,
globalGradleLocalProperty = globalResolver.globalGradleLocalProperty,
localPropertyProvider = localPropertyProvider,
localGradlePropertyProvider = localGradlePropertyProvider,
)
/** @property project The project to resolve properties for. */
public fun createForRootProject(
project: Project,
startParameterProperty: (String) -> Provider =
project.providers.emptyStringProvider(),
globalLocalProperty: (String) -> Provider = project.providers.emptyStringProvider(),
): PropertyResolver {
check(project.rootProject == project) {
"Project '${project.path}' should be the root project"
}
val gradlePropertyProvider: (String) -> Provider = project.providers::gradleProperty
return PropertyResolver(
providers =
object : SimpleProviderFactory {
override fun provider(callable: Callable): Provider {
return project.providers.provider(callable)
}
},
startParameterProperty = startParameterProperty,
globalLocalProperty = globalLocalProperty,
localPropertyProvider = globalLocalProperty,
localGradlePropertyProvider = gradlePropertyProvider,
globalGradleLocalProperty = gradlePropertyProvider,
)
}
}
}
public fun ProviderFactory.emptyStringProvider(): (String) -> Provider = {
provider { null }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy