205 lines
6.0 KiB
TypeScript
Raw Normal View History

2023-05-04 16:55:40 +08:00
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
2023-05-31 16:10:53 +08:00
import * as childProcess from 'child_process';
2023-05-22 13:14:51 +08:00
import { parseArgsStringToArgv } from 'string-argv';
2023-05-04 16:55:40 +08:00
2023-05-22 13:14:51 +08:00
import { logger } from './logger';
2023-05-04 16:55:40 +08:00
import { spawn, exec } from 'child_process';
2023-05-31 16:10:53 +08:00
import { UiUtilWrapper } from './uiUtil';
2023-05-04 16:55:40 +08:00
export function createTempSubdirectory(subdir: string): string {
2023-05-22 13:14:51 +08:00
// 获取系统临时目录
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;
2023-05-04 16:55:40 +08:00
}
export interface CommandResult {
2023-05-22 13:14:51 +08:00
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(' ')}`);
2023-05-22 13:14:51 +08:00
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) {
2023-05-22 13:14:51 +08:00
logger.channel()?.error(stderr);
logger.channel()?.show();
}
if (code === 0) {
resolve({ exitCode: code, stdout, stderr });
} else {
2023-05-31 16:10:53 +08:00
resolve({ exitCode: code, stdout, stderr });
2023-05-22 13:14:51 +08:00
}
});
// Add error event listener to handle command not found exception
this.childProcess.on('error', (error: any) => {
let errorMessage = error.message;
2023-05-22 13:14:51 +08:00
if (error.code === 'ENOENT') {
errorMessage = `Command not found: ${command}`;
2023-06-13 10:45:11 +08:00
logger.channel()?.error(`Command "${command}" not found`);
2023-05-22 13:14:51 +08:00
logger.channel()?.show();
} else {
2023-06-13 10:45:11 +08:00
logger.channel()?.error(`Error: ${error.message}`);
2023-05-22 13:14:51 +08:00
logger.channel()?.show();
}
resolve({ exitCode: error.code, stdout: "", stderr: errorMessage });
2023-05-22 13:14:51 +08:00
});
});
};
public stop() {
if (this.childProcess) {
this.childProcess.kill();
this.childProcess = null;
2023-05-18 16:43:06 +08:00
}
2023-05-22 13:14:51 +08:00
}
}
export async function runCommandAndWriteOutput(
command: string,
args: string[],
outputFile: string | undefined
2023-05-22 13:14:51 +08:00
): Promise<CommandResult> {
const run = new CommandRun();
const options = {
2023-05-31 16:10:53 +08:00
cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.',
2023-05-22 13:14:51 +08:00
};
return run.spawnAsync(command, args, options, undefined, undefined, undefined, outputFile);
}
export async function runCommandStringAndWriteOutput(
2023-05-04 16:55:40 +08:00
commandString: string,
outputFile: string
2023-05-22 13:14:51 +08:00
): Promise<CommandResult> {
const run = new CommandRun();
const options = {
2023-05-31 16:10:53 +08:00
cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.'
2023-05-22 13:14:51 +08:00
};
// 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);
}
2023-05-22 13:14:51 +08:00
export async function getLanguageIdByFileName(fileName: string): Promise<string | undefined> {
try {
2023-05-31 16:10:53 +08:00
const languageId = await UiUtilWrapper.languageId(fileName);
2023-05-22 13:14:51 +08:00
return languageId;
} catch (error) {
// 如果无法打开文件或发生其他错误返回undefined
return undefined;
}
2023-05-31 16:10:53 +08:00
}
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) }
}
2023-05-22 13:14:51 +08:00
}