Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract better-gradle-properties artifact #1034

Merged
merged 3 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Changelog
**Unreleased**
--------------

- **New**: Extract `better-gradle-properties` artifact, which is our hierarchical Gradle properties solution that better handles properties in Gradle. This is what powers `FoundryProperties` but is now extracted to be more portable.
- 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`
- Remove defunct `foundry.git.hooksPath` and `foundry.git.ignoreRevsFile` properties.

0.20.2
------

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
public final class foundry/gradle/properties/GitExecProvidersKt {
public static final fun gitExecProvider (Lorg/gradle/api/provider/ProviderFactory;[Ljava/lang/String;)Lorg/gradle/api/provider/Provider;
}

public final class foundry/gradle/properties/HasConfigurableValuesKt {
public static final fun fromDisallowChanges (Lorg/gradle/api/file/ConfigurableFileCollection;[Ljava/lang/Object;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/ListProperty;Ljava/lang/Iterable;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/ListProperty;Lorg/gradle/api/provider/Provider;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/ListProperty;Lorg/gradle/api/provider/Provider;Lkotlin/jvm/functions/Function1;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/MapProperty;Ljava/util/Map;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/MapProperty;Lorg/gradle/api/provider/Provider;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/MapProperty;Lorg/gradle/api/provider/Provider;Lkotlin/jvm/functions/Function1;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/Property;Ljava/lang/Object;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/Property;Lorg/gradle/api/provider/Provider;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/SetProperty;Ljava/lang/Iterable;)V
public static final fun setDisallowChanges (Lorg/gradle/api/provider/SetProperty;Lorg/gradle/api/provider/Provider;)V
}

public abstract class foundry/gradle/properties/LocalProperties : org/gradle/api/provider/ValueSource {
public fun <init> ()V
public synthetic fun obtain ()Ljava/lang/Object;
public fun obtain ()Ljava/util/Properties;
}

public abstract interface class foundry/gradle/properties/LocalProperties$Parameters : org/gradle/api/provider/ValueSourceParameters {
public abstract fun getPropertiesFile ()Lorg/gradle/api/file/RegularFileProperty;
}

public final class foundry/gradle/properties/PropertyResolver {
public fun <init> (Lorg/gradle/api/Project;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lorg/gradle/api/Project;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun booleanProvider (Ljava/lang/String;)Lorg/gradle/api/provider/Provider;
public final fun booleanProvider (Ljava/lang/String;Lorg/gradle/api/provider/Provider;)Lorg/gradle/api/provider/Provider;
public final fun booleanProvider (Ljava/lang/String;Z)Lorg/gradle/api/provider/Provider;
public static synthetic fun booleanProvider$default (Lfoundry/gradle/properties/PropertyResolver;Ljava/lang/String;ZILjava/lang/Object;)Lorg/gradle/api/provider/Provider;
public final fun booleanValue (Ljava/lang/String;Lorg/gradle/api/provider/Provider;)Z
public final fun booleanValue (Ljava/lang/String;Z)Z
public static synthetic fun booleanValue$default (Lfoundry/gradle/properties/PropertyResolver;Ljava/lang/String;ZILjava/lang/Object;)Z
public final fun intProvider (Ljava/lang/String;I)Lorg/gradle/api/provider/Provider;
public final fun intProvider (Ljava/lang/String;Lorg/gradle/api/provider/Provider;)Lorg/gradle/api/provider/Provider;
public static synthetic fun intProvider$default (Lfoundry/gradle/properties/PropertyResolver;Ljava/lang/String;IILjava/lang/Object;)Lorg/gradle/api/provider/Provider;
public final fun intValue (Ljava/lang/String;I)I
public final fun intValue (Ljava/lang/String;Lorg/gradle/api/provider/Provider;)I
public static synthetic fun intValue$default (Lfoundry/gradle/properties/PropertyResolver;Ljava/lang/String;IILjava/lang/Object;)I
public final fun optionalStringProvider (Ljava/lang/String;)Lorg/gradle/api/provider/Provider;
public final fun optionalStringProvider (Ljava/lang/String;Ljava/lang/String;)Lorg/gradle/api/provider/Provider;
public static synthetic fun optionalStringProvider$default (Lfoundry/gradle/properties/PropertyResolver;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/gradle/api/provider/Provider;
public final fun optionalStringValue (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
public static synthetic fun optionalStringValue$default (Lfoundry/gradle/properties/PropertyResolver;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;
public final fun providerFor (Ljava/lang/String;)Lorg/gradle/api/provider/Provider;
public final fun stringValue (Ljava/lang/String;)Ljava/lang/String;
public final fun stringValue (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
}

public final class foundry/gradle/properties/PropertyUtil {
public static final fun createPropertiesProvider (Lorg/gradle/api/Project;Ljava/lang/String;)Lorg/gradle/api/provider/Provider;
public static final fun getOrCreateExtra (Lorg/gradle/api/Project;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun localGradleProperty (Lorg/gradle/api/Project;Ljava/lang/String;)Lorg/gradle/api/provider/Provider;
public static final fun localProperty (Lorg/gradle/api/Project;Ljava/lang/String;)Lorg/gradle/api/provider/Provider;
public static final fun mapToBoolean (Lorg/gradle/api/provider/Provider;)Lorg/gradle/api/provider/Provider;
public static final fun mapToInt (Lorg/gradle/api/provider/Provider;)Lorg/gradle/api/provider/Provider;
public static final fun markAsNonNullForGradle (Ljava/lang/Object;)V
public static final fun sneakyNull (Ljava/lang/Object;)Ljava/lang/Object;
public static synthetic fun sneakyNull$default (Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;
public static final fun synchronousEnvProperty (Lorg/gradle/api/Project;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
public static synthetic fun synchronousEnvProperty$default (Lorg/gradle/api/Project;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;
}

public abstract class foundry/gradle/properties/StartParameterProperties : org/gradle/api/provider/ValueSource {
public fun <init> ()V
public synthetic fun obtain ()Ljava/lang/Object;
public fun obtain ()Ljava/util/Map;
}

public abstract interface class foundry/gradle/properties/StartParameterProperties$Parameters : org/gradle/api/provider/ValueSourceParameters {
public abstract fun getProperties ()Lorg/gradle/api/provider/MapProperty;
}

26 changes: 26 additions & 0 deletions platforms/gradle/better-gradle-properties/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.
*/
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.mavenPublish)
alias(libs.plugins.lint)
}

dependencies {
implementation(libs.okio)

compileOnly(gradleApi())
}
3 changes: 3 additions & 0 deletions platforms/gradle/better-gradle-properties/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
POM_ARTIFACT_ID=better-gradle-properties
POM_NAME=Better Gradle Properties
POM_DESCRIPTION=Better Gradle Properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,47 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package foundry.gradle.util
package foundry.gradle.properties

import java.io.ByteArrayOutputStream
import java.nio.charset.Charset
import javax.inject.Inject
import okio.Buffer
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.provider.ValueSource
import org.gradle.api.provider.ValueSourceParameters
import org.gradle.process.ExecOperations

internal fun ProviderFactory.gitVersionProvider(): Provider<String> {
return gitExecProvider("git", "--version")
}

internal fun ProviderFactory.gitExecProvider(vararg args: String): Provider<String> {
/**
* Returns a new UTF8 String [Provider] backed by a [ValueSource] that produces a `git` exec
* operation with the given [args].
*
* Because this is a gradle property that could be used at configuration-time, it's recommended to
* be careful when using this to avoid accidental often configuration-cache invalidations.
*/
public fun ProviderFactory.gitExecProvider(vararg args: String): Provider<String> {
require(args.isNotEmpty()) { "Args list is empty" }
return of(GitExecValueSource::class.java) { parameters.args.addAll(*args) }
}

// Adapted from
// https://docs.gradle.org/8.1/userguide/configuration_cache.html#config_cache:requirements:external_processes
internal abstract class GitExecValueSource : ValueSource<String, GitExecValueSource.Parameters> {
@get:Inject abstract val execOperations: ExecOperations
internal abstract class GitExecValueSource
@Inject
constructor(private val execOperations: ExecOperations) :
ValueSource<String, GitExecValueSource.Parameters> {

override fun obtain(): String {
val args = parameters.args.get()
check(args.isNotEmpty()) { "Args list is empty" }
val output = ByteArrayOutputStream()
execOperations.exec {
commandLine(args)
standardOutput = output
val buffer = Buffer()
buffer.outputStream().use { output ->
execOperations.exec {
commandLine(args)
standardOutput = output
}
}
return String(output.toByteArray(), Charset.defaultCharset()).trim { it <= ' ' }
return buffer.readUtf8().trim()
}

interface Parameters : ValueSourceParameters {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package foundry.gradle.util
package foundry.gradle.properties

import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.provider.ListProperty
Expand All @@ -26,60 +26,60 @@ import org.gradle.api.provider.SetProperty
* APIs adapted from `HasConfigurableValues.kt` in AGP. Copied for binary safety.
*/

internal fun ConfigurableFileCollection.fromDisallowChanges(vararg arg: Any) {
public fun ConfigurableFileCollection.fromDisallowChanges(vararg arg: Any) {
from(*arg)
disallowChanges()
}

internal fun <T> Property<T>.setDisallowChanges(value: T?) {
public fun <T> Property<T>.setDisallowChanges(value: T?) {
set(value)
disallowChanges()
}

internal fun <T> Property<T>.setDisallowChanges(value: Provider<out T>) {
public fun <T> Property<T>.setDisallowChanges(value: Provider<out T>) {
set(value)
disallowChanges()
}

internal fun <T> ListProperty<T>.setDisallowChanges(value: Provider<out Iterable<T>>) {
public fun <T> ListProperty<T>.setDisallowChanges(value: Provider<out Iterable<T>>) {
set(value)
disallowChanges()
}

internal fun <T> ListProperty<T>.setDisallowChanges(value: Iterable<T>?) {
public fun <T> ListProperty<T>.setDisallowChanges(value: Iterable<T>?) {
set(value)
disallowChanges()
}

internal fun <K, V> MapProperty<K, V>.setDisallowChanges(map: Provider<Map<K, V>>) {
public fun <K, V> MapProperty<K, V>.setDisallowChanges(map: Provider<Map<K, V>>) {
set(map)
disallowChanges()
}

internal fun <K, V> MapProperty<K, V>.setDisallowChanges(map: Map<K, V>?) {
public fun <K, V> MapProperty<K, V>.setDisallowChanges(map: Map<K, V>?) {
set(map)
disallowChanges()
}

internal fun <T> SetProperty<T>.setDisallowChanges(value: Provider<out Iterable<T>>) {
public fun <T> SetProperty<T>.setDisallowChanges(value: Provider<out Iterable<T>>) {
set(value)
disallowChanges()
}

internal fun <T> SetProperty<T>.setDisallowChanges(value: Iterable<T>?) {
public fun <T> SetProperty<T>.setDisallowChanges(value: Iterable<T>?) {
set(value)
disallowChanges()
}

internal fun <T> ListProperty<T>.setDisallowChanges(
public fun <T> ListProperty<T>.setDisallowChanges(
value: Provider<out Iterable<T>>?,
handleNullable: ListProperty<T>.() -> Unit,
) {
value?.let { set(value) } ?: handleNullable()
disallowChanges()
}

internal fun <K, V> MapProperty<K, V>.setDisallowChanges(
public fun <K, V> MapProperty<K, V>.setDisallowChanges(
map: Provider<Map<K, V>>?,
handleNullable: MapProperty<K, V>.() -> Unit,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package foundry.gradle.util
package foundry.gradle.properties

import org.gradle.api.Project
import org.gradle.api.provider.Provider

/**
* A property resolver that handles multiple property sources.
* 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 project The project to resolve properties for.
* @property startParameterProperty A provider of a property _only_ contained in the project's start
Expand Down
Loading