feat: Improved missing toolchain resistance

This commit is contained in:
FalsePattern 2025-03-10 23:57:56 +01:00
parent 6b8b82e710
commit 88df5b1426
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
9 changed files with 33 additions and 8 deletions

View file

@ -31,6 +31,7 @@ Changelog structure reference:
- Zig - Zig
- `zig env` failure causes an IDE error - `zig env` failure causes an IDE error
- A local toolchain disappearing (std directory or zig exe deleted) is now handled properly
## [20.3.0] ## [20.3.0]

View file

@ -74,12 +74,20 @@ data class ZigProjectConfigurationData(
return@indeterminateStep false return@indeterminateStep false
} }
val result = zig.callWithArgs(workDir, "init") val result = zig.callWithArgs(workDir, "init")
if (result == null) {
Notification(
"zigbrains",
"\"zig init\" could not run because the zig executable was missing!",
NotificationType.ERROR
).notify(project)
return@indeterminateStep false
}
if (result.exitCode != 0) { if (result.exitCode != 0) {
Notification( Notification(
"zigbrains", "zigbrains",
"\"zig init\" failed with exit code ${result.exitCode}! Check the IDE log files!", "\"zig init\" failed with exit code ${result.exitCode}! Check the IDE log files!",
NotificationType.ERROR NotificationType.ERROR
) ).notify(project)
System.err.println(result.stderr) System.err.println(result.stderr)
return@indeterminateStep false return@indeterminateStep false
} }

View file

@ -26,6 +26,7 @@ import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.toNioPathOrNull import com.intellij.openapi.util.io.toNioPathOrNull
import com.intellij.util.xmlb.annotations.Transient import com.intellij.util.xmlb.annotations.Transient
import kotlin.io.path.isDirectory
import kotlin.io.path.pathString import kotlin.io.path.pathString
data class ZigProjectSettings( data class ZigProjectSettings(
@ -41,7 +42,13 @@ data class ZigProjectSettings(
@get:Transient @get:Transient
@set:Transient @set:Transient
override var toolchain: LocalZigToolchain? override var toolchain: LocalZigToolchain?
get() = toolchainPath?.toNioPathOrNull()?.let { LocalZigToolchain(it) } get() {
val nioPath = toolchainPath?.toNioPathOrNull() ?: return null
if (!nioPath.isDirectory()) {
return null
}
return LocalZigToolchain(nioPath)
}
set(value) { set(value) {
toolchainPath = value?.location?.pathString toolchainPath = value?.location?.pathString
} }

View file

@ -30,6 +30,7 @@ interface ZigStepDiscoveryListener {
enum class ErrorType { enum class ErrorType {
MissingToolchain, MissingToolchain,
MissingZigExe,
MissingBuildZig, MissingBuildZig,
GeneralError GeneralError
} }

View file

@ -85,7 +85,9 @@ class ZigStepDiscoveryService(private val project: Project) {
"build", "-l", "build", "-l",
timeoutMillis = currentTimeoutSec * 1000L timeoutMillis = currentTimeoutSec * 1000L
) )
if (result.checkSuccess(LOG)) { if (result == null) {
errorReload(ErrorType.MissingZigExe)
} else if (result.checkSuccess(LOG)) {
currentTimeoutSec = DEFAULT_TIMEOUT_SEC currentTimeoutSec = DEFAULT_TIMEOUT_SEC
val lines = result.stdoutLines val lines = result.stdoutLines
val steps = ArrayList<Pair<String, String?>>() val steps = ArrayList<Pair<String, String?>>()

View file

@ -166,6 +166,7 @@ class BuildToolWindowContext(private val project: Project): Disposable {
withEDTContext { withEDTContext {
getViewport(project)?.setViewportError(ZigBrainsBundle.message(when(type) { getViewport(project)?.setViewportError(ZigBrainsBundle.message(when(type) {
ZigStepDiscoveryListener.ErrorType.MissingToolchain -> "build.tool.window.status.error.missing-toolchain" ZigStepDiscoveryListener.ErrorType.MissingToolchain -> "build.tool.window.status.error.missing-toolchain"
ZigStepDiscoveryListener.ErrorType.MissingZigExe -> "build.tool.window.status.error.missing-zig-exe"
ZigStepDiscoveryListener.ErrorType.MissingBuildZig -> "build.tool.window.status.error.missing-build-zig" ZigStepDiscoveryListener.ErrorType.MissingBuildZig -> "build.tool.window.status.error.missing-build-zig"
ZigStepDiscoveryListener.ErrorType.GeneralError -> "build.tool.window.status.error.general" ZigStepDiscoveryListener.ErrorType.GeneralError -> "build.tool.window.status.error.general"
}), details) }), details)

View file

@ -38,7 +38,7 @@ class ZigCompilerTool(toolchain: AbstractZigToolchain) : ZigTool(toolchain) {
} }
suspend fun getEnv(project: Project?): ZigToolchainEnvironmentSerializable? { suspend fun getEnv(project: Project?): ZigToolchainEnvironmentSerializable? {
val stdout = callWithArgs(toolchain.workingDirectory(project), "env").stdout val stdout = callWithArgs(toolchain.workingDirectory(project), "env")?.stdout ?: return null
return try { return try {
envJson.decodeFromString<ZigToolchainEnvironmentSerializable>(stdout) envJson.decodeFromString<ZigToolchainEnvironmentSerializable>(stdout)
} catch (e: SerializationException) { } catch (e: SerializationException) {

View file

@ -31,12 +31,13 @@ import kotlinx.coroutines.runInterruptible
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull import kotlinx.coroutines.withTimeoutOrNull
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.isRegularFile
abstract class ZigTool(val toolchain: AbstractZigToolchain) { abstract class ZigTool(val toolchain: AbstractZigToolchain) {
abstract val toolName: String abstract val toolName: String
suspend fun callWithArgs(workingDirectory: Path?, vararg parameters: String, timeoutMillis: Long = Long.MAX_VALUE): ProcessOutput { suspend fun callWithArgs(workingDirectory: Path?, vararg parameters: String, timeoutMillis: Long = Long.MAX_VALUE): ProcessOutput? {
val cli = createBaseCommandLine(workingDirectory, *parameters) val cli = createBaseCommandLine(workingDirectory, *parameters) ?: return null
val (process, exitCode) = withContext(Dispatchers.IO) { val (process, exitCode) = withContext(Dispatchers.IO) {
val process = cli.createProcess() val process = cli.createProcess()
@ -59,9 +60,12 @@ abstract class ZigTool(val toolchain: AbstractZigToolchain) {
private suspend fun createBaseCommandLine( private suspend fun createBaseCommandLine(
workingDirectory: Path?, workingDirectory: Path?,
vararg parameters: String vararg parameters: String
): GeneralCommandLine { ): GeneralCommandLine? {
val exe = toolchain.pathToExecutable(toolName)
if (!exe.isRegularFile())
return null
val cli = GeneralCommandLine() val cli = GeneralCommandLine()
.withExePath(toolchain.pathToExecutable(toolName).toString()) .withExePath(exe.toString())
.withWorkingDirectory(workingDirectory) .withWorkingDirectory(workingDirectory)
.withParameters(*parameters) .withParameters(*parameters)
.withCharset(Charsets.UTF_8) .withCharset(Charsets.UTF_8)

View file

@ -113,6 +113,7 @@ build.tool.window.status.not-scanned=Build steps not yet scanned. Click the refr
build.tool.window.status.loading=Running zig build -l build.tool.window.status.loading=Running zig build -l
build.tool.window.status.error.missing-build-zig=No build.zig file found build.tool.window.status.error.missing-build-zig=No build.zig file found
build.tool.window.status.error.missing-toolchain=No zig toolchain configured build.tool.window.status.error.missing-toolchain=No zig toolchain configured
build.tool.window.status.error.missing-zig-exe=Zig executable missing
build.tool.window.status.error.general=Error while running zig build -l build.tool.window.status.error.general=Error while running zig build -l
build.tool.window.status.timeout=zig build -l timed out after {0} seconds. build.tool.window.status.timeout=zig build -l timed out after {0} seconds.
zig=Zig zig=Zig