Skip to content

Commit

Permalink
src/util.ts: throw error when getGoVersion fails
Browse files Browse the repository at this point in the history
In most cases the use of getGoVersion is expected to return a value.
Updating the function to throw an error in the case that a Go
version is not found makes this explicit. For the exceptions where
an explicit binary path is requested we handle the error thrown and
show the existing warnings.

For #57.

Change-Id: Ib80ceec0636134b6694b0080ff19e0295d49d59f
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/400996
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Run-TryBot: Jamal Carvalho <jamal@golang.org>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
  • Loading branch information
jamalc committed Apr 28, 2022
1 parent 95b8c3a commit 27e8258
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 26 deletions.
14 changes: 9 additions & 5 deletions src/goEnvironmentStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,16 @@ export async function setSelectedGo(goOption: vscode.QuickPickItem, promptReload
vscode.window.showErrorMessage(`${newGoBin} is not an executable`);
return false;
}
const newGo = await getGoVersion(newGoBin);
if (!newGo || !newGo.isValid()) {
vscode.window.showErrorMessage(`failed to get "${newGoBin} version", invalid Go binary`);
return false;
let newGo: GoVersion | undefined;
try {
newGo = await getGoVersion(newGoBin);
await updateWorkspaceState('selectedGo', new GoEnvironmentOption(newGo.binaryPath, formatGoVersion(newGo)));
} catch (e) {
if (!newGo || !newGo.isValid()) {
vscode.window.showErrorMessage(`failed to get "${newGoBin} version", invalid Go binary:\n${e}`);
return false;
}
}
await updateWorkspaceState('selectedGo', new GoEnvironmentOption(newGo.binaryPath, formatGoVersion(newGo)));
}
// prompt the user to reload the window.
// promptReload defaults to true and should only be false for tests.
Expand Down
20 changes: 12 additions & 8 deletions src/goInstallTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,24 @@ export async function installAllTools(updateExistingToolsOnly = false) {
);
}

export async function getGoForInstall(goVersion?: GoVersion, silent?: boolean): Promise<GoVersion> {
export async function getGoForInstall(goVersion: GoVersion, silent?: boolean): Promise<GoVersion> {
const configured = getGoConfig().get<string>('toolsManagement.go');
if (!configured) {
return goVersion;
}
if (executableFileExists(configured)) {
const go = await getGoVersion(configured);
if (go) return go;
}
if (!silent) {
outputChannel.appendLine(
`Ignoring misconfigured 'go.toolsManagement.go' (${configured}). Provide a valid Go command.`
);
try {
const go = await getGoVersion(configured);
if (go) return go;
} finally {
if (!silent) {
outputChannel.appendLine(
`Ignoring misconfigured 'go.toolsManagement.go' (${configured}). Provide a valid Go command.`
);
}
}
}

return goVersion;
}

Expand Down
25 changes: 12 additions & 13 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,54 +321,53 @@ export function getUserNameHash() {

/**
* Gets version of Go based on the output of the command `go version`.
* Returns undefined if go version can't be determined because
* go is not available or `go version` fails.
* Throws if go version can't be determined because go is not available
* or `go version` fails.
*/
export async function getGoVersion(goBinPath?: string): Promise<GoVersion | undefined> {
export async function getGoVersion(goBinPath?: string): Promise<GoVersion> {
// TODO(hyangah): limit the number of concurrent getGoVersion call.
// When the extension starts, at least 4 concurrent calls race
// and end up calling `go version`.

const goRuntimePath = goBinPath ?? getBinPath('go');

const warn = (msg: string) => {
const error = (msg: string) => {
outputChannel.appendLine(msg);
console.warn(msg);
return new Error(msg);
};

if (!goRuntimePath) {
warn(`unable to locate "go" binary in GOROOT (${getCurrentGoRoot()}) or PATH (${envPath})`);
return;
throw error(`unable to locate "go" binary in GOROOT (${getCurrentGoRoot()}) or PATH (${envPath})`);
}
if (cachedGoBinPath === goRuntimePath && cachedGoVersion) {
if (cachedGoVersion.isValid()) {
return Promise.resolve(cachedGoVersion);
}
warn(`cached Go version (${JSON.stringify(cachedGoVersion)}) is invalid, recomputing`);
// Don't throw an the error. Continue and recompute go version.
error(`cached Go version (${JSON.stringify(cachedGoVersion)}) is invalid, recomputing`);
}
const docUri = vscode.window.activeTextEditor?.document.uri;
const cwd = getWorkspaceFolderPath(docUri && docUri.fsPath.endsWith('.go') ? docUri : undefined);

let goVersion: GoVersion;
let goVersion: GoVersion | undefined;
try {
const env = toolExecutionEnvironment();
const execFile = util.promisify(cp.execFile);
const { stdout, stderr } = await execFile(goRuntimePath, ['version'], { env, cwd });
if (stderr) {
warn(`failed to run "${goRuntimePath} version": stdout: ${stdout}, stderr: ${stderr}`);
return;
error(`failed to run "${goRuntimePath} version": stdout: ${stdout}, stderr: ${stderr}`);
}
goVersion = new GoVersion(goRuntimePath, stdout);
} catch (err) {
warn(`failed to run "${goRuntimePath} version": ${err} cwd: ${cwd}`);
return;
throw error(`failed to run "${goRuntimePath} version": ${err} cwd: ${cwd}`);
}
if (!goBinPath) {
// if getGoVersion was called with a given goBinPath, don't cache the result.
cachedGoBinPath = goRuntimePath;
cachedGoVersion = goVersion;
if (!cachedGoVersion.isValid()) {
warn(`unable to determine version from the output of "${goRuntimePath} version": "${goVersion.svString}"`);
error(`unable to determine version from the output of "${goRuntimePath} version": "${goVersion.svString}"`);
}
}
return goVersion;
Expand Down

0 comments on commit 27e8258

Please sign in to comment.