| @@ -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 |
|
|
|
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( |
|
|
|
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 |
|
|
|
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(); |
| @@ -21,12 +21,13 public abstract class ExecBuilder implem | |||
|
|
21 | 21 | CommandBuilder, |
|
|
22 | 22 | PipeBuilder, |
|
|
23 | 23 | EnvironmentBuilder, |
|
|
24 | Runnable | |
|
|
25 | { | |
|
|
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; |
| @@ -54,12 +55,9 public abstract class ExecBuilder implem | |||
|
|
54 | 55 | } |
|
|
55 | 56 | |
|
|
56 | 57 | @Override |
|
|
57 |
public ExecBuilder addArguments( |
|
|
|
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 | } |
| @@ -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 |
|
|
|
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,14 +101,6 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 | 104 | public ExecBuilder environment(Map<String,? extends String> env) { |
|
|
109 | 105 | requireNonNull(env, "env parameter can't be null"); |
|
|
110 | 106 | |
| @@ -202,7 +198,7 public abstract class ExecBuilder implem | |||
|
|
202 | 198 | * @return |
|
|
203 | 199 | * @throws IOException |
|
|
204 | 200 | */ |
|
|
205 |
public CompletableFuture<Integer> |
|
|
|
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 | |
| @@ -213,8 +209,7 public abstract class ExecBuilder implem | |||
|
|
213 | 209 | return startInternal( |
|
|
214 | 210 | new SelfCommandSpec(), |
|
|
215 | 211 | new SelfEnvironmentSpec(), |
|
|
216 | new SelfPipeSpec() | |
|
|
217 | ); | |
|
|
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() { |
| @@ -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 |
|
|
|
8 |
CompletableFuture<Integer> |
|
|
|
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< |
|
|
|
12 |
return |
|
|
|
13 |
if ( |
|
|
|
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)); |
| @@ -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. |
|
|
|
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
