autorest.testserver/.scripts/process.js

241 строка
6.2 KiB
JavaScript
Исходник Постоянная ссылка Обычный вид История

2022-02-25 01:36:06 +03:00
const { spawn } = require("child_process");
const { extname, isAbsolute, delimiter, resolve, dirname, basename } = require("path");
const fs = require("fs");
const { promisify } = require("util");
const lstat = promisify(fs.lstat);
const { request } = require("http");
const readline = require("readline");
async function isFile(path) {
try {
return (await lstat(path)).isFile();
} catch (e) {}
return false;
}
function cmdlineToArray(text, result = [], matcher = /[^\s"]+|"([^"]*)"/gi, count = 0) {
text = text.replace(/\\"/g, "\ufffe");
const match = matcher.exec(text);
return match
? cmdlineToArray(
text,
result,
matcher,
result.push(match[1] ? match[1].replace(/\ufffe/g, '\\"') : match[0].replace(/\ufffe/g, '\\"')),
)
: result;
}
function quoteIfNecessary(text) {
if (text && text.indexOf(" ") > -1 && text.charAt(0) != '"') {
return `"${text}"`;
}
return text;
}
const nodePath = quoteIfNecessary(process.execPath);
function getPathVariableName() {
// windows calls it's path 'Path' usually, but this is not guaranteed.
if (process.platform === "win32") {
let PATH = "Path";
Object.keys(process.env).forEach(function (e) {
if (e.match(/^PATH$/i)) {
PATH = e;
}
});
return PATH;
}
return "PATH";
}
async function realPathWithExtension(command) {
const pathExt = (process.env.pathext || ".EXE").split(";");
for (const each of pathExt) {
const filename = `${command}${each}`;
if (await isFile(filename)) {
return filename;
}
}
return undefined;
}
async function getFullPath(command, searchPath) {
command = command.replace(/"/g, "");
const ext = extname(command);
if (isAbsolute(command)) {
// if the file has an extension, or we're not on win32, and this is an actual file, use it.
if (ext || process.platform !== "win32") {
if (await isFile(command)) {
return command;
}
}
// if we're on windows, look for a file with an acceptable extension.
if (process.platform === "win32") {
// try all the PATHEXT extensions to see if it is a recognized program
const cmd = await realPathWithExtension(command);
if (cmd) {
return cmd;
}
}
return undefined;
}
if (searchPath) {
const folders = searchPath.split(delimiter);
for (const each of folders) {
const fullPath = await getFullPath(resolve(each, command));
if (fullPath) {
return fullPath;
}
}
}
return undefined;
}
/*
interface MoreOptions extends SpawnOptions {
onCreate?(cp: ChildProcess): void;
onStdOutData?(chunk: any): void;
onStdErrData?(chunk: any): void;
}
*/
const PathVar = getPathVariableName();
async function execute(cmd, cmdlineargs, options) {
let command;
if (!options && !Array.isArray(cmdlineargs)) {
options = cmdlineargs;
}
options = options || {};
if (Array.isArray(cmdlineargs)) {
command = [cmd, ...cmdlineargs];
} else {
command = cmdlineToArray(cmd);
}
if (command[0] === "node" || command[0] === "node.exe") {
command[0] = nodePath;
}
const env = { ...process.env };
// ensure parameters requiring quotes have them.
for (let i = 0; i < command.length; i++) {
command[i] = quoteIfNecessary(command[i]);
}
const fullCommandPath = await getFullPath(command[0], env[getPathVariableName()]);
// == special case ==
// on Windows, if this command has a space in the name, and it's not an .EXE
// then we're going to have to add the folder to the PATH
// and execute it by just the filename
// and set the path back when we're done.
const special = process.platform === "win32" && fullCommandPath.indexOf(" ") > -1 && !/.exe$/gi.exec(fullCommandPath);
// preserve the current path
const originalPath = process.env[PathVar];
return new Promise((r, j) => {
try {
// insert the dir into the path
if (special) {
process.env[PathVar] = `${dirname(fullCommandPath)}${delimiter}${env[PathVar]}`;
}
// call spawn and return
const cp = spawn(fullCommandPath, command.slice(1), { ...options, stdio: "pipe" });
cp.on("error", (err) => {
console.log(`error! ${err} `);
});
if (options.onCreate) {
options.onCreate(cp);
}
options.onStdOutData ? cp.stdout.on("data", options.onStdOutData) : cp;
options.onStdErrData ? cp.stderr.on("data", options.onStdErrData) : cp;
let err = "";
let out = "";
cp.stderr.on("data", (chunk) => {
err += chunk;
});
cp.stdout.on("data", (chunk) => {
out += chunk;
});
cp.on("close", (code, signal) => r({ stdout: out, stderr: err, error: code }));
} finally {
// regardless, restore the original path on the way out!
process.env[PathVar] = originalPath;
}
});
}
function sleep(delayMS) {
return new Promise((res) => setTimeout(res, delayMS));
}
async function httpGet(addr) {
return new Promise((r, j) =>
request(addr, (response) => {
response.on("error", (err) => {
j(err);
});
if (response.statusCode === 200) {
let data = "";
response.on("data", (chunk) => {
data = data + chunk.toString();
});
response.on("end", () => {
r(data);
});
return;
}
j(response);
}).end(),
);
}
async function httpPost(addr) {
return new Promise((r, j) => {
try {
request(addr, (response) => {
response.on("error", (err) => {
j(err);
});
if (response.statusCode === 200) {
let data = "";
response.on("data", (chunk) => {
data = data + chunk.toString();
});
response.on("end", () => {
r(data);
});
return;
}
j(response);
})
.on("error", (e) => {
j(e);
})
.end();
} catch (e) {
j(e);
}
});
}
async function queryUser(text) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise((r, j) => {
rl.question(text, (answer) => {
r(answer);
rl.close();
});
});
}
module.exports = {
execute,
httpGet,
httpPost,
sleep,
queryUser,
};