Skip to content

Commit faaa62b

Browse files
authored
fix(amazonq): prefer user-specified node executable over bundled (#5946)
it is possible (for example, on NixOS), for the bundled executable to be inoperable
1 parent f10ee74 commit faaa62b

File tree

1 file changed

+37
-34
lines changed
  • plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp

1 file changed

+37
-34
lines changed

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -633,21 +633,23 @@ private class AmazonQServerInstance(private val project: Project, private val cs
633633
}
634634
}
635635

636-
if (Files.exists(nodePath) && Files.isExecutable(nodePath)) {
637-
resolveNodeMetric(true, true)
638-
return nodePath
639-
}
640-
641-
// use alternative node runtime if it is not found
642-
LOG.warn { "Node Runtime download failed. Fallback to user specified node runtime " }
643636
// attempt to use user provided node runtime path
644637
val nodeRuntime = LspSettings.getInstance().getNodeRuntimePath()
645638
if (!nodeRuntime.isNullOrEmpty()) {
646639
LOG.info { "Using node from $nodeRuntime " }
647640

648641
resolveNodeMetric(false, true)
649642
return Path.of(nodeRuntime)
643+
}
644+
645+
// attempt to use bundled node
646+
if (Files.exists(nodePath) && Files.isExecutable(nodePath) && validateNode(nodePath) != null) {
647+
resolveNodeMetric(true, true)
648+
return nodePath
650649
} else {
650+
// use alternative node runtime if it is not found
651+
LOG.warn { "Node Runtime download failed. Fallback to user environment search" }
652+
651653
val localNode = locateNodeCommand()
652654
if (localNode != null) {
653655
LOG.info { "Using node from ${localNode.toAbsolutePath()}" }
@@ -689,34 +691,35 @@ private class AmazonQServerInstance(private val project: Project, private val cs
689691
.asSequence()
690692
.map { it.toPath() }
691693
.filter { Files.isRegularFile(it) && Files.isExecutable(it) }
692-
.firstNotNullOfOrNull { path ->
693-
try {
694-
val process = ProcessBuilder(path.toString(), "--version")
695-
.redirectErrorStream(true)
696-
.start()
697-
698-
if (!process.waitFor(5, TimeUnit.SECONDS)) {
699-
process.destroy()
700-
null
701-
} else if (process.exitValue() == 0) {
702-
val version = process.inputStream.bufferedReader().readText().trim()
703-
val majorVersion = version.removePrefix("v").split(".")[0].toIntOrNull()
704-
705-
if (majorVersion != null && majorVersion >= 18) {
706-
path.toAbsolutePath()
707-
} else {
708-
LOG.debug { "Node version < 18 found at: $path (version: $version)" }
709-
null
710-
}
711-
} else {
712-
LOG.debug { "Failed to get version from node at: $path" }
713-
null
714-
}
715-
} catch (e: Exception) {
716-
LOG.debug(e) { "Failed to check version for node at: $path" }
717-
null
718-
}
694+
.firstNotNullOfOrNull(::validateNode)
695+
}
696+
697+
/** @return null if node is not suitable **/
698+
private fun validateNode(path: Path) = try {
699+
val process = ProcessBuilder(path.toString(), "--version")
700+
.redirectErrorStream(true)
701+
.start()
702+
703+
if (!process.waitFor(5, TimeUnit.SECONDS)) {
704+
process.destroy()
705+
null
706+
} else if (process.exitValue() == 0) {
707+
val version = process.inputStream.bufferedReader().readText().trim()
708+
val majorVersion = version.removePrefix("v").split(".")[0].toIntOrNull()
709+
710+
if (majorVersion != null && majorVersion >= 18) {
711+
path.toAbsolutePath()
712+
} else {
713+
LOG.debug { "Node version < 18 found at: $path (version: $version)" }
714+
null
719715
}
716+
} else {
717+
LOG.debug { "Failed to get version from node at: $path" }
718+
null
719+
}
720+
} catch (e: Exception) {
721+
LOG.debug(e) { "Failed to check version for node at: $path" }
722+
null
720723
}
721724

722725
override fun dispose() {

0 commit comments

Comments
 (0)