[英]How to execute shell commands synchronously in Node?
我正在嘗試同步執行一些 shell 命令以安裝 npm 依賴項、構建包並在 docker 中創建數據庫。
['api', 'front-end'].forEach(async (dir) => {
await new Promise((resolve, reject) => {
console.log(`Installing npm dependencies for ${dir}`);
exec('npm install', { cwd: path.join(initDir, 'pushkin', dir) }, (err) => {
if (err) console.error(`Failed to install npm dependencies for ${dir}: ${err}`);
if (dir !== 'api' && dir !== 'front-end') return;
});
resolve(`${dir} installed...`);
})
.then(() => {
console.log(`Building ${dir}`);
exec('npm run build', { cwd: path.join(process.cwd(), 'pushkin', dir) }, (err) => {
if (err) console.error(`Failed to build ${dir}: ${err}`);
console.log(`${dir} is built`);
});
})
.then(() => {
shell.exec(startDbCommand);
})
.then(() => {
shell.exec(createDbCommand);
})
.then(() => {
shell.exec(stopDbCommand);
});
});
docker 命令是:
const startDbCommand = 'docker-compose -f pushkin/docker-compose.dev.yml up --no-start && docker-compose -f pushkin/docker-compose.dev.yml start test_db';
const createDbCommand = 'docker-compose -f pushkin/docker-compose.dev.yml exec -T test_db psql -U postgres -c "create database test_db"';
const stopDbCommand = 'docker-compose -f pushkin/docker-compose.dev.yml stop test_db';
當我第一次運行它時,出現了這個錯誤:
No container found for test_db_1
Failed to build front-end: Error: Command failed: npm run build
sh: react-scripts: command not found
Failed to build api: Error: Command failed: npm run build
sh: babel: command not found
然而,當我再次運行第二次后,一切似乎都正常了。 這是我寫的Promise鏈的問題嗎? 謝謝。
兩個重要的事情是一個接一個地按順序運行命令(我相信這就是你所說的同步的意思?)以及在出現故障時退出。
項目目錄循環看起來也不合適。 目前它遍歷所有內容,包括 db setup 命令。 看起來你正在做測試設置,所以我相信“同步”順序是:
api
npm install
/ build
npm install
為frontend
安裝/ build
因此,首先,從生成的節點中創建一個spawn
,這樣您就可以await
它了。
function runProcessToCompletion(cmd_array, options){
return new Promise((resolve, reject) => {
const result = {
cmd: cmd_array,
options,
code: null,
output: [],
}
const proc = spawn(cmd_array[0], cmd_array.slice(1), options)
proc.on('error', (error) => {
error.result = result
reject(error)
})
proc.on('close', code => {
result.code = code
if (code !== 0) {
const error = new Error(`PID "${proc.pid}" exited with code "${code}"`)
error.result = result
reject(error)
}
console.log(`Spawned PID "${proc.pid}" exited with code "${code}"`)
resolve(result)
})
proc.stdout.on('data', (data) => {
result.output.push(data.toString())
process.stdout.write(data)
})
proc.stderr.on('data', (data) => {
result.output.push(data.toString())
process.stderr.write(data)
})
if (proc.pid) {
console.log(`Spawned PID "${proc.pid}" for "${cmd_array.join(' ')}"`)
}
})
}
然后,您可以更輕松地將代碼構造為簡單的命令列表。 使用spawn
的好處是你可以避免所有的 shell-isms。 缺點是你錯過了所有的 shell-isms。
例如,需要在沒有 shell PATH
的情況下完全定義可執行文件的路徑
const path = require('path')
const initDir = process.cwd()
const project_dirs = ['api', 'front-end']
const setupDbCommand = ['/usr/local/bin/docker-compose','-f','pushkin/docker-compose.dev.yml','up','--no-start']
const startDbCommand = ['/usr/local/bin/docker-compose','-f','pushkin/docker-compose.dev.yml','start','test_db']
const createDbCommand = ['/usr/local/bin/docker-compose','-f','pushkin/docker-compose.dev.yml','exec','-T','test_db','psql -U postgres -c "create database test_db"']
const stopDbCommand = ['/usr/local/bin/docker-compose','-f','pushkin/docker-compose.dev.yml','stop','test_db']
async function go(){
for (let dir of project_dirs) {
const cwd = path.join(initDir, 'pushkin', dir)
await runProcessToCompletion(['/usr/local/bin/npm','install'], { cwd })
await runProcessToCompletion(['/usr/local/bin/npm','run','build'], { cwd })
}
await runProcessToCompletion(setupDbCommand)
await runProcessToCompletion(startDbCommand)
await runProcessToCompletion(createDbCommand)
await runProcessToCompletion(stopDbCommand)
return true
}
go().catch(err => {
console.error(err)
console.error(err.results)
})
如果沒有 shell 東西太難了,你可以用spawn
選項重新打開它
{ shell: true }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.