Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite68c4dc

Browse files
committed
Add update check
1 parent14507c7 commite68c4dc

File tree

2 files changed

+110
-35
lines changed

2 files changed

+110
-35
lines changed

‎CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
##Unreleased
66

7+
###Added
8+
9+
- When using a recent workspace connection, check if there is an update to the
10+
IDE and prompt to upgrade if an upgrade exists.
11+
712
##2.12.2 - 2024-07-12
813

914
###Fixed

‎src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt‎

Lines changed: 105 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@
22

33
packagecom.coder.gateway
44

5+
importcom.coder.gateway.cli.CoderCLIManager
56
importcom.coder.gateway.models.WorkspaceProjectIDE
7+
importcom.coder.gateway.models.toIdeWithStatus
68
importcom.coder.gateway.models.toRawString
9+
importcom.coder.gateway.models.withWorkspaceProject
710
importcom.coder.gateway.services.CoderRecentWorkspaceConnectionsService
811
importcom.coder.gateway.services.CoderSettingsService
12+
importcom.coder.gateway.util.SemVer
13+
importcom.coder.gateway.util.confirm
914
importcom.coder.gateway.util.humanizeDuration
1015
importcom.coder.gateway.util.isCancellation
1116
importcom.coder.gateway.util.isWorkerTimeout
1217
importcom.coder.gateway.util.suspendingRetryWithExponentialBackOff
13-
importcom.coder.gateway.cli.CoderCLIManager
1418
importcom.intellij.openapi.application.ApplicationManager
1519
importcom.intellij.openapi.components.service
1620
importcom.intellij.openapi.diagnostic.Logger
@@ -20,8 +24,12 @@ import com.intellij.openapi.ui.Messages
2024
importcom.intellij.remote.AuthType
2125
importcom.intellij.remote.RemoteCredentialsHolder
2226
importcom.intellij.remoteDev.hostStatus.UnattendedHostStatus
27+
importcom.jetbrains.gateway.ssh.CachingProductsJsonWrapper
2328
importcom.jetbrains.gateway.ssh.ClientOverSshTunnelConnector
2429
importcom.jetbrains.gateway.ssh.HighLevelHostAccessor
30+
importcom.jetbrains.gateway.ssh.IdeWithStatus
31+
importcom.jetbrains.gateway.ssh.IntelliJPlatformProduct
32+
importcom.jetbrains.gateway.ssh.ReleaseType
2533
importcom.jetbrains.gateway.ssh.SshHostTunnelConnector
2634
importcom.jetbrains.gateway.ssh.deploy.DeployException
2735
importcom.jetbrains.gateway.ssh.deploy.ShellArgument
@@ -58,23 +66,70 @@ class CoderRemoteConnectionHandle {
5866
val clientLifetime=LifetimeDefinition()
5967
clientLifetime.launchUnderBackgroundProgress(CoderGatewayBundle.message("gateway.connector.coder.connection.provider.title")) {
6068
try {
61-
val parameters= getParameters(indicator)
69+
var parameters= getParameters(indicator)
70+
var oldParameters:WorkspaceProjectIDE?=null
6271
logger.debug("Creating connection handle", parameters)
6372
indicator.text=CoderGatewayBundle.message("gateway.connector.coder.connecting")
6473
suspendingRetryWithExponentialBackOff(
6574
action= { attempt->
66-
logger.info("Connecting... (attempt$attempt)")
75+
logger.info("Connecting to remote worker on${parameters.hostname}... (attempt$attempt)")
6776
if (attempt>1) {
6877
// indicator.text is the text above the progress bar.
6978
indicator.text=CoderGatewayBundle.message("gateway.connector.coder.connecting.retry", attempt)
79+
}else {
80+
indicator.text="Connecting to remote worker..."
81+
}
82+
// This establishes an SSH connection to a remote worker binary.
83+
// TODO: Can/should accessors to the same host be shared?
84+
val accessor=HighLevelHostAccessor.create(
85+
RemoteCredentialsHolder().apply {
86+
setHost(CoderCLIManager.getBackgroundHostName(parameters.hostname))
87+
userName="coder"
88+
port=22
89+
authType=AuthType.OPEN_SSH
90+
},
91+
true,
92+
)
93+
if (attempt==1) {
94+
// See if there is a newer (non-EAP) version of the IDE available.
95+
checkUpdate(accessor, parameters, indicator)?.let { update->
96+
// Store the old IDE to delete later.
97+
oldParameters= parameters
98+
// Continue with the new IDE.
99+
parameters= update.withWorkspaceProject(
100+
name= parameters.name,
101+
hostname= parameters.hostname,
102+
projectPath= parameters.projectPath,
103+
deploymentURL= parameters.deploymentURL,
104+
)
105+
}
70106
}
71107
doConnect(
108+
accessor,
72109
parameters,
73110
indicator,
74111
clientLifetime,
75112
settings.setupCommand,
76113
settings.ignoreSetupFailure,
77114
)
115+
// If successful, delete the old IDE and connection.
116+
oldParameters?.let {
117+
indicator.text="Deleting${it.ideName} backend..."
118+
try {
119+
it.idePathOnHost?.let { path->
120+
accessor.removePathOnRemote(accessor.makeRemotePath(ShellArgument.PlainText(path)))
121+
}
122+
recentConnectionsService.removeConnection(it.toRecentWorkspaceConnection())
123+
}catch (ex:Exception) {
124+
logger.error("Failed to delete old IDE or connection", ex)
125+
}
126+
}
127+
indicator.text="Connecting${parameters.ideName} client..."
128+
// The presence handler runs a good deal earlier than the client
129+
// actually appears, which results in some dead space where it can look
130+
// like opening the client silently failed. This delay janks around
131+
// that, so we can keep the progress indicator open a bit longer.
132+
delay(5000)
78133
},
79134
retryIf= {
80135
itisConnectionException||
@@ -122,9 +177,38 @@ class CoderRemoteConnectionHandle {
122177
}
123178

124179
/**
125-
* Deploy (if needed), connect to the IDE, and update the last opened date.
180+
* Return a new (non-EAP) IDE if we should update.
181+
*/
182+
privatesuspendfuncheckUpdate(
183+
accessor:HighLevelHostAccessor,
184+
workspace:WorkspaceProjectIDE,
185+
indicator:ProgressIndicator,
186+
):IdeWithStatus? {
187+
indicator.text="Checking for updates..."
188+
val workspaceOS= accessor.guessOs()
189+
logger.info("Got$workspaceOS for${workspace.hostname}")
190+
val latest=CachingProductsJsonWrapper.getInstance().getAvailableIdes(
191+
IntelliJPlatformProduct.fromProductCode(workspace.ideProduct.productCode)
192+
?:throwException("invalid product code${workspace.ideProduct.productCode}"),
193+
workspaceOS,
194+
)
195+
.filter { it.releaseType==ReleaseType.RELEASE }
196+
.minOfOrNull { it.toIdeWithStatus() }
197+
if (latest!=null&&SemVer.parse(latest.buildNumber)>SemVer.parse(workspace.ideBuildNumber)) {
198+
logger.info("Got newer version:${latest.buildNumber} versus current${workspace.ideBuildNumber}")
199+
if (confirm("Update IDE","There is a new version of this IDE:${latest.buildNumber}","Would you like to update?")) {
200+
return latest
201+
}
202+
}
203+
returnnull
204+
}
205+
206+
/**
207+
* Check for updates, deploy (if needed), connect to the IDE, and update the
208+
* last opened date.
126209
*/
127210
privatesuspendfundoConnect(
211+
accessor:HighLevelHostAccessor,
128212
workspace:WorkspaceProjectIDE,
129213
indicator:ProgressIndicator,
130214
lifetime:LifetimeDefinition,
@@ -134,38 +218,20 @@ class CoderRemoteConnectionHandle {
134218
) {
135219
workspace.lastOpened= localTimeFormatter.format(LocalDateTime.now())
136220

137-
// This establishes an SSH connection to a remote worker binary.
138-
// TODO: Can/should accessors to the same host be shared?
139-
indicator.text="Connecting to remote worker..."
140-
logger.info("Connecting to remote worker on${workspace.hostname}")
141-
val credentials=RemoteCredentialsHolder().apply {
142-
setHost(workspace.hostname)
143-
userName="coder"
144-
port=22
145-
authType=AuthType.OPEN_SSH
146-
}
147-
val backgroundCredentials=RemoteCredentialsHolder().apply {
148-
setHost(CoderCLIManager.getBackgroundHostName(workspace.hostname))
149-
userName="coder"
150-
port=22
151-
authType=AuthType.OPEN_SSH
152-
}
153-
val accessor=HighLevelHostAccessor.create(backgroundCredentials,true)
154-
155221
// Deploy if we need to.
156-
val ideDir=this.deploy(workspace, accessor, indicator, timeout)
222+
val ideDir= deploy(accessor, workspace, indicator, timeout)
157223
workspace.idePathOnHost= ideDir.toRawString()
158224

159225
// Run the setup command.
160-
this.setup(workspace, indicator, setupCommand, ignoreSetupFailure)
226+
setup(workspace, indicator, setupCommand, ignoreSetupFailure)
161227

162228
// Wait for the IDE to come up.
163229
indicator.text="Waiting for${workspace.ideName} backend..."
164230
var status:UnattendedHostStatus?=null
165231
val remoteProjectPath= accessor.makeRemotePath(ShellArgument.PlainText(workspace.projectPath))
166232
val logsDir= accessor.getLogsDir(workspace.ideProduct.productCode, remoteProjectPath)
167233
while (lifetime.status==LifetimeStatus.Alive) {
168-
status= ensureIDEBackend(workspace, accessor, ideDir, remoteProjectPath, logsDir, lifetime,null)
234+
status= ensureIDEBackend(accessor, workspace, ideDir, remoteProjectPath, logsDir, lifetime,null)
169235
if (!status?.joinLink.isNullOrBlank()) {
170236
break
171237
}
@@ -182,15 +248,25 @@ class CoderRemoteConnectionHandle {
182248
// Make the initial connection.
183249
indicator.text="Connecting${workspace.ideName} client..."
184250
logger.info("Connecting${workspace.ideName} client to coder@${workspace.hostname}:22")
185-
val client=ClientOverSshTunnelConnector(lifetime,SshHostTunnelConnector(credentials))
251+
val client=ClientOverSshTunnelConnector(
252+
lifetime,
253+
SshHostTunnelConnector(
254+
RemoteCredentialsHolder().apply {
255+
setHost(workspace.hostname)
256+
userName="coder"
257+
port=22
258+
authType=AuthType.OPEN_SSH
259+
},
260+
),
261+
)
186262
val handle= client.connect(URI(joinLink))// Downloads the client too, if needed.
187263

188264
// Reconnect if the join link changes.
189265
logger.info("Launched${workspace.ideName} client; beginning backend monitoring")
190266
lifetime.coroutineScope.launch {
191267
while (isActive) {
192268
delay(5000)
193-
val newStatus= ensureIDEBackend(workspace, accessor, ideDir, remoteProjectPath, logsDir, lifetime, status)
269+
val newStatus= ensureIDEBackend(accessor, workspace, ideDir, remoteProjectPath, logsDir, lifetime, status)
194270
val newLink= newStatus?.joinLink
195271
if (newLink!=null&& newLink!= status?.joinLink) {
196272
logger.info("${workspace.ideName} backend join link changed; updating")
@@ -231,20 +307,14 @@ class CoderRemoteConnectionHandle {
231307
}
232308
}
233309
}
234-
235-
// The presence handler runs a good deal earlier than the client
236-
// actually appears, which results in some dead space where it can look
237-
// like opening the client silently failed. This delay janks around
238-
// that, so we can keep the progress indicator open a bit longer.
239-
delay(5000)
240310
}
241311

242312
/**
243313
* Deploy the IDE if necessary and return the path to its location on disk.
244314
*/
245315
privatesuspendfundeploy(
246-
workspace:WorkspaceProjectIDE,
247316
accessor:HighLevelHostAccessor,
317+
workspace:WorkspaceProjectIDE,
248318
indicator:ProgressIndicator,
249319
timeout:Duration,
250320
):ShellArgument.RemotePath {
@@ -371,8 +441,8 @@ class CoderRemoteConnectionHandle {
371441
* backend has not started.
372442
*/
373443
privatesuspendfunensureIDEBackend(
374-
workspace:WorkspaceProjectIDE,
375444
accessor:HighLevelHostAccessor,
445+
workspace:WorkspaceProjectIDE,
376446
ideDir:ShellArgument.RemotePath,
377447
remoteProjectPath:ShellArgument.RemotePath,
378448
logsDir:ShellArgument.RemotePath,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp