fix(cli): improve logging with chalk for better visibility

This commit is contained in:
lukashow
2026-02-04 17:54:00 +08:00
parent f178141dc8
commit b7fe04dd61
3 changed files with 63 additions and 27 deletions

View File

@@ -4,6 +4,7 @@ import { PB_BINARY_PATH, PB_DIR, PB_KWARGS, PB_HOST, PB_PORT } from '@/constants
import executeCommand from '@/utils/commands'
import { checkAddressInUse, checkPortInUse, delay, killExistingProcess } from '@/utils/helpers'
import logger from '@/utils/logger'
import chalk from 'chalk'
/**
* Service command configurations
@@ -19,14 +20,14 @@ export const SERVICE_COMMANDS: Record<string, ServiceConfig> = {
command: async () => {
if (checkAddressInUse(PB_HOST, PB_PORT)) {
logger.error(
`Database address ${PB_HOST}:${PB_PORT} is already in use.`
`Database address ${chalk.blue(`${PB_HOST}:${PB_PORT}`)} is already in use.`
)
process.exit(1)
}
if (!fs.existsSync(PB_BINARY_PATH)) {
logger.error(
`PocketBase binary does not exist: ${PB_BINARY_PATH}. Please run "bun forge db init" to initialize the database.`
`PocketBase binary does not exist: ${chalk.blue(PB_BINARY_PATH)}. Please run "bun forge db init" to initialize the database.`
)
process.exit(1)
}

View File

@@ -6,6 +6,7 @@ import { ROOT_DIR } from '@/constants/constants'
import logger from './logger'
import { addDependency, removeDependency } from './packageJson'
import chalk from 'chalk'
interface CommandExecutionOptions {
stdio?: IOType | [IOType, IOType, IOType]
@@ -34,12 +35,12 @@ export default function executeCommand(
cmd = typeof command === 'function' ? command() : command
} catch (error) {
logger.error(`Failed to generate command.`)
logger.debug(`Error details: ${error}`)
logger.debug(`Error details: ${chalk.grey(String(error))}`)
process.exit(1)
}
try {
logger.debug(`Executing: ${cmd}`)
logger.debug(`Executing command ${chalk.blue(cmd)} with arguments: ${chalk.blue(_arguments.length ? _arguments.join(' ') : `${chalk.red('none')}`)}`)
const [toBeExecuted, ...args] = cmd.split(' ')
@@ -51,11 +52,11 @@ export default function executeCommand(
})
if (result.stdout) {
logger.debug(result.stdout.toString())
logger.debug(chalk.grey(result.stdout.toString()))
}
if (result.stderr) {
logger.debug(result.stderr.toString())
logger.debug(chalk.grey(result.stderr.toString()))
}
if (result.error) {
@@ -67,7 +68,7 @@ export default function executeCommand(
}
if (!options.stdio || options.stdio === 'pipe') {
logger.debug(`Completed: ${cmd}`)
logger.debug(`Command Completed: ${chalk.blue(cmd)}, exit code: ${chalk.blue(String(result.status))}`)
}
return result.stdout?.toString().trim() || ''
@@ -76,8 +77,8 @@ export default function executeCommand(
throw error
}
logger.error(`Command execution failed: ${cmd}`)
logger.debug(`Error details: ${error}`)
logger.error(`Command execution failed: ${chalk.blue(cmd)}`)
logger.debug(`Error details: ${chalk.grey(String(error))}`)
process.exit(1)
}
}
@@ -111,7 +112,7 @@ export function installPackage(
fs.rmSync(targetDir, { recursive: true, force: true })
}
logger.debug(`Installing ${fullName} from registry...`)
logger.debug(`Installing ${chalk.blue(fullName)} from registry...`)
executeCommand(`bun add ${fullName}@latest --ignore-scripts`, {
cwd: ROOT_DIR
@@ -120,12 +121,11 @@ export function installPackage(
const installedPath = path.join(ROOT_DIR, 'node_modules', fullName)
if (!fs.existsSync(installedPath)) {
logger.error(`Failed to find installed package at ${installedPath}`)
logger.error(`Failed to find installed package at ${chalk.blue(installedPath)}`)
process.exit(1)
}
logger.debug(`Copying ${fullName} to ${targetDir}...`)
logger.debug(`Copying ${chalk.blue(fullName)} to ${chalk.blue(targetDir)}...`)
fs.cpSync(installedPath, targetDir, { recursive: true, dereference: true })
// Add to target package.json (apps or locales)

View File

@@ -1,3 +1,4 @@
import chalk from 'chalk'
import prompts from 'prompts'
import executeCommand from './commands'
@@ -60,7 +61,7 @@ export function getEnvVar(varName: string, fallback?: string): string {
return fallback
}
logger.error(`Missing required environment variable: ${varName}`)
logger.error(`Missing required environment variable: ${chalk.red(varName)}`)
process.exit(1)
}
@@ -77,7 +78,9 @@ export function killExistingProcess(
if (typeof processKeywordOrPID === 'number') {
process.kill(processKeywordOrPID)
logger.debug(`Killed process with PID: ${String(processKeywordOrPID)}`)
logger.debug(
`Killed process with PID: ${chalk.blue(String(processKeywordOrPID))}`
)
return
}
@@ -92,7 +95,7 @@ export function killExistingProcess(
})
logger.debug(
`Killed process matching keyword: ${processKeywordOrPID} (PID: ${serverInstance})`
`Killed process matching keyword: ${chalk.blue(processKeywordOrPID)} (PID: ${chalk.blue(serverInstance)})`
)
return parseInt(serverInstance, 10)
@@ -129,19 +132,51 @@ export function checkPortInUse(port: number): boolean {
* @returns True if the port is in use, false otherwise
*/
export function checkAddressInUse(address: string, port: string): boolean {
logger.debug(`Checking if address ${address}:${port} is in use...`);
logger.debug(
`Checking if address ${chalk.blue(address)}:${chalk.blue(port)} is in use...`
)
try {
executeCommand('nc', { exitOnError: false }, [
'-zv',
address,
port,
]);
try {
executeCommand('nc', { exitOnError: false }, ['-zv', address, port])
return true;
} catch {
return false;
}
const ssOutput = executeCommand('ss', { exitOnError: false }, [
'-tlnp',
'src',
`${address}:${port}`
])
const lines = ssOutput.trim().split('\n')
if (lines.length > 1) {
const processLine = lines[1]
const processMatch = processLine.match(
/users:\(\("([^"]+)",pid=(\d+),fd=\d+\)\)/
)
if (processMatch) {
const processName = processMatch[1]
const pid = processMatch[2]
logger.error(
`Address ${chalk.blue(address)}:${chalk.blue(port)} is in use by process: ${chalk.blue(processName)} (PID: ${chalk.blue(pid)})`
)
} else {
logger.error(
`Address ${chalk.blue(address)}:${chalk.blue(port)} is in use, but could not parse process info.`
)
}
} else {
logger.error(
`Address ${chalk.blue(address)}:${chalk.blue(port)} is in use, but no process info found.`
)
}
return true
} catch {
return false
}
}
/**