
- Added a new optional parameter 'showError' in checkDevChatDependency function in commandsBase.ts. - Updated the conditions for logging error messages in checkDevChatDependency function. - Updated the call to checkDevChatDependency in dependencyCheck function in statusBarViewBase.ts to pass 'showError' parameter. - Updated the condition for logging stderr in CommandRun class in commonUtil.ts.
205 lines
6.0 KiB
TypeScript
205 lines
6.0 KiB
TypeScript
import * as fs from 'fs';
|
||
import * as os from 'os';
|
||
import * as path from 'path';
|
||
import * as childProcess from 'child_process';
|
||
|
||
import { parseArgsStringToArgv } from 'string-argv';
|
||
|
||
import { logger } from './logger';
|
||
import { spawn, exec } from 'child_process';
|
||
import { UiUtilWrapper } from './uiUtil';
|
||
|
||
export function createTempSubdirectory(subdir: string): string {
|
||
// 获取系统临时目录
|
||
const tempDir = os.tmpdir();
|
||
// 构建完整的目录路径
|
||
let targetDir = path.join(tempDir, subdir, Date.now().toString());
|
||
// 检查目录是否存在,如果存在则重新生成目录名称
|
||
while (fs.existsSync(targetDir)) {
|
||
targetDir = path.join(tempDir, subdir, Date.now().toString());
|
||
}
|
||
// 递归创建目录
|
||
fs.mkdirSync(targetDir, { recursive: true });
|
||
// 返回创建的目录的绝对路径
|
||
return targetDir;
|
||
}
|
||
|
||
export interface CommandResult {
|
||
exitCode: number | null;
|
||
stdout: string;
|
||
stderr: string;
|
||
}
|
||
|
||
export class CommandRun {
|
||
private childProcess: any;
|
||
|
||
// init childProcess in construction function
|
||
constructor() {
|
||
this.childProcess = null;
|
||
}
|
||
|
||
public async spawnAsync(command: string, args: string[], options: object, onData: ((data: string) => void) | undefined, onError: ((data: string) => void) | undefined, onOutputFile: ((command: string, stdout: string, stderr: string) => string) | undefined, outputFile: string | undefined): Promise<CommandResult> {
|
||
return new Promise((resolve, reject) => {
|
||
logger.channel()?.info(`Running command: ${command} ${args.join(' ')}`);
|
||
this.childProcess = spawn(command, args, options);
|
||
|
||
let stdout = '';
|
||
let stderr = '';
|
||
|
||
this.childProcess.stdout.on('data', (data: { toString: () => any; }) => {
|
||
const dataStr = data.toString();
|
||
if (onData) {
|
||
onData(dataStr);
|
||
}
|
||
stdout += dataStr;
|
||
});
|
||
|
||
this.childProcess.stderr.on('data', (data: string) => {
|
||
const dataStr = data.toString();
|
||
if (onError) {
|
||
onError(dataStr);
|
||
}
|
||
stderr += dataStr;
|
||
});
|
||
|
||
this.childProcess.on('close', (code: number) => {
|
||
let outputData = stdout;
|
||
if (onOutputFile) {
|
||
outputData = onOutputFile(command + " " + args.join(" "), stdout, stderr);
|
||
}
|
||
|
||
if (outputFile) {
|
||
fs.writeFileSync(outputFile, outputData);
|
||
}
|
||
|
||
if (stderr && !onError) {
|
||
logger.channel()?.error(stderr);
|
||
logger.channel()?.show();
|
||
}
|
||
|
||
if (code === 0) {
|
||
resolve({ exitCode: code, stdout, stderr });
|
||
} else {
|
||
resolve({ exitCode: code, stdout, stderr });
|
||
}
|
||
});
|
||
|
||
// Add error event listener to handle command not found exception
|
||
this.childProcess.on('error', (error: any) => {
|
||
let errorMessage = error.message;
|
||
if (error.code === 'ENOENT') {
|
||
errorMessage = `Command not found: ${command}`;
|
||
logger.channel()?.error(`Command "${command}" not found`);
|
||
logger.channel()?.show();
|
||
} else {
|
||
logger.channel()?.error(`Error: ${error.message}`);
|
||
logger.channel()?.show();
|
||
}
|
||
resolve({ exitCode: error.code, stdout: "", stderr: errorMessage });
|
||
});
|
||
});
|
||
};
|
||
|
||
public stop() {
|
||
if (this.childProcess) {
|
||
this.childProcess.kill();
|
||
this.childProcess = null;
|
||
}
|
||
}
|
||
}
|
||
|
||
export async function runCommandAndWriteOutput(
|
||
command: string,
|
||
args: string[],
|
||
outputFile: string | undefined
|
||
): Promise<CommandResult> {
|
||
const run = new CommandRun();
|
||
const options = {
|
||
cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.',
|
||
};
|
||
|
||
return run.spawnAsync(command, args, options, undefined, undefined, undefined, outputFile);
|
||
}
|
||
|
||
export async function runCommandStringAndWriteOutput(
|
||
commandString: string,
|
||
outputFile: string
|
||
): Promise<CommandResult> {
|
||
const run = new CommandRun();
|
||
const options = {
|
||
cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.'
|
||
};
|
||
|
||
// Split the commandString into command and args array using string-argv
|
||
const commandParts = parseArgsStringToArgv(commandString);
|
||
const command = commandParts[0];
|
||
const args = commandParts.slice(1);
|
||
|
||
const onOutputFile = (command: string, stdout: string, stderr: string): string => {
|
||
const data = {
|
||
command: commandString,
|
||
content: stdout,
|
||
};
|
||
return JSON.stringify(data);
|
||
};
|
||
|
||
return run.spawnAsync(command, args, options, undefined, undefined, onOutputFile, outputFile);
|
||
}
|
||
|
||
export async function runCommandStringArrayAndWriteOutput(
|
||
commandStringList: string[],
|
||
outputFile: string
|
||
): Promise<CommandResult> {
|
||
const run = new CommandRun();
|
||
const options = {
|
||
cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.'
|
||
};
|
||
|
||
const commandString = commandStringList[0];
|
||
const args: string[] = commandStringList.slice(1);
|
||
const onOutputFile = (command: string, stdout: string, stderr: string): string => {
|
||
const data = {
|
||
command: commandString,
|
||
content: stdout,
|
||
};
|
||
return JSON.stringify(data);
|
||
};
|
||
|
||
return run.spawnAsync(commandString, args, options, undefined, undefined, onOutputFile, outputFile);
|
||
}
|
||
|
||
export async function getLanguageIdByFileName(fileName: string): Promise<string | undefined> {
|
||
try {
|
||
const languageId = await UiUtilWrapper.languageId(fileName);
|
||
return languageId;
|
||
} catch (error) {
|
||
// 如果无法打开文件或发生其他错误,返回undefined
|
||
return undefined;
|
||
}
|
||
}
|
||
|
||
export function runCommand(command: string): string {
|
||
return childProcess.execSync(command).toString();
|
||
}
|
||
|
||
export function runCommandStringAndWriteOutputSync(command: string, outputFile: string): CommandResult {
|
||
try {
|
||
const options = {
|
||
cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.'
|
||
};
|
||
const output = childProcess.execSync(command, options).toString();
|
||
const onOutputFile = (command: string, stdout: string): string => {
|
||
const data = {
|
||
"command": command,
|
||
"content": stdout,
|
||
};
|
||
return JSON.stringify(data);
|
||
};
|
||
fs.writeFileSync(outputFile, onOutputFile(command, output));
|
||
return { exitCode: 0, stdout: output, stderr: '' }
|
||
} catch (error) {
|
||
logger.channel()?.error(`Error occurred: ${error}`);
|
||
logger.channel()?.show();
|
||
return { exitCode: 1, stdout: '', stderr: String(error) }
|
||
}
|
||
} |