Skip to content

[jb] Update the terminal widget tab when the Gitpod Task title changes #12401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/ide/jetbrains/backend-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ plugins {
// Kotlin support - check the latest version at https://plugins.gradle.org/plugin/org.jetbrains.kotlin.jvm
id("org.jetbrains.kotlin.jvm") version "1.7.0"
// gradle-intellij-plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin
id("org.jetbrains.intellij") version "1.8.0"
id("org.jetbrains.intellij") version "1.8.1"
// detekt linter - read more: https://detekt.github.io/detekt/gradle.html
id("io.gitlab.arturbosch.detekt") version "1.17.1"
// ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ package io.gitpod.jetbrains.remote
import com.intellij.openapi.client.ClientProjectSession
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.util.application
import com.jediterm.terminal.ui.TerminalWidget
import com.jediterm.terminal.ui.TerminalWidgetListener
import com.jetbrains.rdserver.terminal.BackendTerminalManager
import io.gitpod.jetbrains.remote.GitpodManager
import io.gitpod.supervisor.api.Status
import io.gitpod.supervisor.api.StatusServiceGrpc
import io.gitpod.supervisor.api.TerminalOuterClass
import io.gitpod.supervisor.api.TerminalServiceGrpc
import io.grpc.StatusRuntimeException
import io.grpc.stub.ClientCallStreamObserver
import io.grpc.stub.ClientResponseObserver
import org.jetbrains.plugins.terminal.ShellTerminalWidget
import org.jetbrains.plugins.terminal.TerminalView
import java.util.*
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit

@Suppress("UnstableApiUsage")
Expand All @@ -30,9 +33,12 @@ class GitpodTerminalService(session: ClientProjectSession) {
private val terminalView = TerminalView.getInstance(session.project)
private val backendTerminalManager = BackendTerminalManager.getInstance(session.project)
private val terminalServiceFutureStub = TerminalServiceGrpc.newFutureStub(GitpodManager.supervisorChannel)
private val terminalServiceStub = TerminalServiceGrpc.newStub(GitpodManager.supervisorChannel)
private val statusServiceStub = StatusServiceGrpc.newStub(GitpodManager.supervisorChannel)

init { start() }
init {
start()
}

private fun start() {
if (application.isHeadlessEnvironment || hasStarted) return
Expand All @@ -49,7 +55,7 @@ class GitpodTerminalService(session: ClientProjectSession) {
}
}

private fun createSharedTerminalAndExecuteCommand(title: String, command: String) {
private fun createSharedTerminalAndExecuteCommand(title: String, command: String): ShellTerminalWidget? {
val registeredTerminals = terminalView.widgets.toMutableList()

backendTerminalManager.createNewSharedTerminal(UUID.randomUUID().toString(), title)
Expand All @@ -59,13 +65,19 @@ class GitpodTerminalService(session: ClientProjectSession) {

widget.terminalTitle.change { applicationTitle = title }

(widget as ShellTerminalWidget).executeCommand(command)
val shellTerminalWidget = widget as ShellTerminalWidget

shellTerminalWidget.executeCommand(command)

return shellTerminalWidget
}

return null
}

private fun createTerminalsAttachedToTasks(
terminals: List<TerminalOuterClass.Terminal>,
tasks: List<Status.TaskStatus>
terminals: List<TerminalOuterClass.Terminal>,
tasks: List<Status.TaskStatus>
) {
if (tasks.isEmpty()) return

Expand Down Expand Up @@ -93,7 +105,7 @@ class GitpodTerminalService(session: ClientProjectSession) {
val taskStatusRequest = Status.TasksStatusRequest.newBuilder().setObserve(true).build()

val taskStatusResponseObserver = object :
ClientResponseObserver<Status.TasksStatusRequest, Status.TasksStatusResponse> {
ClientResponseObserver<Status.TasksStatusRequest, Status.TasksStatusResponse> {
override fun beforeStart(request: ClientCallStreamObserver<Status.TasksStatusRequest>) = Unit

override fun onNext(response: Status.TasksStatusResponse) {
Expand All @@ -120,8 +132,9 @@ class GitpodTerminalService(session: ClientProjectSession) {
}

thisLogger().error(
"gitpod: Got an error while trying to get tasks list from Supervisor. Trying again in on second.",
throwable
"gitpod: Got an error while trying to get tasks list from Supervisor. " +
"Trying again in one second.",
throwable
)
}

Expand Down Expand Up @@ -150,8 +163,9 @@ class GitpodTerminalService(session: ClientProjectSession) {
}

thisLogger().error(
"gitpod: Got an error while trying to get terminals list from Supervisor. Trying again in on second.",
throwable
"gitpod: Got an error while trying to get terminals list from Supervisor. " +
"Trying again in one second.",
throwable
)
}

Expand All @@ -164,9 +178,105 @@ class GitpodTerminalService(session: ClientProjectSession) {
}

private fun createAttachedSharedTerminal(supervisorTerminal: TerminalOuterClass.Terminal) {
createSharedTerminalAndExecuteCommand(
supervisorTerminal.title,
"gp tasks attach ${supervisorTerminal.alias}"
)
val shellTerminalWidget = createSharedTerminalAndExecuteCommand(
supervisorTerminal.title,
"gp tasks attach ${supervisorTerminal.alias}"
) ?: return

exitTaskWhenTerminalWidgetGetsClosed(supervisorTerminal, shellTerminalWidget)

listenForTaskTerminationAndTitleChanges(supervisorTerminal, shellTerminalWidget)
}

private fun listenForTaskTerminationAndTitleChanges(
supervisorTerminal: TerminalOuterClass.Terminal,
shellTerminalWidget: ShellTerminalWidget
) = application.executeOnPooledThread {
var hasOpenSessions = true

while (hasOpenSessions) {
val completableFuture = CompletableFuture<Void>()

val listenTerminalRequest = TerminalOuterClass.ListenTerminalRequest.newBuilder()
.setAlias(supervisorTerminal.alias)
.build()

val listenTerminalResponseObserver =
object : ClientResponseObserver<
TerminalOuterClass.ListenTerminalRequest,
TerminalOuterClass.ListenTerminalResponse
> {
override fun beforeStart(
request: ClientCallStreamObserver<TerminalOuterClass.ListenTerminalRequest>
) {
@Suppress("ObjectLiteralToLambda")
shellTerminalWidget.addListener(object : TerminalWidgetListener {
override fun allSessionsClosed(widget: TerminalWidget) {
hasOpenSessions = false
request.cancel("gitpod: Terminal closed on the client.", null)
}
})
}

override fun onNext(response: TerminalOuterClass.ListenTerminalResponse) {
when {
response.hasTitle() -> application.invokeLater {
shellTerminalWidget.terminalTitle.change {
applicationTitle = response.title
}
}

response.hasExitCode() -> application.invokeLater {
shellTerminalWidget.close()
}
}
}

override fun onCompleted() = Unit

override fun onError(throwable: Throwable) {
completableFuture.completeExceptionally(throwable)
}
}

terminalServiceStub.listen(listenTerminalRequest, listenTerminalResponseObserver)

try {
completableFuture.get()
} catch (throwable: Throwable) {
if (
throwable is StatusRuntimeException ||
throwable is ExecutionException ||
throwable is InterruptedException
) {
shellTerminalWidget.close()
thisLogger().info("gitpod: Stopped listening to " +
"'${supervisorTerminal.title}' terminal due to an expected exception.")
break
}

thisLogger()
.error("gitpod: Got an error while listening to " +
"'${supervisorTerminal.title}' terminal. Trying again in one second.", throwable)
}

TimeUnit.SECONDS.sleep(1)
}
}

private fun exitTaskWhenTerminalWidgetGetsClosed(
supervisorTerminal: TerminalOuterClass.Terminal,
shellTerminalWidget: ShellTerminalWidget
) {
@Suppress("ObjectLiteralToLambda")
shellTerminalWidget.addListener(object : TerminalWidgetListener {
override fun allSessionsClosed(widget: TerminalWidget) {
terminalServiceFutureStub.shutdown(
TerminalOuterClass.ShutdownTerminalRequest.newBuilder()
.setAlias(supervisorTerminal.alias)
.build()
)
}
})
}
}