@@ -12,13 +12,14 @@ import * as semver from "semver"
1212import * as vscode from "vscode"
1313import { makeCoderSdk , startWorkspace , waitForBuild } from "./api"
1414import { extractAgents } from "./api-helper"
15+ import * as cli from "./cliManager"
1516import { Commands } from "./commands"
17+ import { featureSetForVersion , FeatureSet } from "./featureSet"
1618import { getHeaderCommand } from "./headers"
1719import { SSHConfig , SSHValues , mergeSSHConfigValues } from "./sshConfig"
1820import { computeSSHProperties , sshSupportsSetEnv } from "./sshSupport"
1921import { Storage } from "./storage"
2022import { AuthorityPrefix , expandPath , parseRemoteAuthority } from "./util"
21- import { supportsCoderAgentLogDirFlag } from "./version"
2223import { WorkspaceAction } from "./workspaceAction"
2324
2425export interface RemoteDetails extends vscode . Disposable {
@@ -33,7 +34,6 @@ export class Remote {
3334 private readonly storage : Storage ,
3435 private readonly commands : Commands ,
3536 private readonly mode : vscode . ExtensionMode ,
36- private coderVersion : semver . SemVer | null = null ,
3737 ) { }
3838
3939 private async confirmStart ( workspaceName : string ) : Promise < boolean > {
@@ -194,16 +194,34 @@ export class Remote {
194194 // Store for use in commands.
195195 this . commands . workspaceRestClient = workspaceRestClient
196196
197+ let binaryPath : string | undefined
198+ if ( this . mode === vscode . ExtensionMode . Production ) {
199+ binaryPath = await this . storage . fetchBinary ( workspaceRestClient , parts . label )
200+ } else {
201+ try {
202+ // In development, try to use `/tmp/coder` as the binary path.
203+ // This is useful for debugging with a custom bin!
204+ binaryPath = path . join ( os . tmpdir ( ) , "coder" )
205+ await fs . stat ( binaryPath )
206+ } catch ( ex ) {
207+ binaryPath = await this . storage . fetchBinary ( workspaceRestClient , parts . label )
208+ }
209+ }
210+
197211 // First thing is to check the version.
198212 const buildInfo = await workspaceRestClient . getBuildInfo ( )
199- this . coderVersion = semver . parse ( buildInfo . version )
213+
214+ let version : semver . SemVer | null = null
215+ try {
216+ version = semver . parse ( await cli . version ( binaryPath ) )
217+ } catch ( e ) {
218+ version = semver . parse ( buildInfo . version )
219+ }
220+
221+ const featureSet = featureSetForVersion ( version )
222+
200223 // Server versions before v0.14.1 don't support the vscodessh command!
201- if (
202- this . coderVersion ?. major === 0 &&
203- this . coderVersion ?. minor <= 14 &&
204- this . coderVersion ?. patch < 1 &&
205- this . coderVersion ?. prerelease . length === 0
206- ) {
224+ if ( ! featureSet . vscodessh ) {
207225 await this . vscodeProposed . window . showErrorMessage (
208226 "Incompatible Server" ,
209227 {
@@ -501,7 +519,7 @@ export class Remote {
501519 // "Host not found".
502520 try {
503521 this . storage . writeToCoderOutputChannel ( "Updating SSH config..." )
504- await this . updateSSHConfig ( workspaceRestClient , parts . label , parts . host )
522+ await this . updateSSHConfig ( workspaceRestClient , parts . label , parts . host , binaryPath , featureSet )
505523 } catch ( error ) {
506524 this . storage . writeToCoderOutputChannel ( `Failed to configure SSH: ${ error } ` )
507525 throw error
@@ -544,8 +562,8 @@ export class Remote {
544562 /**
545563 * Format's the --log-dir argument for the ProxyCommand
546564 */
547- private async formatLogArg ( ) : Promise < string > {
548- if ( ! supportsCoderAgentLogDirFlag ( this . coderVersion ) ) {
565+ private async formatLogArg ( featureSet : FeatureSet ) : Promise < string > {
566+ if ( ! featureSet . proxyLogDirectory ) {
549567 return ""
550568 }
551569
@@ -563,7 +581,13 @@ export class Remote {
563581
564582 // updateSSHConfig updates the SSH configuration with a wildcard that handles
565583 // all Coder entries.
566- private async updateSSHConfig ( restClient : Api , label : string , hostName : string ) {
584+ private async updateSSHConfig (
585+ restClient : Api ,
586+ label : string ,
587+ hostName : string ,
588+ binaryPath : string ,
589+ featureSet : FeatureSet ,
590+ ) {
567591 let deploymentSSHConfig = { }
568592 try {
569593 const deploymentConfig = await restClient . getDeploymentSSHConfig ( )
@@ -624,20 +648,6 @@ export class Remote {
624648 const sshConfig = new SSHConfig ( sshConfigFile )
625649 await sshConfig . load ( )
626650
627- let binaryPath : string | undefined
628- if ( this . mode === vscode . ExtensionMode . Production ) {
629- binaryPath = await this . storage . fetchBinary ( restClient , label )
630- } else {
631- try {
632- // In development, try to use `/tmp/coder` as the binary path.
633- // This is useful for debugging with a custom bin!
634- binaryPath = path . join ( os . tmpdir ( ) , "coder" )
635- await fs . stat ( binaryPath )
636- } catch ( ex ) {
637- binaryPath = await this . storage . fetchBinary ( restClient , label )
638- }
639- }
640-
641651 const escape = ( str : string ) : string => `"${ str . replace ( / " / g, '\\"' ) } "`
642652 // Escape a command line to be executed by the Coder binary, so ssh doesn't substitute variables.
643653 const escapeSubcommand : ( str : string ) => string =
@@ -659,7 +669,7 @@ export class Remote {
659669 Host : label ? `${ AuthorityPrefix } .${ label } --*` : `${ AuthorityPrefix } --*` ,
660670 ProxyCommand : `${ escape ( binaryPath ) } ${ headerArg } vscodessh --network-info-dir ${ escape (
661671 this . storage . getNetworkInfoPath ( ) ,
662- ) } ${ await this . formatLogArg ( ) } --session-token-file ${ escape ( this . storage . getSessionTokenPath ( label ) ) } --url-file ${ escape (
672+ ) } ${ await this . formatLogArg ( featureSet ) } --session-token-file ${ escape ( this . storage . getSessionTokenPath ( label ) ) } --url-file ${ escape (
663673 this . storage . getUrlPath ( label ) ,
664674 ) } %h`,
665675 ConnectTimeout : "0" ,
0 commit comments