Javascript 如何在节点中同步执行shell命令?

Javascript 如何在节点中同步执行shell命令?,javascript,node.js,docker,Javascript,Node.js,Docker,我正在尝试同步执行一些shell命令,以便在docker中安装npm依赖项、构建包和创建数据库 ['api','front-end'].forEach(异步(dir)=>{ 等待新的承诺((决定,拒绝)=>{ log(`Installing${dir}`的npm依赖项); exec('npm install',{cwd:path.join(initDir,'pushkin',dir)},(err)=>{ if(err)console.error(`Failed to install npm de

我正在尝试同步执行一些shell命令,以便在docker中安装npm依赖项、构建包和创建数据库

['api','front-end'].forEach(异步(dir)=>{
等待新的承诺((决定,拒绝)=>{
log(`Installing${dir}`的npm依赖项);
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!=“前端”)返回;
});
解析(`${dir}已安装…`);
})
.然后(()=>{
log(`Building${dir}`);
exec('npm run build',{cwd:path.join(process.cwd(),'pushkin',dir)},(err)=>{
if(err)console.error(`Failed to build${dir}:${err}`);
log(`${dir}已生成`);
});
})
.然后(()=>{
shell.exec(startDbCommand);
})
.然后(()=>{
exec(createDbCommand);
})
.然后(()=>{
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';
当我第一次运行它时,我得到了以下错误:

找不到用于测试\u db\u 1的容器
未能生成前端:错误:命令失败:npm运行生成
sh:react脚本:未找到命令
未能生成api:错误:命令失败:npm运行生成
sh:babel:未找到命令

然而,在我第二次运行它之后,一切似乎都很好。这是我写的承诺链的问题吗?谢谢。

两件重要的事情是一个接一个地运行命令(我相信这就是你所说的同步?),以及在出现故障时进行紧急救援

项目目录循环看起来也不合适。目前,它在所有内容上循环,包括db setup命令。看起来您正在进行测试设置,因此我相信“同步”顺序是:

  • npm安装
    /
    api构建
  • npm安装
    /
    构建
    用于
    前端
  • 数据库设置
因此,首先,从节点中创建一个承诺,以便您可以等待它

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 ISM。 缺点是你错过了所有的壳牌ISM

例如,到可执行文件的路径需要在没有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)
})
如果没有壳的东西太难了,你可以用


同步?您的问题有点混淆,您的使用承诺,您的意思是异步。。如果需要同步,可以使用
execSync
承诺不会使任何内容同步。它们可以帮助使异步的事情有序化。你能发布你的Dockerfile吗?我不知道你为什么要在nodejs中这样做?为什么不运行dockerfile/docker compose文件中的所有内容?
{ shell: true }