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 env` failure causes an IDE error
- A local toolchain disappearing (std directory or zig exe deleted) is now handled properly
## [20.3.0]

View file

@ -74,12 +74,20 @@ data class ZigProjectConfigurationData(
return@indeterminateStep false
}
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) {
Notification(
"zigbrains",
"\"zig init\" failed with exit code ${result.exitCode}! Check the IDE log files!",
NotificationType.ERROR
)
).notify(project)
System.err.println(result.stderr)
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.util.io.toNioPathOrNull
import com.intellij.util.xmlb.annotations.Transient
import kotlin.io.path.isDirectory
import kotlin.io.path.pathString
data class ZigProjectSettings(
@ -41,7 +42,13 @@ data class ZigProjectSettings(
@get:Transient
@set:Transient
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) {
toolchainPath = value?.location?.pathString
}

View file

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

View file

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

View file

@ -166,6 +166,7 @@ class BuildToolWindowContext(private val project: Project): Disposable {
withEDTContext {
getViewport(project)?.setViewportError(ZigBrainsBundle.message(when(type) {
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.GeneralError -> "build.tool.window.status.error.general"
}), details)

View file

@ -38,7 +38,7 @@ class ZigCompilerTool(toolchain: AbstractZigToolchain) : ZigTool(toolchain) {
}
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 {
envJson.decodeFromString<ZigToolchainEnvironmentSerializable>(stdout)
} catch (e: SerializationException) {

View file

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