goMain: go.locate.tools command (#3116)

* goMain: go.locate.tools command

This command prints the list of configured tools and paths to the tools.
I hope this is useful when debugging the cases where multiple versions
of a tool exist in different directories.

Change-Id: I925422e262978300cbccc97b53d547e4b2f4b146
GitHub-Last-Rev: 4184fd3bb52a51286c3f9950d4710c359a754a03
GitHub-Pull-Request: golang/vscode-go#14
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/224098
Reviewed-by: Rebecca Stambler <rstambler@golang.org>

* src/goMain: avoid extra fs lookups in go.locate.tools

Address the comments from Ramya.

Change-Id: I3a0d6cb1dbb656ffb18da266b370c7e9bcf32b3d
diff --git a/package.json b/package.json
index 1a6adc8..8c05098 100644
--- a/package.json
+++ b/package.json
@@ -141,6 +141,11 @@
         "description": "See the currently set GOPATH."
       },
       {
+        "command": "go.locate.tools",
+        "title": "Go: Locate Configured Go Tools",
+        "description": "List all the Go tools being used by this extension along with their locations."
+      },
+      {
         "command": "go.test.cursor",
         "title": "Go: Test Function At Cursor",
         "description": "Runs a unit test at the cursor."
diff --git a/src/goMain.ts b/src/goMain.ts
index 33cfa90..234a815 100644
--- a/src/goMain.ts
+++ b/src/goMain.ts
@@ -5,6 +5,7 @@
 
 'use strict';
 
+import fs = require('fs');
 import * as path from 'path';
 import vscode = require('vscode');
 import { browsePackages } from './goBrowsePackage';
@@ -43,8 +44,9 @@
 import { playgroundCommand } from './goPlayground';
 import { GoReferencesCodeLensProvider } from './goReferencesCodelens';
 import { GoRunTestCodeLensProvider } from './goRunTestCodelens';
-import { showHideStatus } from './goStatus';
+import { outputChannel, showHideStatus } from './goStatus';
 import { testAtCursor, testCurrentFile, testCurrentPackage, testPrevious, testWorkspace } from './goTest';
+import { getConfiguredTools } from './goTools';
 import { vetCode } from './goVet';
 import {
 	getFromGlobalState,
@@ -198,6 +200,43 @@
 	);
 
 	ctx.subscriptions.push(
+		vscode.commands.registerCommand('go.locate.tools', async () => {
+			outputChannel.show();
+			outputChannel.clear();
+			outputChannel.appendLine('Checking configured tools....');
+			// Tool's path search is done by getBinPathWithPreferredGopath
+			// which searches places in the following order
+			// 1) absolute path for the alternateTool
+			// 2) GOBIN
+			// 3) toolsGopath
+			// 4) gopath
+			// 5) GOROOT
+			// 6) PATH
+			outputChannel.appendLine('GOBIN: ' + process.env['GOBIN']);
+			outputChannel.appendLine('toolsGopath: ' + getToolsGopath());
+			outputChannel.appendLine('gopath: ' + getCurrentGoPath());
+			outputChannel.appendLine('GOROOT: ' + process.env['GOROOT']);
+			outputChannel.appendLine('PATH: ' + process.env['PATH']);
+			outputChannel.appendLine('');
+
+			const goVersion = await getGoVersion();
+			const allTools = getConfiguredTools(goVersion);
+
+			allTools.forEach((tool) => {
+				const toolPath = getBinPath(tool.name);
+				// TODO(hyangah): print alternate tool info if set.
+				let msg = 'not installed';
+				if (path.isAbsolute(toolPath)) {
+					// getBinPath returns the absolute path is the tool exists.
+					// (See getBinPathWithPreferredGopath which is called underneath)
+					msg = 'installed';
+				}
+				outputChannel.appendLine(`   ${tool.name}: ${toolPath} ${msg}`);
+			});
+		})
+	);
+
+	ctx.subscriptions.push(
 		vscode.commands.registerCommand('go.add.tags', (args) => {
 			addTags(args);
 		})