src/goEnvironmentStatus.ts: install Go in module mode

This CL ensures that newly selected Go versions are downloaded in
"module" mode by setting the "GO111MODULE" environment variable to "on"

Updates golang/vscode-go#317

Change-Id: I9f88b602c2a8de41e798ab5ec17902c0f2c1de59
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/242198
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/src/goEnvironmentStatus.ts b/src/goEnvironmentStatus.ts
index 9175d11..40e1f79 100644
--- a/src/goEnvironmentStatus.ts
+++ b/src/goEnvironmentStatus.ts
@@ -15,7 +15,7 @@
 import { toolInstallationEnvironment } from './goEnv';
 import { getCurrentGoRoot, pathExists } from './goPath';
 import { outputChannel } from './goStatus';
-import { getBinPath, getGoConfig, getGoVersion, timeout } from './util';
+import { getBinPath, getGoConfig, getGoVersion, getTempFilePath, rmdirRecursive } from './util';
 
 export class GoEnvironmentOption {
 	public static fromQuickPickItem({ description, label }: vscode.QuickPickItem): GoEnvironmentOption {
@@ -167,12 +167,31 @@
 				throw new Error('Could not find Go tool.');
 			}
 
+			// TODO(bcloud) dedup repeated logic below which comes from
+			// https://github.com/golang/vscode-go/blob/bc23fa854192d04200c8e4f74dca18d2c3021b46/src/goInstallTools.ts#L184
+
+			// Install tools in a temporary directory, to avoid altering go.mod files.
+			const mkdtemp = promisify(fs.mkdtemp);
+			const toolsTmpDir = await mkdtemp(getTempFilePath('go-tools-'));
+			let tmpGoModFile: string;
+
+			// Write a temporary go.mod file to avoid version conflicts.
+			tmpGoModFile = path.join(toolsTmpDir, 'go.mod');
+			const writeFile = promisify(fs.writeFile);
+			await writeFile(tmpGoModFile, 'module tools');
+
 			// use the current go executable to download the new version
-			const env = toolInstallationEnvironment();
+			const env = {
+				...toolInstallationEnvironment(),
+				GO111MODULE: 'on',
+			};
 			const [, ...args] = selectedGo.binpath.split(' ');
 			outputChannel.appendLine(`Running ${goExecutable} ${args.join(' ')}`);
 			try {
-				await execFile(goExecutable, args, { env });
+				await execFile(goExecutable, args, {
+					env,
+					cwd: toolsTmpDir,
+				});
 			} catch (getErr) {
 				outputChannel.appendLine(`Error finding Go: ${getErr}`);
 				throw new Error('Could not find Go version.');
@@ -214,6 +233,10 @@
 
 			outputChannel.appendLine('Updating integrated terminals');
 			vscode.window.terminals.forEach(updateIntegratedTerminal);
+
+			// remove tmp directories
+			outputChannel.appendLine('Cleaning up...');
+			rmdirRecursive(toolsTmpDir);
 			outputChannel.appendLine('Success!');
 		});
 	} else {