@@ -4,7 +4,7 @@ import * as path from 'path';
44import * as os from 'os' ;
55import * as fs from 'fs' ;
66import * 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' ;
88import { ExecuteCommandParams , ExecuteCommandRequest , LanguageClientOptions , RevealOutputChannelOn , ErrorHandler , Message , ErrorAction , CloseAction , DidChangeConfigurationNotification , CancellationToken } from 'vscode-languageclient' ;
99import { LanguageClient } from 'vscode-languageclient/node' ;
1010import { collectJavaExtensions , isContributedPartUpdated } from './plugin' ;
@@ -14,7 +14,7 @@ import { initialize as initializeRecommendation } from './recommendation';
1414import { Commands } from './commands' ;
1515import { ExtensionAPI , ClientStatus } from './extension.api' ;
1616import { 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' ;
1818import { logger , initializeLogFile } from './log' ;
1919import glob = require( 'glob' ) ;
2020import { 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+
412488async 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 ) {
0 commit comments