##// END OF EJS Templates
WIP exec api
cin -
r13:59dae0731c45 default
parent child
Show More
@@ -1,5 +1,7
1 1 package org.implab.gradle.common.dsl;
2 2
3 import java.io.File;
4 import java.io.InputStream;
3 5 import java.util.Optional;
4 6 import java.util.function.Supplier;
5 7
@@ -17,6 +19,22 public class RedirectFromSpec {
17 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 38 public void from(Object input) {
21 39 if (input instanceof Provider<?> inputProvider) {
22 40 this.streamRedirect = inputProvider.map(RedirectFrom::any)::get;
@@ -1,7 +1,5
1 1 package org.implab.gradle.common.exec;
2 2
3 import java.util.stream.Stream;
4
5 3 import org.eclipse.jdt.annotation.NonNullByDefault;
6 4 import org.implab.gradle.common.utils.Values;
7 5
@@ -12,7 +10,8 public interface CommandBuilder {
12 10 /** Sets the executable, the parameters are left intact. */
13 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 15 * are discarded.
17 16 */
18 17 default CommandBuilder commandLine(String executable, String... args) {
@@ -20,10 +19,12 public interface CommandBuilder {
20 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 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 30 default CommandBuilder commandLine(Iterable<? extends String> command) {
@@ -33,6 +34,7 public interface CommandBuilder {
33 34 executable(Values.take(iterator).orElseThrow());
34 35 // cleat arguments
35 36 arguments();
37
36 38 // set new arguments
37 39 while (iterator.hasNext())
38 40 addArguments(iterator.next());
@@ -41,10 +43,13 public interface CommandBuilder {
41 43 }
42 44
43 45 /** Adds the specified arguments to this builder */
44 default CommandBuilder addArguments(String arg0, String... args) {
45 return arguments(() -> Stream
46 .concat(Stream.of(arg0), Stream.of(args))
47 .iterator());
46 CommandBuilder addArguments(String arg0, String... args);
47
48 default CommandBuilder addArguments(Iterable<String> args) {
49 for (String arg : args)
50 addArguments(arg);
51
52 return this;
48 53 }
49 54
50 55 /** Replaces arguments in the builder with the specified one. */
@@ -1,13 +1,10
1 1 package org.implab.gradle.common.exec;
2 2
3 3 import java.io.ByteArrayInputStream;
4 import java.io.File;
5 4 import java.io.IOException;
6 5 import java.nio.charset.StandardCharsets;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Optional;
10 6 import java.util.concurrent.CompletableFuture;
7 import java.util.stream.Collectors;
11 8
12 9 class EchoExecBuilder extends ExecBuilder {
13 10
@@ -19,18 +16,18 class EchoExecBuilder extends ExecBuilde
19 16
20 17 @Override
21 18 protected CompletableFuture<Integer> startInternal(
22 Map<String, String> environment,
23 Optional<File> directory,
24 List<String> commandLine,
25 Optional<RedirectFrom> stdinRedirect,
26 Optional<RedirectTo> stdoutRedirect,
27 Optional<RedirectTo> stderrRedirect) throws IOException {
19 CommandSpec command,
20 EnvironmentSpec environment,
21 PipeSpec redirect) throws IOException {
28 22
29 var outputRedirect = echoToStderr ? stderrRedirect : stdoutRedirect;
23 var outputRedirect = echoToStderr ? redirect.stderr() : redirect.stdout();
30 24
31 25 return outputRedirect
32 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 31 .getBytes(StandardCharsets.UTF_8);
35 32
36 33 return to.redirect(new ByteArrayInputStream(bytes))
@@ -8,16 +8,22 import org.eclipse.jdt.annotation.NonNul
8 8
9 9 @NonNullByDefault
10 10 public interface EnvironmentBuilder {
11 /** Sets the specified environment variable */
11 12 EnvironmentBuilder setVariable(String envVar, String value);
12 13
14 /** Replaces environment with the supplied one */
13 15 EnvironmentBuilder environment(Map<String, ? extends String> env);
14 16
17 /** Unsets the specified variable. If the variable is inherited it removed anyway. */
15 18 EnvironmentBuilder unsetVariable(String envVar);
16 19
20 /** Specifies the working directory */
17 21 EnvironmentBuilder workingDirectory(File directory);
18 22
23 /** Specifies the working directory */
19 24 EnvironmentBuilder workingDirectory(Optional<? extends File> directory);
20 25
26 /** Copies the supplied environment to this one */
21 27 default EnvironmentBuilder from(EnvironmentSpec environmentSpec) {
22 28 return environment(environmentSpec.environment())
23 29 .workingDirectory(environmentSpec.workingDirectory());
@@ -97,6 +97,14 public abstract class ExecBuilder implem
97 97 }
98 98
99 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 108 public ExecBuilder environment(Map<String,? extends String> env) {
101 109 requireNonNull(env, "env parameter can't be null");
102 110
@@ -121,7 +129,7 public abstract class ExecBuilder implem
121 129 }
122 130
123 131 @Override
124 public PipeBuilder stdin(Optional<? extends RedirectFrom> from) {
132 public ExecBuilder stdin(Optional<? extends RedirectFrom> from) {
125 133 requireNonNull(from, "from parameter can't be null");
126 134 inputRedirect = from.orElse(null);
127 135 return this;
@@ -139,7 +147,7 public abstract class ExecBuilder implem
139 147 }
140 148
141 149 @Override
142 public PipeBuilder stdout(Optional<? extends RedirectTo> to) {
150 public ExecBuilder stdout(Optional<? extends RedirectTo> to) {
143 151 requireNonNull(to, "from parameter can't be null");
144 152 outputRedirect = to.orElse(null);
145 153 return this;
@@ -157,20 +165,35 public abstract class ExecBuilder implem
157 165 }
158 166
159 167 @Override
160 public PipeBuilder stderr(Optional<? extends RedirectTo> to) {
168 public ExecBuilder stderr(Optional<? extends RedirectTo> to) {
161 169 requireNonNull(to, "from parameter can't be null");
162 170 errorRedirect = to.orElse(null);
163 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 192 /** Implement this function to */
167 193 protected abstract CompletableFuture<Integer> startInternal(
168 Map<String, String> environment,
169 Optional<File> directory,
170 List<String> commandLine,
171 Optional<RedirectFrom> stdinRedirect,
172 Optional<RedirectTo> stdoutRedirect,
173 Optional<RedirectTo> stderrRedirect) throws IOException;
194 CommandSpec command,
195 EnvironmentSpec environment,
196 PipeSpec redirect) throws IOException;
174 197
175 198 /**
176 199 * Creates and starts new process and returns {@link CompletableFuture}. The
@@ -188,12 +211,55 public abstract class ExecBuilder implem
188 211 commandLine.addAll(arguments);
189 212
190 213 return startInternal(
191 environment,
192 Optional.ofNullable(directory),
193 commandLine,
194 Optional.ofNullable(inputRedirect),
195 Optional.ofNullable(outputRedirect),
196 Optional.ofNullable(errorRedirect));
214 new SelfCommandSpec(),
215 new SelfEnvironmentSpec(),
216 new SelfPipeSpec()
217 );
218 }
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,10 +1,7
1 1 package org.implab.gradle.common.exec;
2 2
3 import java.io.File;
4 3 import java.io.IOException;
5 4 import java.util.List;
6 import java.util.Map;
7 import java.util.Optional;
8 5 import java.util.concurrent.CompletableFuture;
9 6 import java.util.function.Consumer;
10 7
@@ -39,18 +36,22 public interface ExecShell {
39 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 42 * The command line will be passed as a list of strings.
43 *
44 44 * @param consumer The consumer fot the command line
45 45 * @return
46 46 */
47 47 static ExecShell echo(Consumer<List<String>> consumer) {
48 48 return () -> new ExecBuilder() {
49 49 @Override
50 protected CompletableFuture<Integer> startInternal(Map<String, String> environment, Optional<File> directory,
51 List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect,
52 Optional<RedirectTo> stderrRedirect) throws IOException {
53 consumer.accept(commandLine);
50 protected CompletableFuture<Integer> startInternal(
51 CommandSpec command,
52 EnvironmentSpec environment,
53 PipeSpec redirect) throws IOException {
54 consumer.accept(command.commandLine());
54 55 return CompletableFuture.completedFuture(0);
55 56 }
56 57 };
@@ -1,36 +1,28
1 1 package org.implab.gradle.common.exec;
2 2
3 import java.io.File;
4 3 import java.io.IOException;
5 4 import java.lang.ProcessBuilder.Redirect;
6 5 import java.util.ArrayList;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Optional;
10 6 import java.util.concurrent.CompletableFuture;
11 7
12 8 class SystemExecBuilder extends ExecBuilder {
13 9 @Override
14 10 protected CompletableFuture<Integer> startInternal(
15 Map<String, String> environment,
16 Optional<File> directory,
17 List<String> commandLine,
18 Optional<RedirectFrom> stdinRedirect,
19 Optional<RedirectTo> stdoutRedirect,
20 Optional<RedirectTo> stderrRedirect) throws IOException {
11 CommandSpec command,
12 EnvironmentSpec environment,
13 PipeSpec redirect) throws IOException {
21 14
22 var builder = new ProcessBuilder(commandLine);
23
24 directory.ifPresent(builder::directory);
15 var builder = new ProcessBuilder(command.commandLine());
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 21 var tasks = new ArrayList<CompletableFuture<?>>();
30 22
31 if (!stdoutRedirect.isPresent())
23 if (!redirect.stdout().isPresent())
32 24 builder.redirectOutput(Redirect.DISCARD);
33 if (!stderrRedirect.isPresent())
25 if (!redirect.stderr().isPresent())
34 26 builder.redirectError(Redirect.DISCARD);
35 27
36 28 // run process
@@ -38,9 +30,9 class SystemExecBuilder extends ExecBuil
38 30
39 31 tasks.add(proc.onExit());
40 32
41 stdinRedirect.map(from -> from.redirect(proc.getOutputStream())).ifPresent(tasks::add);
42 stdoutRedirect.map(to -> to.redirect(proc.getInputStream())).ifPresent(tasks::add);
43 stderrRedirect.map(to -> to.redirect(proc.getErrorStream())).ifPresent(tasks::add);
33 redirect.stdin().map(from -> from.redirect(proc.getOutputStream())).ifPresent(tasks::add);
34 redirect.stdout().map(to -> to.redirect(proc.getInputStream())).ifPresent(tasks::add);
35 redirect.stderr().map(to -> to.redirect(proc.getErrorStream())).ifPresent(tasks::add);
44 36
45 37 return CompletableFuture
46 38 .allOf(tasks.toArray(new CompletableFuture<?>[0]))
@@ -91,10 +91,10 public abstract class ShellExecTask
91 91
92 92 @TaskAction
93 93 public final void run() throws IOException, InterruptedException, ExecutionException {
94 var execBuilder = execBuilder()
95 .workingDirectory(getWorkingDirectory().get().getAsFile())
96 .environment(getEnvironment().getOrElse(Map.of()))
97 .commandLine(getCommandLine().get());
94 var execBuilder = execBuilder();
95 execBuilder.workingDirectory(getWorkingDirectory().get().getAsFile());
96 execBuilder.environment(getEnvironment().getOrElse(Map.of()));
97 execBuilder.commandLine(getCommandLine().get());
98 98
99 99 getStdout().getRedirection().ifPresent(execBuilder::stdout);
100 100 getStderr().getRedirection().ifPresent(execBuilder::stderr);
@@ -2,7 +2,6 package org.implab.gradle.common.utils;
2 2
3 3 import java.util.Iterator;
4 4 import java.util.Map;
5 import java.util.Spliterator;
6 5 import java.util.Spliterators;
7 6 import java.util.Map.Entry;
8 7 import java.util.Optional;
@@ -21,6 +20,7 public final class Values {
21 20
22 21 /**
23 22 * Converts values in the specified map
23 *
24 24 * @param <K>
25 25 * @param <V>
26 26 * @param <U>
@@ -35,7 +35,8 public final class Values {
35 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 41 public static String toString(Object value) {
41 42 if (value == null) {
@@ -52,9 +53,9 public final class Values {
52 53 }
53 54
54 55 public static <T> Stream<T> stream(Iterator<T> remaining) {
55 var spliterator = Spliterators.spliteratorUnknownSize(remaining, 0);
56
57 return StreamSupport.stream(spliterator, false);
56 return StreamSupport.stream(
57 Spliterators.spliteratorUnknownSize(remaining, 0),
58 false);
58 59 }
59 60
60 61 public static <T> Optional<T> take(Iterator<T> iterator) {
General Comments 0
You need to be logged in to leave comments. Login now