@@ -6,8 +6,10 @@ import (
6
6
"io/ioutil"
7
7
"net/url"
8
8
"os"
9
+ "os/exec"
9
10
"os/user"
10
11
"path/filepath"
12
+ "runtime"
11
13
"sort"
12
14
"strings"
13
15
@@ -132,8 +134,11 @@ func configSSH(configpath *string, remove *bool, next *bool) func(cmd *cobra.Com
132
134
}
133
135
}
134
136
135
- binPath , err := os . Executable ()
137
+ binPath , err := binPath ()
136
138
if err != nil {
139
+ if runtime .GOOS == "windows" {
140
+ return xerrors .Errorf ("Failed to ensure `coder` is in $PATH, please move the `coder` binary to a location in $PATH (such as System32): %w" , err )
141
+ }
137
142
return xerrors .Errorf ("Failed to get executable path: %w" , err )
138
143
}
139
144
@@ -165,6 +170,42 @@ func configSSH(configpath *string, remove *bool, next *bool) func(cmd *cobra.Com
165
170
}
166
171
}
167
172
173
+ // binPath returns the path to the coder binary suitable for use in ssh
174
+ // ProxyCommand.
175
+ func binPath () (string , error ) {
176
+ exePath , err := os .Executable ()
177
+ if err != nil {
178
+ return "" , xerrors .Errorf ("get executable path: %w" , err )
179
+ }
180
+
181
+ // On Windows, the coder-cli executable must be in $PATH for Msys2 and Git
182
+ // Bash to function correctly. To prevent weird behavior when people switch
183
+ // between the two, we require this for all users.
184
+ if runtime .GOOS == "windows" {
185
+ binName := filepath .Base (exePath )
186
+ pathPath , err := exec .LookPath (exePath )
187
+ if err != nil {
188
+ return "" , xerrors .Errorf ("locate %q in $PATH: %w" , binName , err )
189
+ }
190
+
191
+ // Warn the user if the current executable is not the same as the one in
192
+ // $PATH.
193
+ if filepath .Clean (pathPath ) != filepath .Clean (exePath ) {
194
+ clog .LogWarn (
195
+ "The current executable path does not match the executable path found in $PATH." ,
196
+ "This may lead to problems connecting to your workspace via SSH." ,
197
+ fmt .Sprintf ("\t Current executable path: %q" , exePath ),
198
+ fmt .Sprintf ("\t Executable path in $PATH: %q" , pathPath ),
199
+ )
200
+ }
201
+
202
+ return binName , nil
203
+ }
204
+
205
+ // On platforms other than Windows we can use the full path to the binary.
206
+ return exePath , nil
207
+ }
208
+
168
209
// removeOldConfig removes the old ssh configuration from the user's sshconfig.
169
210
// Returns true if the config was modified.
170
211
func removeOldConfig (config string ) (string , bool ) {
@@ -230,7 +271,7 @@ func makeSSHConfig(binPath, host, userName, workspaceName, privateKeyFilepath st
230
271
return fmt .Sprintf (
231
272
`Host coder.%s
232
273
HostName coder.%s
233
- ProxyCommand %s tunnel %s 12213 stdio
274
+ ProxyCommand "%s" tunnel %s 12213 stdio
234
275
StrictHostKeyChecking no
235
276
ConnectTimeout=0
236
277
IdentitiesOnly yes
0 commit comments