Skip to content

Commit 138e1e8

Browse files
committed
extension/src: refactor required tool function
Validate the behavior of third party tool installation. When gopls is enabled, third party tools that is replaced by gopls will not be installed by default. (e.g. "gotests", "gomodifytags") But will be installed if user explicitly triggers the legacy commands. For #1652 Change-Id: I8754f013f252b221a981f6d7ebc5d71aa2440d14 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/713680 Reviewed-by: Peter Weinberger <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 392bfe0 commit 138e1e8

File tree

6 files changed

+86
-59
lines changed

6 files changed

+86
-59
lines changed

extension/src/commands/getConfiguredGoTools.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import path from 'path';
99
import { CommandFactory } from '.';
1010
import { getGoConfig } from '../config';
1111
import { inspectGoToolVersion } from '../goInstallTools';
12-
import { getConfiguredTools } from '../goTools';
12+
import { getRequiredTools } from '../goTools';
1313
import { getBinPath, getCurrentGoPath, getGoEnv, getGoVersion, getToolsGopath } from '../util';
1414
import { getEnvPath, initialEnvPath, getCurrentGoRoot } from '../utils/pathUtils';
1515

@@ -40,7 +40,7 @@ export const getConfiguredGoTools: CommandFactory = () => {
4040
buf.push('\n## Tools\n');
4141
try {
4242
const goVersion = await getGoVersion();
43-
const allTools = getConfiguredTools(getGoConfig());
43+
const allTools = getRequiredTools(getGoConfig());
4444
const goVersionTooOld = goVersion?.lt('1.18') || false;
4545

4646
buf.push(`\tgo:\t${goVersion?.binaryPath}: ${goVersion?.version}`);

extension/src/goExplorer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import os = require('os');
88
import path = require('path');
99
import { getGoConfig } from './config';
1010
import { getBinPath } from './util';
11-
import { getConfiguredTools } from './goTools';
11+
import { getRequiredTools } from './goTools';
1212
import { inspectGoToolVersion } from './goInstallTools';
1313
import { runGoEnv } from './goModules';
1414

@@ -159,7 +159,7 @@ export class GoExplorerProvider implements vscode.TreeDataProvider<vscode.TreeIt
159159
}
160160

161161
private async toolTreeItems() {
162-
const allTools = getConfiguredTools(getGoConfig());
162+
const allTools = getRequiredTools(getGoConfig());
163163
const toolsInfo = await Promise.all(allTools.map((tool) => this.toolDetailCache.get(tool.name)));
164164
const items = [];
165165
for (const t of toolsInfo) {

extension/src/goInstallTools.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { toolExecutionEnvironment, toolInstallationEnvironment } from './goEnv';
1818
import { addGoRuntimeBaseToPATH, clearGoRuntimeBaseFromPATH } from './goEnvironmentStatus';
1919
import { GoExtensionContext } from './context';
2020
import { addGoStatus, initGoStatusBar, outputChannel, removeGoStatus } from './goStatus';
21-
import { containsTool, getConfiguredTools, getImportPathWithVersion, getTool, Tool, ToolAtVersion } from './goTools';
21+
import { containsTool, getRequiredTools, getImportPathWithVersion, getTool, Tool, ToolAtVersion } from './goTools';
2222
import {
2323
getBinPath,
2424
getBinPathWithExplanation,
@@ -71,7 +71,7 @@ export const defaultToolsManager: IToolsManager = {
7171

7272
export async function installAllTools(updateExistingToolsOnly = false) {
7373
const goVersion = await getGoVersion();
74-
let allTools = getConfiguredTools(getGoConfig());
74+
let allTools = getRequiredTools(getGoConfig());
7575

7676
// exclude tools replaced by alternateTools.
7777
const alternateTools: { [key: string]: string } = getGoConfig().get('alternateTools') ?? {};
@@ -701,7 +701,7 @@ async function updateImportantToolsStatus(tm: IToolsManager = defaultToolsManage
701701
* If matcher is provided, only the tools that match the filter will be checked.
702702
*/
703703
function getMissingTools(matcher?: (value: Tool) => boolean): Promise<Tool[]> {
704-
let keys = getConfiguredTools(getGoConfig());
704+
let keys = getRequiredTools(getGoConfig());
705705
if (matcher) {
706706
keys = keys.filter(matcher);
707707
}
@@ -883,7 +883,7 @@ export async function suggestUpdates() {
883883
return;
884884
}
885885

886-
const allTools = getConfiguredTools(getGoConfig());
886+
const allTools = getRequiredTools(getGoConfig());
887887
const toolsToUpdate = await listOutdatedTools(configuredGoVersion, allTools);
888888
if (toolsToUpdate.length === 0) {
889889
return;

extension/src/goTools.ts

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -111,45 +111,53 @@ export function hasModSuffix(tool: Tool): boolean {
111111
return tool.name.endsWith('-gomod');
112112
}
113113

114-
export function getConfiguredTools(goConfig: vscode.WorkspaceConfiguration): Tool[] {
114+
/**
115+
* getRequiredTools returns the tools that required explicitly by the user
116+
* through settings like "go.lintTool", "go.formatTool" and implicitly by the
117+
* extension's functionality like "goplay".
118+
*
119+
* Tools that is replaced by gopls will not be returned if gopls is enabled.
120+
*/
121+
export function getRequiredTools(goConfig: vscode.WorkspaceConfiguration): Tool[] {
115122
// If language server is enabled, don't suggest tools that are replaced by gopls.
116123
// TODO(github.com/golang/vscode-go/issues/388): decide what to do when
117124
// the go version is no longer supported by gopls while the legacy tools are
118125
// no longer working (or we remove the legacy language feature providers completely).
119-
const useLanguageServer = goConfig['useLanguageServer'];
126+
const useLanguageServer = goConfig.get<boolean>('useLanguageServer');
120127

121-
const tools: Tool[] = [];
122-
function maybeAddTool(name: string) {
123-
const tool = allToolsInformation.get(name);
124-
if (tool) {
125-
if (!useLanguageServer || !tool.replacedByGopls) {
126-
tools.push(tool);
127-
}
128-
}
129-
}
130-
131-
// Add the language server if the user has chosen to do so.
132-
if (useLanguageServer) {
133-
maybeAddTool('gopls');
134-
}
135-
136-
// Start with default tools that should always be installed.
137-
for (const name of ['gotests', 'gomodifytags', 'impl', 'goplay']) {
138-
maybeAddTool(name);
139-
}
128+
// The default tools that is required by the extension's functionality.
129+
const toolNames = new Set<string>(['gotests', 'gomodifytags', 'impl', 'goplay']);
140130

141131
// Check if the system supports dlv, i.e. is 64-bit.
142132
// There doesn't seem to be a good way to check if the mips and s390
143133
// families are 64-bit, so just try to install it and hope for the best.
144134
if (process.arch.match(/^(mips|mipsel|ppc64|s390|s390x|x64|arm64)$/)) {
145-
maybeAddTool('dlv');
135+
toolNames.add('dlv');
146136
}
147137

148-
maybeAddTool(getFormatTool(goConfig));
138+
// Configurable linter and formatter through "go.formatTool" and "go.lintTool".
139+
toolNames.add(getFormatTool(goConfig));
140+
const lintToolName = goConfig.get<string>('lintTool');
141+
if (lintToolName) {
142+
toolNames.add(lintToolName);
143+
}
149144

150-
maybeAddTool(goConfig['lintTool']);
145+
// Add the language server if the user has chosen to do so.
146+
if (useLanguageServer) {
147+
toolNames.add('gopls');
148+
}
151149

152-
// Remove duplicates since tools like golangci-lint v2 and gopls are both
153-
// capable of linting and formatting.
154-
return tools.filter((v, i, self) => self.indexOf(v) === i);
150+
const tools: Tool[] = [];
151+
for (const name of toolNames) {
152+
const tool = allToolsInformation.get(name);
153+
if (!tool) {
154+
continue;
155+
}
156+
// If language server is enabled, filter out tools that are replaced by gopls.
157+
if (useLanguageServer && tool.replacedByGopls) {
158+
continue;
159+
}
160+
tools.push(tool);
161+
}
162+
return tools;
155163
}

extension/test/integration/goExplorer.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { TreeItem, Uri, window, workspace } from 'vscode';
99
import { getGoConfig } from '../../src/config';
1010

1111
import { GoExplorerProvider } from '../../src/goExplorer';
12-
import { getConfiguredTools } from '../../src/goTools';
12+
import { getRequiredTools } from '../../src/goTools';
1313
import { resolveHomeDir } from '../../src/utils/pathUtils';
1414
import { MockExtensionContext } from '../mocks/MockContext';
1515

@@ -68,7 +68,7 @@ suite('GoExplorerProvider', () => {
6868
});
6969

7070
test('tools tree items', async () => {
71-
const allTools = getConfiguredTools(getGoConfig());
71+
const allTools = getRequiredTools(getGoConfig());
7272
const expectTools = allTools.map((t) => t.name);
7373
const [, tools] = await explorer.getChildren()!;
7474
const items = (await explorer.getChildren(tools)) as TreeItem[];

extension/test/integration/install.test.ts

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
installTools,
1616
maybeInstallImportantTools
1717
} from '../../src/goInstallTools';
18-
import { Tool, getConfiguredTools, getTool, getToolAtVersion } from '../../src/goTools';
18+
import { Tool, getRequiredTools, getTool, getToolAtVersion } from '../../src/goTools';
1919
import { getBinPath, getGoVersion, GoVersion, rmdirRecursive } from '../../src/util';
2020
import { correctBinname } from '../../src/utils/pathUtils';
2121
import cp = require('child_process');
@@ -355,28 +355,47 @@ function shouldRunSlowTests(): boolean {
355355
return !!process.env['VSCODEGO_BEFORE_RELEASE_TESTS'];
356356
}
357357

358-
suite('getConfiguredTools', () => {
359-
test('require gopls when using language server', async () => {
360-
const configured = getConfiguredTools(
361-
new MockWorkspaceConfiguration(
362-
getGoConfig(),
363-
new Map<string, any>([['useLanguageServer', true]])
364-
)
365-
);
366-
const got = configured.map((tool) => tool.name) ?? [];
367-
assert(got.includes('gopls'), `omitted 'gopls': ${JSON.stringify(got)}`);
368-
});
358+
suite('getRequiredTools', () => {
359+
const testCases: {
360+
name: string;
361+
goConfig: Map<string, any>;
362+
expectedTools: string[];
363+
}[] = [
364+
{
365+
name: 'include gopls when {"go.useLanguageServer": true}',
366+
goConfig: new Map<string, any>([['useLanguageServer', true]]),
367+
// exclude third party tool that is replaced by gopls
368+
expectedTools: ['gopls', 'dlv', 'gotests', 'impl', 'goplay']
369+
},
370+
{
371+
name: 'exclude gopls when {"go.useLanguageServer": true}',
372+
goConfig: new Map<string, any>([['useLanguageServer', false]]),
373+
expectedTools: [
374+
'dlv',
375+
'impl',
376+
'goplay',
377+
// include third party tool that is replaced by gopls
378+
'gomodifytags',
379+
'gotests'
380+
]
381+
},
382+
{
383+
name: 'include golangci-lint specified in "go.lintTool"',
384+
goConfig: new Map<string, any>([
385+
['useLanguageServer', true],
386+
['lintTool', 'golangci-lint']
387+
]),
388+
expectedTools: ['golangci-lint', 'gopls', 'dlv', 'gotests', 'impl', 'goplay']
389+
}
390+
];
369391

370-
test('do not require gopls when not using language server', async () => {
371-
const configured = getConfiguredTools(
372-
new MockWorkspaceConfiguration(
373-
getGoConfig(),
374-
new Map<string, any>([['useLanguageServer', false]])
375-
)
376-
);
377-
const got = configured.map((tool) => tool.name) ?? [];
378-
assert(!got.includes('gopls'), `suggested 'gopls': ${JSON.stringify(got)}`);
379-
});
392+
for (const tc of testCases) {
393+
test(tc.name, async () => {
394+
const configured = getRequiredTools(new MockWorkspaceConfiguration(getGoConfig(), tc.goConfig));
395+
const got = configured.map((tool) => tool.name) ?? [];
396+
assert.deepStrictEqual(got.sort(), tc.expectedTools.sort());
397+
});
398+
}
380399
});
381400

382401
function fakeGoVersion(versionStr: string) {

0 commit comments

Comments
 (0)