/*
* This file is part of tswow (https://github.com/tswow)
*
* Copyright (C) 2020 tswow
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import * as child_process from 'child_process';
import * as readline from 'readline';
import { wfs } from './FileSystem';
import { FilePath } from './FileTree';
/**
* Contains functions for running external programs and managing processes and working directories.
*
* As opposed to the built-in 'child_process' module, wsys functions are synchronous unless otherwise stated
* and prefer promises to callbacks.
*/
export namespace wsys {
/**
* Execute a function in a specific working directory.
* @param dir The directory to execute in
* @param cb The function to execute
*/
export async function inDirectory(dir: string, cb: () => any) {
const old = process.cwd();
process.chdir(dir);
try {
await cb();
} catch (err) {
process.chdir(old);
throw err;
}
process.chdir(old);
}
/**
* Execute a function in a specific working directory, does not allow async calls.
* TODO: This should be the default behavior, not the other way around
* @param dir
* @param cb
*/
export function inDirectorySync(dir: string, cb: () => any) {
const old = process.cwd();
process.chdir(dir);
try {
cb();
} catch (err) {
process.chdir(old);
throw err;
}
process.chdir(old);
}
/**
* Checks if a process is running
* @param winName Name of the process in windows
* @param macName Name of the process in mac
* @param linuxName Name of the process in linux
* @returns true if the process is found running, false otherwise.
*/
export function isRunning(winName: string, macName: string, linuxName: string) {
const plat = process.platform;
const cmd = plat === 'win32' ? 'tasklist' : (plat === 'darwin' ? 'ps -ax | grep ' + macName : (plat === 'linux' ? 'ps -A' : ''));
const proc = plat === 'win32' ? winName : (plat === 'darwin' ? macName : (plat === 'linux' ? linuxName : ''));
if (cmd === '' || proc === '') {
return false;
}
return exec(cmd, 'pipe').toLowerCase().indexOf(proc.toLowerCase()) > -1;
}
/**
* Executes a child process asynchronously
* @param program Command to execute
* @throws if the child process exits with an error
* @returns Promise when the child process exits
*/
export function execAsync(program: string, cwd?: string) {
return new Promise((res, rej) => {
child_process.exec(program, {cwd: cwd ? cwd : process.cwd()}, (err, stdout, stderr) => {
return err ? rej(err) : res(stdout);
});
});
}
/**
* Execute a child process.
* @param program Command to execute
* @param stdio How to handle output from the child process
* ('inherit' will display output to the current command window,
* 'pipe' will return output as a string instead)
* @returns Command output of the child process if `stdio` is 'pipe', undefined otherwise.
*/
export function exec(program: string, stdio: 'ignore'|'inherit'|'pipe' = 'pipe', settings: child_process.ExecSyncOptionsWithBufferEncoding = {}) {
let str = '';
const data = child_process.execSync(program, {stdio: stdio, ...settings});
if( data !== undefined && data !== null ) {
str = data.toString();
}
return str;
}
/**
* Executes a child process in a specific working directory.
* @param dirname Working directory to run the child process in
* @param program Command to execute
* @param stdio How to handle output from the child process
* ('inherit' will display output to the current command window,
* 'pipe' will return output as a string instead)
* @returns Command output of the child process if `stdio` is 'pipe', undefined otherwise.
*/
export function execIn(dirname: FilePath, program: string, stdio: 'ignore'|'inherit'|'pipe' = 'inherit', settings: child_process.ExecSyncOptionsWithBufferEncoding = {}) {
let str = '';
const data = child_process.execSync(program,
{stdio: stdio, cwd: wfs.absPath(dirname), ...settings});
if(stdio==='pipe' && data !== null && data !== undefined) {
str = data.toString();
}
return str;
}
/**
* Sleeps for a specified time
* @param timeout Milliseconds to sleep for.
* @returns Promise that resolves after `timeout` milliseconds.
*/
export function sleep(timeout: number) {
return new Promise((res) => {
setTimeout(() => {
res();
}, timeout);
});
}
/**
* Accept user input in the terminal.
* @param query Text to display before the input
*/
export function userInput(query: string) : Promise {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise(resolve => rl.question(query, ans => {
rl.close();
resolve(ans);
}));
}
}