diff --git a/core/build.gradle.kts b/core/build.gradle.kts index ee402ec..6f28f9d 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -44,3 +44,9 @@ testing { } } } + +// b/250726951 Gradle ProjectBuilder needs reflection access to java.lang. +val jvmAddOpensArgs = listOf("--add-opens=java.base/java.lang=ALL-UNNAMED") +tasks.withType() { + this.jvmArgs(jvmAddOpensArgs) +} diff --git a/core/src/main/kotlin/androidx/build/gradle/core/FileSystemStorageService.kt b/core/src/main/kotlin/androidx/build/gradle/core/FileSystemStorageService.kt index 2704596..733ffac 100644 --- a/core/src/main/kotlin/androidx/build/gradle/core/FileSystemStorageService.kt +++ b/core/src/main/kotlin/androidx/build/gradle/core/FileSystemStorageService.kt @@ -17,6 +17,7 @@ package androidx.build.gradle.core +import org.gradle.api.provider.Provider import java.io.File import java.io.InputStream import java.nio.file.Files @@ -26,7 +27,7 @@ import java.nio.file.Files */ class FileSystemStorageService( override val bucketName: String, - override val isPush: Boolean, + override val isPush: Provider, override val isEnabled: Boolean ) : StorageService { @@ -50,7 +51,7 @@ class FileSystemStorageService( return false } - if (!isPush) { + if (!isPush.get()) { return false } @@ -67,7 +68,7 @@ class FileSystemStorageService( return false } - if (!isPush) { + if (!isPush.get()) { return false } diff --git a/core/src/main/kotlin/androidx/build/gradle/core/RemoteGradleBuildCache.kt b/core/src/main/kotlin/androidx/build/gradle/core/RemoteGradleBuildCache.kt index c5cd198..98a8b0d 100644 --- a/core/src/main/kotlin/androidx/build/gradle/core/RemoteGradleBuildCache.kt +++ b/core/src/main/kotlin/androidx/build/gradle/core/RemoteGradleBuildCache.kt @@ -17,6 +17,7 @@ package androidx.build.gradle.core +import org.gradle.api.provider.Property import org.gradle.caching.configuration.AbstractBuildCache /** @@ -24,6 +25,20 @@ import org.gradle.caching.configuration.AbstractBuildCache */ abstract class RemoteGradleBuildCache : AbstractBuildCache() { + /** + * Runtime switch that determines whether the build attempts to upload entries + * to the remote build cache. + * + * Unlike [org.gradle.caching.configuration.BuildCache.isPush], this flag is **not** + * part of the Gradle Configuration Cache model’s fingerprint and is only used at execution + * time. + * + * Keeping `push = true` in `settings.gradle[.kts]` and gating uploads with this property allows you to + * toggle pushing without invalidating the configuration cache + * + */ + abstract val runtimePush: Property + /** * The name of the bucket that is used to store all the gradle cache entries. * This essentially becomes the root of all cache entries. diff --git a/core/src/main/kotlin/androidx/build/gradle/core/StorageService.kt b/core/src/main/kotlin/androidx/build/gradle/core/StorageService.kt index 0515528..678cf23 100644 --- a/core/src/main/kotlin/androidx/build/gradle/core/StorageService.kt +++ b/core/src/main/kotlin/androidx/build/gradle/core/StorageService.kt @@ -17,6 +17,8 @@ package androidx.build.gradle.core +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import java.io.Closeable import java.io.InputStream @@ -29,7 +31,7 @@ interface StorageService : Closeable { /** * `true` if the underlying storage service supports writes and deletes. */ - val isPush: Boolean + val isPush: Provider /** * If `true`, use the underlying storage service. diff --git a/core/src/test/kotlin/androidx/build/gradle/core/FileStorageServiceTest.kt b/core/src/test/kotlin/androidx/build/gradle/core/FileStorageServiceTest.kt index 63e0001..b9c7c12 100644 --- a/core/src/test/kotlin/androidx/build/gradle/core/FileStorageServiceTest.kt +++ b/core/src/test/kotlin/androidx/build/gradle/core/FileStorageServiceTest.kt @@ -17,14 +17,19 @@ package androidx.build.gradle.core +import org.gradle.api.model.ObjectFactory +import org.gradle.testfixtures.ProjectBuilder import org.junit.Test class FileStorageServiceTest { + + private val objectFactory: ObjectFactory = ProjectBuilder.builder().build().objects + @Test fun testStoreBlob() { val storageService = FileSystemStorageService( bucketName = BUCKET_NAME, - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true ) storageService.use { @@ -39,7 +44,7 @@ class FileStorageServiceTest { fun testLoadBlob() { val storageService = FileSystemStorageService( bucketName = BUCKET_NAME, - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true ) storageService.use { @@ -57,7 +62,7 @@ class FileStorageServiceTest { fun testStoreBlob_noPushSupport() { val storageService = FileSystemStorageService( bucketName = BUCKET_NAME, - isPush = false, + isPush = objectFactory.property(Boolean::class.java).convention(false), isEnabled = true ) storageService.use { @@ -72,7 +77,7 @@ class FileStorageServiceTest { fun testStoreBlob_disabled() { val storageService = FileSystemStorageService( bucketName = BUCKET_NAME, - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = false ) storageService.use { diff --git a/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpBuildCacheService.kt b/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpBuildCacheService.kt index 61d058c..60e2590 100644 --- a/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpBuildCacheService.kt +++ b/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpBuildCacheService.kt @@ -20,6 +20,7 @@ package androidx.build.gradle.gcpbuildcache import androidx.build.gradle.core.FileSystemStorageService import androidx.build.gradle.core.blobKey import org.gradle.api.logging.Logging +import org.gradle.api.provider.Provider import org.gradle.caching.BuildCacheEntryReader import org.gradle.caching.BuildCacheEntryWriter import org.gradle.caching.BuildCacheKey @@ -39,7 +40,7 @@ internal class GcpBuildCacheService( private val bucketName: String, gcpCredentials: GcpCredentials, messageOnAuthenticationFailure: String, - isPush: Boolean, + isPush: Provider, isEnabled: Boolean, inTestMode: Boolean = false ) : BuildCacheService { diff --git a/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpBuildCacheServiceFactory.kt b/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpBuildCacheServiceFactory.kt index 846367e..88fbad0 100644 --- a/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpBuildCacheServiceFactory.kt +++ b/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpBuildCacheServiceFactory.kt @@ -32,7 +32,6 @@ class GcpBuildCacheServiceFactory : BuildCacheServiceFactory { .type("GCP-backed") .config("projectId", buildCache.projectId) .config("bucketName", buildCache.bucketName) - .config("isPushSupported", "${buildCache.isPush}") .config("isEnabled", "${buildCache.isEnabled}") .config( "usingExportedKeyCredentials", @@ -44,7 +43,7 @@ class GcpBuildCacheServiceFactory : BuildCacheServiceFactory { buildCache.bucketName, buildCache.credentials, buildCache.messageOnAuthenticationFailure, - buildCache.isPush, + buildCache.runtimePush.orElse(buildCache.isPush), buildCache.isEnabled ) service.validateConfiguration() diff --git a/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpStorageService.kt b/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpStorageService.kt index 921ef1e..08f090a 100644 --- a/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpStorageService.kt +++ b/gcpbuildcache/src/main/kotlin/androidx/build/gradle/gcpbuildcache/GcpStorageService.kt @@ -27,6 +27,7 @@ import com.google.cloud.http.HttpTransportOptions import com.google.cloud.storage.* import org.gradle.api.GradleException import org.gradle.api.logging.Logging +import org.gradle.api.provider.Provider import java.io.InputStream /** @@ -37,13 +38,13 @@ internal class GcpStorageService( override val bucketName: String, gcpCredentials: GcpCredentials, messageOnAuthenticationFailure: String, - override val isPush: Boolean, + override val isPush: Provider, override val isEnabled: Boolean, private val sizeThreshold: Long = BLOB_SIZE_THRESHOLD ) : StorageService { private val storageOptions by lazy { - storageOptions(projectId, gcpCredentials, messageOnAuthenticationFailure, isPush) + storageOptions(projectId, gcpCredentials, messageOnAuthenticationFailure) } override fun load(cacheKey: String): InputStream? { @@ -62,7 +63,7 @@ internal class GcpStorageService( return false } - if (!isPush) { + if (!isPush.get()) { logger.info("No push support") return false } @@ -77,7 +78,7 @@ internal class GcpStorageService( return false } - if (!isPush) { + if (!isPush.get()) { return false } val blobId = BlobId.of(bucketName, cacheKey) @@ -164,12 +165,10 @@ internal class GcpStorageService( projectId: String, gcpCredentials: GcpCredentials, messageOnAuthenticationFailure: String, - isPushSupported: Boolean ): StorageOptions? { val credentials = credentials( gcpCredentials, messageOnAuthenticationFailure, - isPushSupported ) ?: return null val retrySettings = RetrySettings.newBuilder() retrySettings.maxAttempts = 3 @@ -241,14 +240,10 @@ internal class GcpStorageService( private fun credentials( gcpCredentials: GcpCredentials, messageOnAuthenticationFailure: String, - isPushSupported: Boolean ): GoogleCredentials? { - val scopes = mutableListOf( - STORAGE_READ_ONLY, + val scopes = listOf( + STORAGE_READ_ONLY, STORAGE_READ_WRITE, STORAGE_FULL_CONTROL ) - if (isPushSupported) { - scopes += listOf(STORAGE_READ_WRITE, STORAGE_FULL_CONTROL) - } return when (gcpCredentials) { is ApplicationDefaultGcpCredentials -> { defaultApplicationGcpCredentials(scopes, messageOnAuthenticationFailure, forceClearCache = false) diff --git a/gcpbuildcache/src/test/kotlin/androidx/build/gradle/gcpbuildcache/GcpStorageServiceTest.kt b/gcpbuildcache/src/test/kotlin/androidx/build/gradle/gcpbuildcache/GcpStorageServiceTest.kt index 0f14b9e..8864d60 100644 --- a/gcpbuildcache/src/test/kotlin/androidx/build/gradle/gcpbuildcache/GcpStorageServiceTest.kt +++ b/gcpbuildcache/src/test/kotlin/androidx/build/gradle/gcpbuildcache/GcpStorageServiceTest.kt @@ -17,6 +17,8 @@ package androidx.build.gradle.gcpbuildcache +import org.gradle.api.model.ObjectFactory +import org.gradle.testfixtures.ProjectBuilder import org.junit.Assume.assumeNotNull import org.junit.Test import java.io.File @@ -27,6 +29,8 @@ import java.io.File class GcpStorageServiceTest { private val serviceAccountPath = System.getenv()["GRADLE_CACHE_SERVICE_ACCOUNT_PATH"] + private val objectFactory: ObjectFactory = ProjectBuilder.builder().build().objects + @Test fun testStoreBlob() { assumeNotNull(serviceAccountPath) @@ -35,7 +39,7 @@ class GcpStorageServiceTest { bucketName = BUCKET_NAME, gcpCredentials = ExportedKeyGcpCredentials(File(serviceAccountPath!!)), messageOnAuthenticationFailure = "Please re-authenticate", - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true, sizeThreshold = 0L ) @@ -56,7 +60,7 @@ class GcpStorageServiceTest { bucketName = BUCKET_NAME, gcpCredentials = ExportedKeyGcpCredentials(File(serviceAccountPath!!)), messageOnAuthenticationFailure = "Please re-authenticate", - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true, sizeThreshold = 0L ) @@ -80,7 +84,7 @@ class GcpStorageServiceTest { bucketName = BUCKET_NAME, gcpCredentials = ExportedKeyGcpCredentials(File(serviceAccountPath!!)), messageOnAuthenticationFailure = "Please re-authenticate", - isPush = false, + isPush = objectFactory.property(Boolean::class.java).convention(false), isEnabled = true, sizeThreshold = 0L ) @@ -100,7 +104,7 @@ class GcpStorageServiceTest { bucketName = BUCKET_NAME, gcpCredentials = ExportedKeyGcpCredentials(File(serviceAccountPath!!)), messageOnAuthenticationFailure = "Please re-authenticate", - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true, sizeThreshold = 0L ) @@ -109,7 +113,7 @@ class GcpStorageServiceTest { bucketName = BUCKET_NAME, gcpCredentials = ExportedKeyGcpCredentials(File(serviceAccountPath)), messageOnAuthenticationFailure = "Please re-authenticate", - isPush = false, + isPush = objectFactory.property(Boolean::class.java).convention(false), isEnabled = true, sizeThreshold = 0L ) @@ -135,7 +139,7 @@ class GcpStorageServiceTest { bucketName = BUCKET_NAME, gcpCredentials = ExportedKeyGcpCredentials(File(serviceAccountPath!!)), messageOnAuthenticationFailure = "Please re-authenticate", - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = false, sizeThreshold = 0L ) diff --git a/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3BuildCacheService.kt b/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3BuildCacheService.kt index be2b814..ea4ac43 100644 --- a/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3BuildCacheService.kt +++ b/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3BuildCacheService.kt @@ -20,6 +20,7 @@ package androidx.build.gradle.s3buildcache import androidx.build.gradle.core.FileSystemStorageService import androidx.build.gradle.core.blobKey import org.gradle.api.logging.Logging +import org.gradle.api.provider.Provider import org.gradle.caching.BuildCacheEntryReader import org.gradle.caching.BuildCacheEntryWriter import org.gradle.caching.BuildCacheKey @@ -42,7 +43,7 @@ class S3BuildCacheService( credentials: S3Credentials, region: String, bucketName: String, - isPush: Boolean, + isPush: Provider, isEnabled: Boolean, reducedRedundancy: Boolean, inTestMode: Boolean = false diff --git a/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3BuildCacheServiceFactory.kt b/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3BuildCacheServiceFactory.kt index 2685a71..decbb94 100644 --- a/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3BuildCacheServiceFactory.kt +++ b/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3BuildCacheServiceFactory.kt @@ -34,14 +34,13 @@ class S3BuildCacheServiceFactory : BuildCacheServiceFactory { .config("region", buildCache.region) .config("bucketName", buildCache.bucketName) .config("reducedRedundancy", "${buildCache.reducedRedundancy}") - .config("isPushSupported", "${buildCache.isPush}") .config("isEnabled", "${buildCache.isEnabled}") .config("credentialsType", "${buildCache.credentials}") val service = S3BuildCacheService( region = buildCache.region, bucketName = buildCache.bucketName, - isPush = buildCache.isPush, + isPush = buildCache.runtimePush.orElse(buildCache.isPush), isEnabled = buildCache.isEnabled, reducedRedundancy = buildCache.reducedRedundancy, credentials = buildCache.credentials diff --git a/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3StorageService.kt b/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3StorageService.kt index 21354f6..4d3f6e6 100644 --- a/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3StorageService.kt +++ b/s3buildcache/src/main/kotlin/androidx/build/gradle/s3buildcache/S3StorageService.kt @@ -21,8 +21,7 @@ import androidx.build.gradle.core.FileHandleInputStream import androidx.build.gradle.core.FileHandleInputStream.Companion.handleInputStream import androidx.build.gradle.core.StorageService import org.gradle.api.logging.Logging -import software.amazon.awssdk.core.exception.SdkClientException -import software.amazon.awssdk.core.exception.SdkException +import org.gradle.api.provider.Provider import software.amazon.awssdk.core.exception.SdkServiceException import software.amazon.awssdk.core.sync.RequestBody import software.amazon.awssdk.services.s3.S3Client @@ -37,7 +36,7 @@ import kotlin.io.path.outputStream class S3StorageService( override val bucketName: String, - override val isPush: Boolean, + override val isPush: Provider, override val isEnabled: Boolean, private val client: S3Client, private val region: String, @@ -65,7 +64,7 @@ class S3StorageService( return false } - if (!isPush) { + if (!isPush.get()) { logger.info("No push support") return false } @@ -94,7 +93,7 @@ class S3StorageService( return false } - if (!isPush) { + if (!isPush.get()) { logger.info("No push support") return false } diff --git a/s3buildcache/src/test/kotlin/androidx/build/gradle/s3buildcache/S3StorageServiceTest.kt b/s3buildcache/src/test/kotlin/androidx/build/gradle/s3buildcache/S3StorageServiceTest.kt index f22314c..9932c83 100644 --- a/s3buildcache/src/test/kotlin/androidx/build/gradle/s3buildcache/S3StorageServiceTest.kt +++ b/s3buildcache/src/test/kotlin/androidx/build/gradle/s3buildcache/S3StorageServiceTest.kt @@ -19,6 +19,8 @@ package androidx.build.gradle.s3buildcache import com.adobe.testing.s3mock.S3MockApplication import com.adobe.testing.s3mock.S3MockApplication.* +import org.gradle.api.model.ObjectFactory +import org.gradle.testfixtures.ProjectBuilder import org.junit.After import org.junit.Before import org.junit.Test @@ -34,6 +36,8 @@ class S3StorageServiceTest { private lateinit var s3MockApplication: S3MockApplication private lateinit var client: S3Client + private val objectFactory: ObjectFactory = ProjectBuilder.builder().build().objects + @Before fun setUp() { @@ -63,7 +67,7 @@ class S3StorageServiceTest { region = REGION, bucketName = BUCKET_NAME, client = client, - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true, reducedRedundancy = true, sizeThreshold = SIZE_THRESHOLD @@ -83,7 +87,7 @@ class S3StorageServiceTest { region = REGION, bucketName = BUCKET_NAME, client = client, - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true, reducedRedundancy = true, sizeThreshold = SIZE_THRESHOLD @@ -106,7 +110,7 @@ class S3StorageServiceTest { region = REGION, bucketName = BUCKET_NAME, client = client, - isPush = false, + isPush = objectFactory.property(Boolean::class.java).convention(false), isEnabled = true, reducedRedundancy = true, sizeThreshold = SIZE_THRESHOLD @@ -125,7 +129,7 @@ class S3StorageServiceTest { region = REGION, bucketName = BUCKET_NAME, client = client, - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true, reducedRedundancy = true, sizeThreshold = SIZE_THRESHOLD @@ -134,7 +138,7 @@ class S3StorageServiceTest { region = REGION, bucketName = BUCKET_NAME, client = client, - isPush = false, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = true, reducedRedundancy = true, sizeThreshold = SIZE_THRESHOLD @@ -159,7 +163,7 @@ class S3StorageServiceTest { region = REGION, bucketName = BUCKET_NAME, client = client, - isPush = true, + isPush = objectFactory.property(Boolean::class.java).convention(true), isEnabled = false, reducedRedundancy = true, sizeThreshold = SIZE_THRESHOLD