Skip to content

Commit

Permalink
Set MSRV in rust-toolchain.toml using the gradle.property (#3841)
Browse files Browse the repository at this point in the history
The `rust-toolchain.toml` file for tests now uses the `rust.msrv` value
from the `gradle.properties` file.

This PR also fixes an issue where the `rust-toolchain.toml` file was not
created in the overridden test directory when `overrideTestDir` was set.
This caused the installed compiler version to be used, resulting in
errors with the latest compiler and preventing the use of
`overrideTestDir`.

Closes: #2048

---------

Co-authored-by: Fahad Zubair <fahadzub@amazon.com>
  • Loading branch information
drganjoo and Fahad Zubair authored Oct 1, 2024
1 parent abd28bc commit 684c15f
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ import software.amazon.smithy.rust.codegen.core.util.letIf
import software.amazon.smithy.rust.codegen.core.util.orNullIfEmpty
import software.amazon.smithy.rust.codegen.core.util.runCommand
import java.io.File
import java.io.FileInputStream
import java.nio.file.Files
import java.nio.file.Files.createTempDirectory
import java.nio.file.Path
import java.util.Properties
import kotlin.io.path.absolutePathString
import kotlin.io.path.writeText

Expand All @@ -54,6 +56,8 @@ val TestModuleDocProvider =
}
}

val projectRootDir by lazy { File("git rev-parse --show-toplevel".runCommand().replace("\n", "")) }

/**
* Waiting for Kotlin to stabilize their temp directory functionality
*/
Expand All @@ -65,6 +69,38 @@ private fun tempDir(directory: File? = null): File {
}
}

/**
* This function returns the minimum supported Rust version, as specified in the `gradle.properties` file
* located at the root of the project.
*/
fun msrv(): String {
val properties = Properties()
val propertiesFilePath = projectRootDir.resolve("gradle.properties")

FileInputStream(propertiesFilePath).use { inputStream ->
properties.load(inputStream)
}

return properties.getProperty("rust.msrv")
}

/**
* Generates the `rust-toolchain.toml` file in the specified directory.
*
* The compiler version is set in `gradle.properties` under the `rust.msrv` property.
* The Gradle task `GenerateMsrvTask` generates the Kotlin class
* `software.amazon.smithy.rust.codegen.core.Msrv` and writes the value of `rust.msrv` into it.
*/
private fun File.generateRustToolchainToml() {
resolve("rust-toolchain.toml").writeText(
// Help rust select the right version when we run cargo test.
"""
[toolchain]
channel = "${msrv()}"
""".trimIndent(),
)
}

/**
* Creates a Cargo workspace shared among all tests
*
Expand All @@ -87,8 +123,7 @@ object TestWorkspace {
private val subprojects = mutableListOf<String>()

private val cargoLock: File by lazy {
val projectDir = "git rev-parse --show-toplevel".runCommand().replace("\n", "")
File(projectDir).resolve("aws/sdk/Cargo.lock")
projectRootDir.resolve("aws/sdk/Cargo.lock")
}

init {
Expand Down Expand Up @@ -121,12 +156,7 @@ object TestWorkspace {
version = "0.0.1"
""".trimIndent(),
)
newProject.resolve("rust-toolchain.toml").writeText(
// help rust select the right version when we run cargo test
// TODO(https://github.com/smithy-lang/smithy-rs/issues/2048): load this from the msrv property using a
// method as we do for runtime crate versions
"[toolchain]\nchannel = \"1.78.0\"\n",
)
newProject.generateRustToolchainToml()
// ensure there at least an empty lib.rs file to avoid broken crates
newProject.resolve("src").mkdirs()
newProject.resolve("src/lib.rs").writeText("")
Expand Down Expand Up @@ -181,7 +211,11 @@ fun generatePluginContext(
runtimeConfig: RuntimeConfig? = null,
overrideTestDir: File? = null,
): Pair<PluginContext, Path> {
val testDir = overrideTestDir ?: TestWorkspace.subproject()
val testDir =
overrideTestDir?.apply {
mkdirs()
generateRustToolchainToml()
} ?: TestWorkspace.subproject()
val moduleName = "test_${testDir.nameWithoutExtension}"
val testPath = testDir.toPath()
val manifest = FileManifest.create(testPath)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.rust.codegen.core.util

import io.kotest.matchers.booleans.shouldBeTrue
import io.kotest.matchers.paths.shouldExist
import io.kotest.matchers.shouldNotBe
import org.junit.jupiter.api.Test
import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel
import software.amazon.smithy.rust.codegen.core.testutil.generatePluginContext
import software.amazon.smithy.rust.codegen.core.testutil.projectRootDir
import java.nio.file.Files.createTempDirectory
import java.util.regex.Pattern

internal class RustToolChainTomlTest {
val model =
"""
namespace test
service TestService {
version: "123",
operations: [TestOperation]
}
operation TestOperation {
input:= {}
output:= {}
}
""".asSmithyModel(smithyVersion = "2")

@Test
fun `override test directory in integration test has a rust-toolchain toml file`() {
val dir = createTempDirectory("smithy-test").toFile()
val (_, path) = generatePluginContext(model, overrideTestDir = dir)
path.shouldExist()
val rustToolchainTomlPath = path.resolve("rust-toolchain.toml")
rustToolchainTomlPath.shouldExist()
}

@Test
fun `rust-toolchain toml file has correct value from gradle properties for rust-msrv`() {
val (_, path) = generatePluginContext(model)
val rustToolchainTomlPath = path.resolve("rust-toolchain.toml")
rustToolchainTomlPath.shouldExist()

// Read the MSRV written in `gradle.properties` file.
val msrvPattern = Pattern.compile("rust\\.msrv=(.+)")
val gradlePropertiesPath = projectRootDir.resolve("gradle.properties")
val msrv =
gradlePropertiesPath.useLines { lines ->
lines.firstNotNullOfOrNull { line ->
msrvPattern.matcher(line).let { matcher ->
if (matcher.find()) matcher.group(1) else null
}
}
}
msrv shouldNotBe null

// Read `channel = (\d+)` from `rust-toolchain.toml` file, and
// ensure it matches the one in `gradle.properties`.
val toolchainPattern = Pattern.compile("\\[toolchain]")
val channelPattern = Pattern.compile("channel\\s*=\\s*\"(.+)\"")

val channelMatches =
rustToolchainTomlPath.toFile().useLines { lines ->
// Skip lines until the [toolchain] table is found, then take all lines until the next table.
val toolchainSection =
lines
.dropWhile { !toolchainPattern.matcher(it).find() }
.drop(1)
.takeWhile { !it.trim().startsWith("[") }

// There should be a [toolchain] table, and it must have a key called 'channel' whose value must
// match the `rust.msrv` specified in gradle.properties.
toolchainSection != null &&
toolchainSection.any { line ->
channelPattern.matcher(line).let { matcher ->
matcher.find() && matcher.group(1) == msrv
}
}
}

channelMatches.shouldBeTrue()
}
}

0 comments on commit 684c15f

Please sign in to comment.