Skip to content

Commit 076455e

Browse files
authored
Can select build tool when there is a conflict (#2037)
Can select build tool when there is a conflict Signed-off-by: Sheng Chen <[email protected]>
1 parent cf26b9b commit 076455e

File tree

4 files changed

+84
-7
lines changed

4 files changed

+84
-7
lines changed

src/extension.ts

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as path from 'path';
44
import * as os from 'os';
55
import * as fs from 'fs';
66
import * as fse from 'fs-extra';
7-
import { workspace, extensions, ExtensionContext, window, commands, ViewColumn, Uri, languages, IndentAction, InputBoxOptions, Selection, Position, EventEmitter, OutputChannel, TextDocument, RelativePattern, ConfigurationTarget, WorkspaceConfiguration, env, UIKind } from 'vscode';
7+
import { workspace, extensions, ExtensionContext, window, commands, ViewColumn, Uri, languages, IndentAction, InputBoxOptions, EventEmitter, OutputChannel, TextDocument, RelativePattern, ConfigurationTarget, WorkspaceConfiguration, env, UIKind } from 'vscode';
88
import { ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, RevealOutputChannelOn, ErrorHandler, Message, ErrorAction, CloseAction, DidChangeConfigurationNotification, CancellationToken } from 'vscode-languageclient';
99
import { LanguageClient } from 'vscode-languageclient/node';
1010
import { collectJavaExtensions, isContributedPartUpdated } from './plugin';
@@ -14,7 +14,7 @@ import { initialize as initializeRecommendation } from './recommendation';
1414
import { Commands } from './commands';
1515
import { ExtensionAPI, ClientStatus } from './extension.api';
1616
import { getJavaConfiguration, deleteDirectory, getBuildFilePatterns, getInclusionPatternsFromNegatedExclusion, convertToGlob, getExclusionBlob } from './utils';
17-
import { onConfigurationChange, getJavaServerMode, ServerMode } from './settings';
17+
import { onConfigurationChange, getJavaServerMode, ServerMode, ACTIVE_BUILD_TOOL_STATE } from './settings';
1818
import { logger, initializeLogFile } from './log';
1919
import glob = require('glob');
2020
import { SyntaxLanguageClient } from './syntaxLanguageClient';
@@ -309,7 +309,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
309309
}
310310

311311
if (choice === "Yes") {
312-
startStandardServer(context, requirements, clientOptions, workspacePath, resolve);
312+
await startStandardServer(context, requirements, clientOptions, workspacePath, resolve);
313313
}
314314
});
315315

@@ -348,7 +348,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
348348
}
349349

350350
if (requireStandardServer) {
351-
startStandardServer(context, requirements, clientOptions, workspacePath, resolve);
351+
await startStandardServer(context, requirements, clientOptions, workspacePath, resolve);
352352
}
353353

354354
const onDidGrantWorkspaceTrust = (workspace as any).onDidGrantWorkspaceTrust;
@@ -375,10 +375,16 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
375375
});
376376
}
377377

378-
function startStandardServer(context: ExtensionContext, requirements: requirements.RequirementsData, clientOptions: LanguageClientOptions, workspacePath: string, resolve: (value?: ExtensionAPI | PromiseLike<ExtensionAPI>) => void) {
378+
async function startStandardServer(context: ExtensionContext, requirements: requirements.RequirementsData, clientOptions: LanguageClientOptions, workspacePath: string, resolve: (value?: ExtensionAPI | PromiseLike<ExtensionAPI>) => void) {
379379
if (standardClient.getClientStatus() !== ClientStatus.Uninitialized) {
380380
return;
381381
}
382+
383+
const checkConflicts: boolean = await ensureNoBuildToolConflicts(context, clientOptions);
384+
if (!checkConflicts) {
385+
return;
386+
}
387+
382388
if (apiManager.getApiInstance().serverMode === ServerMode.LIGHTWEIGHT) {
383389
// Before standard server is ready, we are in hybrid.
384390
apiManager.getApiInstance().serverMode = ServerMode.HYBRID;
@@ -409,6 +415,76 @@ async function workspaceContainsBuildFiles(): Promise<boolean> {
409415
return false;
410416
}
411417

418+
async function ensureNoBuildToolConflicts(context: ExtensionContext, clientOptions: LanguageClientOptions): Promise<boolean> {
419+
const isMavenEnabled: boolean = getJavaConfiguration().get<boolean>("import.maven.enabled");
420+
const isGradleEnabled: boolean = getJavaConfiguration().get<boolean>("import.gradle.enabled");
421+
if (isMavenEnabled && isGradleEnabled) {
422+
let activeBuildTool: string | undefined = context.workspaceState.get(ACTIVE_BUILD_TOOL_STATE);
423+
if (!activeBuildTool) {
424+
if (!await hasBuildToolConflicts()) {
425+
return true;
426+
}
427+
activeBuildTool = await window.showInformationMessage("Build tool conflicts are detected in workspace. Which one would you like to use?", "Use Maven", "Use Gradle");
428+
}
429+
430+
if (!activeBuildTool) {
431+
return false; // user cancels
432+
} else if (activeBuildTool.toLocaleLowerCase().includes("maven")) {
433+
// Here we do not persist it in the settings to avoid generating/updating files in user's workspace
434+
// Later if user want to change the active build tool, just directly set the related settings.
435+
clientOptions.initializationOptions.settings.java.import.gradle.enabled = false;
436+
context.workspaceState.update(ACTIVE_BUILD_TOOL_STATE, "maven");
437+
} else if (activeBuildTool.toLocaleLowerCase().includes("gradle")) {
438+
clientOptions.initializationOptions.settings.java.import.maven.enabled = false;
439+
context.workspaceState.update(ACTIVE_BUILD_TOOL_STATE, "gradle");
440+
} else {
441+
throw new Error ("Unknown build tool: " + activeBuildTool); // unreachable
442+
}
443+
}
444+
445+
return true;
446+
}
447+
448+
async function hasBuildToolConflicts(): Promise<boolean> {
449+
const projectConfigurationUris: Uri[] = await getBuildFilesInWorkspace();
450+
const projectConfigurationFsPaths: string[] = projectConfigurationUris.map((uri) => uri.fsPath);
451+
const eclipseDirectories = getDirectoriesByBuildFile(projectConfigurationFsPaths, [], ".project");
452+
// ignore the folders that already has .project file (already imported before)
453+
const gradleDirectories = getDirectoriesByBuildFile(projectConfigurationFsPaths, eclipseDirectories, ".gradle");
454+
const mavenDirectories = getDirectoriesByBuildFile(projectConfigurationFsPaths, eclipseDirectories, "pom.xml");
455+
return gradleDirectories.some((gradleDir) => {
456+
return mavenDirectories.includes(gradleDir);
457+
});
458+
}
459+
460+
async function getBuildFilesInWorkspace(): Promise<Uri[]> {
461+
const buildFiles: Uri[] = [];
462+
const inclusionFilePatterns: string[] = getBuildFilePatterns();
463+
inclusionFilePatterns.push("**/.project");
464+
const inclusionFolderPatterns: string[] = getInclusionPatternsFromNegatedExclusion();
465+
// Since VS Code API does not support put negated exclusion pattern in findFiles(),
466+
// here we first parse the negated exclusion to inclusion and do the search.
467+
if (inclusionFilePatterns.length > 0 && inclusionFolderPatterns.length > 0) {
468+
buildFiles.push(...await workspace.findFiles(convertToGlob(inclusionFilePatterns, inclusionFolderPatterns), null /*force not use default exclusion*/));
469+
}
470+
471+
const inclusionBlob: string = convertToGlob(inclusionFilePatterns);
472+
const exclusionBlob: string = getExclusionBlob();
473+
if (inclusionBlob) {
474+
buildFiles.push(...await workspace.findFiles(inclusionBlob, exclusionBlob));
475+
}
476+
477+
return buildFiles;
478+
}
479+
480+
function getDirectoriesByBuildFile(inclusions: string[], exclusions: string[], fileName: string): string[] {
481+
return inclusions.filter((fsPath) => fsPath.endsWith(fileName)).map((fsPath) => {
482+
return path.dirname(fsPath);
483+
}).filter((inclusion) => {
484+
return !exclusions.includes(inclusion);
485+
});
486+
}
487+
412488
async function promptUserForStandardServer(config: WorkspaceConfiguration): Promise<boolean> {
413489
const choice: string = await window.showInformationMessage("The workspace contains Java projects. Would you like to import them?", "Yes", "Always", "Later");
414490
switch (choice) {

src/settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const DEFAULT_HIDDEN_FILES: string[] = ['**/.classpath', '**/.project', '**/.set
99
export const IS_WORKSPACE_JDK_ALLOWED = "java.ls.isJdkAllowed";
1010
export const IS_WORKSPACE_VMARGS_ALLOWED = "java.ls.isVmargsAllowed";
1111
const extensionName = 'Language Support for Java';
12+
export const ACTIVE_BUILD_TOOL_STATE = "java.activeBuildTool";
1213

1314
const changeItem = {
1415
global: 'Exclude globally',

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function getBuildFilePatterns(): string[] {
5555
patterns.push("**/pom.xml");
5656
}
5757
if (isGradleImporterEnabled) {
58-
patterns.push("**/build.gradle");
58+
patterns.push("**/*.gradle");
5959
}
6060

6161
return patterns;

test/standard-mode-suite/utils.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ suite('Utils Test', () => {
3737

3838
const result: string[] = getBuildFilePatterns();
3939

40-
assert.deepEqual(result, ["**/pom.xml", "**/build.gradle"]);
40+
assert.deepEqual(result, ["**/pom.xml", "**/*.gradle"]);
4141
});
4242

4343
test('getBuildFilePatterns() - no importers is enabled', async function () {

0 commit comments

Comments
 (0)