diff --git a/README.md b/README.md index 5fefee8..9f99ab7 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,17 @@ rustJni{ | Minimum version | `>=1.64.0` | Accepts any version greater than or equal to this | | Wildcard version | `1.86.*`, `1.*.*` | Allows flexibility within minor and/or patch versions | +### How to define a custom path for rust? + +By default, Rust is installed in the following directory: + +- **macOS/Linux**: `~/.cargo/bin` +- **Windows**: `%USERPROFILE%\.cargo\bin` + +However, you can specify a custom installation directory by setting it in your **`local.properties`** file. For example: + +`cargo.dir=/Users//cargo_tmp/.cargo/bin` + ### How can I take a look at some samples? - [Java](./sample/java) - A java sample with 1 method diff --git a/gradle-plugin/build.gradle.kts b/gradle-plugin/build.gradle.kts index 907026c..2384692 100644 --- a/gradle-plugin/build.gradle.kts +++ b/gradle-plugin/build.gradle.kts @@ -9,7 +9,7 @@ repositories { google() } -version = "0.0.25" +version = "0.0.26" group = "io.github.andrefigas.rustjni" gradlePlugin { diff --git a/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/RustJNI.kt b/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/RustJNI.kt index b7b6039..c7d1455 100644 --- a/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/RustJNI.kt +++ b/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/RustJNI.kt @@ -3,6 +3,7 @@ package io.github.andrefigas.rustjni import io.github.andrefigas.rustjni.reflection.ReflectionJVM import io.github.andrefigas.rustjni.reflection.ReflectionNative import io.github.andrefigas.rustjni.utils.FileUtils +import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project import java.io.ByteArrayOutputStream @@ -27,7 +28,6 @@ class RustJNI : Plugin { project.afterEvaluate { val helper = Helper(project, extension) - helper.validateRustVersion() helper.registerCompileTask() helper.registerInitTask() helper.configureAndroidSettings() @@ -69,22 +69,27 @@ class RustJNI : Plugin { executable: String, arguments: List, dir: File = rustDir, - outputProcessor: ((String) -> Unit)? = null + outputProcessor: ((String) -> Unit)? = null, + extraEnv: Map = emptyMap() ) { - val userHome = System.getProperty("user.home") val isWindows = System.getProperty("os.name").lowercase().contains("win") val execExt = if (isWindows) ".exe" else "" - val executablePath = "$userHome${File.separator}.cargo${File.separator}bin${File.separator}$executable$execExt" + + val executablePath = "${getCargoDir()}$executable$execExt" val executableFile = File(executablePath) if (!executableFile.exists()) { throw IllegalStateException("Executable not found at: $executablePath") } - val fullCommand = listOf(executablePath) + arguments + val fullCommand = listOf(executableFile.absolutePath) + arguments try { println("Running $executable command: ${fullCommand.joinToString(" ")} in $dir") + if (extraEnv.isNotEmpty()) { + println("With environment overrides:") + extraEnv.forEach { (k, v) -> println(" $k = $v") } + } val output = if (outputProcessor != null) ByteArrayOutputStream() else null @@ -94,6 +99,7 @@ class RustJNI : Plugin { isIgnoreExitValue = true output?.let { standardOutput = it } errorOutput = System.err + environment(extraEnv) } if (result.exitValue != 0) { @@ -170,6 +176,66 @@ class RustJNI : Plugin { } } + private fun validateRustExecutable(file: File) { + if (!file.exists()) { + throw GradleException("Expected Rust executable not found: ${file.absolutePath}") + } + + if (!file.canExecute()) { + throw GradleException("Rust executable is not executable: ${file.absolutePath}") + } + + val process = try { + ProcessBuilder(file.absolutePath, "--version") + .redirectErrorStream(true) + .start() + } catch (e: Exception) { + throw GradleException("Failed to launch ${file.name} from path: ${file.absolutePath}", e) + } + + val output = process.inputStream.bufferedReader().readText() + val exitCode = process.waitFor() + + if (exitCode != 0) { + throw GradleException("${file.name} failed to execute with exit code $exitCode: $output") + } + + } + + + /** Gets the cargo directory from `local.properties` or defaults to `$HOME/.cargo/bin/`. + * + * Throws an exception if the directory does not exist. + */ + private fun getCargoDir(): String { + val props = Properties() + project.file("${project.rootProject.projectDir}${File.separator}local.properties") + .inputStream().use { props.load(it) } + + var cargoDir = props.getProperty("cargo.dir") + + if (cargoDir.isNullOrEmpty()) { + val userHome = System.getProperty("user.home") + cargoDir = "$userHome${File.separator}.cargo${File.separator}bin" + } + + if (!cargoDir.endsWith(File.separator)) { + cargoDir += File.separator + } + + val cargoDirFile = File(cargoDir) + if (!cargoDirFile.exists() || !cargoDirFile.isDirectory) { + throw GradleException("Cargo directory does not exist: $cargoDir") + } + + val executables = listOf("cargo", "rustc", "rustup") + for (exe in executables) { + validateRustExecutable(File(cargoDirFile, exe)) + } + + return cargoDir + } + private fun parseVersion(version: String): Triple { val parts = version.split(".") if (parts.size != 3) throw IllegalArgumentException("Version must be in format x.y.z") @@ -246,6 +312,7 @@ class RustJNI : Plugin { } private fun compileRustCode() { + validateRustVersion() validateArchitectures() addRustTargets() cleanBuildDirectory() diff --git a/sample/java/app/build.gradle.kts b/sample/java/app/build.gradle.kts index 9a85d6e..81435e6 100644 --- a/sample/java/app/build.gradle.kts +++ b/sample/java/app/build.gradle.kts @@ -3,7 +3,7 @@ import io.github.andrefigas.rustjni.reflection.Visibility plugins { alias(libs.plugins.android.application) alias(libs.plugins.jetbrains.kotlin.android) - id("io.github.andrefigas.rustjni") version "0.0.25" + id("io.github.andrefigas.rustjni") version "0.0.26" } rustJni{ diff --git a/sample/kotlin/app/build.gradle.kts b/sample/kotlin/app/build.gradle.kts index 9a85d6e..81435e6 100644 --- a/sample/kotlin/app/build.gradle.kts +++ b/sample/kotlin/app/build.gradle.kts @@ -3,7 +3,7 @@ import io.github.andrefigas.rustjni.reflection.Visibility plugins { alias(libs.plugins.android.application) alias(libs.plugins.jetbrains.kotlin.android) - id("io.github.andrefigas.rustjni") version "0.0.25" + id("io.github.andrefigas.rustjni") version "0.0.26" } rustJni{