Skip to content

Commit b5fd662

Browse files
committed
Enable configuration cache
Enable the configuration cache feature in Gradle, and adjust various pieces of build logic that aren't configuration cache compatible.
1 parent 8b6b90d commit b5fd662

20 files changed

Lines changed: 271 additions & 170 deletions

build-logic/src/main/kotlin/BuildInfo.kt

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -372,35 +372,33 @@ open class BuildInfo(private val project: Project) {
372372
org.gradle.internal.os.OperatingSystem.current()
373373
}
374374

375-
// could be `commitId: Provider<String> = project.provider { ... }`
376-
val commitId: String by lazy {
377-
// allow -DcommitId=abc123 for build environments that don't have git.
378-
System.getProperty("commitId").let { if (it != null) return@lazy it }
375+
private val computedCommitId: Provider<String> =
379376
// only run command once per build invocation
380377
if (project.path == project.rootProject.path) {
381-
val process =
382-
ProcessBuilder()
383-
.command("git", "rev-parse", "--short", "HEAD")
384-
.directory(project.rootDir)
385-
.start()
386-
process.waitFor().also { exitCode ->
387-
if (exitCode == -1) throw RuntimeException(process.errorStream.reader().readText())
388-
}
389-
process.inputStream.reader().readText().trim()
378+
project.providers
379+
.exec { commandLine("git", "rev-parse", "--short", "HEAD") }
380+
.standardOutput
381+
.asText
382+
.map { it.trim() }
390383
} else {
391384
project.rootProject.extensions.getByType(BuildInfo::class.java).commitId
392385
}
393-
}
394386

395-
val commitish: String by lazy { if (isReleaseBuild) project.version.toString() else commitId }
387+
val commitId: Provider<String> =
388+
// allow -DcommitId=abc123 for build environments that don't have git.
389+
System.getProperty("commitId")?.let { project.providers.provider { it } } ?: computedCommitId
396390

397-
val pklVersion: String by lazy {
391+
val commitish: Provider<String> =
392+
if (isReleaseBuild) project.providers.provider { project.version.toString() } else commitId
393+
394+
val pklVersion: Provider<String> =
398395
if (isReleaseBuild) {
399-
project.version.toString()
396+
project.providers.provider { project.version.toString() }
400397
} else {
401-
project.version.toString().replace("-SNAPSHOT", "-dev+$commitId")
398+
project.providers
399+
.provider { project.version.toString() }
400+
.zip(commitId) { version, id -> version.replace("-SNAPSHOT", "-dev+$id") }
402401
}
403-
}
404402

405403
val pklVersionNonUnique: String by lazy {
406404
if (isReleaseBuild) {

build-logic/src/main/kotlin/InstallGraalVm.kt

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@ import java.util.*
2020
import javax.inject.Inject
2121
import kotlin.io.path.createDirectories
2222
import org.gradle.api.DefaultTask
23+
import org.gradle.api.file.DirectoryProperty
24+
import org.gradle.api.file.RegularFileProperty
2325
import org.gradle.api.internal.file.FileOperations
2426
import org.gradle.api.provider.Property
2527
import org.gradle.api.tasks.Input
28+
import org.gradle.api.tasks.InputFile
29+
import org.gradle.api.tasks.Internal
2630
import org.gradle.api.tasks.TaskAction
2731
import org.gradle.process.ExecOperations
2832

@@ -32,25 +36,32 @@ constructor(
3236
private val fileOperations: FileOperations,
3337
private val execOperations: ExecOperations,
3438
) : DefaultTask() {
35-
@get:Input abstract val graalVm: Property<BuildInfo.GraalVm>
39+
@get:Input abstract val homeDir: Property<String>
40+
41+
@get:InputFile abstract val downloadFile: RegularFileProperty
42+
43+
@get:Input abstract val version: Property<String>
44+
45+
@get:Input abstract val graalVmJdkVersion: Property<String>
46+
47+
@get:Internal abstract val installDir: DirectoryProperty
3648

3749
init {
38-
@Suppress("LeakingThis") onlyIf("GraalVM not installed") { !graalVm.get().installDir.exists() }
50+
@Suppress("LeakingThis") onlyIf("GraalVM not installed") { !installDir.get().asFile.exists() }
3951
}
4052

4153
@TaskAction
4254
@Suppress("unused")
4355
fun run() {
44-
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink
45-
val distroDir = Paths.get(graalVm.get().homeDir, UUID.randomUUID().toString())
56+
val distroDir = Paths.get(homeDir.get(), UUID.randomUUID().toString())
4657
try {
4758
distroDir.createDirectories()
48-
println("Extracting ${graalVm.get().downloadFile} into $distroDir")
59+
println("Extracting ${downloadFile.get().asFile} into $distroDir")
4960
// faster and more reliable than Gradle's `copy { from tarTree() }`
5061
execOperations.exec {
5162
workingDir = distroDir.toFile()
5263
executable = "tar"
53-
args("--strip-components=1", "-xzf", graalVm.get().downloadFile)
64+
args("--strip-components=1", "-xzf", downloadFile.get().asFile)
5465
}
5566

5667
val os = org.gradle.internal.os.OperatingSystem.current()
@@ -59,8 +70,8 @@ constructor(
5970

6071
println("Installing native-image into $distroDir")
6172
val gvmVersionMajor =
62-
requireNotNull(graalVm.get().version.split(".").first().toIntOrNull()) {
63-
"Invalid GraalVM JDK version: ${graalVm.get().graalVmJdkVersion}"
73+
requireNotNull(version.get().split(".").first().toIntOrNull()) {
74+
"Invalid GraalVM JDK version: ${graalVmJdkVersion.get()}"
6475
}
6576
if (gvmVersionMajor < 24) {
6677
execOperations.exec {
@@ -70,11 +81,11 @@ constructor(
7081
}
7182
}
7283

73-
println("Creating symlink ${graalVm.get().installDir} for $distroDir")
74-
val tempLink = Paths.get(graalVm.get().homeDir, UUID.randomUUID().toString())
84+
println("Creating symlink ${installDir.get().asFile} for $distroDir")
85+
val tempLink = Paths.get(homeDir.get(), UUID.randomUUID().toString())
7586
Files.createSymbolicLink(tempLink, distroDir)
7687
try {
77-
Files.move(tempLink, graalVm.get().installDir.toPath(), StandardCopyOption.ATOMIC_MOVE)
88+
Files.move(tempLink, installDir.get().asFile.toPath(), StandardCopyOption.ATOMIC_MOVE)
7889
} catch (e: Exception) {
7990
try {
8091
fileOperations.delete(tempLink.toFile())

build-logic/src/main/kotlin/NativeImageBuild.kt

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@
1616
import javax.inject.Inject
1717
import org.gradle.api.DefaultTask
1818
import org.gradle.api.file.ConfigurableFileCollection
19+
import org.gradle.api.file.ProjectLayout
1920
import org.gradle.api.provider.ListProperty
2021
import org.gradle.api.provider.Property
21-
import org.gradle.api.provider.Provider
2222
import org.gradle.api.services.BuildService
2323
import org.gradle.api.services.BuildServiceParameters
24+
import org.gradle.api.services.ServiceReference
2425
import org.gradle.api.tasks.ClasspathNormalizer
2526
import org.gradle.api.tasks.Input
2627
import org.gradle.api.tasks.InputFiles
2728
import org.gradle.api.tasks.OutputFile
2829
import org.gradle.api.tasks.PathSensitivity
2930
import org.gradle.api.tasks.TaskAction
30-
import org.gradle.kotlin.dsl.registerIfAbsent
3131
import org.gradle.kotlin.dsl.withNormalizer
3232
import org.gradle.process.ExecOperations
3333

@@ -49,45 +49,39 @@ abstract class NativeImageBuild : DefaultTask() {
4949

5050
@get:InputFiles abstract val classpath: ConfigurableFileCollection
5151

52-
private val outputDir = project.layout.buildDirectory.dir("executable")
52+
/** Path to the `native-image` binary (e.g. `<graalVmBaseDir>/bin/native-image`). */
53+
@get:Input abstract val nativeImageExecutable: Property<String>
5354

54-
@get:OutputFile val outputFile = outputDir.flatMap { it.file(imageName) }
55+
@get:Input abstract val graalSdkLibraryName: Property<String>
56+
57+
@get:Input abstract val releaseBuild: Property<Boolean>
58+
59+
@get:Input abstract val nativeArch: Property<Boolean>
60+
61+
/** Divisor applied to `availableProcessors` to throttle native-image CPU usage. */
62+
@get:Input abstract val processorDivisor: Property<Int>
5563

5664
@get:Inject protected abstract val execOperations: ExecOperations
5765

58-
private val graalVm: Provider<BuildInfo.GraalVm> = arch.map { a ->
59-
when (a) {
60-
Architecture.AMD64 -> buildInfo.graalVmAmd64
61-
Architecture.AARCH64 -> buildInfo.graalVmAarch64
62-
}
63-
}
66+
@get:Inject protected abstract val layout: ProjectLayout
6467

65-
private val buildInfo: BuildInfo = project.extensions.getByType(BuildInfo::class.java)
68+
private val outputDir
69+
get() = layout.buildDirectory.dir("executable")
6670

67-
private val nativeImageCommandName =
68-
if (buildInfo.os.isWindows) "native-image.cmd" else "native-image"
71+
@get:OutputFile
72+
val outputFile
73+
get() = outputDir.flatMap { it.file(imageName) }
6974

70-
private val nativeImageExecutable = graalVm.map { "${it.baseDir}/bin/$nativeImageCommandName" }
75+
@get:ServiceReference("nativeImageBuildService")
76+
abstract val buildService: Property<NativeImageBuildService>
7177

7278
private val extraArgsFromProperties by lazy {
7379
System.getProperties()
7480
.filter { it.key.toString().startsWith("pkl.native") }
7581
.map { "${it.key}=${it.value}".substring("pkl.native".length) }
7682
}
7783

78-
private val buildService =
79-
project.gradle.sharedServices.registerIfAbsent(
80-
"nativeImageBuildService",
81-
NativeImageBuildService::class,
82-
) {
83-
maxParallelUsages.set(1)
84-
}
85-
8684
init {
87-
// ensure native-image builds run in serial (prevent `gw buildNative` from consuming all host
88-
// CPU resources).
89-
usesService(buildService)
90-
9185
group = "build"
9286

9387
inputs
@@ -104,8 +98,7 @@ abstract class NativeImageBuild : DefaultTask() {
10498
@Suppress("unused")
10599
protected fun run() {
106100
execOperations.exec {
107-
val exclusions =
108-
listOf(buildInfo.libs.findLibrary("graalSdk").get()).map { it.get().module.name }
101+
val exclusions = listOf(graalSdkLibraryName.get())
109102

110103
executable = nativeImageExecutable.get()
111104
workingDir(outputDir)
@@ -140,10 +133,10 @@ abstract class NativeImageBuild : DefaultTask() {
140133
add("-H:-ParseRuntimeOptions")
141134
// quick build mode: 40% faster compilation, 20% smaller (but presumably also slower)
142135
// executable
143-
if (!buildInfo.isReleaseBuild) {
136+
if (!releaseBuild.get()) {
144137
add("-Ob")
145138
}
146-
if (buildInfo.isNativeArch) {
139+
if (nativeArch.get()) {
147140
add("-march=native")
148141
} else {
149142
add("-march=compatibility")
@@ -155,9 +148,7 @@ abstract class NativeImageBuild : DefaultTask() {
155148
}
156149
add(pathInput.asPath)
157150
// make sure dev machine stays responsive (15% slowdown on my laptop)
158-
val processors =
159-
Runtime.getRuntime().availableProcessors() /
160-
if (buildInfo.os.isMacOsX && !buildInfo.isCiBuild) 4 else 1
151+
val processors = Runtime.getRuntime().availableProcessors() / processorDivisor.get()
161152
add("-J-XX:ActiveProcessorCount=${processors}")
162153
// Pass through all `HOMEBREW_` prefixed environment variables to allow build with shimmed
163154
// tools.

build-logic/src/main/kotlin/PklFormatterSpotless.kt

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616
import com.diffplug.spotless.FormatterFunc
1717
import com.diffplug.spotless.FormatterStep
18+
import java.io.File
1819
import java.io.Serial
1920
import java.io.Serializable
21+
import java.lang.reflect.Method
2022
import java.net.URLClassLoader
2123
import org.gradle.api.artifacts.Configuration
2224

@@ -26,31 +28,45 @@ class PklFormatterStep(@Transient private val configuration: Configuration) : Se
2628
}
2729

2830
fun create(): FormatterStep {
31+
val files = configuration.files.toList()
2932
return FormatterStep.createLazy(
3033
"pkl",
31-
{ PklFormatterStep(configuration) },
32-
{ PklFormatterFunc(configuration) },
34+
{ PklFormatterState(files) },
35+
{ PklFormatterFunc(it.files) },
3336
)
3437
}
3538
}
3639

37-
class PklFormatterFunc(@Transient private val configuration: Configuration) :
38-
FormatterFunc, Serializable {
40+
data class PklFormatterState(val files: List<File>) : Serializable {
3941
companion object {
4042
@Serial private const val serialVersionUID: Long = 1L
4143
}
44+
}
4245

43-
private val classLoader by lazy {
44-
val urls = configuration.files.map { it.toURI().toURL() }
46+
class PklFormatterFunc(private val files: List<File>) : FormatterFunc, Serializable {
47+
companion object {
48+
@Serial private const val serialVersionUID: Long = 1L
49+
}
50+
51+
@delegate:Transient
52+
private val classLoader: URLClassLoader by lazy {
53+
val urls = files.map { it.toURI().toURL() }
4554
// Use the platform classloader as parent to isolate from Gradle's classloader
4655
URLClassLoader(urls.toTypedArray(), ClassLoader.getPlatformClassLoader())
4756
}
4857

49-
private val formatterClass by lazy { classLoader.loadClass("org.pkl.formatter.Formatter") }
58+
@delegate:Transient
59+
private val formatterClass: Class<*> by lazy {
60+
classLoader.loadClass("org.pkl.formatter.Formatter")
61+
}
5062

51-
private val formatMethod by lazy { formatterClass.getMethod("format", String::class.java) }
63+
@delegate:Transient
64+
private val formatMethod: Method by lazy {
65+
formatterClass.getMethod("format", String::class.java)
66+
}
5267

53-
private val formatterInstance by lazy { formatterClass.getConstructor().newInstance() }
68+
@delegate:Transient
69+
private val formatterInstance: Any by lazy { formatterClass.getConstructor().newInstance() }
5470

5571
override fun apply(input: String): String {
5672
return formatMethod(formatterInstance, input) as String

build-logic/src/main/kotlin/PklPublishing.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ fun Project.configurePklPomMetadata() {
4646
connection.set("scm:git:git://github.com/apple/pkl.git")
4747
developerConnection.set("scm:git:ssh://github.com/apple/pkl.git")
4848
val buildInfo = extensions.getByType<BuildInfo>()
49-
url.set("https://github.com/apple/pkl/tree/${buildInfo.commitish}")
49+
url.set(buildInfo.commitish.map { "https://github.com/apple/pkl/tree/$it" })
5050
}
5151
issueManagement {
5252
system.set("GitHub Issues")

build-logic/src/main/kotlin/pklFatJar.gradle.kts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
*/
1616
import org.gradle.api.GradleException
1717
import org.gradle.api.artifacts.Configuration
18+
import org.gradle.api.file.ArchiveOperations
1819
import org.gradle.api.publish.maven.MavenPublication
1920
import org.gradle.api.tasks.bundling.Jar
2021
import org.gradle.api.tasks.testing.Test
2122
import org.gradle.kotlin.dsl.*
23+
import org.gradle.kotlin.dsl.support.serviceOf
2224

2325
plugins {
2426
`java-library`
@@ -150,17 +152,19 @@ tasks.check { dependsOn(testFatJar) }
150152

151153
val validateFatJar by tasks.registering {
152154
val outputFile = layout.buildDirectory.file("validateFatJar/result.txt")
153-
inputs.files(tasks.shadowJar)
155+
val shadowJarFile = tasks.shadowJar.flatMap { it.archiveFile }
156+
val archiveOps = serviceOf<ArchiveOperations>()
157+
inputs.file(shadowJarFile)
154158
inputs.property("nonRelocations", nonRelocations)
155159
outputs.file(outputFile)
160+
val nonRelocations = nonRelocations
156161

157162
doLast {
158163
val unshadowedFiles = mutableListOf<String>()
159-
zipTree(tasks.shadowJar.get().outputs.files.singleFile).visit {
160-
val fileDetails = this
161-
val path = fileDetails.relativePath.pathString
164+
archiveOps.zipTree(shadowJarFile.get().asFile).visit {
165+
val path = relativePath.pathString
162166
if (
163-
!(fileDetails.isDirectory ||
167+
!(isDirectory ||
164168
path.startsWith("org/pkl/") ||
165169
path.startsWith("META-INF/") ||
166170
nonRelocations.any { path.startsWith(it) })

0 commit comments

Comments
 (0)