'use strict' ; import * as child_process from "child_process" ; import * as fse from "fs-extra" ; import * as os from "os" ; import * as path from "path" ; import * as readline from "readline" ; import * as vscode from "vscode" ; import { instrumentOperationStep , sendInfo } from "vscode-extension-telemetry-wrapper" ; import * as xml2js from "xml2js" ; import * as Constants from "./Constants" ; import { DialogMessage } from "./DialogMessage" ; import { localize } from './localize' ; const isWindows = process . platform . indexOf ( 'win' ) === 0 ; const JAVA_FILENAME = 'java' + ( isWindows ? '.exe' : '' ) ; interface IEnv { environmentVariable : string ; value : string ; } export namespace Utility { export async function executeCMD ( outputPane , serverName , command , options , ... args ) { await new Promise < void > ( ( resolve , reject ) : void => { outputPane . show ( ) ; let stderr = '' ; options . env = { ... ( options . env ?? { } ) , ... Utility . getCustomEnv ( ) } ; const commandToSpawn = command . includes ( " " ) ? `"${ command }"` : command ; const p = child_process . spawn ( commandToSpawn , args , options ) ; p . stdout . on ( 'data' , ( data ) : void => outputPane . append ( serverName ? `[${ serverName }]: ${ data . toString ( ) }` : data . toString ( ) ) ) ; p . stderr . on ( 'data' , ( data ) => { stderr = stderr . concat ( data . toString ( ) ) ; outputPane . append ( serverName ? `[${ serverName }]: ${ data . toString ( ) }` : data . toString ( ) ) ; } ) ; p . on ( 'error' , ( err ) => { reject ( err ) ; } ) ; p . on ( 'exit' , ( code ) => { if ( code !== 0 ) { reject ( new Error ( localize ( 'tomcatExt.commandfailed' , 'Command failed with exit code {0}' , code ) ) ) ; } resolve ( ) ; } ) ; } ) ; } export async function openFile ( file ) { if ( ! await fse . pathExists ( file ) ) { throw new Error ( localize ( 'tomcatExt.fileNotExist' , `File ${ file } does not exist.` ) ) ; } vscode . window . showTextDocument ( vscode . Uri . file ( file ) , { preview : false } ) ; } export function trackTelemetryStep ( operationId , step , callback ) { return instrumentOperationStep ( operationId , step , callback ) ( ) ; } export function infoTelemetryStep ( operationId , step ) { sendInfo ( operationId , { finishedStep : step } ) ; } export function disableAutoRestart ( ) { const config = vscode . workspace . getConfiguration ( 'tomcat' ) ; if ( config ) { config . update ( Constants . RESTART_CONFIG_ID , false , true ) ; } } export async function getServerStoragePath ( defaultStoragePath , serverName ) { return path . join ( await getWorkspace ( defaultStoragePath ) , serverName ) ; } export async function getServerName ( installPath , defaultStoragePath , existingServerNames ) { const workspace = await getWorkspace ( defaultStoragePath ) ; await fse . ensureDir ( workspace ) ; const fileNames = await fse . readdir ( workspace ) ; let serverName = path . basename ( installPath ) ; let index = 1 ; while ( fileNames . indexOf ( serverName ) >= 0 || existingServerNames . indexOf ( serverName ) >= 0 ) { serverName = path . basename ( installPath ) . concat ( `-${ index }` ) ; index += 1 ; } return serverName ; } async function getWorkspace ( defaultStoragePath ) { const config = vscode . workspace . getConfiguration ( 'tomcat' ) ; if ( config ) { const workspace = config . get < string > ( 'workspace' ) ; if ( workspace && workspace !== '' ) { await fse . ensureDir ( workspace ) ; return workspace ; } } return path . join ( defaultStoragePath , 'tomcat' ) ; } export async function validateInstallPath ( installPath ) { const configFileExists = fse . pathExists ( path . join ( installPath , 'conf' , 'server.xml' ) ) ; const serverWebFileExists = fse . pathExists ( path . join ( installPath , 'conf' , 'web.xml' ) ) ; const serverBootstrapJarFileExists = fse . pathExists ( path . join ( installPath , 'bin' , 'bootstrap.jar' ) ) ; const serverJuliJarFileExists = fse . pathExists ( path . join ( installPath , 'bin' , 'tomcat-juli.jar' ) ) ; return await configFileExists && await serverWebFileExists && await serverBootstrapJarFileExists && await serverJuliJarFileExists ; } export async function needRestart ( httpPort , httpsPort , serverConfog ) { const newHttpPort = await getPort ( serverConfog , Constants . PortKind . Http ) ; const newHttpsPort = await getPort ( serverConfog , Constants . PortKind . Https ) ; let restartConfig = false ; const config = vscode . workspace . getConfiguration ( 'tomcat' ) ; if ( config ) { restartConfig = config . get < boolean > ( Constants . RESTART_CONFIG_ID ) ; } return restartConfig && ( httpPort !== newHttpPort || httpsPort !== newHttpsPort ) ; } export async function readFileLineByLine ( file , filterFunction ? ) { let result = [ ] ; await new Promise < void > ( ( resolve ) => { const lineReader = readline . createInterface ( { input : fse . createReadStream ( file ) , crlfDelay : Infinity } ) ; lineReader . on ( 'line' , ( line ) => { if ( ! filterFunction || filterFunction ( line ) ) { result = result . concat ( line ) ; } } ) ; lineReader . on ( 'close' , ( ) => { resolve ( ) ; } ) ; } ) ; return result ; } export function getTempStoragePath ( ) { const chars = [ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' ] ; let result = '' ; for ( let i = 0 ; i < 5 ; i += 1 ) { const idx = Math . floor ( chars . length * Math . random ( ) ) ; result += chars [ idx ] ; } return path . resolve ( os . tmpdir ( ) , `vscodetomcat_${ result }` ) ; } export async function getPort ( serverXml , kind ) { if ( ! await fse . pathExists ( serverXml ) ) { throw new Error ( DialogMessage . noServer ) ; } const xml = await fse . readFile ( serverXml , 'utf8' ) ; let port ; try { const jsonObj = await parseXml ( xml ) ; if ( kind === Constants . PortKind . Server ) { port = jsonObj . Server . $ . port ; } else if ( kind === Constants . PortKind . Http ) { port = jsonObj . Server . Service . find ( ( item ) => item . $ . name === Constants . CATALINA ) . Connector . find ( ( item ) => ( item . $ . protocol === undefined || item . $ . protocol . startsWith ( Constants . HTTP ) ) ) . $ . port ; } else if ( kind === Constants . PortKind . Https ) { port = jsonObj . Server . Service . find ( ( item ) => item . $ . name === Constants . CATALINA ) . Connector . find ( ( item ) => ( item . $ . SSLEnabled . toLowerCase ( ) === 'true' ) ) . $ . port ; } } catch ( err ) { port = undefined ; } return port ; } export async function setPort ( serverXml , kind , value ) { if ( ! await fse . pathExists ( serverXml ) ) { throw new Error ( DialogMessage . noServer ) ; } const xml = await fse . readFile ( serverXml , 'utf8' ) ; const jsonObj = await parseXml ( xml ) ; if ( kind === Constants . PortKind . Server ) { jsonObj . Server . $ . port = value ; } else { const catalinaService = jsonObj . Server . Service . find ( ( item ) => item . $ . name === Constants . CATALINA ) ; if ( kind === Constants . PortKind . Http ) { const httpConnector = catalinaService . Connector . find ( ( item ) => ( ! item . $ . protocol || item . $ . protocol . startsWith ( Constants . HTTP ) ) ) ; httpConnector . $ . port = value ; } else if ( kind === Constants . PortKind . Https ) { const httpsConnector = catalinaService . Connector . find ( ( item ) => ( item . $ . SSLEnabled . toLowerCase ( ) === 'true' ) ) ; httpsConnector . $ . port = value ; } } const builder = new xml2js . Builder ( ) ; const newXml = builder . buildObject ( jsonObj ) ; await fse . writeFile ( serverXml , newXml ) ; } export async function copyServerConfig ( source , target ) { const xml = await fse . readFile ( source , 'utf8' ) ; const jsonObj = await parseXml ( xml ) ; const builder = new xml2js . Builder ( ) ; const newXml = builder . buildObject ( jsonObj ) ; await fse . ensureFile ( target ) ; await fse . writeFile ( target , newXml ) ; } export async function parseXml ( xml ) { return new Promise ( ( resolve , reject ) : void => { xml2js . parseString ( xml , { explicitArray : true } , ( err , res ) => { if ( err ) { return reject ( err ) ; } return resolve ( res ) ; } ) ; } ) ; } export function getJavaExecutable ( ) { const customEnv = getCustomEnv ( ) ; let javaPath = customEnv [ "JAVA_HOME" ] ; if ( ! javaPath ) { const config = vscode . workspace . getConfiguration ( 'java' ) ; if ( config ) { javaPath = config . get < string > ( 'home' ) ; } } return javaPath ? path . join ( javaPath , 'bin' , JAVA_FILENAME ) : JAVA_FILENAME ; } export function getCustomEnv ( ) { const tomcatConfig = vscode . workspace . getConfiguration ( 'tomcat' ) ; const config = tomcatConfig ?. get < IEnv [ ] > ( 'customEnv' ) ?? [ ] ; const customEnv = { } ; config . forEach ( ( env ) => { customEnv [ env . environmentVariable ] = env . value ; } ) ; return { ... process . env , ... customEnv } ; } }