I’ve been doing some work on CFEXECUTE for Lucee 7
https://luceeserver.atlassian.net/browse/LDEV-2015
add cfexecute onProgress, onError listeners to stream output and allow cancelling execution
https://luceeserver.atlassian.net/browse/LDEV-3667
component extends="org.lucee.cfml.test.LuceeTestCase" labels="execute" {
function beforeAll(){
variables.exe = isWindows() ? "cmd" : "bash";
variables.dir = getDirectoryFromPath(getCurrentTemplatePath());
}
function run() {
describe("cfexecute with onError and onProgress", function() {
beforeEach(function(currentSpec){
_logger("", true);
_logger(currentSpec, true);
});
it(title="cfexecute progress and error listeners", body=function() {
var args = isWindows() ? "/c dir Issue*.cfc" : "-c 'ls -lH Issue*.cfc'";
cfexecute(name=exe, timeout="1", arguments=args , directory=dir,
This file has been truncated. show original
CFEXECUTE support setting environment variables
https://luceeserver.atlassian.net/browse/LDEV-5499
component extends="org.lucee.cfml.test.LuceeTestCase" labels="execute" {
function run() {
describe("cfexecute", function() {
it(title="cfexecute environment windows", body=function() {
var env = {
"LUCEE": "rocks",
"LUCEE_LDEV5499_RANDOM": createGUID()
};
var exe = isWindows() ? "cmd" : "bash";
var args = isWindows() ? ["/c", "set"] : "-c 'set'";
cfexecute(name=exe, timeout="1", arguments=args , environment=env, variable="variables.result");
expect( find( env[ "LUCEE" ], result ) ).toBeGT( 0 ); // don't leak env
expect( find( env[ "LUCEE_LDEV5499_RANDOM" ], result ) ).toBeGT( 0 ); // don't leak env
});
This file has been truncated. show original
CFEXECUTE allow returning exit code
includes a new result attribute, like cfhttp { output: "", error: "", exitCode: 1 }
https://luceeserver.atlassian.net/browse/LDEV-5500
component extends="org.lucee.cfml.test.LuceeTestCase" labels="execute" {
function run() {
describe("cfexecute", function() {
it(title="cfexecute result variable with exit code", body=function() {
var exe = isWindows() ? "cmd" : "bash";
var args = isWindows() ? "/c exit /B 7" : "-c 'exit 7'";
cfexecute(name=exe, timeout="1", arguments=args , result="local.result");
expect( result.exitCode ).toBe( 7 );
expect( result ).toHaveKey( "output" );
expect( result ).toHaveKey( "error" );
});
it(title="cfexecute exitCode variable", body=function() {
var exe = isWindows() ? "cmd" : "bash";
var args = isWindows() ? "/c exit /B 7" : "-c 'exit 7'";
cfexecute(name=exe, timeout="1", arguments=args , variable="local.result", exitCodeVariable="local.exitCode");
This file has been truncated. show original
switch CFEXECUTE to using ProcessBuilder
https://luceeserver.atlassian.net/browse/LDEV-5503
BTW Did you know you can already pass arguments as an array?
4 Likes
I do not think everyone understands how much of a feature this is.
If you want an interactive ColdFusion shell, this allows for it.
WTG @Zackster
1 Like
glad you get it!
we’d need to add a listener accessing exposing the getOutputStream for the process to make it interactive
https://luceeserver.atlassian.net/browse/LDEV-5510
but this is already great for running a process (like a testsuite, build, backup, script, etc) and streaming the output back to the browser, rather than waiting for it to complete
3 Likes
I agree… this is a huge feature. This would eliminate my need to run rabbitmq, which is what I’m using to send tasks to commandbox. Due to the limitations of cfexecute, I had no good way to hand off execution to an external program or process (in this case, commandbox task runners). Instead I had to build out what felt like a lot of infrastructure to do a very simple thing (tell another program to do something).
3 Likes
Once you do, it would take Lucee CF to a whole other level of development and integration.
1 Like
Now I’m also passing the java Process into the onProgress listener
Can’t quite get the tests working, I need something to pause to read in from stdin, something like cmd /c pause
doesn’t work
lucee:7.0
← zspitzer:LDEV-5510
opened 10:39PM - 15 Apr 25 UTC
https://luceeserver.atlassian.net/browse/LDEV-5510
As for what’s not working, is it something about the pause
? Like is it that you want to have to enter input vs just pressing any key to continue? The date
command (in windows) does that.
Or is it that you want this to not pause indefinitelly? In that case, you could try timeout /t 5
, which will wait 5 seconds before proceeding.
And in linux, you could be read -t 5 somevar
, which awaits user input that’s assigned to that var or gives up after 5 seconds.
Or is it somehow a different challenge you face?
if its windows commands it would be start and wait
ie
start / wait cmd.exe
This will wait for the process to complete, you can optionally force a time out so if its not completed by that time, you can move along
if you want it to start and then run until it hits a certain amount of time you would use
start cmd.exe timeout /t 300
where 300 is the number of seconds before the operation times out
the actual change is tiny, how about I merge it and you have a play?
Sure. I have some free time later today.
ok, that’s up as 7.0.0.196-SNAPSHOT
1 Like
Zackster:
7.0.0.196-SNAPSHOT
using this code:
<cfset command = "cmd /c echo Hello World!">
<cfexecute name="cmd.exe"
arguments="/c #command#"
timeout="100"
variable="output"
/>
<cfoutput>#output#</cfoutput>
<cfset command2 = "cmd /c dir">
<cfexecute name="cmd.exe"
arguments="/c #command2#"
timeout="100"
variable="output2"
/>
<cfoutput>#output2#</cfoutput>
This is amazing…
2 Likes