##// 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 dependencies {
14 dependencies {
15 compileOnly "org.eclipse.jdt:org.eclipse.jdt.annotation:2.3.0"
15 compileOnly libs.jdt.annotations
16
16 api gradleApi()
17 api gradleApi()
17 }
18 }
18
19
@@ -1,5 +1,7
1 package org.implab.gradle.common.exec;
1 package org.implab.gradle.common.exec;
2
2
3 import java.util.function.Consumer;
4
3 import org.eclipse.jdt.annotation.NonNullByDefault;
5 import org.eclipse.jdt.annotation.NonNullByDefault;
4 import org.implab.gradle.common.utils.Values;
6 import org.implab.gradle.common.utils.Values;
5
7
@@ -42,8 +44,22 public interface CommandBuilder {
42 return this;
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 /** Adds the specified arguments to this builder */
61 /** Adds the specified arguments to this builder */
46 CommandBuilder addArguments(String arg0, String... args);
62 CommandBuilder addArguments(String... args);
47
63
48 default CommandBuilder addArguments(Iterable<String> args) {
64 default CommandBuilder addArguments(Iterable<String> args) {
49 for (String arg : args)
65 for (String arg : args)
@@ -9,13 +9,15 import org.eclipse.jdt.annotation.NonNul
9 @NonNullByDefault
9 @NonNullByDefault
10 public interface EnvironmentBuilder {
10 public interface EnvironmentBuilder {
11 /** Sets the specified environment variable */
11 /** Sets the specified environment variable */
12 EnvironmentBuilder setVariable(String envVar, String value);
12 EnvironmentBuilder putEnvironment(String envVar, String value);
13
13
14 /** Replaces environment with the supplied one */
14 /** Replaces environment with the supplied one */
15 EnvironmentBuilder environment(Map<String, ? extends String> env);
15 EnvironmentBuilder environment(Map<String, ? extends String> env);
16
16
17 /** Unsets the specified variable. If the variable is inherited it removed anyway. */
17 /**
18 EnvironmentBuilder unsetVariable(String envVar);
18 * Enables or disables environment inheritance for the child process
19 */
20 EnvironmentBuilder inheritEnvironment(boolean inherit);
19
21
20 /** Specifies the working directory */
22 /** Specifies the working directory */
21 EnvironmentBuilder workingDirectory(File directory);
23 EnvironmentBuilder workingDirectory(File directory);
@@ -5,6 +5,9 import java.util.Map;
5 import java.util.Optional;
5 import java.util.Optional;
6
6
7 public interface EnvironmentSpec {
7 public interface EnvironmentSpec {
8
9 boolean inheritEnvironment();
10
8 Map<String,String> environment();
11 Map<String,String> environment();
9
12
10 Optional<File> workingDirectory();
13 Optional<File> workingDirectory();
@@ -21,12 +21,13 public abstract class ExecBuilder implem
21 CommandBuilder,
21 CommandBuilder,
22 PipeBuilder,
22 PipeBuilder,
23 EnvironmentBuilder,
23 EnvironmentBuilder,
24 Runnable
24 Executable {
25 {
26 private String executable;
25 private String executable;
27
26
28 private final List<String> arguments = new ArrayList<>();
27 private final List<String> arguments = new ArrayList<>();
29
28
29 private boolean inheritEnvironment = true;
30
30 private final Map<String, String> environment = new HashMap<>();
31 private final Map<String, String> environment = new HashMap<>();
31
32
32 private @Nullable File directory;
33 private @Nullable File directory;
@@ -54,12 +55,9 public abstract class ExecBuilder implem
54 }
55 }
55
56
56 @Override
57 @Override
57 public ExecBuilder addArguments(String arg0, String... args) {
58 public ExecBuilder addArguments(String... args) {
58 requireNonNull(arg0, "arg0 parameter can't be null");
59 arguments.add(arg0);
60
61 for (var arg : args)
59 for (var arg : args)
62 arguments.add(arg);
60 arguments.add(requireNonNull(arg, "arguments element shouldn't be null"));
63
61
64 return this;
62 return this;
65 }
63 }
@@ -81,6 +79,12 public abstract class ExecBuilder implem
81 return this;
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 * Sets the environment value. The value cannot be null.
89 * Sets the environment value. The value cannot be null.
86 *
90 *
@@ -88,7 +92,7 public abstract class ExecBuilder implem
88 * @param value The value to set,
92 * @param value The value to set,
89 */
93 */
90 @Override
94 @Override
91 public ExecBuilder setVariable(String envVar, String value) {
95 public ExecBuilder putEnvironment(String envVar, String value) {
92 requireNonNull(value, "Value can't be null");
96 requireNonNull(value, "Value can't be null");
93 requireNonNull(envVar, "envVar parameter can't be null");
97 requireNonNull(envVar, "envVar parameter can't be null");
94
98
@@ -97,14 +101,6 public abstract class ExecBuilder implem
97 }
101 }
98
102
99 @Override
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 requireNonNull(env, "env parameter can't be null");
105 requireNonNull(env, "env parameter can't be null");
110
106
@@ -202,7 +198,7 public abstract class ExecBuilder implem
202 * @return
198 * @return
203 * @throws IOException
199 * @throws IOException
204 */
200 */
205 public CompletableFuture<Integer> run() throws IOException {
201 public CompletableFuture<Integer> exec() throws IOException {
206 if (executable == null || executable.isEmpty())
202 if (executable == null || executable.isEmpty())
207 throw new IllegalStateException("The executable isn't set");
203 throw new IllegalStateException("The executable isn't set");
208
204
@@ -213,8 +209,7 public abstract class ExecBuilder implem
213 return startInternal(
209 return startInternal(
214 new SelfCommandSpec(),
210 new SelfCommandSpec(),
215 new SelfEnvironmentSpec(),
211 new SelfEnvironmentSpec(),
216 new SelfPipeSpec()
212 new SelfPipeSpec());
217 );
218 }
213 }
219
214
220 private class SelfCommandSpec implements CommandSpec {
215 private class SelfCommandSpec implements CommandSpec {
@@ -231,6 +226,10 public abstract class ExecBuilder implem
231 }
226 }
232
227
233 private class SelfEnvironmentSpec implements EnvironmentSpec {
228 private class SelfEnvironmentSpec implements EnvironmentSpec {
229 @Override
230 public boolean inheritEnvironment() {
231 return inheritEnvironment;
232 }
234
233
235 @Override
234 @Override
236 public Map<String, String> environment() {
235 public Map<String, String> environment() {
@@ -4,16 +4,15 import java.io.IOException;
4 import java.util.concurrent.CompletableFuture;
4 import java.util.concurrent.CompletableFuture;
5 import java.util.concurrent.CompletionException;
5 import java.util.concurrent.CompletionException;
6
6
7 public interface Runnable {
7 public interface Executable {
8 CompletableFuture<Integer> run() throws IOException;
8 CompletableFuture<Integer> exec() throws IOException;
9
9
10 /** Starts process and will throw error if error code is non-zero */
10 /** Starts process and will throw error if error code is non-zero */
11 default CompletableFuture<Integer> run(boolean throwOnError) throws IOException {
11 default CompletableFuture<Void> execChecked() throws IOException {
12 return run().thenApply(code -> {
12 return exec().thenAccept(code -> {
13 if (!throwOnError && code != 0)
13 if (code != 0)
14 throw new CompletionException(new IOException(
14 throw new CompletionException(new IOException(
15 String.format("The process is terminated with code %d", code)));
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 import java.io.OutputStream;
6 import java.io.OutputStream;
7 import java.util.concurrent.CompletableFuture;
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 * lazy redirection. {@link #redirect(OutputStream)} is called when the process
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 public interface RedirectFrom {
15 public interface RedirectFrom {
14 CompletableFuture<Void> redirect(OutputStream to);
16 CompletableFuture<Void> redirect(OutputStream to);
15
17
18 /**
19 * Read file contents and redirect it to the output stream.
20 */
16 public static RedirectFrom file(final File file) {
21 public static RedirectFrom file(final File file) {
17 return to -> CompletableFuture.runAsync(() -> {
22 return to -> CompletableFuture.runAsync(() -> {
18 try (var from = new FileInputStream(file); to) {
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 import org.eclipse.jdt.annotation.NonNullByDefault;
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 @NonNullByDefault
19 @NonNullByDefault
17 public interface RedirectTo {
20 public interface RedirectTo {
@@ -20,6 +23,7 public interface RedirectTo {
20 public interface StringConsumer extends Consumer<String> {
23 public interface StringConsumer extends Consumer<String> {
21 }
24 }
22
25
26 /** Creates a redirect to the specified consumer */
23 public static RedirectTo consumer(final Consumer<String> consumer) {
27 public static RedirectTo consumer(final Consumer<String> consumer) {
24 return consumer(new StringConsumer() {
28 return consumer(new StringConsumer() {
25 @Override
29 @Override
@@ -29,6 +33,7 public interface RedirectTo {
29 });
33 });
30 }
34 }
31
35
36 /** Creates a redirect to the specified consumer */
32 public static RedirectTo consumer(final StringConsumer consumer) {
37 public static RedirectTo consumer(final StringConsumer consumer) {
33 return (src) -> CompletableFuture.runAsync(() -> {
38 return (src) -> CompletableFuture.runAsync(() -> {
34 try (Scanner sc = new Scanner(src)) {
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 public static RedirectTo file(final File file) {
52 public static RedirectTo file(final File file) {
43 return src -> CompletableFuture.runAsync(() -> {
53 return src -> CompletableFuture.runAsync(() -> {
44 try (OutputStream out = new FileOutputStream(file)) {
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 public static RedirectTo stream(final OutputStream dest) {
63 public static RedirectTo stream(final OutputStream dest) {
53 return src -> CompletableFuture.runAsync(() -> {
64 return src -> CompletableFuture.runAsync(() -> {
54 try (dest; src) {
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 public static RedirectTo any(final Object output) {
77 public static RedirectTo any(final Object output) {
63 if (output instanceof StringConsumer fn) {
78 if (output instanceof StringConsumer fn) {
64 return consumer(s -> fn.accept(s));
79 return consumer(s -> fn.accept(s));
@@ -16,6 +16,10 class SystemExecBuilder extends ExecBuil
16
16
17 environment.workingDirectory().ifPresent(builder::directory);
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 builder.environment().putAll(environment.environment());
23 builder.environment().putAll(environment.environment());
20
24
21 var tasks = new ArrayList<CompletableFuture<?>>();
25 var tasks = new ArrayList<CompletableFuture<?>>();
@@ -100,7 +100,7 public abstract class ShellExecTask
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.exec().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 {
General Comments 0
You need to be logged in to leave comments. Login now