import * as fse from "fs-extra" ; import * as _ from "lodash" ; import * as minimatch from "minimatch" ; import { platform } from "os" ; import * as path from "path" ; import { Disposable , ExtensionContext , Uri , window , workspace , WorkspaceFolder } from "vscode" ; import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper" ; import { Commands } from "../commands" ; import { Jdtls } from "../java/jdtls" ; import { Settings } from "../settings" ; import { Utility } from "../utility" ; import { DataNode } from "../views/dataNode" ; export class LibraryController implements Disposable { private disposable : Disposable ; public constructor ( public readonly context ) { this . disposable = Disposable . from ( instrumentOperationAsVsCodeCommand ( Commands . JAVA_PROJECT_ADD_LIBRARIES , ( ) => this . addLibraries ( ) ) , instrumentOperationAsVsCodeCommand ( Commands . JAVA_PROJECT_ADD_LIBRARY_FOLDERS , ( ) => this . addLibraries ( true ) ) , instrumentOperationAsVsCodeCommand ( Commands . JAVA_PROJECT_REMOVE_LIBRARY , ( node ) => node . uri && this . removeLibrary ( Uri . parse ( node . uri ) . fsPath ) ) , instrumentOperationAsVsCodeCommand ( Commands . JAVA_PROJECT_REFRESH_LIBRARIES , ( ) => this . refreshLibraries ( ) ) ) ; } public dispose ( ) { this . disposable . dispose ( ) ; } public async addLibraryGlobs ( libraryGlobs ) { const setting = Settings . referencedLibraries ( ) ; setting . exclude = this . dedupAlreadyCoveredPattern ( libraryGlobs , ... setting . exclude ) ; setting . include = this . updatePatternArray ( setting . include , ... libraryGlobs ) ; Settings . updateReferencedLibraries ( setting ) ; } public async addLibraries ( canSelectFolders ? ) { const workspaceFolder = Utility . getDefaultWorkspaceFolder ( ) ; const isMac = platform ( ) === "darwin" ; const results = await window . showOpenDialog ( { defaultUri : workspaceFolder && workspaceFolder . uri , canSelectFiles : ! canSelectFolders , canSelectFolders : canSelectFolders || isMac , canSelectMany : true , openLabel : canSelectFolders ? "Select Library Folders" : "Select Jar Libraries" , filters : canSelectFolders ? { Folders : [ "*" ] } : { "Jar Files" : [ "jar" ] } , } ) ; if ( ! results ) { return ; } this . addLibraryGlobs ( await Promise . all ( results . map ( async ( uri ) => { const uriPath = workspace . asRelativePath ( uri , false ) ; const isLibraryFolder = canSelectFolders || isMac && ( await fse . stat ( uri . fsPath ) ) . isDirectory ( ) ; return isLibraryFolder ? uriPath + "/**/*.jar" : uriPath ; } ) ) ) ; } public async removeLibrary ( removalFsPath ) { const setting = Settings . referencedLibraries ( ) ; const removedPaths = _ . remove ( setting . include , ( include ) => { if ( path . isAbsolute ( include ) ) { return Uri . file ( include ) . fsPath === removalFsPath ; } else { return include === workspace . asRelativePath ( removalFsPath , false ) ; } } ) ; if ( removedPaths . length === 0 ) { setting . exclude = this . updatePatternArray ( setting . exclude , workspace . asRelativePath ( removalFsPath , false ) ) ; } Settings . updateReferencedLibraries ( setting ) ; } public async refreshLibraries ( ) { const workspaceFolder = Utility . getDefaultWorkspaceFolder ( ) ; if ( workspaceFolder ) { await Jdtls . refreshLibraries ( workspaceFolder . uri . toString ( ) ) ; } } /**
     * Check if the `update` patterns are already covered by `origin` patterns and return those uncovered
     */ private dedupAlreadyCoveredPattern ( origin , ... update ) { return update . filter ( ( newPattern ) => { return ! origin . some ( ( originPattern ) => { return minimatch ( newPattern , originPattern ) ; } ) ; } ) ; } private updatePatternArray ( origin , ... update ) { update = this . dedupAlreadyCoveredPattern ( origin , ... update ) ; origin . push ( ... update ) ; return _ . uniq ( origin ) ; } }