/* * 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); })); } }