Move Gradle build logic to a setup hook

This commit is contained in:
Tad Fisher
2024-06-13 15:21:58 -07:00
parent a4ef499401
commit b32bf21a6c
26 changed files with 768 additions and 470 deletions

View File

@@ -16,7 +16,8 @@ fun connect(
config: Config,
projectDir: File = config.projectDir,
): ProjectConnection =
GradleConnector.newConnector()
GradleConnector
.newConnector()
.apply {
when (val source = config.gradleSource) {
is GradleSource.Distribution -> useDistribution(source.uri)
@@ -24,8 +25,7 @@ fun connect(
GradleSource.Project -> useBuildDistribution()
is GradleSource.Wrapper -> useGradleVersion(source.version)
}
}
.forProjectDirectory(projectDir)
}.forProjectDirectory(projectDir)
.connect()
suspend fun ProjectConnection.buildModel(): GradleBuild =
@@ -67,8 +67,7 @@ suspend fun ProjectConnection.build(
"--refresh-dependencies",
"--gradle-user-home=${config.gradleHome}",
"--init-script=${config.appHome}/init.gradle",
)
.apply {
).apply {
if (config.logger.stacktrace) {
addArguments("--stacktrace")
}
@@ -80,12 +79,14 @@ suspend fun ProjectConnection.build(
withSystemProperties(
mapOf(
"org.gradle.internal.operations.trace" to
config.outDir.toPath().resolve("debug").absolutePathString(),
config.outDir
.toPath()
.resolve("debug")
.absolutePathString(),
),
)
}
}
.run(
}.run(
object : ResultHandler<DependencySet> {
override fun onComplete(result: DependencySet) {
continuation.resume(result)

View File

@@ -48,13 +48,19 @@ val JsonFormat =
}
sealed interface GradleSource {
data class Distribution(val uri: URI) : GradleSource
data class Distribution(
val uri: URI,
) : GradleSource
data class Path(val path: File) : GradleSource
data class Path(
val path: File,
) : GradleSource
data object Project : GradleSource
data class Wrapper(val version: String) : GradleSource
data class Wrapper(
val version: String,
) : GradleSource
}
enum class LogLevel {
@@ -64,9 +70,10 @@ enum class LogLevel {
ERROR,
}
class Gradle2Nix : CliktCommand(
name = "gradle2nix",
) {
class Gradle2Nix :
CliktCommand(
name = "gradle2nix",
) {
private val tasks: List<String> by option(
"--task",
"-t",
@@ -93,8 +100,7 @@ class Gradle2Nix : CliktCommand(
"-o",
metavar = "DIR",
help = "Path to write generated files",
)
.file(canBeFile = false, canBeDir = true)
).file(canBeFile = false, canBeDir = true)
.defaultLazy("<project>") { projectDir }
internal val lockFile: String by option(
@@ -133,8 +139,7 @@ class Gradle2Nix : CliktCommand(
private val logLevel: LogLevel by option(
"--log",
help = "Print messages with this priority or higher",
)
.enum<LogLevel>(key = { it.name.lowercase() })
).enum<LogLevel>(key = { it.name.lowercase() })
.default(LogLevel.INFO, "info")
private val dumpEvents: Boolean by option(
@@ -192,7 +197,9 @@ class Gradle2Nix : CliktCommand(
addAll(root.editableBuilds)
}
builds.mapNotNull { build ->
build.rootProject.projectDirectory.resolve("buildSrc").takeIf { it.exists() }
build.rootProject.projectDirectory
.resolve("buildSrc")
.takeIf { it.exists() }
}
}

View File

@@ -8,8 +8,8 @@ import kotlin.io.encoding.ExperimentalEncodingApi
fun processDependencies(
config: Config,
dependencySets: Iterable<DependencySet>,
): Env {
return buildMap<DependencyCoordinates, Map<String, Artifact>> {
): Env =
buildMap<DependencyCoordinates, Map<String, Artifact>> {
for (dependencySet in dependencySets) {
val env = dependencySet.toEnv()
@@ -40,16 +40,14 @@ fun processDependencies(
artifacts.toSortedMap()
}.toSortedMap(coordinatesComparator)
.mapKeys { (coordinates, _) -> coordinates.id }
}
private fun DependencySet.toEnv(): Map<DependencyCoordinates, Map<String, Artifact>> {
return dependencies.associate { dep ->
private fun DependencySet.toEnv(): Map<DependencyCoordinates, Map<String, Artifact>> =
dependencies.associate { dep ->
dep.coordinates to
dep.artifacts.associate {
it.name to Artifact(it.url, it.hash.toSri())
}
}
}
@OptIn(ExperimentalEncodingApi::class, ExperimentalStdlibApi::class)
internal fun String.toSri(): String =

View File

@@ -2,7 +2,11 @@ package org.nixos.gradle2nix
import java.util.concurrent.ConcurrentHashMap
class Version(val source: String, val parts: List<String>, base: Version?) : Comparable<Version> {
class Version(
val source: String,
val parts: List<String>,
base: Version?,
) : Comparable<Version> {
private val base: Version
val numericParts: List<Long?>

View File

@@ -3,45 +3,46 @@ package org.nixos.gradle2nix
import io.kotest.core.extensions.install
import io.kotest.core.spec.style.FunSpec
class GoldenTest : FunSpec({
install(MavenRepo)
class GoldenTest :
FunSpec({
install(MavenRepo)
context("basic") {
golden("basic/basic-java-project")
golden("basic/basic-kotlin-project")
}
context("buildsrc") {
golden("buildsrc/plugin-in-buildsrc")
}
context("dependency") {
golden("dependency/classifier")
golden("dependency/maven-bom")
golden("dependency/snapshot")
golden("dependency/snapshot-dynamic")
golden("dependency/snapshot-redirect")
}
context("included-build") {
golden("included-build")
}
context("integration") {
golden("integration/settings-buildscript")
}
context("ivy") {
golden("ivy/basic")
}
context("plugin") {
golden("plugin/resolves-from-default-repo")
}
// FIXME Need s3mock or similar to generate golden data.
xcontext("s3") {
golden("s3/maven")
golden("s3/maven-snapshot")
}
context("settings") {
golden("settings/buildscript")
golden("settings/dependency-resolution-management")
}
context("subprojects") {
golden("subprojects/multi-module")
}
})
context("basic") {
golden("basic/basic-java-project")
golden("basic/basic-kotlin-project")
}
context("buildsrc") {
golden("buildsrc/plugin-in-buildsrc")
}
context("dependency") {
golden("dependency/classifier")
golden("dependency/maven-bom")
golden("dependency/snapshot")
golden("dependency/snapshot-dynamic")
golden("dependency/snapshot-redirect")
}
context("included-build") {
golden("included-build")
}
context("integration") {
golden("integration/settings-buildscript")
}
context("ivy") {
golden("ivy/basic")
}
context("plugin") {
golden("plugin/resolves-from-default-repo")
}
// FIXME Need s3mock or similar to generate golden data.
xcontext("s3") {
golden("s3/maven")
golden("s3/maven-snapshot")
}
context("settings") {
golden("settings/buildscript")
golden("settings/dependency-resolution-management")
}
context("subprojects") {
golden("subprojects/multi-module")
}
})

View File

@@ -47,9 +47,7 @@ private val json =
val testLogger = Logger(logLevel = LogLevel.DEBUG, stacktrace = true)
fun fixture(path: String): File {
return Paths.get("../fixtures", path).toFile()
}
fun fixture(path: String): File = Paths.get("../fixtures", path).toFile()
@OptIn(ExperimentalKotest::class, ExperimentalSerializationApi::class, KotestInternal::class)
suspend fun TestScope.fixture(
@@ -60,7 +58,8 @@ suspend fun TestScope.fixture(
val tmp = Paths.get("build/tmp/gradle2nix").apply { toFile().mkdirs() }
val baseDir = Paths.get("../fixtures/projects", project).toFile()
val children =
baseDir.listFiles(FileFilter { it.isDirectory && (it.name == "groovy" || it.name == "kotlin") })
baseDir
.listFiles(FileFilter { it.isDirectory && (it.name == "groovy" || it.name == "kotlin") })
?.toList()
val cases =
if (children.isNullOrEmpty()) {
@@ -175,8 +174,8 @@ object MavenRepo : MountableExtension<MavenRepo.Config, NettyApplicationEngine>,
return tryStart(3).also { this.server = it }
}
private fun tryStart(attempts: Int): NettyApplicationEngine {
return try {
private fun tryStart(attempts: Int): NettyApplicationEngine =
try {
val p = config.port ?: Random.nextInt(10000, 65000)
val s =
embeddedServer(Netty, port = p, host = config.host) {
@@ -202,7 +201,6 @@ object MavenRepo : MountableExtension<MavenRepo.Config, NettyApplicationEngine>,
} catch (e: Throwable) {
if (config.port == null && attempts > 0) tryStart(attempts - 1) else throw e
}
}
override suspend fun afterSpec(spec: Spec) {
server?.stop()