##// END OF EJS Templates
sync
cin -
r15:a8aa61eea9d1 default
parent child
Show More
@@ -1,13 +1,13
1 1 package org.implab.gradle.common.dsl;
2 2
3 3
4 4 import org.gradle.api.provider.ListProperty;
5 5
6 public interface CommandSpec {
6 public interface TaskCommandSpecMixin {
7 7 ListProperty<String> getCommandLine();
8 8
9 9 void commandLine(Object arg0, Object... args);
10 10
11 11 void args(Object arg0, Object... args);
12 12
13 13 }
@@ -1,48 +1,52
1 1 package org.implab.gradle.common.dsl;
2 2
3 3 import java.util.HashMap;
4 4 import java.util.Map;
5 5
6 6 import org.gradle.api.Action;
7 7 import org.gradle.api.file.DirectoryProperty;
8 8 import org.gradle.api.provider.MapProperty;
9 import org.gradle.api.provider.Property;
9 10 import org.implab.gradle.common.utils.Closures;
10 11 import org.implab.gradle.common.utils.Values;
11 12
12 13 import groovy.lang.Closure;
13 14
14 15 /**
15 16 * Configuration properties of the execution shell. This object specifies a
16 17 * working directory and environment variables for the processes started within
17 18 * this shell.
18 19 */
19 public interface EnvironmentSpec {
20 public interface TaskEnvSpecMixin {
21
22 /** Inherit environment from current process */
23 Property<Boolean> getInheritEnvironment();
20 24
21 25 /** Working directory */
22 26 DirectoryProperty getWorkingDirectory();
23 27
24 28 /** Environment variables */
25 29 MapProperty<String, String> getEnvironment();
26 30
27 31 /**
28 32 * Configures the environment variable using the specified action. The
29 33 * action is called when the value is calculated;
30 34 */
31 35 default void env(Action<Map<String, Object>> configure) {
32 36 var provider = getEnvironment()
33 37 .orElse(Map.of())
34 38 .map((base) -> {
35 39 var props = new HashMap<String, Object>(base);
36 40
37 41 configure.execute(props);
38 42
39 43 return Values.mapValues(props, Values::toString);
40 44 });
41 45
42 46 getEnvironment().set(provider);
43 47 }
44 48
45 49 default void env(Closure<?> configure) {
46 50 env(Closures.action(configure));
47 51 }
48 52 }
@@ -1,12 +1,12
1 1 package org.implab.gradle.common.dsl;
2 2
3 3 import org.eclipse.jdt.annotation.NonNullByDefault;
4 4
5 5 @NonNullByDefault
6 public interface PipeSpec {
6 public interface TaskPipeSpecMixin {
7 7 RedirectToSpec getStdout();
8 8
9 9 RedirectToSpec getStderr();
10 10
11 11 RedirectFromSpec getStdin();
12 12 }
@@ -1,110 +1,115
1 1 package org.implab.gradle.common.tasks;
2 2
3 3 import java.io.IOException;
4 4 import java.util.Map;
5 5 import java.util.concurrent.ExecutionException;
6 6 import java.util.stream.Stream;
7 7
8 8 import org.gradle.api.DefaultTask;
9 9 import org.gradle.api.file.DirectoryProperty;
10 10 import org.gradle.api.provider.ListProperty;
11 11 import org.gradle.api.provider.MapProperty;
12 import org.gradle.api.provider.Property;
12 13 import org.gradle.api.tasks.Internal;
13 14 import org.gradle.api.tasks.TaskAction;
14 import org.implab.gradle.common.dsl.CommandSpec;
15 import org.implab.gradle.common.dsl.PipeSpec;
15 import org.implab.gradle.common.dsl.TaskCommandSpecMixin;
16 import org.implab.gradle.common.dsl.TaskPipeSpecMixin;
16 17 import org.implab.gradle.common.dsl.RedirectFromSpec;
17 18 import org.implab.gradle.common.dsl.RedirectToSpec;
18 import org.implab.gradle.common.dsl.EnvironmentSpec;
19 import org.implab.gradle.common.dsl.TaskEnvSpecMixin;
19 20 import org.implab.gradle.common.exec.ExecBuilder;
20 21 import org.implab.gradle.common.utils.ObjectsMixin;
21 22 import org.implab.gradle.common.utils.Strings;
22 23 import org.implab.gradle.common.utils.ThrowingConsumer;
23 24
24 25 public abstract class ShellExecTask
25 26 extends DefaultTask
26 implements CommandSpec, PipeSpec, EnvironmentSpec, ObjectsMixin {
27 implements TaskCommandSpecMixin, TaskPipeSpecMixin, TaskEnvSpecMixin, ObjectsMixin {
27 28
28 29 private final RedirectToSpec redirectStderr = new RedirectToSpec();
29 30
30 31 private final RedirectToSpec redirectStdout = new RedirectToSpec();
31 32
32 33 private final RedirectFromSpec redirectStdin = new RedirectFromSpec();
33 34
34 35 @Internal
35 36 @Override
37 public abstract Property<Boolean> getInheritEnvironment();
38
39 @Internal
40 @Override
36 41 public abstract DirectoryProperty getWorkingDirectory();
37 42
38 43 @Internal
39 44 @Override
40 45 public abstract MapProperty<String, String> getEnvironment();
41 46
42 47 @Internal
43 48 @Override
44 49 public abstract ListProperty<String> getCommandLine();
45 50
46 51 /**
47 52 * STDIN redirection, if not specified, no input will be passed to the command
48 53 */
49 54 @Internal
50 55 @Override
51 56 public RedirectFromSpec getStdin() {
52 57 return redirectStdin;
53 58 }
54 59
55 60 /**
56 61 * STDOUT redirection, if not specified, redirected to logger::info
57 62 */
58 63 @Internal
59 64 @Override
60 65 public RedirectToSpec getStdout() {
61 66 return redirectStdout;
62 67 }
63 68
64 69 /**
65 70 * STDERR redirection, if not specified, redirected to logger::error
66 71 */
67 72 @Internal
68 73 @Override
69 74 public RedirectToSpec getStderr() {
70 75 return redirectStderr;
71 76 }
72 77
73 78 @Override
74 79 public void commandLine(Object arg0, Object... args) {
75 80 getCommandLine().set(provider(() -> Stream.concat(
76 81 Stream.of(arg0),
77 82 Stream.of(args))
78 83 .map(Strings::asString).toList()));
79 84
80 85 }
81 86
82 87 @Override
83 88 public void args(Object arg0, Object... args) {
84 89 getCommandLine().addAll(provider(() -> Stream.concat(
85 90 Stream.of(arg0),
86 91 Stream.of(args))
87 92 .map(Strings::asString).toList()));
88 93 }
89 94
90 95 protected abstract ExecBuilder execBuilder();
91 96
92 97 @TaskAction
93 98 public final void run() throws IOException, InterruptedException, ExecutionException {
94 99 var execBuilder = execBuilder();
95 100 execBuilder.workingDirectory(getWorkingDirectory().get().getAsFile());
96 101 execBuilder.environment(getEnvironment().getOrElse(Map.of()));
97 102 execBuilder.commandLine(getCommandLine().get());
98 103
99 104 getStdout().getRedirection().ifPresent(execBuilder::stdout);
100 105 getStderr().getRedirection().ifPresent(execBuilder::stderr);
101 106 getStdin().getRedirection().ifPresent(execBuilder::stdin);
102 107
103 108 execBuilder.exec().thenAccept(ThrowingConsumer.guard(this::checkRetCode)).join();
104 109 }
105 110
106 111 protected void checkRetCode(Integer code) throws IOException {
107 112 throw new IOException(String.format("The process is terminated with code %s", code));
108 113 }
109 114
110 115 }
@@ -1,24 +1,21
1 1 package org.implab.gradle.common.utils;
2 2
3 3 import groovy.lang.Closure;
4 4
5 5 import org.eclipse.jdt.annotation.NonNullByDefault;
6 6 import org.gradle.api.Action;
7 7
8 8 @NonNullByDefault
9 9 public final class Closures {
10 10 private Closures() {
11 11 }
12 12
13 13 public static <T> Action<T> action(Closure<?> closure) {
14 return arg -> {
15 closure.setDelegate(arg);
16 closure.call(arg);
17 };
14 return arg -> apply(closure, arg);
18 15 }
19 16
20 17 public static void apply(Closure<?> action, Object target) {
21 18 action.setDelegate(target);
22 19 action.call(target);
23 20 }
24 21 }
@@ -1,89 +1,93
1 1 package org.implab.gradle.common.utils;
2 2
3 3 import java.util.Iterator;
4 4 import java.util.Map;
5 5 import java.util.Spliterators;
6 6 import java.util.Map.Entry;
7 7 import java.util.Optional;
8 8 import java.util.function.Function;
9 9 import java.util.function.Supplier;
10 10 import java.util.stream.Collectors;
11 11 import java.util.stream.Stream;
12 12 import java.util.stream.StreamSupport;
13 13
14 14 import org.gradle.api.provider.Provider;
15 15
16 16 public final class Values {
17 17
18 18 private Values() {
19 19 }
20 20
21 21 /**
22 22 * Converts values in the specified map
23 23 *
24 24 * @param <K>
25 25 * @param <V>
26 26 * @param <U>
27 27 * @param map
28 28 * @param mapper
29 29 * @return
30 30 */
31 31 public static <K, V, U> Map<K, U> mapValues(Map<K, V> map, Function<V, U> mapper) {
32 32 Function<Entry<K, V>, V> getter = Entry::getValue;
33 33
34 34 return map.entrySet().stream()
35 35 .collect(Collectors.toMap(Entry::getKey, getter.andThen(mapper)));
36 36 }
37 37
38 38 /**
39 39 * Converts the supplied value to a string.
40 40 */
41 41 public static String toString(Object value) {
42 42 if (value == null) {
43 43 return null;
44 44 } else if (value instanceof String string) {
45 45 return string;
46 46 } else if (value instanceof Provider<?> provider) {
47 47 return toString(provider.getOrNull());
48 48 } else if (value instanceof Supplier<?> supplier) {
49 49 return toString(supplier.get());
50 50 } else {
51 51 return value.toString();
52 52 }
53 53 }
54 54
55 55 public static <T> Stream<T> stream(Iterator<T> remaining) {
56 56 return StreamSupport.stream(
57 57 Spliterators.spliteratorUnknownSize(remaining, 0),
58 58 false);
59 59 }
60 60
61 61 public static <T> Optional<T> take(Iterator<T> iterator) {
62 62 return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty();
63 63 }
64 64
65 65 public static <T> Iterable<T> iterable(T[] values) {
66 66 return () -> new ArrayIterator<>(values);
67 67 }
68 68
69 public static <T> Optional<T> optional(Provider<T> provider) {
70 return provider.isPresent() ? Optional.of(provider.get()) : Optional.empty();
71 }
72
69 73 private static class ArrayIterator<T> implements Iterator<T> {
70 74 private final T[] data;
71 75
72 76 private int pos = 0;
73 77
74 78 ArrayIterator(T[] data) {
75 79 this.data = data;
76 80 }
77 81
78 82 @Override
79 83 public boolean hasNext() {
80 84 return pos < data.length;
81 85 }
82 86
83 87 @Override
84 88 public T next() {
85 89 return data[pos++];
86 90 }
87 91 }
88 92
89 93 }
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now