##// END OF EJS Templates
WIP exec api
cin -
r13:59dae0731c45 default
parent child
Show More
@@ -1,27 +1,45
1 package org.implab.gradle.common.dsl;
1 package org.implab.gradle.common.dsl;
2
2
3 import java.io.File;
4 import java.io.InputStream;
3 import java.util.Optional;
5 import java.util.Optional;
4 import java.util.function.Supplier;
6 import java.util.function.Supplier;
5
7
6 import org.gradle.api.provider.Provider;
8 import org.gradle.api.provider.Provider;
7 import org.implab.gradle.common.exec.RedirectFrom;
9 import org.implab.gradle.common.exec.RedirectFrom;
8
10
9 public class RedirectFromSpec {
11 public class RedirectFromSpec {
10 private Supplier<RedirectFrom> streamRedirect;
12 private Supplier<RedirectFrom> streamRedirect;
11
13
12 public boolean isRedirected() {
14 public boolean isRedirected() {
13 return streamRedirect != null;
15 return streamRedirect != null;
14 }
16 }
15
17
16 public Optional<RedirectFrom> getRedirection() {
18 public Optional<RedirectFrom> getRedirection() {
17 return streamRedirect != null ? Optional.ofNullable(streamRedirect.get()) : Optional.empty();
19 return streamRedirect != null ? Optional.ofNullable(streamRedirect.get()) : Optional.empty();
18 }
20 }
19
21
22 public void fromFile(File file) {
23 this.streamRedirect = () -> RedirectFrom.file(file);
24 }
25
26 public void fromFile(Provider<File> fileProvider) {
27 this.streamRedirect = fileProvider.map(RedirectFrom::file)::getOrNull;
28 }
29
30 public void fromStream(InputStream stream) {
31 this.streamRedirect = () -> RedirectFrom.stream(stream);
32 }
33
34 public void fromStream(Provider<InputStream> streamProvider) {
35 this.streamRedirect = streamProvider.map(RedirectFrom::stream)::getOrNull;
36 }
37
20 public void from(Object input) {
38 public void from(Object input) {
21 if (input instanceof Provider<?> inputProvider) {
39 if (input instanceof Provider<?> inputProvider) {
22 this.streamRedirect = inputProvider.map(RedirectFrom::any)::get;
40 this.streamRedirect = inputProvider.map(RedirectFrom::any)::get;
23 } else {
41 } else {
24 this.streamRedirect = () -> RedirectFrom.any(input);
42 this.streamRedirect = () -> RedirectFrom.any(input);
25 }
43 }
26 }
44 }
27 }
45 }
@@ -1,62 +1,67
1 package org.implab.gradle.common.exec;
1 package org.implab.gradle.common.exec;
2
2
3 import java.util.stream.Stream;
4
5 import org.eclipse.jdt.annotation.NonNullByDefault;
3 import org.eclipse.jdt.annotation.NonNullByDefault;
6 import org.implab.gradle.common.utils.Values;
4 import org.implab.gradle.common.utils.Values;
7
5
8 /** Command builder interface, used to specify the executable and parameters */
6 /** Command builder interface, used to specify the executable and parameters */
9 @NonNullByDefault
7 @NonNullByDefault
10 public interface CommandBuilder {
8 public interface CommandBuilder {
11
9
12 /** Sets the executable, the parameters are left intact. */
10 /** Sets the executable, the parameters are left intact. */
13 CommandBuilder executable(String executable);
11 CommandBuilder executable(String executable);
14
12
15 /** Sets the specified executable and parameters, old executable and parameters
13 /**
14 * Sets the specified executable and parameters, old executable and parameters
16 * are discarded.
15 * are discarded.
17 */
16 */
18 default CommandBuilder commandLine(String executable, String... args) {
17 default CommandBuilder commandLine(String executable, String... args) {
19 return executable(executable)
18 return executable(executable)
20 .arguments(args);
19 .arguments(args);
21 }
20 }
22
21
23 /** Sets the specified executable and parameters, old executable and parameters
22 /**
23 * Sets the specified executable and parameters, old executable and parameters
24 * are discarded.
24 * are discarded.
25 *
25 *
26 * @param command The command line. Must contain at least one element (executable).
26 * @param command The command line. Must contain at least one element
27 * (executable).
27 *
28 *
28 */
29 */
29 default CommandBuilder commandLine(Iterable<? extends String> command) {
30 default CommandBuilder commandLine(Iterable<? extends String> command) {
30 var iterator = command.iterator();
31 var iterator = command.iterator();
31
32
32 // set executable
33 // set executable
33 executable(Values.take(iterator).orElseThrow());
34 executable(Values.take(iterator).orElseThrow());
34 // cleat arguments
35 // cleat arguments
35 arguments();
36 arguments();
37
36 // set new arguments
38 // set new arguments
37 while (iterator.hasNext())
39 while (iterator.hasNext())
38 addArguments(iterator.next());
40 addArguments(iterator.next());
39
41
40 return this;
42 return this;
41 }
43 }
42
44
43 /** Adds the specified arguments to this builder */
45 /** Adds the specified arguments to this builder */
44 default CommandBuilder addArguments(String arg0, String... args) {
46 CommandBuilder addArguments(String arg0, String... args);
45 return arguments(() -> Stream
47
46 .concat(Stream.of(arg0), Stream.of(args))
48 default CommandBuilder addArguments(Iterable<String> args) {
47 .iterator());
49 for (String arg : args)
50 addArguments(arg);
51
52 return this;
48 }
53 }
49
54
50 /** Replaces arguments in the builder with the specified one. */
55 /** Replaces arguments in the builder with the specified one. */
51 default CommandBuilder arguments(String... args) {
56 default CommandBuilder arguments(String... args) {
52 return arguments(Values.iterable(args));
57 return arguments(Values.iterable(args));
53 }
58 }
54
59
55 /** Replaces arguments in the builder with the specified one. */
60 /** Replaces arguments in the builder with the specified one. */
56 CommandBuilder arguments(Iterable<String> args);
61 CommandBuilder arguments(Iterable<String> args);
57
62
58 default CommandBuilder from(CommandSpec commandSpec) {
63 default CommandBuilder from(CommandSpec commandSpec) {
59 return executable(commandSpec.executable())
64 return executable(commandSpec.executable())
60 .arguments(commandSpec.arguments());
65 .arguments(commandSpec.arguments());
61 }
66 }
62 }
67 }
@@ -1,42 +1,39
1 package org.implab.gradle.common.exec;
1 package org.implab.gradle.common.exec;
2
2
3 import java.io.ByteArrayInputStream;
3 import java.io.ByteArrayInputStream;
4 import java.io.File;
5 import java.io.IOException;
4 import java.io.IOException;
6 import java.nio.charset.StandardCharsets;
5 import java.nio.charset.StandardCharsets;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Optional;
10 import java.util.concurrent.CompletableFuture;
6 import java.util.concurrent.CompletableFuture;
7 import java.util.stream.Collectors;
11
8
12 class EchoExecBuilder extends ExecBuilder {
9 class EchoExecBuilder extends ExecBuilder {
13
10
14 private final boolean echoToStderr;
11 private final boolean echoToStderr;
15
12
16 public EchoExecBuilder(boolean echoToStderr) {
13 public EchoExecBuilder(boolean echoToStderr) {
17 this.echoToStderr = echoToStderr;
14 this.echoToStderr = echoToStderr;
18 }
15 }
19
16
20 @Override
17 @Override
21 protected CompletableFuture<Integer> startInternal(
18 protected CompletableFuture<Integer> startInternal(
22 Map<String, String> environment,
19 CommandSpec command,
23 Optional<File> directory,
20 EnvironmentSpec environment,
24 List<String> commandLine,
21 PipeSpec redirect) throws IOException {
25 Optional<RedirectFrom> stdinRedirect,
26 Optional<RedirectTo> stdoutRedirect,
27 Optional<RedirectTo> stderrRedirect) throws IOException {
28
22
29 var outputRedirect = echoToStderr ? stderrRedirect : stdoutRedirect;
23 var outputRedirect = echoToStderr ? redirect.stderr() : redirect.stdout();
30
24
31 return outputRedirect
25 return outputRedirect
32 .map(to -> {
26 .map(to -> {
33 var bytes = String.format("exec: %s", commandLine)
27 var bytes = String
28 .format(
29 "exec: %s",
30 command.commandLine().stream().collect(Collectors.joining(" ")))
34 .getBytes(StandardCharsets.UTF_8);
31 .getBytes(StandardCharsets.UTF_8);
35
32
36 return to.redirect(new ByteArrayInputStream(bytes))
33 return to.redirect(new ByteArrayInputStream(bytes))
37 .thenApply((x) -> 0);
34 .thenApply((x) -> 0);
38 })
35 })
39 .orElse(CompletableFuture.completedFuture(0));
36 .orElse(CompletableFuture.completedFuture(0));
40 }
37 }
41
38
42 }
39 }
@@ -1,25 +1,31
1 package org.implab.gradle.common.exec;
1 package org.implab.gradle.common.exec;
2
2
3 import java.io.File;
3 import java.io.File;
4 import java.util.Map;
4 import java.util.Map;
5 import java.util.Optional;
5 import java.util.Optional;
6
6
7 import org.eclipse.jdt.annotation.NonNullByDefault;
7 import org.eclipse.jdt.annotation.NonNullByDefault;
8
8
9 @NonNullByDefault
9 @NonNullByDefault
10 public interface EnvironmentBuilder {
10 public interface EnvironmentBuilder {
11 /** Sets the specified environment variable */
11 EnvironmentBuilder setVariable(String envVar, String value);
12 EnvironmentBuilder setVariable(String envVar, String value);
12
13
14 /** Replaces environment with the supplied one */
13 EnvironmentBuilder environment(Map<String, ? extends String> env);
15 EnvironmentBuilder environment(Map<String, ? extends String> env);
14
16
17 /** Unsets the specified variable. If the variable is inherited it removed anyway. */
15 EnvironmentBuilder unsetVariable(String envVar);
18 EnvironmentBuilder unsetVariable(String envVar);
16
19
20 /** Specifies the working directory */
17 EnvironmentBuilder workingDirectory(File directory);
21 EnvironmentBuilder workingDirectory(File directory);
18
22
23 /** Specifies the working directory */
19 EnvironmentBuilder workingDirectory(Optional<? extends File> directory);
24 EnvironmentBuilder workingDirectory(Optional<? extends File> directory);
20
25
26 /** Copies the supplied environment to this one */
21 default EnvironmentBuilder from(EnvironmentSpec environmentSpec) {
27 default EnvironmentBuilder from(EnvironmentSpec environmentSpec) {
22 return environment(environmentSpec.environment())
28 return environment(environmentSpec.environment())
23 .workingDirectory(environmentSpec.workingDirectory());
29 .workingDirectory(environmentSpec.workingDirectory());
24 }
30 }
25 }
31 }
@@ -1,199 +1,265
1 package org.implab.gradle.common.exec;
1 package org.implab.gradle.common.exec;
2
2
3 import java.util.ArrayList;
3 import java.util.ArrayList;
4 import java.util.HashMap;
4 import java.util.HashMap;
5 import java.util.List;
5 import java.util.List;
6 import java.util.Map;
6 import java.util.Map;
7 import java.util.Optional;
7 import java.util.Optional;
8 import java.util.concurrent.CompletableFuture;
8 import java.util.concurrent.CompletableFuture;
9
9
10 import org.eclipse.jdt.annotation.NonNullByDefault;
10 import org.eclipse.jdt.annotation.NonNullByDefault;
11 import org.eclipse.jdt.annotation.Nullable;
11 import org.eclipse.jdt.annotation.Nullable;
12
12
13 import java.io.File;
13 import java.io.File;
14 import java.io.IOException;
14 import java.io.IOException;
15
15
16 import static java.util.Objects.requireNonNull;
16 import static java.util.Objects.requireNonNull;
17
17
18 /** Command line builder */
18 /** Command line builder */
19 @NonNullByDefault
19 @NonNullByDefault
20 public abstract class ExecBuilder implements
20 public abstract class ExecBuilder implements
21 CommandBuilder,
21 CommandBuilder,
22 PipeBuilder,
22 PipeBuilder,
23 EnvironmentBuilder,
23 EnvironmentBuilder,
24 Runnable
24 Runnable
25 {
25 {
26 private String executable;
26 private String executable;
27
27
28 private final List<String> arguments = new ArrayList<>();
28 private final List<String> arguments = new ArrayList<>();
29
29
30 private final Map<String, String> environment = new HashMap<>();
30 private final Map<String, String> environment = new HashMap<>();
31
31
32 private @Nullable File directory;
32 private @Nullable File directory;
33
33
34 private RedirectFrom inputRedirect;
34 private RedirectFrom inputRedirect;
35
35
36 private RedirectTo outputRedirect;
36 private RedirectTo outputRedirect;
37
37
38 private RedirectTo errorRedirect;
38 private RedirectTo errorRedirect;
39
39
40 @Override
40 @Override
41 public ExecBuilder executable(String executable) {
41 public ExecBuilder executable(String executable) {
42 requireNonNull(executable, "cmd can't be null");
42 requireNonNull(executable, "cmd can't be null");
43 this.executable = executable;
43 this.executable = executable;
44 return this;
44 return this;
45 }
45 }
46
46
47 @Override
47 @Override
48 public ExecBuilder arguments(Iterable<String> args) {
48 public ExecBuilder arguments(Iterable<String> args) {
49 requireNonNull(args, "Args must not be null");
49 requireNonNull(args, "Args must not be null");
50 arguments.clear();
50 arguments.clear();
51 for(var arg: args)
51 for(var arg: args)
52 arguments.add(arg);
52 arguments.add(arg);
53 return this;
53 return this;
54 }
54 }
55
55
56 @Override
56 @Override
57 public ExecBuilder addArguments(String arg0, String... args) {
57 public ExecBuilder addArguments(String arg0, String... args) {
58 requireNonNull(arg0, "arg0 parameter can't be null");
58 requireNonNull(arg0, "arg0 parameter can't be null");
59 arguments.add(arg0);
59 arguments.add(arg0);
60
60
61 for (var arg : args)
61 for (var arg : args)
62 arguments.add(arg);
62 arguments.add(arg);
63
63
64 return this;
64 return this;
65 }
65 }
66
66
67 /** Sets the working directory */
67 /** Sets the working directory */
68 @Override
68 @Override
69 public ExecBuilder workingDirectory(File directory) {
69 public ExecBuilder workingDirectory(File directory) {
70 requireNonNull(directory, "directory parameter can't be null");
70 requireNonNull(directory, "directory parameter can't be null");
71
71
72 this.directory = directory;
72 this.directory = directory;
73 return this;
73 return this;
74 }
74 }
75
75
76 @Override
76 @Override
77 public ExecBuilder workingDirectory(Optional<? extends File> directory) {
77 public ExecBuilder workingDirectory(Optional<? extends File> directory) {
78 requireNonNull(directory, "directory parameter can't be null");
78 requireNonNull(directory, "directory parameter can't be null");
79
79
80 this.directory = directory.orElse(null);
80 this.directory = directory.orElse(null);
81 return this;
81 return this;
82 }
82 }
83
83
84 /**
84 /**
85 * Sets the environment value. The value cannot be null.
85 * Sets the environment value. The value cannot be null.
86 *
86 *
87 * @param envVar The name of the environment variable
87 * @param envVar The name of the environment variable
88 * @param value The value to set,
88 * @param value The value to set,
89 */
89 */
90 @Override
90 @Override
91 public ExecBuilder setVariable(String envVar, String value) {
91 public ExecBuilder setVariable(String envVar, String value) {
92 requireNonNull(value, "Value can't be null");
92 requireNonNull(value, "Value can't be null");
93 requireNonNull(envVar, "envVar parameter can't be null");
93 requireNonNull(envVar, "envVar parameter can't be null");
94
94
95 environment.put(envVar, value);
95 environment.put(envVar, value);
96 return this;
96 return this;
97 }
97 }
98
98
99 @Override
99 @Override
100 public ExecBuilder unsetVariable(String envVar) {
101 requireNonNull(envVar, "envVar parameter can't be null");
102
103 environment.remove(envVar);
104 return this;
105 }
106
107 @Override
100 public ExecBuilder environment(Map<String,? extends String> env) {
108 public ExecBuilder environment(Map<String,? extends String> env) {
101 requireNonNull(env, "env parameter can't be null");
109 requireNonNull(env, "env parameter can't be null");
102
110
103 environment.clear();
111 environment.clear();
104 environment.putAll(env);
112 environment.putAll(env);
105 return this;
113 return this;
106 }
114 }
107
115
108 /**
116 /**
109 * Sets redirection for the stdin, {@link RedirectFrom} will be applied
117 * Sets redirection for the stdin, {@link RedirectFrom} will be applied
110 * every time the process is started.
118 * every time the process is started.
111 *
119 *
112 * <p>
120 * <p>
113 * If redirection
121 * If redirection
114 */
122 */
115 @Override
123 @Override
116 public ExecBuilder stdin(RedirectFrom from) {
124 public ExecBuilder stdin(RedirectFrom from) {
117 requireNonNull(from, "from parameter can't be null");
125 requireNonNull(from, "from parameter can't be null");
118
126
119 inputRedirect = from;
127 inputRedirect = from;
120 return this;
128 return this;
121 }
129 }
122
130
123 @Override
131 @Override
124 public PipeBuilder stdin(Optional<? extends RedirectFrom> from) {
132 public ExecBuilder stdin(Optional<? extends RedirectFrom> from) {
125 requireNonNull(from, "from parameter can't be null");
133 requireNonNull(from, "from parameter can't be null");
126 inputRedirect = from.orElse(null);
134 inputRedirect = from.orElse(null);
127 return this;
135 return this;
128 }
136 }
129
137
130 /**
138 /**
131 * Sets redirection for the stdout, {@link RedirectTo} will be applied
139 * Sets redirection for the stdout, {@link RedirectTo} will be applied
132 * every time the process is started.
140 * every time the process is started.
133 */
141 */
134 @Override
142 @Override
135 public ExecBuilder stdout(RedirectTo out) {
143 public ExecBuilder stdout(RedirectTo out) {
136 requireNonNull(out, "out parameter can't be null");
144 requireNonNull(out, "out parameter can't be null");
137 outputRedirect = out;
145 outputRedirect = out;
138 return this;
146 return this;
139 }
147 }
140
148
141 @Override
149 @Override
142 public PipeBuilder stdout(Optional<? extends RedirectTo> to) {
150 public ExecBuilder stdout(Optional<? extends RedirectTo> to) {
143 requireNonNull(to, "from parameter can't be null");
151 requireNonNull(to, "from parameter can't be null");
144 outputRedirect = to.orElse(null);
152 outputRedirect = to.orElse(null);
145 return this;
153 return this;
146 }
154 }
147
155
148 /**
156 /**
149 * Sets redirection for the stderr, {@link RedirectTo} will be applied
157 * Sets redirection for the stderr, {@link RedirectTo} will be applied
150 * every time the process is started.
158 * every time the process is started.
151 */
159 */
152 @Override
160 @Override
153 public ExecBuilder stderr(RedirectTo err) {
161 public ExecBuilder stderr(RedirectTo err) {
154 requireNonNull(err, "err parameter can't be null");
162 requireNonNull(err, "err parameter can't be null");
155 errorRedirect = err;
163 errorRedirect = err;
156 return this;
164 return this;
157 }
165 }
158
166
159 @Override
167 @Override
160 public PipeBuilder stderr(Optional<? extends RedirectTo> to) {
168 public ExecBuilder stderr(Optional<? extends RedirectTo> to) {
161 requireNonNull(to, "from parameter can't be null");
169 requireNonNull(to, "from parameter can't be null");
162 errorRedirect = to.orElse(null);
170 errorRedirect = to.orElse(null);
163 return this;
171 return this;
164 }
172 }
165
173
174 @Override
175 public ExecBuilder from(CommandSpec commandSpec) {
176 CommandBuilder.super.from(commandSpec);
177 return this;
178 }
179
180 @Override
181 public ExecBuilder from(PipeSpec pipeSpec) {
182 PipeBuilder.super.from(pipeSpec);
183 return this;
184 }
185
186 @Override
187 public ExecBuilder from(EnvironmentSpec environmentSpec) {
188 EnvironmentBuilder.super.from(environmentSpec);
189 return this;
190 }
191
166 /** Implement this function to */
192 /** Implement this function to */
167 protected abstract CompletableFuture<Integer> startInternal(
193 protected abstract CompletableFuture<Integer> startInternal(
168 Map<String, String> environment,
194 CommandSpec command,
169 Optional<File> directory,
195 EnvironmentSpec environment,
170 List<String> commandLine,
196 PipeSpec redirect) throws IOException;
171 Optional<RedirectFrom> stdinRedirect,
172 Optional<RedirectTo> stdoutRedirect,
173 Optional<RedirectTo> stderrRedirect) throws IOException;
174
197
175 /**
198 /**
176 * Creates and starts new process and returns {@link CompletableFuture}. The
199 * Creates and starts new process and returns {@link CompletableFuture}. The
177 * process may be a remote process, or a shell process or etc.
200 * process may be a remote process, or a shell process or etc.
178 *
201 *
179 * @return
202 * @return
180 * @throws IOException
203 * @throws IOException
181 */
204 */
182 public CompletableFuture<Integer> run() throws IOException {
205 public CompletableFuture<Integer> run() throws IOException {
183 if (executable == null || executable.isEmpty())
206 if (executable == null || executable.isEmpty())
184 throw new IllegalStateException("The executable isn't set");
207 throw new IllegalStateException("The executable isn't set");
185
208
186 var commandLine = new ArrayList<String>();
209 var commandLine = new ArrayList<String>();
187 commandLine.add(executable);
210 commandLine.add(executable);
188 commandLine.addAll(arguments);
211 commandLine.addAll(arguments);
189
212
190 return startInternal(
213 return startInternal(
191 environment,
214 new SelfCommandSpec(),
192 Optional.ofNullable(directory),
215 new SelfEnvironmentSpec(),
193 commandLine,
216 new SelfPipeSpec()
194 Optional.ofNullable(inputRedirect),
217 );
195 Optional.ofNullable(outputRedirect),
218 }
196 Optional.ofNullable(errorRedirect));
219
220 private class SelfCommandSpec implements CommandSpec {
221
222 @Override
223 public String executable() {
224 return executable;
225 }
226
227 @Override
228 public List<String> arguments() {
229 return arguments;
230 }
231 }
232
233 private class SelfEnvironmentSpec implements EnvironmentSpec {
234
235 @Override
236 public Map<String, String> environment() {
237 return environment;
238 }
239
240 @Override
241 public Optional<File> workingDirectory() {
242 return Optional.ofNullable( directory);
243 }
244 }
245
246 private class SelfPipeSpec implements PipeSpec {
247
248 @Override
249 public Optional<RedirectTo> stdout() {
250 return Optional.ofNullable(outputRedirect);
251 }
252
253 @Override
254 public Optional<RedirectTo> stderr() {
255 return Optional.ofNullable(errorRedirect);
256 }
257
258 @Override
259 public Optional<RedirectFrom> stdin() {
260 return Optional.ofNullable(inputRedirect);
197 }
261 }
198
262
199 }
263 }
264
265 }
@@ -1,58 +1,59
1 package org.implab.gradle.common.exec;
1 package org.implab.gradle.common.exec;
2
2
3 import java.io.File;
4 import java.io.IOException;
3 import java.io.IOException;
5 import java.util.List;
4 import java.util.List;
6 import java.util.Map;
7 import java.util.Optional;
8 import java.util.concurrent.CompletableFuture;
5 import java.util.concurrent.CompletableFuture;
9 import java.util.function.Consumer;
6 import java.util.function.Consumer;
10
7
11 /** Shell used to start processes */
8 /** Shell used to start processes */
12 public interface ExecShell {
9 public interface ExecShell {
13
10
14 /** Creates new process builder {@link ExecBuilder} */
11 /** Creates new process builder {@link ExecBuilder} */
15 ExecBuilder executable();
12 ExecBuilder executable();
16
13
17 /**
14 /**
18 * Creates default process execution "shell" which will execute processes
15 * Creates default process execution "shell" which will execute processes
19 * directly.
16 * directly.
20 */
17 */
21 static ExecShell system() {
18 static ExecShell system() {
22 return () -> new SystemExecBuilder();
19 return () -> new SystemExecBuilder();
23 }
20 }
24
21
25 /**
22 /**
26 * Creates a stub shell which will print command to STDERR and return 0 (no
23 * Creates a stub shell which will print command to STDERR and return 0 (no
27 * error).
24 * error).
28 */
25 */
29 static ExecShell echoStderr() {
26 static ExecShell echoStderr() {
30 return () -> new EchoExecBuilder(true);
27 return () -> new EchoExecBuilder(true);
31 }
28 }
32
29
33 /**
30 /**
34 * Creates a stub shell which will print command to STDOUT and return 0 (no
31 * Creates a stub shell which will print command to STDOUT and return 0 (no
35 * error).
32 * error).
36 */
33 */
37
34
38 static ExecShell echo() {
35 static ExecShell echo() {
39 return () -> new EchoExecBuilder(false);
36 return () -> new EchoExecBuilder(false);
40 }
37 }
41
38
42 /** Creates a stub shell which will call the specified consumer and will supply a command line to it.
39 /**
40 * Creates a stub shell which will call the specified consumer and will supply a
41 * command line to it.
43 * The command line will be passed as a list of strings.
42 * The command line will be passed as a list of strings.
43 *
44 * @param consumer The consumer fot the command line
44 * @param consumer The consumer fot the command line
45 * @return
45 * @return
46 */
46 */
47 static ExecShell echo(Consumer<List<String>> consumer) {
47 static ExecShell echo(Consumer<List<String>> consumer) {
48 return () -> new ExecBuilder() {
48 return () -> new ExecBuilder() {
49 @Override
49 @Override
50 protected CompletableFuture<Integer> startInternal(Map<String, String> environment, Optional<File> directory,
50 protected CompletableFuture<Integer> startInternal(
51 List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect,
51 CommandSpec command,
52 Optional<RedirectTo> stderrRedirect) throws IOException {
52 EnvironmentSpec environment,
53 consumer.accept(commandLine);
53 PipeSpec redirect) throws IOException {
54 consumer.accept(command.commandLine());
54 return CompletableFuture.completedFuture(0);
55 return CompletableFuture.completedFuture(0);
55 }
56 }
56 };
57 };
57 }
58 }
58 }
59 }
@@ -1,49 +1,41
1 package org.implab.gradle.common.exec;
1 package org.implab.gradle.common.exec;
2
2
3 import java.io.File;
4 import java.io.IOException;
3 import java.io.IOException;
5 import java.lang.ProcessBuilder.Redirect;
4 import java.lang.ProcessBuilder.Redirect;
6 import java.util.ArrayList;
5 import java.util.ArrayList;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Optional;
10 import java.util.concurrent.CompletableFuture;
6 import java.util.concurrent.CompletableFuture;
11
7
12 class SystemExecBuilder extends ExecBuilder {
8 class SystemExecBuilder extends ExecBuilder {
13 @Override
9 @Override
14 protected CompletableFuture<Integer> startInternal(
10 protected CompletableFuture<Integer> startInternal(
15 Map<String, String> environment,
11 CommandSpec command,
16 Optional<File> directory,
12 EnvironmentSpec environment,
17 List<String> commandLine,
13 PipeSpec redirect) throws IOException {
18 Optional<RedirectFrom> stdinRedirect,
19 Optional<RedirectTo> stdoutRedirect,
20 Optional<RedirectTo> stderrRedirect) throws IOException {
21
14
22 var builder = new ProcessBuilder(commandLine);
15 var builder = new ProcessBuilder(command.commandLine());
23
24 directory.ifPresent(builder::directory);
25
16
26 builder.environment().putAll(environment);
17 environment.workingDirectory().ifPresent(builder::directory);
27
18
28 // TODO Auto-generated method stub
19 builder.environment().putAll(environment.environment());
20
29 var tasks = new ArrayList<CompletableFuture<?>>();
21 var tasks = new ArrayList<CompletableFuture<?>>();
30
22
31 if (!stdoutRedirect.isPresent())
23 if (!redirect.stdout().isPresent())
32 builder.redirectOutput(Redirect.DISCARD);
24 builder.redirectOutput(Redirect.DISCARD);
33 if (!stderrRedirect.isPresent())
25 if (!redirect.stderr().isPresent())
34 builder.redirectError(Redirect.DISCARD);
26 builder.redirectError(Redirect.DISCARD);
35
27
36 // run process
28 // run process
37 var proc = builder.start();
29 var proc = builder.start();
38
30
39 tasks.add(proc.onExit());
31 tasks.add(proc.onExit());
40
32
41 stdinRedirect.map(from -> from.redirect(proc.getOutputStream())).ifPresent(tasks::add);
33 redirect.stdin().map(from -> from.redirect(proc.getOutputStream())).ifPresent(tasks::add);
42 stdoutRedirect.map(to -> to.redirect(proc.getInputStream())).ifPresent(tasks::add);
34 redirect.stdout().map(to -> to.redirect(proc.getInputStream())).ifPresent(tasks::add);
43 stderrRedirect.map(to -> to.redirect(proc.getErrorStream())).ifPresent(tasks::add);
35 redirect.stderr().map(to -> to.redirect(proc.getErrorStream())).ifPresent(tasks::add);
44
36
45 return CompletableFuture
37 return CompletableFuture
46 .allOf(tasks.toArray(new CompletableFuture<?>[0]))
38 .allOf(tasks.toArray(new CompletableFuture<?>[0]))
47 .thenApply(t -> proc.exitValue());
39 .thenApply(t -> proc.exitValue());
48 }
40 }
49 }
41 }
@@ -1,110 +1,110
1 package org.implab.gradle.common.tasks;
1 package org.implab.gradle.common.tasks;
2
2
3 import java.io.IOException;
3 import java.io.IOException;
4 import java.util.Map;
4 import java.util.Map;
5 import java.util.concurrent.ExecutionException;
5 import java.util.concurrent.ExecutionException;
6 import java.util.stream.Stream;
6 import java.util.stream.Stream;
7
7
8 import org.gradle.api.DefaultTask;
8 import org.gradle.api.DefaultTask;
9 import org.gradle.api.file.DirectoryProperty;
9 import org.gradle.api.file.DirectoryProperty;
10 import org.gradle.api.provider.ListProperty;
10 import org.gradle.api.provider.ListProperty;
11 import org.gradle.api.provider.MapProperty;
11 import org.gradle.api.provider.MapProperty;
12 import org.gradle.api.tasks.Internal;
12 import org.gradle.api.tasks.Internal;
13 import org.gradle.api.tasks.TaskAction;
13 import org.gradle.api.tasks.TaskAction;
14 import org.implab.gradle.common.dsl.CommandSpec;
14 import org.implab.gradle.common.dsl.CommandSpec;
15 import org.implab.gradle.common.dsl.PipeSpec;
15 import org.implab.gradle.common.dsl.PipeSpec;
16 import org.implab.gradle.common.dsl.RedirectFromSpec;
16 import org.implab.gradle.common.dsl.RedirectFromSpec;
17 import org.implab.gradle.common.dsl.RedirectToSpec;
17 import org.implab.gradle.common.dsl.RedirectToSpec;
18 import org.implab.gradle.common.dsl.EnvironmentSpec;
18 import org.implab.gradle.common.dsl.EnvironmentSpec;
19 import org.implab.gradle.common.exec.ExecBuilder;
19 import org.implab.gradle.common.exec.ExecBuilder;
20 import org.implab.gradle.common.utils.ObjectsMixin;
20 import org.implab.gradle.common.utils.ObjectsMixin;
21 import org.implab.gradle.common.utils.Strings;
21 import org.implab.gradle.common.utils.Strings;
22 import org.implab.gradle.common.utils.ThrowingConsumer;
22 import org.implab.gradle.common.utils.ThrowingConsumer;
23
23
24 public abstract class ShellExecTask
24 public abstract class ShellExecTask
25 extends DefaultTask
25 extends DefaultTask
26 implements CommandSpec, PipeSpec, EnvironmentSpec, ObjectsMixin {
26 implements CommandSpec, PipeSpec, EnvironmentSpec, ObjectsMixin {
27
27
28 private final RedirectToSpec redirectStderr = new RedirectToSpec();
28 private final RedirectToSpec redirectStderr = new RedirectToSpec();
29
29
30 private final RedirectToSpec redirectStdout = new RedirectToSpec();
30 private final RedirectToSpec redirectStdout = new RedirectToSpec();
31
31
32 private final RedirectFromSpec redirectStdin = new RedirectFromSpec();
32 private final RedirectFromSpec redirectStdin = new RedirectFromSpec();
33
33
34 @Internal
34 @Internal
35 @Override
35 @Override
36 public abstract DirectoryProperty getWorkingDirectory();
36 public abstract DirectoryProperty getWorkingDirectory();
37
37
38 @Internal
38 @Internal
39 @Override
39 @Override
40 public abstract MapProperty<String, String> getEnvironment();
40 public abstract MapProperty<String, String> getEnvironment();
41
41
42 @Internal
42 @Internal
43 @Override
43 @Override
44 public abstract ListProperty<String> getCommandLine();
44 public abstract ListProperty<String> getCommandLine();
45
45
46 /**
46 /**
47 * STDIN redirection, if not specified, no input will be passed to the command
47 * STDIN redirection, if not specified, no input will be passed to the command
48 */
48 */
49 @Internal
49 @Internal
50 @Override
50 @Override
51 public RedirectFromSpec getStdin() {
51 public RedirectFromSpec getStdin() {
52 return redirectStdin;
52 return redirectStdin;
53 }
53 }
54
54
55 /**
55 /**
56 * STDOUT redirection, if not specified, redirected to logger::info
56 * STDOUT redirection, if not specified, redirected to logger::info
57 */
57 */
58 @Internal
58 @Internal
59 @Override
59 @Override
60 public RedirectToSpec getStdout() {
60 public RedirectToSpec getStdout() {
61 return redirectStdout;
61 return redirectStdout;
62 }
62 }
63
63
64 /**
64 /**
65 * STDERR redirection, if not specified, redirected to logger::error
65 * STDERR redirection, if not specified, redirected to logger::error
66 */
66 */
67 @Internal
67 @Internal
68 @Override
68 @Override
69 public RedirectToSpec getStderr() {
69 public RedirectToSpec getStderr() {
70 return redirectStderr;
70 return redirectStderr;
71 }
71 }
72
72
73 @Override
73 @Override
74 public void commandLine(Object arg0, Object... args) {
74 public void commandLine(Object arg0, Object... args) {
75 getCommandLine().set(provider(() -> Stream.concat(
75 getCommandLine().set(provider(() -> Stream.concat(
76 Stream.of(arg0),
76 Stream.of(arg0),
77 Stream.of(args))
77 Stream.of(args))
78 .map(Strings::asString).toList()));
78 .map(Strings::asString).toList()));
79
79
80 }
80 }
81
81
82 @Override
82 @Override
83 public void args(Object arg0, Object... args) {
83 public void args(Object arg0, Object... args) {
84 getCommandLine().addAll(provider(() -> Stream.concat(
84 getCommandLine().addAll(provider(() -> Stream.concat(
85 Stream.of(arg0),
85 Stream.of(arg0),
86 Stream.of(args))
86 Stream.of(args))
87 .map(Strings::asString).toList()));
87 .map(Strings::asString).toList()));
88 }
88 }
89
89
90 protected abstract ExecBuilder execBuilder();
90 protected abstract ExecBuilder execBuilder();
91
91
92 @TaskAction
92 @TaskAction
93 public final void run() throws IOException, InterruptedException, ExecutionException {
93 public final void run() throws IOException, InterruptedException, ExecutionException {
94 var execBuilder = execBuilder()
94 var execBuilder = execBuilder();
95 .workingDirectory(getWorkingDirectory().get().getAsFile())
95 execBuilder.workingDirectory(getWorkingDirectory().get().getAsFile());
96 .environment(getEnvironment().getOrElse(Map.of()))
96 execBuilder.environment(getEnvironment().getOrElse(Map.of()));
97 .commandLine(getCommandLine().get());
97 execBuilder.commandLine(getCommandLine().get());
98
98
99 getStdout().getRedirection().ifPresent(execBuilder::stdout);
99 getStdout().getRedirection().ifPresent(execBuilder::stdout);
100 getStderr().getRedirection().ifPresent(execBuilder::stderr);
100 getStderr().getRedirection().ifPresent(execBuilder::stderr);
101 getStdin().getRedirection().ifPresent(execBuilder::stdin);
101 getStdin().getRedirection().ifPresent(execBuilder::stdin);
102
102
103 execBuilder.run().thenAccept(ThrowingConsumer.guard(this::checkRetCode)).join();
103 execBuilder.run().thenAccept(ThrowingConsumer.guard(this::checkRetCode)).join();
104 }
104 }
105
105
106 protected void checkRetCode(Integer code) throws IOException{
106 protected void checkRetCode(Integer code) throws IOException {
107 throw new IOException(String.format("The process is terminated with code %s", code));
107 throw new IOException(String.format("The process is terminated with code %s", code));
108 }
108 }
109
109
110 }
110 }
@@ -1,88 +1,89
1 package org.implab.gradle.common.utils;
1 package org.implab.gradle.common.utils;
2
2
3 import java.util.Iterator;
3 import java.util.Iterator;
4 import java.util.Map;
4 import java.util.Map;
5 import java.util.Spliterator;
6 import java.util.Spliterators;
5 import java.util.Spliterators;
7 import java.util.Map.Entry;
6 import java.util.Map.Entry;
8 import java.util.Optional;
7 import java.util.Optional;
9 import java.util.function.Function;
8 import java.util.function.Function;
10 import java.util.function.Supplier;
9 import java.util.function.Supplier;
11 import java.util.stream.Collectors;
10 import java.util.stream.Collectors;
12 import java.util.stream.Stream;
11 import java.util.stream.Stream;
13 import java.util.stream.StreamSupport;
12 import java.util.stream.StreamSupport;
14
13
15 import org.gradle.api.provider.Provider;
14 import org.gradle.api.provider.Provider;
16
15
17 public final class Values {
16 public final class Values {
18
17
19 private Values() {
18 private Values() {
20 }
19 }
21
20
22 /**
21 /**
23 * Converts values in the specified map
22 * Converts values in the specified map
23 *
24 * @param <K>
24 * @param <K>
25 * @param <V>
25 * @param <V>
26 * @param <U>
26 * @param <U>
27 * @param map
27 * @param map
28 * @param mapper
28 * @param mapper
29 * @return
29 * @return
30 */
30 */
31 public static <K, V, U> Map<K, U> mapValues(Map<K, V> map, Function<V, U> mapper) {
31 public static <K, V, U> Map<K, U> mapValues(Map<K, V> map, Function<V, U> mapper) {
32 Function<Entry<K, V>, V> getter = Entry::getValue;
32 Function<Entry<K, V>, V> getter = Entry::getValue;
33
33
34 return map.entrySet().stream()
34 return map.entrySet().stream()
35 .collect(Collectors.toMap(Entry::getKey, getter.andThen(mapper)));
35 .collect(Collectors.toMap(Entry::getKey, getter.andThen(mapper)));
36 }
36 }
37
37
38 /** Converts the supplied value to a string.
38 /**
39 * Converts the supplied value to a string.
39 */
40 */
40 public static String toString(Object value) {
41 public static String toString(Object value) {
41 if (value == null) {
42 if (value == null) {
42 return null;
43 return null;
43 } else if (value instanceof String string) {
44 } else if (value instanceof String string) {
44 return string;
45 return string;
45 } else if (value instanceof Provider<?> provider) {
46 } else if (value instanceof Provider<?> provider) {
46 return toString(provider.getOrNull());
47 return toString(provider.getOrNull());
47 } else if (value instanceof Supplier<?> supplier) {
48 } else if (value instanceof Supplier<?> supplier) {
48 return toString(supplier.get());
49 return toString(supplier.get());
49 } else {
50 } else {
50 return value.toString();
51 return value.toString();
51 }
52 }
52 }
53 }
53
54
54 public static <T> Stream<T> stream(Iterator<T> remaining) {
55 public static <T> Stream<T> stream(Iterator<T> remaining) {
55 var spliterator = Spliterators.spliteratorUnknownSize(remaining, 0);
56 return StreamSupport.stream(
56
57 Spliterators.spliteratorUnknownSize(remaining, 0),
57 return StreamSupport.stream(spliterator, false);
58 false);
58 }
59 }
59
60
60 public static <T> Optional<T> take(Iterator<T> iterator) {
61 public static <T> Optional<T> take(Iterator<T> iterator) {
61 return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty();
62 return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty();
62 }
63 }
63
64
64 public static <T> Iterable<T> iterable(T[] values) {
65 public static <T> Iterable<T> iterable(T[] values) {
65 return () -> new ArrayIterator<>(values);
66 return () -> new ArrayIterator<>(values);
66 }
67 }
67
68
68 private static class ArrayIterator<T> implements Iterator<T> {
69 private static class ArrayIterator<T> implements Iterator<T> {
69 private final T[] data;
70 private final T[] data;
70
71
71 private int pos = 0;
72 private int pos = 0;
72
73
73 ArrayIterator(T[] data) {
74 ArrayIterator(T[] data) {
74 this.data = data;
75 this.data = data;
75 }
76 }
76
77
77 @Override
78 @Override
78 public boolean hasNext() {
79 public boolean hasNext() {
79 return pos < data.length;
80 return pos < data.length;
80 }
81 }
81
82
82 @Override
83 @Override
83 public T next() {
84 public T next() {
84 return data[pos++];
85 return data[pos++];
85 }
86 }
86 }
87 }
87
88
88 }
89 }
General Comments 0
You need to be logged in to leave comments. Login now