| @@ -0,0 +1,13 | |||||
|
|
1 | package org.implab.gradle.common.dsl; | |||
|
|
2 | ||||
|
|
3 | ||||
|
|
4 | import org.gradle.api.provider.ListProperty; | |||
|
|
5 | ||||
|
|
6 | public interface CommandSpec { | |||
|
|
7 | ListProperty<String> getCommandLine(); | |||
|
|
8 | ||||
|
|
9 | void commandLine(Object arg0, Object... args); | |||
|
|
10 | ||||
|
|
11 | void args(Object arg0, Object... args); | |||
|
|
12 | ||||
|
|
13 | } | |||
| @@ -0,0 +1,48 | |||||
|
|
1 | package org.implab.gradle.common.dsl; | |||
|
|
2 | ||||
|
|
3 | import java.util.HashMap; | |||
|
|
4 | import java.util.Map; | |||
|
|
5 | ||||
|
|
6 | import org.gradle.api.Action; | |||
|
|
7 | import org.gradle.api.file.DirectoryProperty; | |||
|
|
8 | import org.gradle.api.provider.MapProperty; | |||
|
|
9 | import org.implab.gradle.common.utils.Closures; | |||
|
|
10 | import org.implab.gradle.common.utils.Values; | |||
|
|
11 | ||||
|
|
12 | import groovy.lang.Closure; | |||
|
|
13 | ||||
|
|
14 | /** | |||
|
|
15 | * Configuration properties of the execution shell. This object specifies a | |||
|
|
16 | * working directory and environment variables for the processes started within | |||
|
|
17 | * this shell. | |||
|
|
18 | */ | |||
|
|
19 | public interface EnvironmentSpec { | |||
|
|
20 | ||||
|
|
21 | /** Working directory */ | |||
|
|
22 | DirectoryProperty getWorkingDirectory(); | |||
|
|
23 | ||||
|
|
24 | /** Environment variables */ | |||
|
|
25 | MapProperty<String, String> getEnvironment(); | |||
|
|
26 | ||||
|
|
27 | /** | |||
|
|
28 | * Configures the environment variable using the specified action. The | |||
|
|
29 | * action is called when the value is calculated; | |||
|
|
30 | */ | |||
|
|
31 | default void env(Action<Map<String, Object>> configure) { | |||
|
|
32 | var provider = getEnvironment() | |||
|
|
33 | .orElse(Map.of()) | |||
|
|
34 | .map((base) -> { | |||
|
|
35 | var props = new HashMap<String, Object>(base); | |||
|
|
36 | ||||
|
|
37 | configure.execute(props); | |||
|
|
38 | ||||
|
|
39 | return Values.mapValues(props, Values::toString); | |||
|
|
40 | }); | |||
|
|
41 | ||||
|
|
42 | getEnvironment().set(provider); | |||
|
|
43 | } | |||
|
|
44 | ||||
|
|
45 | default void env(Closure<?> configure) { | |||
|
|
46 | env(Closures.action(configure)); | |||
|
|
47 | } | |||
|
|
48 | } | |||
| @@ -0,0 +1,12 | |||||
|
|
1 | package org.implab.gradle.common.dsl; | |||
|
|
2 | ||||
|
|
3 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
4 | ||||
|
|
5 | @NonNullByDefault | |||
|
|
6 | public interface PipeSpec { | |||
|
|
7 | RedirectToSpec getStdout(); | |||
|
|
8 | ||||
|
|
9 | RedirectToSpec getStderr(); | |||
|
|
10 | ||||
|
|
11 | RedirectFromSpec getStdin(); | |||
|
|
12 | } | |||
| @@ -0,0 +1,34 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import java.util.stream.Stream; | |||
|
|
4 | ||||
|
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
6 | import org.implab.gradle.common.utils.Values; | |||
|
|
7 | ||||
|
|
8 | @NonNullByDefault | |||
|
|
9 | public interface CommandBuilder { | |||
|
|
10 | ||||
|
|
11 | CommandBuilder executable(String executable); | |||
|
|
12 | ||||
|
|
13 | default CommandBuilder commandLine(String executable, String... args) { | |||
|
|
14 | return executable(executable) | |||
|
|
15 | .arguments(args); | |||
|
|
16 | } | |||
|
|
17 | ||||
|
|
18 | default CommandBuilder arg(String arg0, String... args) { | |||
|
|
19 | return arguments(() -> Stream | |||
|
|
20 | .concat(Stream.of(arg0), Stream.of(args)) | |||
|
|
21 | .iterator()); | |||
|
|
22 | } | |||
|
|
23 | ||||
|
|
24 | default CommandBuilder arguments(String... args) { | |||
|
|
25 | return arguments(Values.iterable(args)); | |||
|
|
26 | } | |||
|
|
27 | ||||
|
|
28 | CommandBuilder arguments(Iterable<String> args); | |||
|
|
29 | ||||
|
|
30 | default CommandBuilder from(CommandSpec commandSpec) { | |||
|
|
31 | return executable(commandSpec.executable()) | |||
|
|
32 | .arguments(commandSpec.arguments()); | |||
|
|
33 | } | |||
|
|
34 | } | |||
| @@ -0,0 +1,16 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import java.util.List; | |||
|
|
4 | import java.util.stream.Stream; | |||
|
|
5 | ||||
|
|
6 | public interface CommandSpec { | |||
|
|
7 | ||||
|
|
8 | String executable(); | |||
|
|
9 | ||||
|
|
10 | List<String> arguments(); | |||
|
|
11 | ||||
|
|
12 | default List<String> commandLine() { | |||
|
|
13 | return Stream.concat(Stream.of(executable()), arguments().stream()).toList(); | |||
|
|
14 | } | |||
|
|
15 | ||||
|
|
16 | } | |||
| @@ -0,0 +1,25 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import java.io.File; | |||
|
|
4 | import java.util.Map; | |||
|
|
5 | import java.util.Optional; | |||
|
|
6 | ||||
|
|
7 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
8 | ||||
|
|
9 | @NonNullByDefault | |||
|
|
10 | public interface EnvironmentBuilder { | |||
|
|
11 | EnvironmentBuilder setVariable(String envVar, String value); | |||
|
|
12 | ||||
|
|
13 | EnvironmentBuilder environment(Map<String, ? extends String> env); | |||
|
|
14 | ||||
|
|
15 | EnvironmentBuilder unsetVariable(String envVar); | |||
|
|
16 | ||||
|
|
17 | EnvironmentBuilder workingDirectory(File directory); | |||
|
|
18 | ||||
|
|
19 | EnvironmentBuilder workingDirectory(Optional<? extends File> directory); | |||
|
|
20 | ||||
|
|
21 | default EnvironmentBuilder from(EnvironmentSpec environmentSpec) { | |||
|
|
22 | return environment(environmentSpec.environment()) | |||
|
|
23 | .workingDirectory(environmentSpec.workingDirectory()); | |||
|
|
24 | } | |||
|
|
25 | } | |||
| @@ -0,0 +1,11 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import java.io.File; | |||
|
|
4 | import java.util.Map; | |||
|
|
5 | import java.util.Optional; | |||
|
|
6 | ||||
|
|
7 | public interface EnvironmentSpec { | |||
|
|
8 | Map<String,String> environment(); | |||
|
|
9 | ||||
|
|
10 | Optional<File> workingDirectory(); | |||
|
|
11 | } | |||
| @@ -0,0 +1,27 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import java.util.Optional; | |||
|
|
4 | ||||
|
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
6 | ||||
|
|
7 | @NonNullByDefault | |||
|
|
8 | public interface PipeBuilder { | |||
|
|
9 | PipeBuilder stdin(RedirectFrom from); | |||
|
|
10 | ||||
|
|
11 | PipeBuilder stdin(Optional<? extends RedirectFrom> from); | |||
|
|
12 | ||||
|
|
13 | PipeBuilder stdout(RedirectTo to); | |||
|
|
14 | ||||
|
|
15 | PipeBuilder stdout(Optional<? extends RedirectTo> to); | |||
|
|
16 | ||||
|
|
17 | PipeBuilder stderr(RedirectTo to); | |||
|
|
18 | ||||
|
|
19 | PipeBuilder stderr(Optional<? extends RedirectTo> to); | |||
|
|
20 | ||||
|
|
21 | default PipeBuilder from(PipeSpec pipeSpec) { | |||
|
|
22 | return stdin(pipeSpec.stdin()) | |||
|
|
23 | .stdout(pipeSpec.stdout()) | |||
|
|
24 | .stderr(pipeSpec.stderr()); | |||
|
|
25 | } | |||
|
|
26 | ||||
|
|
27 | } | |||
| @@ -0,0 +1,14 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import java.util.Optional; | |||
|
|
4 | ||||
|
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
6 | ||||
|
|
7 | @NonNullByDefault | |||
|
|
8 | public interface PipeSpec { | |||
|
|
9 | Optional<RedirectTo> stdout(); | |||
|
|
10 | ||||
|
|
11 | Optional<RedirectTo> stderr(); | |||
|
|
12 | ||||
|
|
13 | Optional<RedirectFrom> stdin(); | |||
|
|
14 | } | |||
| @@ -0,0 +1,19 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import java.io.IOException; | |||
|
|
4 | import java.util.concurrent.CompletableFuture; | |||
|
|
5 | import java.util.concurrent.CompletionException; | |||
|
|
6 | ||||
|
|
7 | public interface Runnable { | |||
|
|
8 | CompletableFuture<Integer> run() throws IOException; | |||
|
|
9 | ||||
|
|
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) | |||
|
|
14 | throw new CompletionException(new IOException( | |||
|
|
15 | String.format("The process is terminated with code %d", code))); | |||
|
|
16 | return code; | |||
|
|
17 | }); | |||
|
|
18 | } | |||
|
|
19 | } | |||
| @@ -0,0 +1,18 | |||||
|
|
1 | package org.implab.gradle.common.utils; | |||
|
|
2 | ||||
|
|
3 | import java.util.concurrent.CompletionException; | |||
|
|
4 | import java.util.function.Consumer; | |||
|
|
5 | ||||
|
|
6 | public interface ThrowingConsumer<T, E extends Throwable> { | |||
|
|
7 | void accept(T value) throws E; | |||
|
|
8 | ||||
|
|
9 | static <T> Consumer<T> guard(ThrowingConsumer<T,?> target) { | |||
|
|
10 | return arg -> { | |||
|
|
11 | try { | |||
|
|
12 | target.accept(arg); | |||
|
|
13 | } catch (Throwable err) { | |||
|
|
14 | throw new CompletionException(err); | |||
|
|
15 | } | |||
|
|
16 | }; | |||
|
|
17 | } | |||
|
|
18 | } | |||
| @@ -0,0 +1,73 | |||||
|
|
1 | package org.implab.gradle.common.utils; | |||
|
|
2 | ||||
|
|
3 | import java.util.Iterator; | |||
|
|
4 | import java.util.Map; | |||
|
|
5 | import java.util.Map.Entry; | |||
|
|
6 | import java.util.function.Function; | |||
|
|
7 | import java.util.function.Supplier; | |||
|
|
8 | import java.util.stream.Collectors; | |||
|
|
9 | ||||
|
|
10 | import org.gradle.api.provider.Provider; | |||
|
|
11 | ||||
|
|
12 | public final class Values { | |||
|
|
13 | ||||
|
|
14 | private Values() { | |||
|
|
15 | } | |||
|
|
16 | ||||
|
|
17 | /** | |||
|
|
18 | * Converts values in the specified map | |||
|
|
19 | * @param <K> | |||
|
|
20 | * @param <V> | |||
|
|
21 | * @param <U> | |||
|
|
22 | * @param map | |||
|
|
23 | * @param mapper | |||
|
|
24 | * @return | |||
|
|
25 | */ | |||
|
|
26 | public static <K, V, U> Map<K, U> mapValues(Map<K, V> map, Function<V, U> mapper) { | |||
|
|
27 | Function<Entry<K, V>, V> getter = Entry::getValue; | |||
|
|
28 | ||||
|
|
29 | return map.entrySet().stream() | |||
|
|
30 | .collect(Collectors.toMap(Entry::getKey, getter.andThen(mapper))); | |||
|
|
31 | } | |||
|
|
32 | ||||
|
|
33 | /** Converts the supplied value to a string. | |||
|
|
34 | */ | |||
|
|
35 | public static String toString(Object value) { | |||
|
|
36 | if (value == null) { | |||
|
|
37 | return null; | |||
|
|
38 | } else if (value instanceof String string) { | |||
|
|
39 | return string; | |||
|
|
40 | } else if (value instanceof Provider<?> provider) { | |||
|
|
41 | return toString(provider.getOrNull()); | |||
|
|
42 | } else if (value instanceof Supplier<?> supplier) { | |||
|
|
43 | return toString(supplier.get()); | |||
|
|
44 | } else { | |||
|
|
45 | return value.toString(); | |||
|
|
46 | } | |||
|
|
47 | } | |||
|
|
48 | ||||
|
|
49 | public static <T> Iterable<T> iterable(T[] values) { | |||
|
|
50 | return () -> new ArrayIterator<>(values); | |||
|
|
51 | } | |||
|
|
52 | ||||
|
|
53 | private static class ArrayIterator<T> implements Iterator<T> { | |||
|
|
54 | private final T[] data; | |||
|
|
55 | ||||
|
|
56 | private int pos = 0; | |||
|
|
57 | ||||
|
|
58 | ArrayIterator(T[] data) { | |||
|
|
59 | this.data = data; | |||
|
|
60 | } | |||
|
|
61 | ||||
|
|
62 | @Override | |||
|
|
63 | public boolean hasNext() { | |||
|
|
64 | return pos < data.length; | |||
|
|
65 | } | |||
|
|
66 | ||||
|
|
67 | @Override | |||
|
|
68 | public T next() { | |||
|
|
69 | return data[pos++]; | |||
|
|
70 | } | |||
|
|
71 | } | |||
|
|
72 | ||||
|
|
73 | } | |||
| @@ -1,3 +1,4 | |||||
| 1 | syntax: glob |
|
1 | syntax: glob | |
| 2 | .gradle/ |
|
2 | .gradle/ | |
| 3 | common/build/ |
|
3 | common/build/ | |
|
|
4 | common/bin/ | |||
| @@ -1,7 +1,5 | |||||
| 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; |
|
|||
| 5 | import java.util.Optional; |
|
3 | import java.util.Optional; | |
| 6 | import java.util.function.Supplier; |
|
4 | import java.util.function.Supplier; | |
| 7 |
|
5 | |||
| @@ -19,19 +17,11 public class RedirectFromSpec { | |||||
| 19 | return streamRedirect != null ? Optional.ofNullable(streamRedirect.get()) : Optional.empty(); |
|
17 | return streamRedirect != null ? Optional.ofNullable(streamRedirect.get()) : Optional.empty(); | |
| 20 | } |
|
18 | } | |
| 21 |
|
19 | |||
| 22 |
public void from |
|
20 | public void from(Object input) { | |
| 23 | this.streamRedirect = () -> RedirectFrom.file(file); |
|
21 | if (input instanceof Provider<?> inputProvider) { | |
| 24 | } |
|
22 | this.streamRedirect = inputProvider.map(RedirectFrom::any)::get; | |
| 25 |
|
23 | } else { | ||
| 26 | public void fromFile(Provider<File> file) { |
|
24 | this.streamRedirect = () -> RedirectFrom.any(input); | |
| 27 | this.streamRedirect = file.map(RedirectFrom::file)::get; |
|
25 | } | |
| 28 | } |
|
|||
| 29 |
|
||||
| 30 | public void fromStream(InputStream stream) { |
|
|||
| 31 | this.streamRedirect = () -> RedirectFrom.stream(stream); |
|
|||
| 32 | } |
|
|||
| 33 |
|
||||
| 34 | public void fromStream(Provider<InputStream> stream) { |
|
|||
| 35 | this.streamRedirect = stream.map(RedirectFrom::stream)::get; |
|
|||
| 36 | } |
|
26 | } | |
| 37 | } |
|
27 | } | |
| @@ -6,37 +6,52 import java.util.Optional; | |||||
| 6 | import java.util.function.Consumer; |
|
6 | import java.util.function.Consumer; | |
| 7 | import java.util.function.Supplier; |
|
7 | import java.util.function.Supplier; | |
| 8 |
|
8 | |||
|
|
9 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
10 | import org.eclipse.jdt.annotation.Nullable; | |||
| 9 | import org.gradle.api.provider.Provider; |
|
11 | import org.gradle.api.provider.Provider; | |
| 10 | import org.implab.gradle.common.exec.RedirectTo; |
|
12 | import org.implab.gradle.common.exec.RedirectTo; | |
| 11 |
|
13 | |||
|
|
14 | @NonNullByDefault | |||
| 12 | public class RedirectToSpec { |
|
15 | public class RedirectToSpec { | |
| 13 | private Supplier<RedirectTo> streamRedirect; |
|
16 | private Supplier<RedirectTo> streamRedirect; | |
| 14 |
|
17 | |||
| 15 | public boolean isRedirected() { |
|
18 | public boolean isRedirected() { | |
| 16 |
return |
|
19 | return getRedirection().isPresent(); | |
| 17 | } |
|
20 | } | |
| 18 |
|
21 | |||
| 19 | public Optional<RedirectTo> getRedirection() { |
|
22 | public Optional<RedirectTo> getRedirection() { | |
| 20 | return streamRedirect != null ? Optional.ofNullable(streamRedirect.get()) : Optional.empty(); |
|
23 | return streamRedirect != null ? Optional.ofNullable(streamRedirect.get()) : Optional.empty(); | |
| 21 | } |
|
24 | } | |
| 22 |
|
25 | |||
|
|
26 | public @Nullable RedirectTo getRedirectionOrNull() { | |||
|
|
27 | return streamRedirect != null ? streamRedirect.get() : null; | |||
|
|
28 | } | |||
|
|
29 | ||||
| 23 | public void toFile(File file) { |
|
30 | public void toFile(File file) { | |
| 24 | this.streamRedirect = () -> RedirectTo.file(file); |
|
31 | this.streamRedirect = () -> RedirectTo.file(file); | |
| 25 | } |
|
32 | } | |
| 26 |
|
33 | |||
| 27 | public void toFile(Provider<File> file) { |
|
34 | public void toFile(Provider<File> fileProvider) { | |
| 28 | this.streamRedirect = file.map(RedirectTo::file)::get; |
|
35 | this.streamRedirect = fileProvider.map(RedirectTo::file)::getOrNull; | |
| 29 | } |
|
36 | } | |
| 30 |
|
37 | |||
| 31 | public void toStream(OutputStream stream) { |
|
38 | public void toStream(OutputStream stream) { | |
| 32 | this.streamRedirect = () -> RedirectTo.stream(stream); |
|
39 | this.streamRedirect = () -> RedirectTo.stream(stream); | |
| 33 | } |
|
40 | } | |
| 34 |
|
41 | |||
| 35 | public void toStream(Provider<OutputStream> stream) { |
|
42 | public void toStream(Provider<OutputStream> streamProvider) { | |
| 36 | this.streamRedirect = stream.map(RedirectTo::stream)::get; |
|
43 | this.streamRedirect = streamProvider.map(RedirectTo::stream)::getOrNull; | |
| 37 | } |
|
44 | } | |
| 38 |
|
45 | |||
| 39 | public void toConsumer(Consumer<String> consumer) { |
|
46 | public void to(Object output) { | |
|
|
47 | if (output instanceof Provider<?> outputProvider) { | |||
|
|
48 | this.streamRedirect = outputProvider.map(RedirectTo::any)::get; | |||
|
|
49 | } else { | |||
|
|
50 | this.streamRedirect = () -> RedirectTo.any(output); | |||
|
|
51 | } | |||
|
|
52 | } | |||
|
|
53 | ||||
|
|
54 | public void consume(Consumer<String> consumer) { | |||
| 40 | this.streamRedirect = () -> RedirectTo.consumer(consumer); |
|
55 | this.streamRedirect = () -> RedirectTo.consumer(consumer); | |
| 41 | } |
|
56 | } | |
| 42 | } |
|
57 | } | |
| @@ -18,15 +18,25 class EchoExecBuilder extends ExecBuilde | |||||
| 18 | } |
|
18 | } | |
| 19 |
|
19 | |||
| 20 | @Override |
|
20 | @Override | |
| 21 |
protected CompletableFuture<Integer> startInternal( |
|
21 | protected CompletableFuture<Integer> startInternal( | |
| 22 | List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect, |
|
22 | Map<String, String> environment, | |
|
|
23 | Optional<File> directory, | |||
|
|
24 | List<String> commandLine, | |||
|
|
25 | Optional<RedirectFrom> stdinRedirect, | |||
|
|
26 | Optional<RedirectTo> stdoutRedirect, | |||
| 23 | Optional<RedirectTo> stderrRedirect) throws IOException { |
|
27 | Optional<RedirectTo> stderrRedirect) throws IOException { | |
|
|
28 | ||||
| 24 | var outputRedirect = echoToStderr ? stderrRedirect : stdoutRedirect; |
|
29 | var outputRedirect = echoToStderr ? stderrRedirect : stdoutRedirect; | |
| 25 |
|
30 | |||
| 26 |
return outputRedirect |
|
31 | return outputRedirect | |
| 27 | var bytes = String.format("exec: %s", commandLine).getBytes(StandardCharsets.UTF_8); |
|
32 | .map(to -> { | |
| 28 | return to.redirect(new ByteArrayInputStream(bytes)).thenApply((x) -> 0); |
|
33 | var bytes = String.format("exec: %s", commandLine) | |
| 29 | }).orElse(CompletableFuture.completedFuture(0)); |
|
34 | .getBytes(StandardCharsets.UTF_8); | |
|
|
35 | ||||
|
|
36 | return to.redirect(new ByteArrayInputStream(bytes)) | |||
|
|
37 | .thenApply((x) -> 0); | |||
|
|
38 | }) | |||
|
|
39 | .orElse(CompletableFuture.completedFuture(0)); | |||
| 30 | } |
|
40 | } | |
| 31 |
|
41 | |||
| 32 | } |
|
42 | } | |
| @@ -4,26 +4,32 import java.util.ArrayList; | |||||
| 4 | import java.util.HashMap; |
|
4 | import java.util.HashMap; | |
| 5 | import java.util.List; |
|
5 | import java.util.List; | |
| 6 | import java.util.Map; |
|
6 | import java.util.Map; | |
| 7 | import java.util.Objects; |
|
|||
| 8 | import java.util.Optional; |
|
7 | import java.util.Optional; | |
| 9 | import java.util.concurrent.CompletableFuture; |
|
8 | import java.util.concurrent.CompletableFuture; | |
| 10 | import java.util.stream.Stream; |
|
|||
| 11 | import java.util.Collection; |
|
|||
| 12 |
|
9 | |||
| 13 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
10 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
|
|
11 | import org.eclipse.jdt.annotation.Nullable; | |||
| 14 |
|
12 | |||
| 15 | import java.io.File; |
|
13 | import java.io.File; | |
| 16 | import java.io.IOException; |
|
14 | import java.io.IOException; | |
| 17 |
|
15 | |||
|
|
16 | import static java.util.Objects.requireNonNull; | |||
|
|
17 | ||||
| 18 | /** Command line builder */ |
|
18 | /** Command line builder */ | |
| 19 | @NonNullByDefault |
|
19 | @NonNullByDefault | |
| 20 |
public abstract class ExecBuilder |
|
20 | public abstract class ExecBuilder implements | |
|
|
21 | CommandBuilder, | |||
|
|
22 | PipeBuilder, | |||
|
|
23 | EnvironmentBuilder, | |||
|
|
24 | Runnable | |||
|
|
25 | { | |||
|
|
26 | private String executable; | |||
| 21 |
|
27 | |||
| 22 |
private final List<String> |
|
28 | private final List<String> arguments = new ArrayList<>(); | |
| 23 |
|
29 | |||
| 24 | private final Map<String, String> environment = new HashMap<>(); |
|
30 | private final Map<String, String> environment = new HashMap<>(); | |
| 25 |
|
31 | |||
| 26 | private File directory; |
|
32 | private @Nullable File directory; | |
| 27 |
|
33 | |||
| 28 | private RedirectFrom inputRedirect; |
|
34 | private RedirectFrom inputRedirect; | |
| 29 |
|
35 | |||
| @@ -31,60 +37,83 public abstract class ExecBuilder { | |||||
| 31 |
|
37 | |||
| 32 | private RedirectTo errorRedirect; |
|
38 | private RedirectTo errorRedirect; | |
| 33 |
|
39 | |||
| 34 | /** Sets command line, clears previous one if any */ |
|
40 | @Override | |
| 35 |
public ExecBuilder |
|
41 | public ExecBuilder executable(String executable) { | |
| 36 | commandLine.clear(); |
|
42 | requireNonNull(executable, "cmd can't be null"); | |
| 37 | commandLine.add(cmd); |
|
43 | this.executable = executable; | |
| 38 | Stream.of(args).forEach(commandLine::add); |
|
44 | return this; | |
|
|
45 | } | |||
|
|
46 | ||||
|
|
47 | @Override | |||
|
|
48 | public ExecBuilder arguments(Iterable<String> args) { | |||
|
|
49 | requireNonNull(args, "Args must not be null"); | |||
|
|
50 | arguments.clear(); | |||
|
|
51 | for(var arg: args) | |||
|
|
52 | arguments.add(arg); | |||
| 39 | return this; |
|
53 | return this; | |
| 40 | } |
|
54 | } | |
| 41 |
|
55 | |||
| 42 |
public ExecBuilder command( |
|
56 | public ExecBuilder commandLine(Iterable<? extends String> cmd) { | |
| 43 | this.commandLine.clear(); |
|
57 | requireNonNull(cmd, "cmd can't be null"); | |
| 44 | this.commandLine.addAll(cmd); |
|
58 | ||
|
|
59 | this.arguments.clear(); | |||
|
|
60 | for (var arg : cmd) | |||
|
|
61 | this.arguments.add(arg); | |||
| 45 | return this; |
|
62 | return this; | |
| 46 | } |
|
63 | } | |
| 47 |
|
64 | |||
| 48 | /** Adds an argument to the command line */ |
|
65 | @Override | |
| 49 |
public ExecBuilder arg |
|
66 | public ExecBuilder arg(String arg0, String... args) { | |
| 50 |
|
|
67 | requireNonNull(arg0, "arg0 parameter can't be null"); | |
| 51 |
|
|
68 | arguments.add(arg0); | |
|
|
69 | ||||
|
|
70 | for (var arg : args) | |||
|
|
71 | arguments.add(arg); | |||
|
|
72 | ||||
| 52 | return this; |
|
73 | return this; | |
| 53 | } |
|
74 | } | |
| 54 |
|
75 | |||
| 55 | /** Sets the working directory */ |
|
76 | /** Sets the working directory */ | |
| 56 | public ExecBuilder directory(File directory) { |
|
77 | @Override | |
| 57 | Objects.requireNonNull(directory, "directory parameter can't be null"); |
|
78 | public ExecBuilder workingDirectory(File directory) { | |
|
|
79 | requireNonNull(directory, "directory parameter can't be null"); | |||
|
|
80 | ||||
| 58 | this.directory = directory; |
|
81 | this.directory = directory; | |
| 59 | return this; |
|
82 | return this; | |
| 60 | } |
|
83 | } | |
| 61 |
|
84 | |||
|
|
85 | @Override | |||
|
|
86 | public ExecBuilder workingDirectory(Optional<? extends File> directory) { | |||
|
|
87 | requireNonNull(directory, "directory parameter can't be null"); | |||
|
|
88 | ||||
|
|
89 | this.directory = directory.orElse(null); | |||
|
|
90 | return this; | |||
|
|
91 | } | |||
|
|
92 | ||||
| 62 | /** |
|
93 | /** | |
| 63 | * Sets the environment value. The value cannot be null. |
|
94 | * Sets the environment value. The value cannot be null. | |
| 64 | * |
|
95 | * | |
| 65 | * @param envVar The name of the environment variable |
|
96 | * @param envVar The name of the environment variable | |
| 66 | * @param value The value to set, |
|
97 | * @param value The value to set, | |
| 67 | */ |
|
98 | */ | |
| 68 | public ExecBuilder setEnvironment(String envVar, String value) { |
|
99 | @Override | |
| 69 | Objects.requireNonNull(value, "Value can't be null"); |
|
100 | public ExecBuilder setVariable(String envVar, String value) { | |
| 70 |
|
|
101 | requireNonNull(value, "Value can't be null"); | |
|
|
102 | requireNonNull(envVar, "envVar parameter can't be null"); | |||
|
|
103 | ||||
| 71 | environment.put(envVar, value); |
|
104 | environment.put(envVar, value); | |
| 72 | return this; |
|
105 | return this; | |
| 73 | } |
|
106 | } | |
| 74 |
|
107 | |||
| 75 | public ExecBuilder setEnvironment(Map<String, String> env) { |
|
108 | @Override | |
| 76 | Objects.requireNonNull(env, "env parameter can't be null"); |
|
109 | public ExecBuilder environment(Map<String,? extends String> env) { | |
|
|
110 | requireNonNull(env, "env parameter can't be null"); | |||
| 77 |
|
111 | |||
| 78 | environment.clear(); |
|
112 | environment.clear(); | |
| 79 | environment.putAll(env); |
|
113 | environment.putAll(env); | |
| 80 | return this; |
|
114 | return this; | |
| 81 | } |
|
115 | } | |
| 82 |
|
116 | |||
| 83 | public ExecBuilder unsetEnvironment(String envVar) { |
|
|||
| 84 | environment.remove(envVar); |
|
|||
| 85 | return this; |
|
|||
| 86 | } |
|
|||
| 87 |
|
||||
| 88 | /** |
|
117 | /** | |
| 89 | * Sets redirection for the stdin, {@link RedirectFrom} will be applied |
|
118 | * Sets redirection for the stdin, {@link RedirectFrom} will be applied | |
| 90 | * every time the process is started. |
|
119 | * every time the process is started. | |
| @@ -92,36 +121,61 public abstract class ExecBuilder { | |||||
| 92 | * <p> |
|
121 | * <p> | |
| 93 | * If redirection |
|
122 | * If redirection | |
| 94 | */ |
|
123 | */ | |
|
|
124 | @Override | |||
| 95 | public ExecBuilder stdin(RedirectFrom from) { |
|
125 | public ExecBuilder stdin(RedirectFrom from) { | |
| 96 |
|
|
126 | requireNonNull(from, "from parameter can't be null"); | |
|
|
127 | ||||
| 97 | inputRedirect = from; |
|
128 | inputRedirect = from; | |
| 98 | return this; |
|
129 | return this; | |
| 99 | } |
|
130 | } | |
| 100 |
|
131 | |||
|
|
132 | @Override | |||
|
|
133 | public PipeBuilder stdin(Optional<? extends RedirectFrom> from) { | |||
|
|
134 | requireNonNull(from, "from parameter can't be null"); | |||
|
|
135 | inputRedirect = from.orElse(null); | |||
|
|
136 | return this; | |||
|
|
137 | } | |||
|
|
138 | ||||
| 101 | /** |
|
139 | /** | |
| 102 | * Sets redirection for the stdout, {@link RedirectTo} will be applied |
|
140 | * Sets redirection for the stdout, {@link RedirectTo} will be applied | |
| 103 | * every time the process is started. |
|
141 | * every time the process is started. | |
| 104 | */ |
|
142 | */ | |
|
|
143 | @Override | |||
| 105 | public ExecBuilder stdout(RedirectTo out) { |
|
144 | public ExecBuilder stdout(RedirectTo out) { | |
| 106 |
|
|
145 | requireNonNull(out, "out parameter can't be null"); | |
| 107 | outputRedirect = out; |
|
146 | outputRedirect = out; | |
| 108 | return this; |
|
147 | return this; | |
| 109 | } |
|
148 | } | |
| 110 |
|
149 | |||
|
|
150 | @Override | |||
|
|
151 | public PipeBuilder stdout(Optional<? extends RedirectTo> to) { | |||
|
|
152 | requireNonNull(to, "from parameter can't be null"); | |||
|
|
153 | outputRedirect = to.orElse(null); | |||
|
|
154 | return this; | |||
|
|
155 | } | |||
|
|
156 | ||||
| 111 | /** |
|
157 | /** | |
| 112 | * Sets redirection for the stderr, {@link RedirectTo} will be applied |
|
158 | * Sets redirection for the stderr, {@link RedirectTo} will be applied | |
| 113 | * every time the process is started. |
|
159 | * every time the process is started. | |
| 114 | */ |
|
160 | */ | |
|
|
161 | @Override | |||
| 115 | public ExecBuilder stderr(RedirectTo err) { |
|
162 | public ExecBuilder stderr(RedirectTo err) { | |
| 116 |
|
|
163 | requireNonNull(err, "err parameter can't be null"); | |
| 117 | errorRedirect = err; |
|
164 | errorRedirect = err; | |
| 118 | return this; |
|
165 | return this; | |
| 119 | } |
|
166 | } | |
| 120 |
|
167 | |||
| 121 | /** Implement this function to */ |
|
168 | @Override | |
|
|
169 | public PipeBuilder stderr(Optional<? extends RedirectTo> to) { | |||
|
|
170 | requireNonNull(to, "from parameter can't be null"); | |||
|
|
171 | errorRedirect = to.orElse(null); | |||
|
|
172 | return this; | |||
|
|
173 | } | |||
|
|
174 | ||||
|
|
175 | /** Implement this function to */ | |||
| 122 | protected abstract CompletableFuture<Integer> startInternal( |
|
176 | protected abstract CompletableFuture<Integer> startInternal( | |
| 123 | Map<String, String> environment, |
|
177 | Map<String, String> environment, | |
| 124 | File directory, |
|
178 | Optional<File> directory, | |
| 125 | List<String> commandLine, |
|
179 | List<String> commandLine, | |
| 126 | Optional<RedirectFrom> stdinRedirect, |
|
180 | Optional<RedirectFrom> stdinRedirect, | |
| 127 | Optional<RedirectTo> stdoutRedirect, |
|
181 | Optional<RedirectTo> stdoutRedirect, | |
| @@ -134,10 +188,17 public abstract class ExecBuilder { | |||||
| 134 | * @return |
|
188 | * @return | |
| 135 | * @throws IOException |
|
189 | * @throws IOException | |
| 136 | */ |
|
190 | */ | |
| 137 |
public CompletableFuture<Integer> |
|
191 | public CompletableFuture<Integer> run() throws IOException { | |
|
|
192 | if (executable == null || executable.isEmpty()) | |||
|
|
193 | throw new IllegalStateException("The executable isn't set"); | |||
|
|
194 | ||||
|
|
195 | var commandLine = new ArrayList<String>(); | |||
|
|
196 | commandLine.add(executable); | |||
|
|
197 | commandLine.addAll(arguments); | |||
|
|
198 | ||||
| 138 | return startInternal( |
|
199 | return startInternal( | |
| 139 | environment, |
|
200 | environment, | |
| 140 | directory, |
|
201 | Optional.ofNullable(directory), | |
| 141 | commandLine, |
|
202 | commandLine, | |
| 142 | Optional.ofNullable(inputRedirect), |
|
203 | Optional.ofNullable(inputRedirect), | |
| 143 | Optional.ofNullable(outputRedirect), |
|
204 | Optional.ofNullable(outputRedirect), | |
| @@ -12,7 +12,7 import java.util.function.Consumer; | |||||
| 12 | public interface ExecShell { |
|
12 | public interface ExecShell { | |
| 13 |
|
13 | |||
| 14 | /** Creates new process builder {@link ExecBuilder} */ |
|
14 | /** Creates new process builder {@link ExecBuilder} */ | |
| 15 |
ExecBuilder b |
|
15 | ExecBuilder executable(); | |
| 16 |
|
16 | |||
| 17 | /** |
|
17 | /** | |
| 18 | * Creates default process execution "shell" which will execute processes |
|
18 | * Creates default process execution "shell" which will execute processes | |
| @@ -47,7 +47,7 public interface ExecShell { | |||||
| 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, File directory, |
|
50 | protected CompletableFuture<Integer> startInternal(Map<String, String> environment, Optional<File> directory, | |
| 51 | List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect, |
|
51 | List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect, | |
| 52 | Optional<RedirectTo> stderrRedirect) throws IOException { |
|
52 | Optional<RedirectTo> stderrRedirect) throws IOException { | |
| 53 | consumer.accept(commandLine); |
|
53 | consumer.accept(commandLine); | |
| @@ -33,5 +33,17 public interface RedirectFrom { | |||||
| 33 | }); |
|
33 | }); | |
| 34 | } |
|
34 | } | |
| 35 |
|
35 | |||
|
|
36 | public static RedirectFrom any(final Object output) { | |||
|
|
37 | if (output instanceof File f) { | |||
|
|
38 | return file(f); | |||
|
|
39 | } else if (output instanceof InputStream stm) { | |||
|
|
40 | return stream(stm); | |||
|
|
41 | } else if (output instanceof RedirectFrom self) { | |||
|
|
42 | return self; | |||
|
|
43 | } else { | |||
|
|
44 | throw new IllegalArgumentException("The specified argument type isn't supported: " + output.getClass()); | |||
|
|
45 | } | |||
|
|
46 | } | |||
|
|
47 | ||||
| 36 |
|
48 | |||
| 37 | } |
|
49 | } | |
| @@ -8,14 +8,28 import java.util.Scanner; | |||||
| 8 | import java.util.concurrent.CompletableFuture; |
|
8 | import java.util.concurrent.CompletableFuture; | |
| 9 | import java.util.function.Consumer; |
|
9 | import java.util.function.Consumer; | |
| 10 |
|
10 | |||
|
|
11 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
12 | ||||
| 11 | /** |
|
13 | /** | |
| 12 | * RedirectSpec |
|
14 | * RedirectSpec | |
| 13 | */ |
|
15 | */ | |
|
|
16 | @NonNullByDefault | |||
| 14 | public interface RedirectTo { |
|
17 | public interface RedirectTo { | |
| 15 | CompletableFuture<Void> redirect(InputStream from); |
|
18 | CompletableFuture<Void> redirect(InputStream from); | |
| 16 |
|
19 | |||
|
|
20 | public interface StringConsumer extends Consumer<String> { | |||
|
|
21 | } | |||
|
|
22 | ||||
| 17 | public static RedirectTo consumer(final Consumer<String> consumer) { |
|
23 | public static RedirectTo consumer(final Consumer<String> consumer) { | |
|
|
24 | return consumer(new StringConsumer() { | |||
|
|
25 | @Override | |||
|
|
26 | public void accept(String s) { | |||
|
|
27 | consumer.accept(s); | |||
|
|
28 | } | |||
|
|
29 | }); | |||
|
|
30 | } | |||
| 18 |
|
31 | |||
|
|
32 | public static RedirectTo consumer(final StringConsumer consumer) { | |||
| 19 | return (src) -> CompletableFuture.runAsync(() -> { |
|
33 | return (src) -> CompletableFuture.runAsync(() -> { | |
| 20 | try (Scanner sc = new Scanner(src)) { |
|
34 | try (Scanner sc = new Scanner(src)) { | |
| 21 | while (sc.hasNextLine()) { |
|
35 | while (sc.hasNextLine()) { | |
| @@ -44,4 +58,18 public interface RedirectTo { | |||||
| 44 | } |
|
58 | } | |
| 45 | }); |
|
59 | }); | |
| 46 | } |
|
60 | } | |
|
|
61 | ||||
|
|
62 | public static RedirectTo any(final Object output) { | |||
|
|
63 | if (output instanceof StringConsumer fn) { | |||
|
|
64 | return consumer(s -> fn.accept(s)); | |||
|
|
65 | } else if (output instanceof File f) { | |||
|
|
66 | return file(f); | |||
|
|
67 | } else if (output instanceof OutputStream stm) { | |||
|
|
68 | return stream(stm); | |||
|
|
69 | } else if (output instanceof RedirectTo self) { | |||
|
|
70 | return self; | |||
|
|
71 | } else { | |||
|
|
72 | throw new IllegalArgumentException("The specified argument type isn't supported: " + output.getClass()); | |||
|
|
73 | } | |||
|
|
74 | } | |||
| 47 | } No newline at end of file |
|
75 | } | |
| @@ -11,12 +11,17 import java.util.concurrent.CompletableF | |||||
| 11 |
|
11 | |||
| 12 | class SystemExecBuilder extends ExecBuilder { |
|
12 | class SystemExecBuilder extends ExecBuilder { | |
| 13 | @Override |
|
13 | @Override | |
| 14 |
protected CompletableFuture<Integer> startInternal( |
|
14 | protected CompletableFuture<Integer> startInternal( | |
| 15 | List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect, |
|
15 | Map<String, String> environment, | |
| 16 | Optional<RedirectTo> stderrRedirect) throws IOException { |
|
16 | Optional<File> directory, | |
|
|
17 | List<String> commandLine, | |||
|
|
18 | Optional<RedirectFrom> stdinRedirect, | |||
|
|
19 | Optional<RedirectTo> stdoutRedirect, | |||
|
|
20 | Optional<RedirectTo> stderrRedirect) throws IOException { | |||
| 17 |
|
21 | |||
| 18 | var builder = new ProcessBuilder(commandLine) |
|
22 | var builder = new ProcessBuilder(commandLine); | |
| 19 | .directory(directory); |
|
23 | ||
|
|
24 | directory.ifPresent(builder::directory); | |||
| 20 |
|
25 | |||
| 21 | builder.environment().putAll(environment); |
|
26 | builder.environment().putAll(environment); | |
| 22 |
|
27 | |||
| @@ -1,12 +1,29 | |||||
| 1 | package org.implab.gradle.common.tasks; |
|
1 | package org.implab.gradle.common.tasks; | |
| 2 |
|
2 | |||
|
|
3 | import java.io.IOException; | |||
|
|
4 | import java.util.Map; | |||
|
|
5 | import java.util.concurrent.ExecutionException; | |||
|
|
6 | import java.util.stream.Stream; | |||
|
|
7 | ||||
| 3 | import org.gradle.api.DefaultTask; |
|
8 | import org.gradle.api.DefaultTask; | |
|
|
9 | import org.gradle.api.file.DirectoryProperty; | |||
| 4 | import org.gradle.api.provider.ListProperty; |
|
10 | import org.gradle.api.provider.ListProperty; | |
|
|
11 | import org.gradle.api.provider.MapProperty; | |||
| 5 | import org.gradle.api.tasks.Internal; |
|
12 | import org.gradle.api.tasks.Internal; | |
|
|
13 | import org.gradle.api.tasks.TaskAction; | |||
|
|
14 | import org.implab.gradle.common.dsl.CommandSpec; | |||
|
|
15 | import org.implab.gradle.common.dsl.PipeSpec; | |||
| 6 | import org.implab.gradle.common.dsl.RedirectFromSpec; |
|
16 | import org.implab.gradle.common.dsl.RedirectFromSpec; | |
| 7 | import org.implab.gradle.common.dsl.RedirectToSpec; |
|
17 | import org.implab.gradle.common.dsl.RedirectToSpec; | |
|
|
18 | import org.implab.gradle.common.dsl.EnvironmentSpec; | |||
|
|
19 | import org.implab.gradle.common.exec.ExecBuilder; | |||
|
|
20 | import org.implab.gradle.common.utils.ObjectsMixin; | |||
|
|
21 | import org.implab.gradle.common.utils.Strings; | |||
|
|
22 | import org.implab.gradle.common.utils.ThrowingConsumer; | |||
| 8 |
|
23 | |||
| 9 |
public abstract class Exec |
|
24 | public abstract class ShellExecTask | |
|
|
25 | extends DefaultTask | |||
|
|
26 | implements CommandSpec, PipeSpec, EnvironmentSpec, ObjectsMixin { | |||
| 10 |
|
27 | |||
| 11 | private final RedirectToSpec redirectStderr = new RedirectToSpec(); |
|
28 | private final RedirectToSpec redirectStderr = new RedirectToSpec(); | |
| 12 |
|
29 | |||
| @@ -15,13 +32,22 public abstract class ExecuteTask extend | |||||
| 15 | private final RedirectFromSpec redirectStdin = new RedirectFromSpec(); |
|
32 | private final RedirectFromSpec redirectStdin = new RedirectFromSpec(); | |
| 16 |
|
33 | |||
| 17 | @Internal |
|
34 | @Internal | |
|
|
35 | @Override | |||
|
|
36 | public abstract DirectoryProperty getWorkingDirectory(); | |||
|
|
37 | ||||
|
|
38 | @Internal | |||
|
|
39 | @Override | |||
|
|
40 | public abstract MapProperty<String, String> getEnvironment(); | |||
|
|
41 | ||||
|
|
42 | @Internal | |||
|
|
43 | @Override | |||
| 18 | public abstract ListProperty<String> getCommandLine(); |
|
44 | public abstract ListProperty<String> getCommandLine(); | |
| 19 |
|
45 | |||
| 20 |
|
||||
| 21 | /** |
|
46 | /** | |
| 22 | * STDIN redirection, if not specified, no input will be passed to the command |
|
47 | * STDIN redirection, if not specified, no input will be passed to the command | |
| 23 | */ |
|
48 | */ | |
| 24 | @Internal |
|
49 | @Internal | |
|
|
50 | @Override | |||
| 25 | public RedirectFromSpec getStdin() { |
|
51 | public RedirectFromSpec getStdin() { | |
| 26 | return redirectStdin; |
|
52 | return redirectStdin; | |
| 27 | } |
|
53 | } | |
| @@ -30,6 +56,7 public abstract class ExecuteTask extend | |||||
| 30 | * STDOUT redirection, if not specified, redirected to logger::info |
|
56 | * STDOUT redirection, if not specified, redirected to logger::info | |
| 31 | */ |
|
57 | */ | |
| 32 | @Internal |
|
58 | @Internal | |
|
|
59 | @Override | |||
| 33 | public RedirectToSpec getStdout() { |
|
60 | public RedirectToSpec getStdout() { | |
| 34 | return redirectStdout; |
|
61 | return redirectStdout; | |
| 35 | } |
|
62 | } | |
| @@ -38,15 +65,46 public abstract class ExecuteTask extend | |||||
| 38 | * STDERR redirection, if not specified, redirected to logger::error |
|
65 | * STDERR redirection, if not specified, redirected to logger::error | |
| 39 | */ |
|
66 | */ | |
| 40 | @Internal |
|
67 | @Internal | |
|
|
68 | @Override | |||
| 41 | public RedirectToSpec getStderr() { |
|
69 | public RedirectToSpec getStderr() { | |
| 42 | return redirectStderr; |
|
70 | return redirectStderr; | |
| 43 | } |
|
71 | } | |
| 44 |
|
72 | |||
|
|
73 | @Override | |||
|
|
74 | public void commandLine(Object arg0, Object... args) { | |||
|
|
75 | getCommandLine().set(provider(() -> Stream.concat( | |||
|
|
76 | Stream.of(arg0), | |||
|
|
77 | Stream.of(args)) | |||
|
|
78 | .map(Strings::asString).toList())); | |||
| 45 |
|
79 | |||
| 46 | /** Appends specified parameters to the command line */ |
|
80 | } | |
| 47 | void commandLine(String... args) { |
|
81 | ||
| 48 | getCommandLine().addAll(args); |
|
82 | @Override | |
| 49 | } |
|
83 | public void args(Object arg0, Object... args) { | |
| 50 |
|
84 | getCommandLine().addAll(provider(() -> Stream.concat( | ||
| 51 |
|
85 | Stream.of(arg0), | ||
|
|
86 | Stream.of(args)) | |||
|
|
87 | .map(Strings::asString).toList())); | |||
|
|
88 | } | |||
|
|
89 | ||||
|
|
90 | protected abstract ExecBuilder execBuilder(); | |||
|
|
91 | ||||
|
|
92 | @TaskAction | |||
|
|
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()); | |||
|
|
98 | ||||
|
|
99 | getStdout().getRedirection().ifPresent(execBuilder::stdout); | |||
|
|
100 | getStderr().getRedirection().ifPresent(execBuilder::stderr); | |||
|
|
101 | getStdin().getRedirection().ifPresent(execBuilder::stdin); | |||
|
|
102 | ||||
|
|
103 | execBuilder.run().thenAccept(ThrowingConsumer.guard(this::checkRetCode)).join(); | |||
|
|
104 | } | |||
|
|
105 | ||||
|
|
106 | protected void checkRetCode(Integer code) throws IOException{ | |||
|
|
107 | throw new IOException(String.format("The process is terminated with code %s", code)); | |||
|
|
108 | } | |||
|
|
109 | ||||
| 52 | } |
|
110 | } | |
| @@ -2,13 +2,31 package org.implab.gradle.common.utils; | |||||
| 2 |
|
2 | |||
| 3 | import java.util.regex.Pattern; |
|
3 | import java.util.regex.Pattern; | |
| 4 |
|
4 | |||
|
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
6 | import org.gradle.api.provider.Provider; | |||
|
|
7 | ||||
|
|
8 | @NonNullByDefault | |||
| 5 | public class Strings { |
|
9 | public class Strings { | |
| 6 |
|
10 | |||
| 7 | private static final Pattern firstLetter = Pattern.compile("^\\w"); |
|
11 | private static final Pattern firstLetter = Pattern.compile("^\\w"); | |
| 8 |
|
12 | |||
| 9 | public static String capitalize(String string) { |
|
13 | public static String capitalize(String string) { | |
| 10 |
|
|
14 | return string == null ? null | |
| 11 | return ""; |
|
15 | : string.length() == 0 ? string | |
| 12 |
|
|
16 | : firstLetter.matcher(string).replaceFirst(m -> m.group().toUpperCase()); | |
|
|
17 | } | |||
|
|
18 | ||||
|
|
19 | public static void argumentNotNullOrEmpty(String value, String argumentName) { | |||
|
|
20 | if (value == null || value.length() == 0) | |||
|
|
21 | throw new IllegalArgumentException(String.format("Argument %s can't be null or empty", argumentName)); | |||
|
|
22 | } | |||
|
|
23 | ||||
|
|
24 | public static String asString(Object value) { | |||
|
|
25 | if (value == null) | |||
|
|
26 | return null; | |||
|
|
27 | if (value instanceof Provider<?> provider) | |||
|
|
28 | return asString(provider.get()); | |||
|
|
29 | else | |||
|
|
30 | return value.toString(); | |||
| 13 | } |
|
31 | } | |
| 14 | } |
|
32 | } | |
| 1 | NO CONTENT: modified file, binary diff hidden |
|
NO CONTENT: modified file, binary diff hidden |
| @@ -1,6 +1,6 | |||||
| 1 | distributionBase=GRADLE_USER_HOME |
|
1 | distributionBase=GRADLE_USER_HOME | |
| 2 | distributionPath=wrapper/dists |
|
2 | distributionPath=wrapper/dists | |
| 3 |
distributionUrl=https\://services.gradle.org/distributions/gradle-8. |
|
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip | |
| 4 | networkTimeout=10000 |
|
4 | networkTimeout=10000 | |
| 5 | validateDistributionUrl=true |
|
5 | validateDistributionUrl=true | |
| 6 | zipStoreBase=GRADLE_USER_HOME |
|
6 | zipStoreBase=GRADLE_USER_HOME | |
| @@ -43,11 +43,11 set JAVA_EXE=java.exe | |||||
| 43 | %JAVA_EXE% -version >NUL 2>&1 |
|
43 | %JAVA_EXE% -version >NUL 2>&1 | |
| 44 | if %ERRORLEVEL% equ 0 goto execute |
|
44 | if %ERRORLEVEL% equ 0 goto execute | |
| 45 |
|
45 | |||
| 46 | echo. |
|
46 | echo. 1>&2 | |
| 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
|
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 | |
| 48 | echo. |
|
48 | echo. 1>&2 | |
| 49 | echo Please set the JAVA_HOME variable in your environment to match the |
|
49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 | |
| 50 | echo location of your Java installation. |
|
50 | echo location of your Java installation. 1>&2 | |
| 51 |
|
51 | |||
| 52 | goto fail |
|
52 | goto fail | |
| 53 |
|
53 | |||
| @@ -57,11 +57,11 set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |||||
| 57 |
|
57 | |||
| 58 | if exist "%JAVA_EXE%" goto execute |
|
58 | if exist "%JAVA_EXE%" goto execute | |
| 59 |
|
59 | |||
| 60 | echo. |
|
60 | echo. 1>&2 | |
| 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
|
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 | |
| 62 | echo. |
|
62 | echo. 1>&2 | |
| 63 | echo Please set the JAVA_HOME variable in your environment to match the |
|
63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 | |
| 64 | echo location of your Java installation. |
|
64 | echo location of your Java installation. 1>&2 | |
| 65 |
|
65 | |||
| 66 | goto fail |
|
66 | goto fail | |
| 67 |
|
67 | |||
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now
