nodeJS: ejecutando un lote de commands childprocess en una cascada

Estoy tratando de ejecutar elegantemente cinco commands de git uno tras otro, manteniendo la capacidad de detectar errores y progreso:

  • estado de git
  • git pull
  • git add.
  • git commit -am "commit message"
  • git push

Nota de fuente abierta: He estudiado diferentes bibliotecas de nodo-git y decidí por diferentes motivos implementarlo por mi count.

Usando Q , he creado un método diferido para ejecutar processs secundarios:

var exec = require('child_process').exec, path = require('path'), Q = require('q'), gitPath = path.resolve(__dirname + "/../projects/langs"); function run(command) { var defernetworking = Q.defer(); exec(command, {cwd: gitPath}, function puts(error, stdout, stderr) { if (error) { defernetworking.reject(new Error(error)); } else { defernetworking.resolve(stdout); } }); return defernetworking.promise; } 

Sin embargo, quiero evitar la pirámide de la perdición :

 function option1() { // Pyramid of doom run("git status").then(function (output) { console.log(output); run("git pull").then(function (output) { console.log(output); run("git add .").then(function (output) { console.log(output); // etc. }); }); }); } 

Y no se siente muy elegante:

 function options1a() { // Pyramid of doom run("git status").then(function (output) { console.log(output); run("git pull"); }).then(function (output) { console.log(output); run("git add .") }).then(function (output) { console.log(output); }); } 

Vi una tercera opción pero parece que no funciona:

 function promiseWaterfall(tasks) { var resolvedPromise = Q(undefined); var finalTaskPromise = tasks.networkinguce(function (prevTaskPromise, task) { return prevTaskPromise.then(task); }, resolvedPromise); // initial value return finalTaskPromise; } promiseWaterfall([ run("git status"), run("git pull"), run("git add .") ]).then(function () { console.log(arguments); }); 

Y estoy jugando con una cuarta opción de usar la biblioteca asíncrona :

 async.waterfall([ function(callback){ callback(null, 'one', 'two'); }, function(arg1, arg2, callback){ callback(null, 'three'); }, function(arg1, callback){ // arg1 now equals 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' }); 

Pero esto parece llevarme hacia un path sin promises.

¿Cómo hago para que funcione elegantemente? ¿Alguna de las mejores prácticas?

Estoy familiarizado con las promises de when.js, así que responderé a su pregunta con esa biblioteca de promises. Proporciona funciones auxiliares para este tipo de cosas similares a la lib asíncrona basada en callback. Consulte su documentation API para get más ejemplos.

En el siguiente código, estoy usando el module when/sequence para realizar lo que estás buscando. También modifiqué un poco la organización de código para mantener las cosas algo modulares (por ejemplo, no incrustando el git cwd dentro de la function de run en su ejemplo).

Aquí hay una implementación completamente funcional. Asegúrate de cambiar el git cwd a tu propio repository git, ya que actualmente está apuntando a uno de los míos.

 var exec = require('child_process').exec , when = require('when') , sequence = require('when/sequence'); // simple promise wrapper for exec function exec_p(command, options) { options = options || {}; var defer = when.defer(); exec(command, options, function(error, stdout, stderr) { return error ? defer.reject(stderr + new Error(error.stack || error)) : defer.resolve(stdout); }); return defer.promise; } // Some simple git wrapper function Git(config) { var self = this; self.config = config; return function(gitCommand) { return exec_p('git ' + gitCommand, self.config); }; } // create a new instnace of git and specify our options var git = new Git({ cwd: "/home/trev/git/tsenior" }); // we can now use sequence & our newly created git wrapper to easily // can things in order one after another sequence([ function() { return git('status'); }, function() { return git('status'); }, function() { return git('status'); }, function() { return git('status'); } ]).then(function(results) { // handle the results here console.log(results); }).otherwise(function(error) { // handle any errors here console.error(error.stack || error); process.exit(1); }); 

El código provisto no contiene console.log después de cada paso (simplemente registra los resultados al final), pero se puede modificar fácilmente para hacerlo.

    Intereting Posts