##// END OF EJS Templates
WIP
cin -
r14:bed0567066c1 default
parent child
Show More
@@ -0,0 +1,7
1 [versions]
2 immutables = "2.10.1"
3 jdt = "2.3.0"
4
5 [libraries]
6 immutables = { module = "org.immutables:value", version.ref = "immutables" }
7 jdt-annotations = { module = "org.eclipse.jdt:org.eclipse.jdt.annotation", version.ref = "jdt" }
@@ -12,7 +12,8 java {
12 12 }
13 13
14 14 dependencies {
15 compileOnly "org.eclipse.jdt:org.eclipse.jdt.annotation:2.3.0"
15 compileOnly libs.jdt.annotations
16
16 17 api gradleApi()
17 18 }
18 19
@@ -1,5 +1,7
1 1 package org.implab.gradle.common.exec;
2 2
3 import java.util.function.Consumer;
4
3 5 import org.eclipse.jdt.annotation.NonNullByDefault;
4 6 import org.implab.gradle.common.utils.Values;
5 7
@@ -42,8 +44,22 public interface CommandBuilder {
42 44 return this;
43 45 }
44 46
47 default Consumer<Boolean> flag(String name) {
48 return f -> {
49 if (f)
50 addArguments(name);
51 };
52 }
53
54 default Consumer<String> param(String name) {
55 return v -> {
56 if (v != null && v.length() > 0)
57 addArguments(name, v);
58 };
59 }
60
45 61 /** Adds the specified arguments to this builder */
46 CommandBuilder addArguments(String arg0, String... args);
62 CommandBuilder addArguments(String... args);
47 63
48 64 default CommandBuilder addArguments(Iterable<String> args) {
49 65 for (String arg : args)
@@ -9,13 +9,15 import org.eclipse.jdt.annotation.NonNul
9 9 @NonNullByDefault
10 10 public interface EnvironmentBuilder {
11 11 /** Sets the specified environment variable */
12 EnvironmentBuilder setVariable(String envVar, String value);
12 EnvironmentBuilder putEnvironment(String envVar, String value);
13 13
14 14 /** Replaces environment with the supplied one */
15 15 EnvironmentBuilder environment(Map<String, ? extends String> env);
16 16
17 /** Unsets the specified variable. If the variable is inherited it removed anyway. */
18 EnvironmentBuilder unsetVariable(String envVar);
17 /**
18 * Enables or disables environment inheritance for the child process
19 */
20 EnvironmentBuilder inheritEnvironment(boolean inherit);
19 21
20 22 /** Specifies the working directory */
21 23 EnvironmentBuilder workingDirectory(File directory);
@@ -5,6 +5,9 import java.util.Map;
5 5 import java.util.Optional;
6 6
7 7 public interface EnvironmentSpec {
8
9 boolean inheritEnvironment();
10
8 11 Map<String,String> environment();
9 12
10 13 Optional<File> workingDirectory();
@@ -18,15 +18,16 import static java.util.Objects.requireN
18 18 /** Command line builder */
19 19 @NonNullByDefault
20 20 public abstract class ExecBuilder implements
21 CommandBuilder,
22 PipeBuilder,
23 EnvironmentBuilder,
24 Runnable
25 {
21 CommandBuilder,
22 PipeBuilder,
23 EnvironmentBuilder,
24 Executable {
26 25 private String executable;
27 26
28 27 private final List<String> arguments = new ArrayList<>();
29 28
29 private boolean inheritEnvironment = true;
30
30 31 private final Map<String, String> environment = new HashMap<>();
31 32
32 33 private @Nullable File directory;
@@ -48,18 +49,15 public abstract class ExecBuilder implem
48 49 public ExecBuilder arguments(Iterable<String> args) {
49 50 requireNonNull(args, "Args must not be null");
50 51 arguments.clear();
51 for(var arg: args)
52 for (var arg : args)
52 53 arguments.add(arg);
53 54 return this;
54 55 }
55 56
56 57 @Override
57 public ExecBuilder addArguments(String arg0, String... args) {
58 requireNonNull(arg0, "arg0 parameter can't be null");
59 arguments.add(arg0);
60
58 public ExecBuilder addArguments(String... args) {
61 59 for (var arg : args)
62 arguments.add(arg);
60 arguments.add(requireNonNull(arg, "arguments element shouldn't be null"));
63 61
64 62 return this;
65 63 }
@@ -68,7 +66,7 public abstract class ExecBuilder implem
68 66 @Override
69 67 public ExecBuilder workingDirectory(File directory) {
70 68 requireNonNull(directory, "directory parameter can't be null");
71
69
72 70 this.directory = directory;
73 71 return this;
74 72 }
@@ -81,6 +79,12 public abstract class ExecBuilder implem
81 79 return this;
82 80 }
83 81
82 @Override
83 public ExecBuilder inheritEnvironment(boolean inherit) {
84 this.inheritEnvironment = inherit;
85 return this;
86 }
87
84 88 /**
85 89 * Sets the environment value. The value cannot be null.
86 90 *
@@ -88,7 +92,7 public abstract class ExecBuilder implem
88 92 * @param value The value to set,
89 93 */
90 94 @Override
91 public ExecBuilder setVariable(String envVar, String value) {
95 public ExecBuilder putEnvironment(String envVar, String value) {
92 96 requireNonNull(value, "Value can't be null");
93 97 requireNonNull(envVar, "envVar parameter can't be null");
94 98
@@ -97,15 +101,7 public abstract class ExecBuilder implem
97 101 }
98 102
99 103 @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
108 public ExecBuilder environment(Map<String,? extends String> env) {
104 public ExecBuilder environment(Map<String, ? extends String> env) {
109 105 requireNonNull(env, "env parameter can't be null");
110 106
111 107 environment.clear();
@@ -123,7 +119,7 public abstract class ExecBuilder implem
123 119 @Override
124 120 public ExecBuilder stdin(RedirectFrom from) {
125 121 requireNonNull(from, "from parameter can't be null");
126
122
127 123 inputRedirect = from;
128 124 return this;
129 125 }
@@ -202,7 +198,7 public abstract class ExecBuilder implem
202 198 * @return
203 199 * @throws IOException
204 200 */
205 public CompletableFuture<Integer> run() throws IOException {
201 public CompletableFuture<Integer> exec() throws IOException {
206 202 if (executable == null || executable.isEmpty())
207 203 throw new IllegalStateException("The executable isn't set");
208 204
@@ -211,10 +207,9 public abstract class ExecBuilder implem
211 207 commandLine.addAll(arguments);
212 208
213 209 return startInternal(
214 new SelfCommandSpec(),
215 new SelfEnvironmentSpec(),
216 new SelfPipeSpec()
217 );
210 new SelfCommandSpec(),
211 new SelfEnvironmentSpec(),
212 new SelfPipeSpec());
218 213 }
219 214
220 215 private class SelfCommandSpec implements CommandSpec {
@@ -231,6 +226,10 public abstract class ExecBuilder implem
231 226 }
232 227
233 228 private class SelfEnvironmentSpec implements EnvironmentSpec {
229 @Override
230 public boolean inheritEnvironment() {
231 return inheritEnvironment;
232 }
234 233
235 234 @Override
236 235 public Map<String, String> environment() {
@@ -239,7 +238,7 public abstract class ExecBuilder implem
239 238
240 239 @Override
241 240 public Optional<File> workingDirectory() {
242 return Optional.ofNullable( directory);
241 return Optional.ofNullable(directory);
243 242 }
244 243 }
245 244
@@ -4,16 +4,15 import java.io.IOException;
4 4 import java.util.concurrent.CompletableFuture;
5 5 import java.util.concurrent.CompletionException;
6 6
7 public interface Runnable {
8 CompletableFuture<Integer> run() throws IOException;
7 public interface Executable {
8 CompletableFuture<Integer> exec() throws IOException;
9 9
10 10 /** Starts process and will throw error if error code is non-zero */
11 default CompletableFuture<Integer> run(boolean throwOnError) throws IOException {
12 return run().thenApply(code -> {
13 if (!throwOnError && code != 0)
11 default CompletableFuture<Void> execChecked() throws IOException {
12 return exec().thenAccept(code -> {
13 if (code != 0)
14 14 throw new CompletionException(new IOException(
15 15 String.format("The process is terminated with code %d", code)));
16 return code;
17 16 });
18 17 }
19 18 }
@@ -6,13 +6,18 import java.io.InputStream;
6 6 import java.io.OutputStream;
7 7 import java.util.concurrent.CompletableFuture;
8 8
9 /** Describes how to redirect input streams. This interface is used to configure
9 /**
10 * Describes how to redirect input streams. This interface is used to configure
10 11 * lazy redirection. {@link #redirect(OutputStream)} is called when the process
11 * is started.
12 * is started. Before the process is started the redirection isn't invoked and
13 * no resources are allocated or used.
12 14 */
13 15 public interface RedirectFrom {
14 16 CompletableFuture<Void> redirect(OutputStream to);
15 17
18 /**
19 * Read file contents and redirect it to the output stream.
20 */
16 21 public static RedirectFrom file(final File file) {
17 22 return to -> CompletableFuture.runAsync(() -> {
18 23 try (var from = new FileInputStream(file); to) {
@@ -45,5 +50,4 public interface RedirectFrom {
45 50 }
46 51 }
47 52
48
49 53 }
@@ -11,7 +11,10 import java.util.function.Consumer;
11 11 import org.eclipse.jdt.annotation.NonNullByDefault;
12 12
13 13 /**
14 * RedirectSpec
14 * Redirection specification for the {@link InputStream}. Redirection is invoked
15 * when the {@link InputStream} becomes available, for example, on process
16 * start. Before the process is started the redirection isn't invoked and no
17 * resources are allocated or used.
15 18 */
16 19 @NonNullByDefault
17 20 public interface RedirectTo {
@@ -20,6 +23,7 public interface RedirectTo {
20 23 public interface StringConsumer extends Consumer<String> {
21 24 }
22 25
26 /** Creates a redirect to the specified consumer */
23 27 public static RedirectTo consumer(final Consumer<String> consumer) {
24 28 return consumer(new StringConsumer() {
25 29 @Override
@@ -29,6 +33,7 public interface RedirectTo {
29 33 });
30 34 }
31 35
36 /** Creates a redirect to the specified consumer */
32 37 public static RedirectTo consumer(final StringConsumer consumer) {
33 38 return (src) -> CompletableFuture.runAsync(() -> {
34 39 try (Scanner sc = new Scanner(src)) {
@@ -39,6 +44,11 public interface RedirectTo {
39 44 });
40 45 }
41 46
47 /**
48 * Creates a redirect to the specified file. There will be opened the output
49 * stream in this redirection and original stream will be transferred to this
50 * this output stream.
51 */
42 52 public static RedirectTo file(final File file) {
43 53 return src -> CompletableFuture.runAsync(() -> {
44 54 try (OutputStream out = new FileOutputStream(file)) {
@@ -49,6 +59,7 public interface RedirectTo {
49 59 });
50 60 }
51 61
62 /** Creates a redirect to the specified output stream. */
52 63 public static RedirectTo stream(final OutputStream dest) {
53 64 return src -> CompletableFuture.runAsync(() -> {
54 65 try (dest; src) {
@@ -59,6 +70,10 public interface RedirectTo {
59 70 });
60 71 }
61 72
73 /**
74 * Creates the redirection to the specified destination, actual type of
75 * redirection will be determined from the type of the output object.
76 */
62 77 public static RedirectTo any(final Object output) {
63 78 if (output instanceof StringConsumer fn) {
64 79 return consumer(s -> fn.accept(s));
@@ -8,7 +8,7 import java.util.concurrent.CompletableF
8 8 class SystemExecBuilder extends ExecBuilder {
9 9 @Override
10 10 protected CompletableFuture<Integer> startInternal(
11 CommandSpec command,
11 CommandSpec command,
12 12 EnvironmentSpec environment,
13 13 PipeSpec redirect) throws IOException {
14 14
@@ -16,6 +16,10 class SystemExecBuilder extends ExecBuil
16 16
17 17 environment.workingDirectory().ifPresent(builder::directory);
18 18
19 // if the env isn't inherited we need to clear it
20 if (!environment.inheritEnvironment())
21 builder.environment().clear();
22
19 23 builder.environment().putAll(environment.environment());
20 24
21 25 var tasks = new ArrayList<CompletableFuture<?>>();
@@ -100,7 +100,7 public abstract class ShellExecTask
100 100 getStderr().getRedirection().ifPresent(execBuilder::stderr);
101 101 getStdin().getRedirection().ifPresent(execBuilder::stdin);
102 102
103 execBuilder.run().thenAccept(ThrowingConsumer.guard(this::checkRetCode)).join();
103 execBuilder.exec().thenAccept(ThrowingConsumer.guard(this::checkRetCode)).join();
104 104 }
105 105
106 106 protected void checkRetCode(Integer code) throws IOException {
General Comments 0
You need to be logged in to leave comments. Login now