import * as fse from "fs-extra" ; import * as path from "path" ; import * as vscode from "vscode" ; import { Uri , workspace } from "vscode" ; import { sendInfo } from "vscode-extension-telemetry-wrapper" ; import { mavenTerminal } from "../mavenTerminal" ; import { Settings } from "../Settings" ; import { getPathToExtensionRoot } from "../utils/contextUtils" ; import { getEmbeddedMavenWrapper , getMaven } from "../utils/mavenUtils" ; import { Utils } from "../utils/Utils" ; import { Archetype } from "./Archetype" ; import { runSteps , selectArchetypeStep , specifyArchetypeVersionStep , specifyArtifactIdStep , specifyGroupIdStep , specifyTargetFolderStep } from "./createProject" ; import { IProjectCreationMetadata , IProjectCreationStep } from "./createProject/types" ; const REMOTE_ARCHETYPE_CATALOG_URL = "https://repo.maven.apache.org/maven2/archetype-catalog.xml" ; export namespace ArchetypeModule { export async function createMavenProject ( entry , _operationId ) { const metadata = { targetFolderHint : workspace . workspaceFolders ?. [ 0 ] ?. uri . fsPath } ; if ( entry instanceof Uri ) { metadata . targetFolderHint = entry . fsPath ; } else if ( typeof entry === 'object' ) { Object . assign ( metadata , entry ) ; } const steps = [ ] ; if ( ! metadata . archetypeArtifactId || ! metadata . archetypeGroupId || ! metadata . archetypeVersion ) { steps . push ( selectArchetypeStep , specifyArchetypeVersionStep ) ; } if ( ! metadata . groupId ) { steps . push ( specifyGroupIdStep ) ; } if ( ! metadata . artifactId ) { steps . push ( specifyArtifactIdStep ) ; } if ( ! metadata . targetFolder ) { steps . push ( specifyTargetFolderStep ) ; } const success = await runSteps ( steps , metadata ) ; if ( success ) { await executeInTerminalHandler ( metadata ) ; } } export async function updateArchetypeCatalog ( ) { const xml = await Utils . downloadFile ( REMOTE_ARCHETYPE_CATALOG_URL , true ) ; const archetypes = await listArchetypeFromXml ( xml ) ; const targetFilePath = path . join ( getPathToExtensionRoot ( ) , "resources" , "archetypes.json" ) ; await fse . ensureFile ( targetFilePath ) ; await fse . writeJSON ( targetFilePath , archetypes ) ; } async function executeInTerminalHandler ( metadata ) { const { archetypeArtifactId , archetypeGroupId , archetypeVersion , groupId , artifactId , targetFolder } = metadata ; if ( archetypeArtifactId === undefined || archetypeGroupId === undefined || archetypeVersion === undefined ) { throw new Error ( "Archetype information is incomplete." ) ; } sendInfo ( "" , { archetypeArtifactId , archetypeGroupId , archetypeVersion } ) ; const cmdArgs = [ "org.apache.maven.plugins:maven-archetype-plugin:3.1.2:generate" , `-DarchetypeArtifactId="${ archetypeArtifactId }"` , `-DarchetypeGroupId="${ archetypeGroupId }"` , `-DarchetypeVersion="${ archetypeVersion }"` , `-DgroupId="${ groupId }"` , `-DartifactId="${ artifactId }"` ] ; let cwd = targetFolder ; let mvnPath = await getMaven ( ) ; if ( mvnPath === undefined ) { cmdArgs . push ( `-DoutputDirectory="${ targetFolder }"` ) ; mvnPath = getEmbeddedMavenWrapper ( ) ; cwd = path . dirname ( mvnPath ) ; } if ( mvnPath === undefined ) { return ; } const mvnString = wrappedWithQuotes ( await mavenTerminal . formattedPathForTerminal ( mvnPath ) ) ; const defaultArgs = Settings . Executable . options ( metadata . targetFolder ) ; const mvnSettingsFile = Settings . getSettingsFilePath ( ) ; const mvnSettingsArg = mvnSettingsFile ? `-s "${ await mavenTerminal . formattedPathForTerminal ( mvnSettingsFile ) }"` : undefined ; let commandLine = [ mvnString , ... cmdArgs , defaultArgs , mvnSettingsArg ] . filter ( Boolean ) . join ( " " ) ; const options = { cwd } ; if ( vscode . env . remoteName === undefined && process . platform === "win32" ) { options . shellQuoting = shellQuotes . cmd ; options . executable = "cmd.exe" ; options . shellArgs = [ "/c" ] ; commandLine = `"${ commandLine }"` ; } else { options . shellQuoting = shellQuotes . bash ; } const execution = new vscode . ShellExecution ( commandLine , options ) ; const createProjectTask = new vscode . Task ( { type : "maven" , targetFolder , artifactId } , vscode . TaskScope . Global , "createProject" , "maven" , execution ) ; vscode . tasks . executeTask ( createProjectTask ) ; } export async function listArchetypeFromXml ( xmlString ) { try { const xmlObject = await Utils . parseXmlContent ( xmlString ) ; const catalog = xmlObject && xmlObject [ "archetype-catalog" ] ; const dict = { } ; const archetypeList = catalog . archetypes [ 0 ] . archetype ; archetypeList . forEach ( archetype => { const groupId = archetype . groupId && archetype . groupId [ 0 ] ; const artifactId = archetype . artifactId && archetype . artifactId [ 0 ] ; const description = archetype . description && archetype . description [ 0 ] ; const version = archetype . version && archetype . version [ 0 ] ; const repository = archetype . repository && archetype . repository [ 0 ] ; const identifier = `${ groupId }:${ artifactId }` ; if ( dict [ identifier ] === undefined ) { dict [ identifier ] = new Archetype ( artifactId , groupId , repository , description ) ; } if ( dict [ identifier ] . versions . indexOf ( version ) < 0 ) { dict [ identifier ] . versions . push ( version ) ; } } ) ; return Object . keys ( dict ) . map ( ( k ) => dict [ k ] ) ; } catch ( err ) { console . error ( err ) ; } return [ ] ; } } export class ArchetypeMetadata { public groupId : string ; public artifactId : string ; public versions : string [ ] ; public version : string ; public isLoadMore : boolean ; } function wrappedWithQuotes ( mvn ) { if ( mvn === "mvn" ) { return mvn ; } else { return `"${ mvn }"` ; } } const shellQuotes = { cmd : { strong : "\"" } , powershell : { escape : { escapeChar : "`" , charsToEscape : " \"'()" } , strong : "'" , weak : "\"" } , bash : { escape : { escapeChar : "\\" , charsToEscape : " \"'" } , strong : "'" , weak : "\"" } , zsh : { escape : { escapeChar : "\\" , charsToEscape : " \"'" } , strong : "'" , weak : "\"" } } ;