import * as fs from "fs" ; import * as _ from "lodash" ; import * as path from "path" ; import * as vscode from "vscode" ; import { Settings } from "../../Settings" ; import { taskExecutor } from "../../taskExecutor" ; import { getPathToExtensionRoot } from "../../utils/contextUtils" ; import { Utils } from "../../utils/Utils" ; import { EffectivePomProvider } from "../EffectivePomProvider" ; import { mavenExplorerProvider } from "../mavenExplorerProvider" ; import { DependenciesMenu } from "./DependenciesMenu" ; import { Dependency } from "./Dependency" ; import { IEffectivePom } from "./IEffectivePom" ; import { ITreeItem } from "./ITreeItem" ; import { LifecycleMenu } from "./LifecycleMenu" ; import { MavenPlugin } from "./MavenPlugin" ; import { PluginsMenu } from "./PluginsMenu" ; const CONTEXT_VALUE = "maven:project" ; export class MavenProject implements ITreeItem { public parent ? : MavenProject ; public pomPath : string ; public _fullDependencyText : string ; public conflictNodes : Dependency [ ] ; public dependencyNodes : Dependency [ ] ; private ePomProvider : EffectivePomProvider ; private _ePom : any ; private _pom : any ; private properties : Map < string , string > = new Map ( ) ; constructor ( pomPath ) { this . pomPath = pomPath ; this . ePomProvider = new EffectivePomProvider ( pomPath ) ; const options = Settings . Pomfile . prefetchEffectivePom ( ) ? undefined : { cacheOnly : true } ; taskExecutor . execute ( async ( ) => { try { await this . getEffectivePom ( options ) ; } catch ( error ) { } } ) ; } public get name ( ) : string { if ( this . _pom ?. project ?. name ?. [ 0 ] !== undefined ) { const rawName = this . _pom . project . name [ 0 ] ; return this . fillProperties ( rawName ) ; } else { return this . _pom ?. project ?. artifactId ?. [ 0 ] ; } } public get fullText ( ) : string { return this . _fullDependencyText ; } public set fullText ( text ) { this . _fullDependencyText = text ; } public get groupId ( ) : string { return this . _pom ?. project ?. groupId ?. [ 0 ] ?? this . _pom ?. project ?. parent ?. [ 0 ] ?. groupId ?. [ 0 ] ?? this . parent ?. groupId ; } public get artifactId ( ) : string { return this . _pom ?. project ?. artifactId ?. [ 0 ] ; } public get id ( ) : string { return `${ this . groupId }:${ this . artifactId }` ; } public get packaging ( ) : string { return _ . get ( this . _pom , "project.packaging[0]" ) ; } public get moduleNames ( ) : string [ ] { const moduleNames = _ . get ( this . _pom , "project.modules[0].module" ) ; return moduleNames ? moduleNames : [ ] ; } public get plugins ( ) : MavenPlugin [ ] { let plugins ; if ( _ . has ( this . _ePom , "projects.project" ) ) { const project = this . _ePom . projects . project . find ( ( elem ) => this . name === _ . get ( elem , "artifactId[0]" ) ) ; if ( project ) { plugins = _ . get ( project , "build[0].plugins[0].plugin" ) ; } } else { plugins = _ . get ( this . _ePom , "project.build[0].plugins[0].plugin" ) ; } return this . _convertXmlPlugin ( plugins ) ; } public get dependencies ( ) : any [ ] { let deps = [ ] ; if ( _ . has ( this . _ePom , "projects.project" ) ) { const project = ( this . _ePom . projects . project ) . find ( ( elem ) => this . name === _ . get ( elem , "artifactId[0]" ) ) ; if ( project ) { deps = _ . get ( project , "build[0].plugins[0].plugin" ) ; } } else { deps = _ . get ( this . _ePom , "project.dependencies[0].dependency" ) ; } return deps ; } return public get modules ( ) : string [ ] { return this . moduleNames . map ( moduleName => { const relative = path . join ( path . dirname ( this . pomPath ) , moduleName ) ; if ( fs . existsSync ( relative ) && fs . statSync ( relative ) . isFile ( ) ) { return relative ; } else { return path . join ( relative , "pom.xml" ) ; } } ) ; } /**
     * Absolute path of parent POM, inferred from `parent.relativePath`.
     */ public get parentPomPath ( ) : string { const relativePath = this . _pom ?. project ?. parent ?. [ 0 ] ?. relativePath ?. [ 0 ] ?? "../pom.xml" ; return path . join ( path . dirname ( this . pomPath ) , relativePath ) ; } public async getTreeItem ( ) { await this . parsePom ( ) ; const label = this . name ?? this . artifactId ?? "[Corrupted]" ; const iconFile = this . packaging === "pom" ? "root.svg" : "project.svg" ; const treeItem = new vscode . TreeItem ( label ) ; treeItem . iconPath = { light : getPathToExtensionRoot ( "resources" , "icons" , "light" , iconFile ) , dark : getPathToExtensionRoot ( "resources" , "icons" , "dark" , iconFile ) } ; treeItem . collapsibleState = vscode . TreeItemCollapsibleState . Collapsed ; treeItem . description = this . id ; return treeItem ; } public getContextValue ( ) { return CONTEXT_VALUE ; } public getChildren ( ) { const ret = [ ] ; ret . push ( new LifecycleMenu ( this ) ) ; ret . push ( new PluginsMenu ( this ) ) ; ret . push ( new DependenciesMenu ( this ) ) ; if ( this . moduleNames . length > 0 && Settings . viewType ( ) === "hierarchical" ) { const projects = this . modules . map ( m => mavenExplorerProvider . getMavenProject ( m ) ) . filter ( Boolean ) as MavenProject [ ] ; ret . push ( ... projects ) ; } return ret ; } public async refreshEffectivePom ( ) { await this . ePomProvider . calculateEffectivePom ( ) ; } public async getEffectivePom ( options ? ) { let res = { pomPath : this . pomPath } ; try { res = await this . ePomProvider . getEffectivePom ( options ) ; this . _ePom = res ?. ePom ; } catch ( error ) { console . error ( error ) ; throw new Error ( "Failed to calculate Effective POM. Please check output window 'Maven for Java' for more details." ) ; } return res ; } public async refresh ( ) { await this . _refreshPom ( ) ; } public async parsePom ( ) { try { this . _pom = await Utils . parseXmlFile ( this . pomPath ) ; this . updateProperties ( ) ; } catch ( error ) { this . _pom = undefined ; } } public getDependencyVersion ( gid , aid ) { const deps = this . dependencies ; const targetDep = deps ?. find ( elem => _ . get ( elem , "groupId[0]" ) === gid && _ . get ( elem , "artifactId[0]" ) === aid ) ; return targetDep ?. version ?. [ 0 ] ; } private async _refreshPom ( ) { await this . parsePom ( ) ; mavenExplorerProvider . refresh ( this ) ; } private _convertXmlPlugin ( plugins ) { if ( plugins && plugins . length > 0 ) { return plugins . map ( p => new MavenPlugin ( this , _ . has ( p , "groupId[0]" ) ? _ . get ( p , "groupId[0]" ) : "org.apache.maven.plugins" , _ . get ( p , "artifactId[0]" ) , _ . get ( p , "version[0]" ) ) ) ; } return [ ] ; } private updateProperties ( ) { if ( this ?. _pom ?. project ?. properties ?. [ 0 ] !== undefined ) { for ( const [ key , value ] of Object . entries < any > ( this . _pom . project . properties [ 0 ] ) ) { this . properties . set ( key , value [ 0 ] ) ; } } } private fillProperties ( rawName ) { const stringTemplatePattern = /\$\{.*?\}/g ; const matches = rawName . match ( stringTemplatePattern ) ; if ( matches === null ) { return rawName ; } let name = rawName ; for ( const placeholder of matches ) { const key = placeholder . slice ( 2 , placeholder . length - 1 ) ; const value = this . getProperty ( key ) ; if ( value !== undefined ) { name = name . replace ( placeholder , value ) ; } } return name ; } param key returns private getProperty ( key ) { if ( this . properties . has ( key ) ) { return this . properties . get ( key ) ; } let cur = mavenExplorerProvider . getMavenProject ( this . parentPomPath ) ?? this . parent ; while ( cur !== undefined ) { if ( cur . properties . has ( key ) ) { return cur . properties . get ( key ) ; } cur = mavenExplorerProvider . getMavenProject ( cur . parentPomPath ) ?? cur . parent ; } return undefined ; } }