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>
diff --git a/package.json b/package.json
index fac30ac..796e0ee 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "go-nightly",
   "displayName": "Go Nightly",
-  "version": "0.0.0-development",
+  "version": "0.0.0",
   "publisher": "golang",
   "description": "Rich Go language support for Visual Studio Code (Nightly)",
   "author": {
@@ -146,6 +146,11 @@
         "description": "See the currently set GOPATH."
       },
       {
+        "command": "go.locate.tools",
+        "title": "Go: Locate Configured Tools",
+        "description": "List all configured tools."
+      },
+      {
         "command": "go.test.cursor",
         "title": "Go: Test Function At Cursor",
         "description": "Runs a unit test at the cursor."
@@ -1568,4 +1573,4 @@
       ]
     }
   }
-}
+}
\ No newline at end of file
diff --git a/src/goMain.ts b/src/goMain.ts
index eb6a69f..4de4089 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, setGlobalState, updateGlobalState } from './stateUtils';
 import { disposeTelemetryReporter, sendTelemetryEventForConfig } from './telemetry';
@@ -190,6 +192,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.
+				fs.exists(toolPath, (exists) => {
+					let msg = 'not found';
+					if (exists) {
+						msg = 'installed';
+					}
+					outputChannel.appendLine(`   ${tool.name}: ${toolPath} ${msg}`);
+				});
+			});
+		})
+	);
+
+	ctx.subscriptions.push(
 		vscode.commands.registerCommand('go.add.tags', (args) => {
 			addTags(args);
 		})