diff --git a/Makefile b/Makefile
index 44047c50..1467310e 100644
--- a/Makefile
+++ b/Makefile
@@ -48,7 +48,7 @@ log/jshint.log: log/npm-dev-install.log lib/spellcast.js test/spellcast-test.js
# Mocha BDD STDOUT test
log/mocha.log: log/npm-dev-install.log lib/spellcast.js test/spellcast-test.js
- ${MOCHA} test/spellcast-test.js -R list | tee log/mocha.log ; exit $${PIPESTATUS[0]}
+ ${MOCHA} test/spellcast-test.js -R spec | tee log/mocha.log ; exit $${PIPESTATUS[0]}
# README
README.md: documentation.md bdd-spec.md
diff --git a/README.md b/README.md
index 8aa7c56f..343f5f70 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,12 @@ Full BDD spec generated by Mocha:
echo
delayed-echo
bob blihblih one
+scroll line: one
+scroll line: three
+scroll line: two
+scroll line: one
+scroll line: three
+scroll line: two
one more time: one
one more time: two
one more time: three
@@ -74,7 +80,7 @@ cleanup( function() {
} ) ;
```
-should substitute variable (aka formula) accordingly.
+should substitute variable (aka formula) accordingly in 'sh' block.
```js
cleanup( function() {
@@ -90,6 +96,22 @@ cleanup( function() {
} ) ;
```
+should write a new formula with the output of an 'sh' block.
+
+```js
+cleanup( function() {
+
+ var book = new spellcast.Book( fs.readFileSync( 'spellbook' ).toString() ) ;
+
+ book.cast( 'write-formula' , function( error )
+ {
+ expect( error ).not.ok() ;
+ expect( getCastedLog( 'write-formula' ) ).to.be( 'scroll line: one\nscroll line: three\nscroll line: two\nscroll line: one\nscroll line: three\nscroll line: two\n' ) ;
+ done() ;
+ } ) ;
+} ) ;
+```
+
# 'foreach' block
should .
diff --git a/bdd-spec.md b/bdd-spec.md
index 8354713e..d6d34ba2 100644
--- a/bdd-spec.md
+++ b/bdd-spec.md
@@ -1,6 +1,12 @@
echo
delayed-echo
bob blihblih one
+scroll line: one
+scroll line: three
+scroll line: two
+scroll line: one
+scroll line: three
+scroll line: two
one more time: one
one more time: two
one more time: three
@@ -56,7 +62,7 @@ cleanup( function() {
} ) ;
```
-should substitute variable (aka formula) accordingly.
+should substitute variable (aka formula) accordingly in 'sh' block.
```js
cleanup( function() {
@@ -72,6 +78,22 @@ cleanup( function() {
} ) ;
```
+should write a new formula with the output of an 'sh' block.
+
+```js
+cleanup( function() {
+
+ var book = new spellcast.Book( fs.readFileSync( 'spellbook' ).toString() ) ;
+
+ book.cast( 'write-formula' , function( error )
+ {
+ expect( error ).not.ok() ;
+ expect( getCastedLog( 'write-formula' ) ).to.be( 'scroll line: one\nscroll line: three\nscroll line: two\nscroll line: one\nscroll line: three\nscroll line: two\n' ) ;
+ done() ;
+ } ) ;
+} ) ;
+```
+
# 'foreach' block
should .
diff --git a/format.md b/format.md
index 3ac1620e..adc510bf 100644
--- a/format.md
+++ b/format.md
@@ -5,15 +5,17 @@
# Variable substitution
-Variables aka formula are defined in the 'formula' block.
+Variables aka *formula* are defined in the *formula* block.
-A formula only consists of a string, no other type are supported ATM.
+A *formula* only consists of a string, no other type are supported ATM.
Once a formula is defined, it can be used with the syntax `${variableName}`, where 'variableName' is the name
of the variable.
When a variable is encountered, it is substituted by its string value.
+TODOC: list formula
+
# References
@@ -36,8 +38,19 @@ This block defines formula, i.e. variables and values used for substitution.
* parallel: this shell block will execute each command in parallel mode, if a number is passed, this is the maximum
of commands running in parallel
* ignore: if a command return a non-zero status, it will continue nontheless
+* write-formula: this specify a variable name (aka a *formula*) which will be populated by each line of the output
+ of this shell block, the formula is used as a list
+* splitter: this specify a splitter for the 'write' argument, by default '\n' is the splitter
+* silence: dispell all output to stdout
+* amnesia: dispell all output to log files
Each child of this block is a shell command to execute.
+## foreach
+
+TODOC: everything about foreach
+
+
+
diff --git a/lib/spellcast.js b/lib/spellcast.js
index ecb6d2bd..2b3b4f46 100644
--- a/lib/spellcast.js
+++ b/lib/spellcast.js
@@ -26,6 +26,7 @@
/*
TODO:
+ * turn arguments using hyphen in spellbooks into camelCase (e.g. write-formula should be writeFormula in code)
* automatically check versus the 'spellbook' file (just like if 'spellbook' was added to all 'summon' block)
* escape formula variable substitution
* new blocks:
@@ -33,6 +34,7 @@
- wand
- zap
- ssh : like sh but remotely
+ * find the right regexp for split(/,/) because '\,' should not split
*/
@@ -661,31 +663,50 @@ spellcast.Book.prototype.castSummon = function castSummon( summon , castExecutio
spellcast.Book.prototype.castShell = function castShell( shell , castExecution , callback )
{
- var plan ;
+ var plan , splitter , self = this ;
plan = async
- .foreach( shell.shellCommands , this.execShellCommand.bind( this , castExecution ) )
+ .map( shell.shellCommands , this.execShellCommand.bind( this , castExecution , shell.args ) )
.nice( 0 ) ;
//console.log( shell ) ;
- if ( shell.args.parallel )
- {
- if ( shell.args.parallel === true ) { plan.parallel( shell.args.parallel ) ; }
- else { plan.parallel( parseInt( shell.args.parallel ) ) ; }
- }
+ if ( ! shell.args.parallel ) { plan.parallel( false ) ; }
+ else if ( shell.args.parallel === true ) { plan.parallel() ; }
+ else { plan.parallel( parseInt( shell.args.parallel ) ) ; }
if ( ! shell.args.ignore ) { plan.fatal( true ) ; }
- plan.exec( callback ) ;
+ if ( shell.args['write-formula'] && typeof shell.args['write-formula'] !== 'string' ) { delete shell.args['write-formula'] ; }
+
+
+ // Let's exec the plan and process the final outcome!
+
+ plan.exec( function( error , outputMap ) {
+
+ if ( error ) { callback( error ) ; return ; }
+
+ if ( shell.args['write-formula'] )
+ {
+ splitter = shell.args.splitter || '\n' ;
+ self.formula[ shell.args['write-formula'] ] = outputMap.join( '' ).trim().split( splitter ) ;
+
+ /*
+ console.log( "outputMap:" , outputMap[0] ) ;
+ console.log( "full output:" , output ) ;
+ */
+ }
+
+ callback() ;
+ } ) ;
//plan.exec( function() { console.log( 'castShell: Done!' ) ; callback() ; } ) ;
} ;
-spellcast.Book.prototype.execShellCommand = function execShellCommand( castExecution , shellCommand , callback )
+spellcast.Book.prototype.execShellCommand = function execShellCommand( castExecution , args , shellCommand , callback )
{
- var child , onStdout , onStderr , onStdin , onceExit , onIgnoredError ;
+ var child , onStdout , onStderr , onStdin , onceExit , onIgnoredError , output = '' ;
//console.log( 'Exec command: ' , shellCommand ) ;
@@ -705,41 +726,36 @@ spellcast.Book.prototype.execShellCommand = function execShellCommand( castExecu
// For some reason, 'exit' can be triggered before some 'data' event, so we have to delay removeListener() a bit
setTimeout( function() {
+
child.stdout.removeListener( 'data' , onStdout ) ;
child.stderr.removeListener( 'data' , onStderr ) ;
- } , 200 ) ;
+
+ // If there is an 'write-formula' arguments, we must trigger the callback in this timeout event,
+ // if not we take the risk that we will miss some output and we don't want that
+ if ( args['write-formula'] ) { callback( status , output ) ; }
+
+ } , 0 ) ;
- callback( status ) ;
+ // If there isn't an 'write-formula' arguments, then we can trigger the callback now
+ if ( ! args['write-formula'] ) { callback( status ) ; }
} ;
onStdout = function( chunk ) {
// Send the command's stdout to the process stdout and the output file
- process.stdout.write( chunk ) ;
- //castExecution.outputFile.write( 'Stdout:\n' ) ;
- castExecution.outputFile.write( chunk ) ;
- //castExecution.outputFile.write( '\n' ) ;
+ if ( ! args.silence ) { process.stdout.write( chunk ) ; }
+ if ( ! args.amnesia ) { castExecution.outputFile.write( chunk ) ; }
+ if ( args['write-formula'] ) { output += chunk ; }
} ;
onStderr = function( chunk ) {
// Send the command's stderr to the process stderr and the output file
- process.stderr.write( chunk ) ;
-
- //castExecution.outputFile.write( 'Stderr:\n' ) ;
- castExecution.outputFile.write( chunk ) ;
- //castExecution.outputFile.write( '\n' ) ;
+ if ( ! args.silence ) { process.stderr.write( chunk ) ; }
+ if ( ! args.amnesia ) { castExecution.outputFile.write( chunk ) ; }
} ;
onStdin = function( chunk ) {
// Send the process stdin to the command's stdin
child.stdin.write( chunk ) ;
-
- // tmp:
- /*
- console.log( 'Received STDIN:' , chunk.toString() ) ;
- castExecution.outputFile.write( 'Stdin:\n' ) ;
- castExecution.outputFile.write( chunk ) ;
- castExecution.outputFile.write( '\n' ) ;
- */
} ;
// Prevent message sent to command that ignore them, then emit ECONNRESET when finished
diff --git a/test/ls/one b/test/ls/one
new file mode 100644
index 00000000..43dd47ea
--- /dev/null
+++ b/test/ls/one
@@ -0,0 +1 @@
+one
\ No newline at end of file
diff --git a/test/ls/three b/test/ls/three
new file mode 100644
index 00000000..1d19714f
--- /dev/null
+++ b/test/ls/three
@@ -0,0 +1 @@
+three
\ No newline at end of file
diff --git a/test/ls/two b/test/ls/two
new file mode 100644
index 00000000..64c5e588
--- /dev/null
+++ b/test/ls/two
@@ -0,0 +1 @@
+two
\ No newline at end of file
diff --git a/test/spellbook b/test/spellbook
index 60566803..5e97a328 100644
--- a/test/spellbook
+++ b/test/spellbook
@@ -27,7 +27,15 @@ formula
sh
echo end: ${list}
-
+.write-formula
+ sh amnesia silence write-formula:scroll
+ ls ls/
+ ls ls/
+
+ foreach scroll
+ sh
+ echo scroll line: ${scroll}
+
diff --git a/test/spellcast-test.js b/test/spellcast-test.js
index 4a8ddede..4779a4db 100644
--- a/test/spellcast-test.js
+++ b/test/spellcast-test.js
@@ -122,7 +122,7 @@ describe( "'sh' block" , function() {
} ) ;
} ) ;
- it( "should substitute variable (aka formula) accordingly" , function( done ) {
+ it( "should substitute variable (aka formula) accordingly in 'sh' block" , function( done ) {
cleanup( function() {
@@ -137,6 +137,21 @@ describe( "'sh' block" , function() {
} ) ;
} ) ;
+ it( "should write a new formula with the output of an 'sh' block" , function( done ) {
+
+ cleanup( function() {
+
+ var book = new spellcast.Book( fs.readFileSync( 'spellbook' ).toString() ) ;
+
+ book.cast( 'write-formula' , function( error )
+ {
+ expect( error ).not.ok() ;
+ expect( getCastedLog( 'write-formula' ) ).to.be( 'scroll line: one\nscroll line: three\nscroll line: two\nscroll line: one\nscroll line: three\nscroll line: two\n' ) ;
+ done() ;
+ } ) ;
+ } ) ;
+ } ) ;
+
/*
it( "should launch editor" , function( done ) {