2014-07-03 50 views
2

我正在構建Yeoman生成器,完成後我想執行一些命令行操作,如'npm install','bower install'和'grunt less'。我爲此使用spawnCommand,並使用事件偵聽器嵌套所有操作以同步執行它們。然而,爲了避免這種無休止的嵌套,我正在尋找一個更清晰的實現,以使其易於擴展。 完美的是,我想擁有一個帶有命令的數組(例如['npm install','grunt install','less:dev']),並通過正確的錯誤檢測同步處理。在Yeoman生成器完成後同步執行命令行操作

// Install npm packages 
this.spawnCommand('npm', ['install']) 
    .on('exit', function (err) { 
     if (err) { 
      this.log.error('npm package installation failed. Please run \'npm install\' and \'bower install\'. Error: ' + err); 
     } else { 
      // Install bower packages 
      this.spawnCommand('bower', ['install']) 
       .on('exit', function (err) { 
        if (err) { 
         this.log.error('bower package installation failed. Please run \'bower install\'. Error: ' + err); 
        } else { 
         this.spawnCommand('grunt', ['less']) 
          .on('exit', function (err) { 
           if (err) { 
            this.log.error('Less compilation failed. Please run \'grunt less:dev\'. Error: ' + err); 
           } else { 

           } 

          }.bind(this)); 
        } 

       }.bind(this)); 
     } 

    }.bind(this)); 
+0

不是「同步」,而是「連續」。 – Bergi

+0

你有沒有嘗試過推廣這個功能? – Bergi

+0

您可能想看看承諾,但我不知道如何輕鬆地將庫包含在yeoman腳本中。 – Bergi

回答

2

是這樣的嗎? (雖然未經測試):

this.processTask = function (task) { 
    this.spawnCommand(task.cmd, task.args) 
     .on('exit', function (err) { 
      if (err) { 
       this.log.error('task failed. Error: ' + err); 
      } else { 
       this.emit('nextTask'); 
      } 
     }); 
}; 

this.on('nextTask' function(){ 
    var next = this.tasks.shift(); 
    if (next){ 
     this.processTask(next); 
    } else { 
     console.log('we are done'); 
    } 
}.bind(this)); 

//preparing the list of tasks: 
this.tasks = []; 
this.tasks.push({cmd: 'npm', args:['install']}); 
this.tasks.push({cmd: 'bower', args:['install']}); 
this.tasks.push({cmd: 'grunt', args:['less']}); 

//start first task 

this.processTask(this.tasks.shift()); 
+0

我在嘗試解決類似問題時遇到了上述建議。它真的幫了我很大忙,但我需要做一點小改動才能運作。您需要將'this'與'exit'回調函數中的'spawnCommand'綁定: '.on('exit',function(err){ifrError} {this.log.error('task failed。錯誤:'+ err); } else { this.emit('nextTask'); } } .bind(this));' – Matt

+1

嗨馬特,我應用了您的修復程序。我很高興它幫助你。 – mvermand

0

我用execSync從Node.js的,它似乎工作,比如:

var child_process = require('child_process'); 

var result = execSync('grunt less'); 

Node.js的0.12和1.10 io.js支持execSync:

child_process.execSync(command[, options]) 

並返回「Buffer | String來自命令的stdout」,它可能是一個錯誤代碼。 API documentation.

The back story about the synchronous API

0

你可以做一個腳本像init.sh,並把你的命令了需要,才能在運行它,如:

#!/usr/bin/env bash 
npm install 
your-funky-command 
gulp something-special 
gulp 

...那麼你需要的地方把spawnCommand代碼(我這樣做在end法),加上服用點是這樣的:

var done = this.async(); 
    this.spawnCommand('sh', ['init.sh'], /* maybe cwd? {cwd: 'src'} */) 
    .on('close', done); 

是不是漂亮或什麼,但它的工作原理,並很明顯。


可選,如果你需要一個命令只運行,如果上一個成功,這樣做:

#!/usr/bin/env bash 
npm install \ 
    && your-funky-command \ 
    && gulp something-special \ 
    && gulp 

(獎金好處是,現在您的應用程序初始化邏輯不再依賴於呦)。