diff --git a/src/liberty/devCommands.ts b/src/liberty/devCommands.ts index e38ab280..6d0a8633 100644 --- a/src/liberty/devCommands.ts +++ b/src/liberty/devCommands.ts @@ -18,9 +18,9 @@ import { LibertyProject, ProjectProvider } from "./libertyProject"; import { getReport, filterProjects } from "../util/helperUtil"; import { COMMAND_TITLES, LIBERTY_MAVEN_PROJECT, LIBERTY_GRADLE_PROJECT, LIBERTY_MAVEN_PROJECT_CONTAINER, LIBERTY_GRADLE_PROJECT_CONTAINER, LIBERTY_SERVER_ENV_PORT_REGEX } from "../definitions/constants"; import { getGradleTestReport } from "../util/gradleUtil"; -import { pathExists } from "fs-extra"; import { DashboardData } from "./dashboard"; import { ProjectStartCmdParam } from "./projectStartCmdParam"; +import { getCommandForMaven, getCommandForGradle, defaultWindowsShell } from "../util/commandUtils"; export const terminals: { [libProjectId: number]: LibertyProject } = {}; @@ -99,22 +99,17 @@ export async function startDevMode(libProject?: LibertyProject | undefined): Pro console.log(localize("starting.liberty.dev.on", libProject.getLabel())); let terminal = libProject.getTerminal(); if (terminal === undefined) { - const path = Path.dirname(libProject.getPath()); - terminal = libProject.createTerminal(path); - if (terminal !== undefined) { - terminals[Number(terminal.processId)] = libProject; - } + //function call to create new terminal for LTV + terminal = createTerminalforLiberty(libProject, terminal); } if (terminal !== undefined) { terminal.show(); libProject.setTerminal(terminal); if (libProject.getContextValue() === LIBERTY_MAVEN_PROJECT || libProject.getContextValue() === LIBERTY_MAVEN_PROJECT_CONTAINER) { - const mvnCmdStart = await mvnCmd(libProject.getPath()); - const cmd = `${mvnCmdStart} io.openliberty.tools:liberty-maven-plugin:dev -f "${libProject.getPath()}"`; + const cmd = await getCommandForMaven(libProject.getPath(), "io.openliberty.tools:liberty-maven-plugin:dev", libProject.getTerminalType()); terminal.sendText(cmd); // start dev mode on current project } else if (libProject.getContextValue() === LIBERTY_GRADLE_PROJECT || libProject.getContextValue() === LIBERTY_GRADLE_PROJECT_CONTAINER) { - const gradleCmdStart = await gradleCmd(libProject.getPath()); - const cmd = `${gradleCmdStart} libertyDev -b="${libProject.getPath()}"`; + const cmd = await getCommandForGradle(libProject.getPath(), "libertyDev", libProject.getTerminalType()); terminal.sendText(cmd); // start dev mode on current project } } @@ -358,11 +353,8 @@ export async function customDevMode(libProject?: LibertyProject | undefined, par if (libProject !== undefined) { let terminal = libProject.getTerminal(); if (terminal === undefined) { - const path = Path.dirname(libProject.getPath()); - terminal = libProject.createTerminal(path); - if (terminal !== undefined) { - terminals[Number(terminal.processId)] = libProject; - } + //function call to create new terminal for LTV + terminal = createTerminalforLiberty(libProject, terminal); } if (terminal !== undefined) { terminal.show(); @@ -408,12 +400,10 @@ export async function customDevMode(libProject?: LibertyProject | undefined, par } if (libProject.getContextValue() === LIBERTY_MAVEN_PROJECT || libProject.getContextValue() === LIBERTY_MAVEN_PROJECT_CONTAINER) { - const mvnCmdStart = await mvnCmd(libProject.getPath()); - const cmd = `${mvnCmdStart} io.openliberty.tools:liberty-maven-plugin:dev ${customCommand} -f "${libProject.getPath()}"`; + const cmd = await getCommandForMaven(libProject.getPath(), "io.openliberty.tools:liberty-maven-plugin:dev", libProject.getTerminalType(), customCommand); terminal.sendText(cmd); } else if (libProject.getContextValue() === LIBERTY_GRADLE_PROJECT || libProject.getContextValue() === LIBERTY_GRADLE_PROJECT_CONTAINER) { - const gradleCmdStart = await gradleCmd(libProject.getPath()); - const cmd = `${gradleCmdStart} libertyDev ${customCommand} -b="${libProject.getPath()}"`; + const cmd = await getCommandForGradle(libProject.getPath(), "libertyDev", libProject.getTerminalType(), customCommand); terminal.sendText(cmd); } } @@ -433,22 +423,17 @@ export async function startContainerDevMode(libProject?: LibertyProject | undefi if (libProject !== undefined) { let terminal = libProject.getTerminal(); if (terminal === undefined) { - const path = Path.dirname(libProject.getPath()); - terminal = libProject.createTerminal(path); - if (terminal !== undefined) { - terminals[Number(terminal.processId)] = libProject; - } + //function call to create new terminal for LTV + terminal = createTerminalforLiberty(libProject, terminal); } if (terminal !== undefined) { terminal.show(); libProject.setTerminal(terminal); if (libProject.getContextValue() === LIBERTY_MAVEN_PROJECT_CONTAINER) { - const mvnCmdStart = await mvnCmd(libProject.getPath()); - const cmd = `${mvnCmdStart} io.openliberty.tools:liberty-maven-plugin:devc -f "${libProject.getPath()}"`; + const cmd = await getCommandForMaven(libProject.getPath(), "io.openliberty.tools:liberty-maven-plugin:devc", libProject.getTerminalType()); terminal.sendText(cmd); } else if (libProject.getContextValue() === LIBERTY_GRADLE_PROJECT_CONTAINER) { - const gradleCmdStart = await gradleCmd(libProject.getPath()); - const cmd = `${gradleCmdStart} libertyDevc -b="${libProject.getPath()}"`; + const cmd = await getCommandForGradle(libProject.getPath(), "libertyDevc", libProject.getTerminalType()); terminal.sendText(cmd); } } @@ -529,85 +514,19 @@ export function deleteTerminal(terminal: vscode.Terminal): void { console.error(localize("unable.to.delete.terminal", terminal.name)); } } - - -// return Maven executable path, Maven wrapper, or mvn -export async function mvnCmd(pomPath: string): Promise { - - // attempt to use the Maven executable path, if empty try using mvn or mvnw according to the preferMavenWrapper setting - const mavenExecutablePath: string | undefined = vscode.workspace.getConfiguration("maven").get("executable.path"); - if (mavenExecutablePath) { - return mavenExecutablePath; - } - const preferMavenWrapper: boolean | undefined = vscode.workspace.getConfiguration("maven").get("executable.preferMavenWrapper"); - if (preferMavenWrapper) { - const localMvnwPath: string | undefined = await getLocalMavenWrapper(Path.dirname(pomPath)); - if (localMvnwPath) { - return localMvnwPath; - } - } - return "mvn"; -} - -export async function gradleCmd(buildGradle: string): Promise { - const preferGradleWrapper: boolean | undefined = vscode.workspace.getConfiguration("java").get("import.gradle.wrapper.enabled"); - if (preferGradleWrapper) { - const localGradlewPath: string | undefined = await getLocalGradleWrapper(Path.dirname(buildGradle)); - if (localGradlewPath) { - return localGradlewPath; - } - } - return "gradle"; -} - -/** - * Search for potential Maven wrapper, return undefined if does not exist - * - * Reused from vscode-maven - * https://github.com/microsoft/vscode-maven/blob/2ab8f392f418c8e0fe2903387f2b0013a1c50e78/src/utils/mavenUtils.ts - * @param projectFolder - */ -async function getLocalMavenWrapper(projectFolder: string): Promise { - const mvnw: string = isWin() ? "mvnw.cmd" : "mvnw"; - - // walk up parent folders - let current: string = projectFolder; - while (Path.basename(current)) { - const potentialMvnwPath: string = Path.join(current, mvnw); - if (await pathExists(potentialMvnwPath)) { - return potentialMvnwPath; - } - current = Path.dirname(current); - } - return undefined; -} - /** - * Search for potential Gradle wrapper, return undefined if it does not exist - * Modified from vscode-maven, see getLocalMavenWrapper method above - * @param projectFolder + * function to create new terminal of default type */ -async function getLocalGradleWrapper(projectFolder: string): Promise { - const gradlew: string = isWin() ? "gradlew.bat" : "gradlew"; - - // walk up parent folders - let current: string = projectFolder; - while (Path.basename(current)) { - const potentialGradlewPath: string = Path.join(current, gradlew); - if (await pathExists(potentialGradlewPath)) { - return potentialGradlewPath; - } - current = Path.dirname(current); +function createTerminalforLiberty(libProject: LibertyProject, terminal: vscode.Terminal | undefined) { + const path = Path.dirname(libProject.getPath()); + //fetch the default terminal details and store it in LibertyProject object + const terminalType = defaultWindowsShell(); + libProject.setTerminalType(terminalType); + terminal = libProject.createTerminal(path); + if (terminal !== undefined) { + terminals[Number(terminal.processId)] = libProject; } - return undefined; -} - -/** - * Reused from vscode-maven - * https://github.com/microsoft/vscode-maven/blob/2ab8f392f418c8e0fe2903387f2b0013a1c50e78/src/utils/mavenUtils.ts - */ -function isWin(): boolean { - return process.platform.startsWith("win"); + return terminal; } /* @@ -645,4 +564,4 @@ function checkReportAndDisplay(report: any, reportType: string, reportTypeLabel: resolve(exists); }); }); -} \ No newline at end of file +} diff --git a/src/liberty/libertyProject.ts b/src/liberty/libertyProject.ts index 8c860c09..8abae9ff 100644 --- a/src/liberty/libertyProject.ts +++ b/src/liberty/libertyProject.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020, 2023 IBM Corporation. + * Copyright (c) 2020, 2024 IBM Corporation. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -442,6 +442,7 @@ export class LibertyProject extends vscode.TreeItem { public contextValue: string, public terminal?: vscode.Terminal, public readonly command?: vscode.Command, // ? indicates optional param + public terminalType?: string, ) { super(label, collapsibleState); this.tooltip = this.path; @@ -488,6 +489,13 @@ export class LibertyProject extends vscode.TreeItem { public setTerminal(terminal: vscode.Terminal): void { this.terminal = terminal; } + public getTerminalType(): string | undefined { + return this.terminalType; + } + + public setTerminalType(terminalType: string): void { + this.terminalType = terminalType; + } public createTerminal(projectHome: string): vscode.Terminal | undefined { if (this.terminal === undefined) { diff --git a/src/util/commandUtils.ts b/src/util/commandUtils.ts new file mode 100644 index 00000000..bfa2ac99 --- /dev/null +++ b/src/util/commandUtils.ts @@ -0,0 +1,258 @@ +/** + * Copyright (c) 2024 IBM Corporation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import * as Path from "path"; +import * as vscode from "vscode"; +import { pathExists } from "fs-extra"; + +/** + * Reused from vscode-maven + * https://github.com/microsoft/vscode-maven/blob/main/src/mavenTerminal.ts + */ +enum ShellType { + CMD = "Command Prompt", + POWERSHELL = "PowerShell", + GIT_BASH = "Git Bash", + WSL = "WSL Bash", + OTHERS = "Others" +} + +/** + * Return the maven command based on the OS and Terminal for start, start in container, start.. + */ +export async function getCommandForMaven(pomPath: string, command: string, terminalType?: string, customCommand?: string): Promise { + + // attempt to use the Maven executable path, if empty try using mvn or mvnw according to the preferMavenWrapper setting + const mavenExecutablePath: string | undefined = vscode.workspace.getConfiguration("maven").get("executable.path"); + if (mavenExecutablePath) { + return formDefaultCommand(mavenExecutablePath, pomPath, command, "-f ", customCommand); + } + let mvnCmdStart = await mvnCmd(pomPath); + if (mvnCmdStart === "mvn") { + return formDefaultCommand(mvnCmdStart, pomPath, command, "-f ", customCommand); + } + //checking the OS type for command customization + if (isWin()) { + return getMavenCommandForWin(mvnCmdStart, pomPath, command, terminalType, customCommand); + } else { + return formLinuxBasedCommand(mvnCmdStart, command, "./mvnw ", customCommand); + } +} + +/** + * Return the gradle command based on the OS and Terminal for start, start in container, start.. + */ +export async function getCommandForGradle(buildGradlePath: string, command: string, terminalType?: String, customCommand?: string): Promise { + let gradleCmdStart = await gradleCmd(buildGradlePath); + + if (gradleCmdStart === "gradle") { + return formDefaultCommand(gradleCmdStart, buildGradlePath, command, "-b=", customCommand); + } + //checking the OS type for command customization + if (isWin()) { + return getGradleCommandForWin(gradleCmdStart, buildGradlePath, command, terminalType, customCommand); + } else { + gradleCmdStart = Path.join(gradleCmdStart, "gradlew"); + return formDefaultCommand(gradleCmdStart, buildGradlePath, command, "-b=", customCommand); + } +} + +/** + * Reused from vscode-maven + * https://github.com/microsoft/vscode-maven/blob/main/src/mavenTerminal.ts + */ +function toDefaultWslPath(p: string): string { + const arr: string[] = p.split(":\\"); + if (arr.length === 2) { + const drive: string = arr[0].toLowerCase(); + const dir: string = arr[1].replace(/\\/g, "/"); + return `/mnt/${drive}/${dir}`; + } else { + return p.replace(/\\/g, "/"); + } +} + +/** + * Reused from vscode-maven + * https://github.com/microsoft/vscode-maven/blob/2ab8f392f418c8e0fe2903387f2b0013a1c50e78/src/utils/mavenUtils.ts + */ +export function isWin(): boolean { + return process.platform.startsWith("win"); +} + +/** + * Returns maven wrapper path or mvn + */ +async function mvnCmd(pomPath: string): Promise { + const preferMavenWrapper: boolean | undefined = vscode.workspace.getConfiguration("maven").get("executable.preferMavenWrapper"); + if (preferMavenWrapper) { + const localMvnwPath: string | undefined = await getLocalMavenWrapperDir(Path.dirname(pomPath)); + if (localMvnwPath) { + return `${localMvnwPath}`; + } + } + return "mvn"; +} + +/** + * Returns gradle wrapper path or gradle + */ +async function gradleCmd(buildGradle: string): Promise { + const preferGradleWrapper: boolean | undefined = vscode.workspace.getConfiguration("java").get("import.gradle.wrapper.enabled"); + if (preferGradleWrapper) { + const localGradlewPath: string | undefined = await getLocalGradleWrapperDir(Path.dirname(buildGradle)); + if (localGradlewPath) { + return `${localGradlewPath}`; + } + } + return "gradle"; +} + +/** + * Search for potential Gradle wrapper, return undefined if does not exist + * Modified from vscode-maven, see getLocalMavenWrapperDir method below + * @param projectFolder + */ +async function getLocalGradleWrapperDir(projectFolder: string): Promise { + const gradlew: string = isWin() ? "gradlew.bat" : "gradlew"; + // walk up parent folders + let currentDir: string = projectFolder; + while (Path.basename(currentDir)) { + const potentialGradlewPath: string = Path.join(currentDir, gradlew); + if (await pathExists(potentialGradlewPath)) { + return currentDir; + } + currentDir = Path.dirname(currentDir); + } + return undefined; +} + +/** + * Search for potential Maven wrapper, return undefined if it does not exist + * Modified from vscode-maven + * https://github.com/microsoft/vscode-maven/blob/2ab8f392f418c8e0fe2903387f2b0013a1c50e78/src/utils/mavenUtils.ts + * @param projectFolder + */ +async function getLocalMavenWrapperDir(projectFolder: string): Promise { + const mvnw: string = isWin() ? "mvnw.cmd" : "mvnw"; + // walk up parent folders + let currentDir: string = projectFolder; + while (Path.basename(currentDir)) { + const potentialMvnwPath: string = Path.join(currentDir, mvnw); + if (await pathExists(potentialMvnwPath)) { + return currentDir; + } + currentDir = Path.dirname(currentDir); + } + return undefined; +} + +/** + * Returns the gradle command for windows OS based on the terminal configured + */ +function getGradleCommandForWin(gradleCmdStart: string, buildGradlePath: string, command: string, terminalType?: String, customCommand?: string): string { + switch (terminalType) { + case ShellType.GIT_BASH: + gradleCmdStart = Path.join(gradleCmdStart, "gradlew"); + return formDefaultCommand(gradleCmdStart, buildGradlePath, command, "-b=", customCommand); //Bash + case ShellType.POWERSHELL: + gradleCmdStart = Path.join(gradleCmdStart, "gradlew.bat"); + return formPowershellCommand(gradleCmdStart, buildGradlePath, command, "-b=", customCommand); + case ShellType.WSL: + return formLinuxBasedCommand(toDefaultWslPath(gradleCmdStart), command, "./gradlew ", customCommand); //Wsl + default: + // The default case is ShellType CMD or OTHERS + gradleCmdStart = Path.join(gradleCmdStart, "gradlew.bat"); + return formDefaultCommand(gradleCmdStart, buildGradlePath, command, "-b=", customCommand); + } +} + +/** + * Returns the maven command for windows OS based on the terminal configured + */ +function getMavenCommandForWin(mvnCmdStart: string, pomPath: string, command: string, terminalType?: String, customCommand?: string): string { + switch (terminalType) { + case ShellType.GIT_BASH: + return formLinuxBasedCommand(mvnCmdStart, command, "./mvnw ", customCommand); + case ShellType.POWERSHELL: + mvnCmdStart = Path.join(mvnCmdStart, "mvnw.cmd"); + return formPowershellCommand(mvnCmdStart, pomPath, command, "-f ", customCommand); + case ShellType.WSL: + mvnCmdStart = toDefaultWslPath(mvnCmdStart); + return formLinuxBasedCommand(mvnCmdStart, command, "./mvnw ", customCommand); + default: + // The default case is ShellType CMD or OTHERS + mvnCmdStart = Path.join(mvnCmdStart, "mvnw.cmd"); + return formDefaultCommand(mvnCmdStart, pomPath, command, "-f ", customCommand); + } +} + +/** + * Returns the Powershell based command for windows OS + */ +function formPowershellCommand(cmdStart: string, projectPath: string, command: string, cmdOption: String, customCommand?: string): string { + if (customCommand) { + return "& \"" + cmdStart + "\" " + `${command}` + ` ${customCommand}` + ` ${cmdOption}"${projectPath}"`; //Powershell for start.. + } + return "& \"" + cmdStart + "\" " + `${command}` + ` ${cmdOption}"${projectPath}"`; //PowerShell +} + +/** + * Returns the Linux based command + */ +function formLinuxBasedCommand(cmdStart: string, command: string, wrapperType: String, customCommand?: string): string { + if (customCommand) { + return "cd \"" + cmdStart + "\" && " + `${wrapperType}` + `${command}` + ` ${customCommand}`; //Bash or WSL for start.. + } + return "cd \"" + cmdStart + "\" && " + `${wrapperType}` + `${command}`; //Bash or WSL command +} + +/** + * Returns default command + */ +function formDefaultCommand(projectPath: string, buildFilePath: String, command: string, cmdOption: String, customCommand?: string): string { + if (customCommand) { + return "\"" + projectPath + "\" " + `${command}` + ` ${customCommand}` + ` ${cmdOption}"${buildFilePath}"`; + } + return "\"" + projectPath + "\" " + `${command}` + ` ${cmdOption}"${buildFilePath}"`; +} + +/** + * Reused from vscode-maven - currentWindowsShell() + * https://github.com/microsoft/vscode-maven/blob/main/src/mavenTerminal.ts + * method to fetch default terminal configured + */ +export function defaultWindowsShell(): ShellType { + const defaultWindowsShellPath: string = vscode.env.shell; + const executable: string = Path.basename(defaultWindowsShellPath); + switch (executable.toLowerCase()) { + case "cmd.exe": + return ShellType.CMD; + case "pwsh.exe": + case "powershell.exe": + case "pwsh": // pwsh on mac/linux + return ShellType.POWERSHELL; + case "bash.exe": + case 'git-cmd.exe': + return ShellType.GIT_BASH; + case 'wsl.exe': + case 'ubuntu.exe': + case 'ubuntu1804.exe': + case 'kali.exe': + case 'debian.exe': + case 'opensuse-42.exe': + case 'sles-12.exe': + return ShellType.WSL; + default: + return ShellType.OTHERS; + } +} + +