@@ -157,25 +157,16 @@ export async function installTools(
157
157
158
158
outputChannel . appendLine ( '' ) ; // Blank line for spacing.
159
159
160
- const toInstall : Promise < { tool : Tool ; reason : string } > [ ] = [ ] ;
160
+ const failures : { tool : ToolAtVersion ; reason : string } [ ] = [ ] ;
161
161
for ( const tool of missing ) {
162
162
const modulesOffForTool = modulesOff ;
163
163
164
- const reason = installTool ( tool , goVersion , envForTools , ! modulesOffForTool ) ;
165
- toInstall . push ( Promise . resolve ( { tool, reason : await reason } ) ) ;
166
- }
167
-
168
- const results = await Promise . all ( toInstall ) ;
169
-
170
- const failures : { tool : ToolAtVersion ; reason : string } [ ] = [ ] ;
171
- for ( const result of results ) {
172
- if ( result . reason === '' ) {
164
+ const failed = await installTool ( tool , goVersion , envForTools , ! modulesOffForTool ) ;
165
+ if ( failed ) {
166
+ failures . push ( { tool, reason : failed } ) ;
167
+ } else if ( tool . name === 'gopls' ) {
173
168
// Restart the language server if a new binary has been installed.
174
- if ( result . tool . name === 'gopls' ) {
175
- restartLanguageServer ( 'installation' ) ;
176
- }
177
- } else {
178
- failures . push ( result ) ;
169
+ restartLanguageServer ( 'installation' ) ;
179
170
}
180
171
}
181
172
@@ -222,16 +213,61 @@ export async function installTool(
222
213
return reason ;
223
214
}
224
215
}
225
- let toolsTmpDir = '' ;
216
+
217
+ const env = Object . assign ( { } , envForTools ) ;
218
+ env [ 'GO111MODULE' ] = modulesOn ? 'on' : 'off' ;
219
+
220
+ let importPath : string ;
221
+ if ( ! modulesOn ) {
222
+ importPath = getImportPath ( tool , goVersion ) ;
223
+ } else {
224
+ let version : semver . SemVer | string | undefined = tool . version ;
225
+ if ( ! version ) {
226
+ if ( tool . usePrereleaseInPreviewMode && isInPreviewMode ( ) ) {
227
+ version = await latestToolVersion ( tool , true ) ;
228
+ } else if ( tool . defaultVersion ) {
229
+ version = tool . defaultVersion ;
230
+ }
231
+ }
232
+ importPath = getImportPathWithVersion ( tool , version , goVersion ) ;
233
+ }
234
+
226
235
try {
227
- toolsTmpDir = await tmpDirForToolInstallation ( ) ;
236
+ if ( ! modulesOn || goVersion . lt ( '1.16' ) || hasModSuffix ( tool ) || tool . name === 'dlv-dap' ) {
237
+ await installToolWithGoGet ( tool , goVersion , env , modulesOn , importPath ) ;
238
+ } else {
239
+ await installToolWithGoInstall ( goVersion , env , importPath ) ;
240
+ }
241
+ const toolInstallPath = getBinPath ( tool . name ) ;
242
+ outputChannel . appendLine ( `Installing ${ importPath } (${ toolInstallPath } ) SUCCEEDED` ) ;
228
243
} catch ( e ) {
229
- return `Failed to create a temp directory: ${ e } ` ;
244
+ outputChannel . appendLine ( `Installing ${ importPath } FAILED` ) ;
245
+ outputChannel . appendLine ( `${ JSON . stringify ( e , null , 1 ) } ` ) ;
246
+ return `failed to install ${ tool . name } (${ importPath } ): ${ e } ` ;
230
247
}
248
+ }
231
249
232
- const env = Object . assign ( { } , envForTools ) ;
233
- env [ 'GO111MODULE' ] = modulesOn ? 'on' : 'off' ;
250
+ async function installToolWithGoInstall ( goVersion : GoVersion , env : NodeJS . Dict < string > , importPath : string ) {
251
+ // Unlike installToolWithGoGet, `go install` in module mode
252
+ // can run in the current directory safely. So, use the user-specified go tool path.
253
+ const goBinary = goVersion . binaryPath || getBinPath ( 'go' ) ;
254
+ const opts = {
255
+ env,
256
+ cwd : getWorkspaceFolderPath ( )
257
+ } ;
234
258
259
+ const execFile = util . promisify ( cp . execFile ) ;
260
+ logVerbose ( `$ ${ goBinary } install -x ${ importPath } } (cwd: ${ opts . cwd } )` ) ;
261
+ await execFile ( goBinary , [ 'install' , '-x' , importPath ] , opts ) ;
262
+ }
263
+
264
+ async function installToolWithGoGet (
265
+ tool : ToolAtVersion ,
266
+ goVersion : GoVersion ,
267
+ env : NodeJS . Dict < string > ,
268
+ modulesOn : boolean ,
269
+ importPath : string
270
+ ) {
235
271
// Some users use direnv-like setup where the choice of go is affected by
236
272
// the current directory path. In order to avoid choosing a different go,
237
273
// we will explicitly use `GOROOT/bin/go` instead of goVersion.binaryPath
@@ -241,7 +277,7 @@ export async function installTool(
241
277
: goVersion . binaryPath ;
242
278
243
279
// Build the arguments list for the tool installation.
244
- const args = [ 'get' , '-v ' ] ;
280
+ const args = [ 'get' , '-x ' ] ;
245
281
// Only get tools at master if we are not using modules.
246
282
if ( ! modulesOn ) {
247
283
args . push ( '-u' ) ;
@@ -251,33 +287,24 @@ export async function installTool(
251
287
if ( hasModSuffix ( tool ) || tool . name === 'dlv-dap' ) {
252
288
args . push ( '-d' ) ; // get the version, but don't build.
253
289
}
254
- let importPath : string ;
255
- if ( ! modulesOn ) {
256
- importPath = getImportPath ( tool , goVersion ) ;
257
- } else {
258
- let version : semver . SemVer | string | undefined = tool . version ;
259
- if ( ! version ) {
260
- if ( tool . usePrereleaseInPreviewMode && isInPreviewMode ( ) ) {
261
- version = await latestToolVersion ( tool , true ) ;
262
- } else if ( tool . defaultVersion ) {
263
- version = tool . defaultVersion ;
264
- }
265
- }
266
- importPath = getImportPathWithVersion ( tool , version , goVersion ) ;
267
- }
268
290
args . push ( importPath ) ;
269
291
270
- let output = 'no output' ;
271
- let result = '' ;
292
+ let toolsTmpDir = '' ;
293
+ try {
294
+ toolsTmpDir = await tmpDirForToolInstallation ( ) ;
295
+ } catch ( e ) {
296
+ throw new Error ( `Failed to create a temp directory: ${ e } ` ) ;
297
+ }
298
+
299
+ const opts = {
300
+ env,
301
+ cwd : toolsTmpDir
302
+ } ;
272
303
try {
273
- const opts = {
274
- env,
275
- cwd : toolsTmpDir
276
- } ;
277
304
const execFile = util . promisify ( cp . execFile ) ;
278
- const { stdout , stderr } = await execFile ( goBinary , args , opts ) ;
279
- output = ` ${ stdout } ${ stderr } ` ;
280
- logVerbose ( `install: ${ goBinary } ${ args . join ( ' ' ) } \n ${ stdout } ${ stderr } ` ) ;
305
+ logVerbose ( `$ ${ goBinary } ${ args . join ( ' ' ) } (cwd: ${ opts . cwd } )` ) ;
306
+ await execFile ( goBinary , args , opts ) ;
307
+
281
308
if ( hasModSuffix ( tool ) || tool . name === 'dlv-dap' ) {
282
309
// Actual installation of the -gomod tool and dlv-dap is done by running go build.
283
310
let destDir = env [ 'GOBIN' ] ;
@@ -291,21 +318,17 @@ export async function installTool(
291
318
const outputFile = path . join ( destDir , correctBinname ( tool . name ) ) ;
292
319
293
320
// go build does not take @version suffix yet.
294
- const importPath = getImportPath ( tool , goVersion ) ;
295
- await execFile ( goBinary , [ 'build' , '-o' , outputFile , importPath ] , opts ) ;
321
+ const importPathWithoutVersion = getImportPath ( tool , goVersion ) ;
322
+ logVerbose ( `$ ${ goBinary } build -o ${ outputFile } ${ importPathWithoutVersion } (cwd: ${ opts . cwd } )` ) ;
323
+ await execFile ( goBinary , [ 'build' , '-o' , outputFile , importPathWithoutVersion ] , opts ) ;
296
324
}
297
- const toolInstallPath = getBinPath ( tool . name ) ;
298
- outputChannel . appendLine ( `Installing ${ importPath } (${ toolInstallPath } ) SUCCEEDED` ) ;
299
325
} catch ( e ) {
300
- outputChannel . appendLine ( `Installing ${ importPath } FAILED` ) ;
301
- outputChannel . appendLine ( `${ JSON . stringify ( e , null , 1 ) } ` ) ;
302
- result = `failed to install ${ tool . name } (${ importPath } ): ${ e } ${ output } ` ;
326
+ logVerbose ( `FAILED: ${ JSON . stringify ( e , null , 1 ) } ` ) ;
327
+ throw e ;
303
328
} finally {
304
329
// Delete the temporary installation directory.
305
330
rmdirRecursive ( toolsTmpDir ) ;
306
331
}
307
-
308
- return result ;
309
332
}
310
333
311
334
export function declinedToolInstall ( toolName : string ) {
@@ -662,11 +685,11 @@ async function defaultInspectGoToolVersion(binPath: string): Promise<{ goVersion
662
685
dep github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
663
686
664
687
if the binary was built in GOPATH mode => the following code will throw an error which will be handled.
665
- /Users/hakim/go/bin/gopls: go1.16
688
+ /Users/hakim/go/bin/gopls: go1.16
666
689
667
690
if the binary was built in dev branch, in module mode => the following code will not throw an error,
668
691
and return (devel) as the moduleVersion.
669
- /Users/hakim/go/bin/gopls: go1.16
692
+ /Users/hakim/go/bin/gopls: go1.16
670
693
path golang.org/x/tools/gopls
671
694
mod golang.org/x/tools/gopls (devel)
672
695
dep github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
0 commit comments