##// END OF EJS Templates
WIP exec api
cin -
r13:59dae0731c45 default
parent child
Show More
@@ -1,5 +1,7
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
@@ -17,6 +19,22 public class RedirectFromSpec {
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;
@@ -1,7 +1,5
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
@@ -12,7 +10,8 public interface CommandBuilder {
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) {
@@ -20,10 +19,12 public interface CommandBuilder {
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) {
@@ -33,6 +34,7 public interface CommandBuilder {
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());
@@ -41,10 +43,13 public interface CommandBuilder {
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. */
@@ -1,13 +1,10
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
@@ -19,18 +16,18 class EchoExecBuilder extends ExecBuilde
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))
@@ -8,16 +8,22 import org.eclipse.jdt.annotation.NonNul
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());
@@ -97,6 +97,14 public abstract class ExecBuilder implem
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
@@ -121,7 +129,7 public abstract class ExecBuilder implem
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;
@@ -139,7 +147,7 public abstract class ExecBuilder implem
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;
@@ -157,20 +165,35 public abstract class ExecBuilder implem
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
@@ -188,12 +211,55 public abstract class ExecBuilder implem
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,10 +1,7
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
@@ -39,18 +36,22 public interface ExecShell {
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 };
@@ -1,36 +1,28
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
@@ -38,9 +30,9 class SystemExecBuilder extends ExecBuil
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]))
@@ -91,10 +91,10 public abstract class ShellExecTask
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);
@@ -2,7 +2,6 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;
@@ -21,6 +20,7 public final class Values {
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>
@@ -35,7 +35,8 public final class Values {
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) {
@@ -52,9 +53,9 public final class Values {
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) {
General Comments 0
You need to be logged in to leave comments. Login now