remove requirement for cmd in exec node config + new style info

This commit is contained in:
Dave Conway-Jones 2017-03-29 21:44:58 +01:00
parent 9928e8562a
commit 3f349c3531
3 changed files with 27 additions and 18 deletions

View File

@ -45,24 +45,32 @@
<script type="text/x-red" data-help-name="exec"> <script type="text/x-red" data-help-name="exec">
<p>Calls out to a system command.<br/></p> <p>Calls out to a system command.<br/></p>
<p>Provides 3 outputs: stdout, stderr, and return code.</p> <p><b>Inputs</b></p>
<p>By default uses the <code>exec</code> system call which calls the command, waits for it to complete, and <ul><li><code>msg.payload</code> - optionally appended to the configured command.</li></ul>
returns the normal output to the first port, any error text to the second port, and a return code object to the <ul><li><code><i>msg.kill</i></code> - can be used to kill a running command, see below.</li></ul>
third port. For example a succesful command should return <code>{ code: 0 }</code>.</p> <ul><li><code><i>msg.pid</i></code> - can be used to kill a specific running command, see below.</li></ul>
<p><b>Outputs</b></p>
<ol>
<li>stdout, <code>msg.payload</code> containing the returned output from the command.</li>
<li>stderr, <code>msg.payload</code> containing any error output from the command.</li>
<li>return code, <code>msg.payload</code> containing the return (see below).</li>
</ol>
<p><b>Details</b></p>
<p>By default uses the <code>exec</code> system call which calls the command, waits for it to complete, and then
returns the output. For example a succesful command should have a return code of <code>{ code: 0 }</code>.</p>
<p>Optionally can use <code>spawn</code> instead, which returns the output from stdout and stderr <p>Optionally can use <code>spawn</code> instead, which returns the output from stdout and stderr
as the command runs, usually one line at a time. On completion it then returns a numeric return code as the command runs, usually one line at a time. On completion it then returns a numeric return code
on the 3rd port. For example a successful command should return <code>0</code>.</p> on the 3rd port. For example a successful command should return <code>0</code>.</p>
<p>The <code>exec</code> method spawns a subshell and therefore can be used for more complicated
commands involving pipes. However, it waits for completion of the whole command before returing anything.</p>
<p>The optional <b>append</b> gets added to the command after <code>msg.payload</code> - so you can do <p>The optional <b>append</b> gets added to the command after <code>msg.payload</code> - so you can do
things like pipe the result to another command.</p> things like pipe the result to another command.</p>
<p>Commands or parameters with spaces should be enclosed in quotes - <i>"This is a single parameter"</i></p> <p>Commands or parameters with spaces should be enclosed in quotes - <i>"This is a single parameter"</i></p>
<p>The <code>payload</code> is usually a <i>string</i>, unless binary is detected, in which case it contains a <i>buffer</i>.</p> <p>The returned <code>payload</code> is usually a <i>string</i>, unless non-UTF8 characters are detected, in which
case it contains a <i>buffer</i>.</p>
<p>The blue status icon and PID will be visible while the node is active. This can be read by a <code>status</code> node.</p> <p>The blue status icon and PID will be visible while the node is active. This can be read by a <code>status</code> node.</p>
<p>Sending <code>msg.kill</code> will kill a single active process. <code>msg.kill</code> should be a string containing <p>Sending <code>msg.kill</code> will kill a single active process. <code>msg.kill</code> should be a string containing
the type of signal to be sent, e.g. "SIGINT", "SIGQUIT", "SIGHUP", etc. Defaults to "SIGTERM" if blank (""). the type of signal to be sent, e.g. "SIGINT", "SIGQUIT", "SIGHUP", etc. Defaults to "SIGTERM" if blank ("").
If there is more than one process running then <code>msg.pid</code> must also be set with the value of the PID to be killed.</p> If there is more than one process running then <code>msg.pid</code> must also be set with the value of the PID to be killed.</p>
<p><b>Tip: </b>If running a Python app you may need to use the <code>-u</code> parameter to stop the output being buffered.</p> <p><b>Tip</b>: If running a Python app you may need to use the <code>-u</code> parameter to stop the output being buffered.</p>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
@ -70,7 +78,7 @@
category: 'advanced-function', category: 'advanced-function',
color:"darksalmon", color:"darksalmon",
defaults: { defaults: {
command: {value:"",required:true}, command: {value:""},
addpay: {value:true}, addpay: {value:true},
append: {value:""}, append: {value:""},
useSpawn: {value:""}, useSpawn: {value:""},

View File

@ -119,7 +119,7 @@ module.exports = function(RED) {
msg.payload = new Buffer(stdout,"binary"); msg.payload = new Buffer(stdout,"binary");
if (isUtf8(msg.payload)) { msg.payload = msg.payload.toString(); } if (isUtf8(msg.payload)) { msg.payload = msg.payload.toString(); }
var msg2 = null; var msg2 = null;
if(stderr) { if (stderr) {
msg2 = {payload: stderr}; msg2 = {payload: stderr};
} }
var msg3 = null; var msg3 = null;
@ -147,6 +147,7 @@ module.exports = function(RED) {
} }
} }
}); });
this.on('close',function() { this.on('close',function() {
for (var pid in node.activeProcesses) { for (var pid in node.activeProcesses) {
/* istanbul ignore else */ /* istanbul ignore else */

View File

@ -52,7 +52,7 @@ describe('exec node', function() {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:false, append:""}, var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:false, append:""},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec', var spy = sinon.stub(child_process, 'exec',
function(arg1,arg2,arg3,arg4) { function(arg1, arg2, arg3, arg4) {
//console.log(arg1); //console.log(arg1);
// arg3(error,stdout,stderr); // arg3(error,stdout,stderr);
arg3(null,arg1,arg1.toUpperCase()); arg3(null,arg1,arg1.toUpperCase());
@ -70,7 +70,7 @@ describe('exec node', function() {
if (received < 3) { if (received < 3) {
return; return;
} }
try{ try {
var msg = messages[0]; var msg = messages[0];
msg.should.have.property("payload"); msg.should.have.property("payload");
msg.payload.should.be.a.String(); msg.payload.should.be.a.String();
@ -78,7 +78,7 @@ describe('exec node', function() {
msg = messages[1]; msg = messages[1];
msg.should.have.property("payload"); msg.should.have.property("payload");
msg.payload.should.be.a.String, msg.payload.should.be.a.String;
msg.payload.should.equal("ECHO"); msg.payload.should.equal("ECHO");
msg = messages[2]; msg = messages[2];
@ -112,7 +112,7 @@ describe('exec node', function() {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more"}, var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec', var spy = sinon.stub(child_process, 'exec',
function(arg1,arg2,arg3,arg4) { function(arg1, arg2, arg3, arg4) {
//console.log(arg1); //console.log(arg1);
// arg3(error,stdout,stderr); // arg3(error,stdout,stderr);
arg3(null,arg1,arg1.toUpperCase()); arg3(null,arg1,arg1.toUpperCase());
@ -165,7 +165,7 @@ describe('exec node', function() {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more"}, var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec', var spy = sinon.stub(child_process, 'exec',
function(arg1,arg2,arg3,arg4) { function(arg1, arg2, arg3, arg4) {
//console.log(arg1); //console.log(arg1);
// arg3(error,stdout,stderr); // arg3(error,stdout,stderr);
arg3("error",new Buffer([0x01,0x02,0x03,0x88])); arg3("error",new Buffer([0x01,0x02,0x03,0x88]));
@ -275,7 +275,7 @@ describe('exec node', function() {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"error", addpay:false, append:""}, var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"error", addpay:false, append:""},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec', var spy = sinon.stub(child_process, 'exec',
function(arg1,arg2,arg3,arg4) { function(arg1, arg2, arg3, arg4) {
//console.log(arg1); //console.log(arg1);
// arg3(error,stdout,stderr); // arg3(error,stdout,stderr);
arg3({code: 1},arg1,arg1.toUpperCase()); arg3({code: 1},arg1,arg1.toUpperCase());
@ -292,7 +292,7 @@ describe('exec node', function() {
if (received < 3) { if (received < 3) {
return; return;
} }
try{ try {
var msg = messages[0]; var msg = messages[0];
msg.should.have.property("payload"); msg.should.have.property("payload");
msg.payload.should.be.a.String(); msg.payload.should.be.a.String();
@ -300,7 +300,7 @@ describe('exec node', function() {
msg = messages[1]; msg = messages[1];
msg.should.have.property("payload"); msg.should.have.property("payload");
msg.payload.should.be.a.String, msg.payload.should.be.a.String;
msg.payload.should.equal("ERROR"); msg.payload.should.equal("ERROR");
msg = messages[2]; msg = messages[2];