2828import io .serverlessworkflow .impl .expressions .ExpressionUtils ;
2929import java .io .IOException ;
3030import java .io .OutputStream ;
31+ import java .util .Map ;
3132import java .util .Objects ;
3233import java .util .concurrent .CompletableFuture ;
3334
34- public abstract class RunExecutor <T extends TaskBase > extends RegularTaskExecutor <T > {
35+ public abstract class RunTaskExecutor <T extends TaskBase > extends RegularTaskExecutor <T > {
3536
36- protected RunExecutor (RegularTaskExecutorBuilder <T > builder ) {
37+ protected RunTaskExecutor (RegularTaskExecutorBuilder <T > builder ) {
3738 super (builder );
3839 }
3940
@@ -48,18 +49,18 @@ protected RunTaskExecutorBuilder(
4849 @ Override
4950 protected RegularTaskExecutor <RunTask > buildInstance () {
5051 if (task .getRun ().getRunShell () != null ) {
51- return new RunShellExecutor (this );
52+ return new RunShellTaskExecutor (this );
5253 } else {
5354 throw new RuntimeException ("Unsupported run task type" );
5455 }
5556 }
5657 }
5758
58- public static class RunShellExecutor extends RunExecutor <RunTask > {
59+ public static class RunShellTaskExecutor extends RunTaskExecutor <RunTask > {
5960
6061 private final WorkflowApplication application ;
6162
62- protected RunShellExecutor (RegularTaskExecutorBuilder <RunTask > builder ) {
63+ protected RunShellTaskExecutor (RegularTaskExecutorBuilder <RunTask > builder ) {
6364 super (builder );
6465 this .application = builder .application ;
6566 }
@@ -68,42 +69,44 @@ protected RunShellExecutor(RegularTaskExecutorBuilder<RunTask> builder) {
6869 protected CompletableFuture <WorkflowModel > internalExecute (
6970 WorkflowContext workflow , TaskContext taskContext ) {
7071
71- if (taskContext .task () != null && taskContext .task () instanceof RunTask runTask ) {
72+ if (taskContext .task () != null
73+ && taskContext .task () instanceof RunTask runTask
74+ && runTask .getRun ().getRunShell () != null ) {
7275 RunShell runShell = runTask .getRun ().getRunShell ();
76+ String shellCommand = runShell .getShell ().getCommand ();
77+
78+ Objects .requireNonNull (
79+ shellCommand , "Shell command must be provided in RunShell taskContext" );
7380
7481 try {
7582 String command =
76- ExpressionUtils .isExpr (runShell . getShell (). getCommand () )
83+ ExpressionUtils .isExpr (shellCommand )
7784 ? WorkflowUtils .buildStringResolver (
78- application ,
79- runShell .getShell ().getCommand (),
80- taskContext .input ().asJavaObject ())
85+ application , shellCommand , taskContext .input ().asJavaObject ())
8186 .apply (workflow , taskContext , taskContext .input ())
82- : runShell .getShell ().getCommand ();
83-
84- Objects .requireNonNull (command , "Shell command must be provided in RunShell taskContext" );
85-
86- ProcessBuilder builder = new ProcessBuilder (command .split (" " ));
87-
88- Process process = builder .start ();
89-
90- // get output of process
91- StringBuilder output = new StringBuilder ();
92- StringBuilder error = new StringBuilder ();
93- process .getInputStream ().transferTo (getOutputStream (output ));
94- process .getErrorStream ().transferTo (getOutputStream (error ));
95-
96- boolean isAwait = runTask .getRun ().get ().isAwait ();
97- if (!isAwait ) {
98- throw new UnsupportedOperationException ("Non-await RunShell is not supported yet" );
87+ : shellCommand ;
88+
89+ ProcessBuilder processBuilder = new ProcessBuilder ("sh" , "-c" , command );
90+
91+ if (runShell .getShell ().getEnvironment () != null
92+ && !runShell .getShell ().getEnvironment ().getAdditionalProperties ().isEmpty ()) {
93+ for (Map .Entry <String , Object > entry :
94+ runShell .getShell ().getEnvironment ().getAdditionalProperties ().entrySet ()) {
95+ String value =
96+ ExpressionUtils .isExpr (entry .getValue ())
97+ ? WorkflowUtils .buildStringResolver (
98+ application ,
99+ entry .getValue ().toString (),
100+ taskContext .input ().asJavaObject ())
101+ .apply (workflow , taskContext , taskContext .input ())
102+ : entry .getValue ().toString ();
103+ processBuilder .environment ().put (entry .getKey (), value );
104+ }
99105 }
100106
101- int exitCode = process .waitFor ();
102-
103- ProcessResult result =
104- new ProcessResult (exitCode , output .toString ().trim (), error .toString ().trim ());
107+ ProcessResult result = startProcessUsing (processBuilder );
105108
106- return CompletableFuture .completedFuture ( application .modelFactory ().fromAny (result ));
109+ return CompletableFuture .supplyAsync (() -> application .modelFactory ().fromAny (result ));
107110
108111 } catch (IOException | InterruptedException e ) {
109112 throw new RuntimeException (e );
@@ -113,6 +116,21 @@ protected CompletableFuture<WorkflowModel> internalExecute(
113116 throw new RuntimeException ("Task must be of type RunTask" );
114117 }
115118
119+ private ProcessResult startProcessUsing (ProcessBuilder processBuilder )
120+ throws IOException , InterruptedException {
121+ Process process = processBuilder .start ();
122+
123+ StringBuilder output = new StringBuilder ();
124+ StringBuilder error = new StringBuilder ();
125+
126+ process .getInputStream ().transferTo (getOutputStream (output ));
127+ process .getErrorStream ().transferTo (getOutputStream (error ));
128+
129+ int exitCode = process .waitFor ();
130+
131+ return new ProcessResult (exitCode , output .toString ().trim (), error .toString ().trim ());
132+ }
133+
116134 private static OutputStream getOutputStream (StringBuilder output ) {
117135 return new OutputStream () {
118136 @ Override
0 commit comments