| @@ -0,0 +1,32 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import java.io.ByteArrayInputStream; | |||
|
|
4 | import java.io.File; | |||
|
|
5 | import java.io.IOException; | |||
|
|
6 | import java.nio.charset.StandardCharsets; | |||
|
|
7 | import java.util.List; | |||
|
|
8 | import java.util.Map; | |||
|
|
9 | import java.util.Optional; | |||
|
|
10 | import java.util.concurrent.CompletableFuture; | |||
|
|
11 | ||||
|
|
12 | class EchoExecBuilder extends ExecBuilder { | |||
|
|
13 | ||||
|
|
14 | private final boolean echoToStderr; | |||
|
|
15 | ||||
|
|
16 | public EchoExecBuilder(boolean echoToStderr) { | |||
|
|
17 | this.echoToStderr = echoToStderr; | |||
|
|
18 | } | |||
|
|
19 | ||||
|
|
20 | @Override | |||
|
|
21 | protected CompletableFuture<Integer> startInternal(Map<String, String> environment, File directory, | |||
|
|
22 | List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect, | |||
|
|
23 | Optional<RedirectTo> stderrRedirect) throws IOException { | |||
|
|
24 | var outputRedirect = echoToStderr ? stderrRedirect : stdoutRedirect; | |||
|
|
25 | ||||
|
|
26 | return outputRedirect.map(to -> { | |||
|
|
27 | var bytes = String.format("exec: %s", commandLine).getBytes(StandardCharsets.UTF_8); | |||
|
|
28 | return to.redirect(new ByteArrayInputStream(bytes)).thenApply((x) -> 0); | |||
|
|
29 | }).orElse(CompletableFuture.completedFuture(0)); | |||
|
|
30 | } | |||
|
|
31 | ||||
|
|
32 | } | |||
| @@ -1,61 +1,124 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
|
|
3 | import java.util.ArrayList; | |||
|
|
4 | import java.util.HashMap; | |||
|
|
5 | import java.util.List; | |||
|
|
6 | import java.util.Map; | |||
|
|
7 | import java.util.Objects; | |||
|
|
8 | import java.util.Optional; | |||
| 3 | import java.util.concurrent.CompletableFuture; |
|
9 | import java.util.concurrent.CompletableFuture; | |
|
|
10 | import java.util.stream.Stream; | |||
| 4 |
|
11 | |||
| 5 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
12 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 6 |
|
13 | |||
| 7 | import java.io.File; |
|
14 | import java.io.File; | |
| 8 | import java.io.IOException; |
|
15 | import java.io.IOException; | |
| 9 |
|
16 | |||
| 10 | /** Command line builder */ |
|
17 | /** Command line builder */ | |
| 11 | @NonNullByDefault |
|
18 | @NonNullByDefault | |
| 12 |
public |
|
19 | public abstract class ExecBuilder { | |
|
|
20 | ||||
|
|
21 | private final List<String> commandLine = new ArrayList<>(); | |||
|
|
22 | ||||
|
|
23 | private final Map<String, String> environment = new HashMap<>(); | |||
|
|
24 | ||||
|
|
25 | private File directory; | |||
|
|
26 | ||||
|
|
27 | private RedirectFrom inputRedirect; | |||
|
|
28 | ||||
|
|
29 | private RedirectTo outputRedirect; | |||
|
|
30 | ||||
|
|
31 | private RedirectTo errorRedirect; | |||
| 13 |
|
32 | |||
| 14 | /** Sets command line, clears previous one if any */ |
|
33 | /** Sets command line, clears previous one if any */ | |
| 15 |
void command(String cmd, String... args) |
|
34 | public void command(String cmd, String... args) { | |
|
|
35 | commandLine.clear(); | |||
|
|
36 | commandLine.add(cmd); | |||
|
|
37 | Stream.of(args).forEach(commandLine::add); | |||
|
|
38 | } | |||
| 16 |
|
39 | |||
| 17 | /** Adds an argument to the command line */ |
|
40 | /** Adds an argument to the command line */ | |
| 18 |
void argument(String arg) |
|
41 | public void argument(String arg) { | |
|
|
42 | Objects.requireNonNull(arg, "arg parameter can't be null"); | |||
|
|
43 | commandLine.add(arg); | |||
|
|
44 | } | |||
| 19 |
|
45 | |||
| 20 | /** Sets the working directory */ |
|
46 | /** Sets the working directory */ | |
| 21 |
void directory(File directory) |
|
47 | public void directory(File directory) { | |
|
|
48 | Objects.requireNonNull(directory, "directory parameter can't be null"); | |||
|
|
49 | this.directory = directory; | |||
|
|
50 | } | |||
| 22 |
|
51 | |||
| 23 | /** |
|
52 | /** | |
| 24 | * Sets the environment value. The value cannot be null. |
|
53 | * Sets the environment value. The value cannot be null. | |
| 25 | * |
|
54 | * | |
| 26 | * @param envVar The name of the environment variable |
|
55 | * @param envVar The name of the environment variable | |
| 27 |
* @param value The value to set, |
|
56 | * @param value The value to set, | |
| 28 | */ |
|
57 | */ | |
| 29 |
void setEnvironment(String envVar, String value) |
|
58 | public void setEnvironment(String envVar, String value) { | |
|
|
59 | Objects.requireNonNull(value, "Value can't be null"); | |||
|
|
60 | Objects.requireNonNull(envVar, "envVar parameter can't be null"); | |||
|
|
61 | environment.put(envVar, value); | |||
|
|
62 | } | |||
| 30 |
|
63 | |||
| 31 |
void unsetEnvironment(String envVar) |
|
64 | public void unsetEnvironment(String envVar) { | |
|
|
65 | environment.remove(envVar); | |||
|
|
66 | } | |||
| 32 |
|
67 | |||
| 33 | /** |
|
68 | /** | |
| 34 | * Sets redirection for the stdin, {@link RedirectFrom} will be applied |
|
69 | * Sets redirection for the stdin, {@link RedirectFrom} will be applied | |
| 35 | * every time the process is started. |
|
70 | * every time the process is started. | |
| 36 | * |
|
71 | * | |
| 37 | * <p>If redirection |
|
72 | * <p> | |
|
|
73 | * If redirection | |||
| 38 | */ |
|
74 | */ | |
| 39 |
void stdin(RedirectFrom from) |
|
75 | public void stdin(RedirectFrom from) { | |
|
|
76 | Objects.requireNonNull(from, "from parameter can't be null"); | |||
|
|
77 | inputRedirect = from; | |||
|
|
78 | } | |||
| 40 |
|
79 | |||
| 41 | /** |
|
80 | /** | |
| 42 | * Sets redirection for the stdout, {@link RedirectTo} will be applied |
|
81 | * Sets redirection for the stdout, {@link RedirectTo} will be applied | |
| 43 | * every time the process is started. |
|
82 | * every time the process is started. | |
| 44 | */ |
|
83 | */ | |
| 45 |
void stdout(RedirectTo out) |
|
84 | public void stdout(RedirectTo out) { | |
|
|
85 | Objects.requireNonNull(out, "out parameter can't be null"); | |||
|
|
86 | outputRedirect = out; | |||
|
|
87 | } | |||
| 46 |
|
88 | |||
| 47 | /** |
|
89 | /** | |
| 48 | * Sets redirection for the stderr, {@link RedirectTo} will be applied |
|
90 | * Sets redirection for the stderr, {@link RedirectTo} will be applied | |
| 49 | * every time the process is started. |
|
91 | * every time the process is started. | |
| 50 | */ |
|
92 | */ | |
| 51 |
void stderr(RedirectTo err) |
|
93 | public void stderr(RedirectTo err) { | |
|
|
94 | Objects.requireNonNull(err, "err parameter can't be null"); | |||
|
|
95 | errorRedirect = err; | |||
|
|
96 | } | |||
|
|
97 | ||||
|
|
98 | /** Implement this function to */ | |||
|
|
99 | protected abstract CompletableFuture<Integer> startInternal( | |||
|
|
100 | Map<String, String> environment, | |||
|
|
101 | File directory, | |||
|
|
102 | List<String> commandLine, | |||
|
|
103 | Optional<RedirectFrom> stdinRedirect, | |||
|
|
104 | Optional<RedirectTo> stdoutRedirect, | |||
|
|
105 | Optional<RedirectTo> stderrRedirect) throws IOException; | |||
| 52 |
|
106 | |||
| 53 | /** |
|
107 | /** | |
| 54 | * Creates and starts new process and returns {@link CompletableFuture}. The |
|
108 | * Creates and starts new process and returns {@link CompletableFuture}. The | |
| 55 | * process may be a remote process, or a shell process or etc. |
|
109 | * process may be a remote process, or a shell process or etc. | |
|
|
110 | * | |||
| 56 | * @return |
|
111 | * @return | |
| 57 | * @throws IOException |
|
112 | * @throws IOException | |
| 58 | */ |
|
113 | */ | |
| 59 |
CompletableFuture<Integer> start() throws IOException |
|
114 | public CompletableFuture<Integer> start() throws IOException { | |
|
|
115 | return startInternal( | |||
|
|
116 | environment, | |||
|
|
117 | directory, | |||
|
|
118 | commandLine, | |||
|
|
119 | Optional.ofNullable(inputRedirect), | |||
|
|
120 | Optional.ofNullable(outputRedirect), | |||
|
|
121 | Optional.ofNullable(errorRedirect)); | |||
|
|
122 | } | |||
| 60 |
|
123 | |||
| 61 | } |
|
124 | } | |
| @@ -1,16 +1,58 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
|
|
3 | import java.io.File; | |||
|
|
4 | import java.io.IOException; | |||
|
|
5 | import java.util.List; | |||
|
|
6 | import java.util.Map; | |||
|
|
7 | import java.util.Optional; | |||
|
|
8 | import java.util.concurrent.CompletableFuture; | |||
|
|
9 | import java.util.function.Consumer; | |||
|
|
10 | ||||
| 3 | /** Shell used to start processes */ |
|
11 | /** Shell used to start processes */ | |
| 4 | public interface ExecShell { |
|
12 | public interface ExecShell { | |
| 5 |
|
13 | |||
| 6 | /** Creates new process builder {@link ExecBuilder} */ |
|
14 | /** Creates new process builder {@link ExecBuilder} */ | |
| 7 | ExecBuilder builder(); |
|
15 | ExecBuilder builder(); | |
| 8 |
|
16 | |||
| 9 | /** |
|
17 | /** | |
| 10 | * Creates default process execution "shell" which will execute processes |
|
18 | * Creates default process execution "shell" which will execute processes | |
| 11 | * directly. |
|
19 | * directly. | |
| 12 | */ |
|
20 | */ | |
| 13 | static ExecShell system() { |
|
21 | static ExecShell system() { | |
| 14 | return () -> new SystemExecBuilder(); |
|
22 | return () -> new SystemExecBuilder(); | |
| 15 | } |
|
23 | } | |
|
|
24 | ||||
|
|
25 | /** | |||
|
|
26 | * Creates a stub shell which will print command to STDERR and return 0 (no | |||
|
|
27 | * error). | |||
|
|
28 | */ | |||
|
|
29 | static ExecShell echoStderr() { | |||
|
|
30 | return () -> new EchoExecBuilder(true); | |||
|
|
31 | } | |||
|
|
32 | ||||
|
|
33 | /** | |||
|
|
34 | * Creates a stub shell which will print command to STDOUT and return 0 (no | |||
|
|
35 | * error). | |||
|
|
36 | */ | |||
|
|
37 | ||||
|
|
38 | static ExecShell echo() { | |||
|
|
39 | return () -> new EchoExecBuilder(false); | |||
|
|
40 | } | |||
|
|
41 | ||||
|
|
42 | /** Creates a stub shell which will call the specified consumer and will supply a command line to it. | |||
|
|
43 | * The command line will be passed as a list of strings. | |||
|
|
44 | * @param consumer The consumer fot the command line | |||
|
|
45 | * @return | |||
|
|
46 | */ | |||
|
|
47 | static ExecShell echo(Consumer<List<String>> consumer) { | |||
|
|
48 | return () -> new ExecBuilder() { | |||
|
|
49 | @Override | |||
|
|
50 | protected CompletableFuture<Integer> startInternal(Map<String, String> environment, File directory, | |||
|
|
51 | List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect, | |||
|
|
52 | Optional<RedirectTo> stderrRedirect) throws IOException { | |||
|
|
53 | consumer.accept(commandLine); | |||
|
|
54 | return CompletableFuture.completedFuture(0); | |||
|
|
55 | } | |||
|
|
56 | }; | |||
|
|
57 | } | |||
| 16 | } |
|
58 | } | |
| @@ -1,98 +1,44 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
| 3 | import java.io.File; |
|
3 | import java.io.File; | |
| 4 | import java.io.IOException; |
|
4 | import java.io.IOException; | |
| 5 | import java.lang.ProcessBuilder.Redirect; |
|
5 | import java.lang.ProcessBuilder.Redirect; | |
| 6 | import java.util.ArrayList; |
|
6 | import java.util.ArrayList; | |
|
|
7 | import java.util.List; | |||
|
|
8 | import java.util.Map; | |||
|
|
9 | import java.util.Optional; | |||
| 7 | import java.util.concurrent.CompletableFuture; |
|
10 | import java.util.concurrent.CompletableFuture; | |
| 8 |
|
11 | |||
| 9 |
class SystemExecBuilder |
|
12 | class SystemExecBuilder extends ExecBuilder { | |
| 10 |
|
13 | @Override | ||
| 11 | private final ProcessBuilder builder = new ProcessBuilder(); |
|
14 | protected CompletableFuture<Integer> startInternal(Map<String, String> environment, File directory, | |
| 12 |
|
15 | List<String> commandLine, Optional<RedirectFrom> stdinRedirect, Optional<RedirectTo> stdoutRedirect, | ||
| 13 | private RedirectFrom inputRedirect; |
|
16 | Optional<RedirectTo> stderrRedirect) throws IOException { | |
| 14 |
|
17 | |||
| 15 | private RedirectTo outputRedirect; |
|
18 | var builder = new ProcessBuilder(commandLine) | |
|
|
19 | .directory(directory); | |||
| 16 |
|
20 | |||
| 17 | private RedirectTo errorRedirect; |
|
21 | builder.environment().putAll(environment); | |
| 18 |
|
22 | |||
| 19 | @Override |
|
|||
| 20 | public CompletableFuture<Integer> start() throws IOException { |
|
|||
| 21 | // TODO Auto-generated method stub |
|
23 | // TODO Auto-generated method stub | |
| 22 | var tasks = new ArrayList<CompletableFuture<?>>(); |
|
24 | var tasks = new ArrayList<CompletableFuture<?>>(); | |
| 23 |
|
25 | |||
| 24 | // discard stdout if not redirected |
|
26 | if (!stdoutRedirect.isPresent()) | |
| 25 | if (outputRedirect == null) |
|
|||
| 26 | builder.redirectOutput(Redirect.DISCARD); |
|
27 | builder.redirectOutput(Redirect.DISCARD); | |
| 27 |
|
28 | if (!stderrRedirect.isPresent()) | ||
| 28 | // discard stderr if not redirected |
|
|||
| 29 | if (errorRedirect == null) |
|
|||
| 30 | builder.redirectError(Redirect.DISCARD); |
|
29 | builder.redirectError(Redirect.DISCARD); | |
| 31 |
|
30 | |||
| 32 | // run process |
|
31 | // run process | |
| 33 | var proc = builder.start(); |
|
32 | var proc = builder.start(); | |
| 34 |
|
33 | |||
| 35 | tasks.add(proc.onExit()); |
|
34 | tasks.add(proc.onExit()); | |
| 36 |
|
35 | |||
| 37 | if (inputRedirect != null) |
|
36 | stdinRedirect.map(from -> from.redirect(proc.getOutputStream())).ifPresent(tasks::add); | |
| 38 |
|
|
37 | stdoutRedirect.map(to -> to.redirect(proc.getInputStream())).ifPresent(tasks::add); | |
| 39 |
|
38 | stderrRedirect.map(to -> to.redirect(proc.getErrorStream())).ifPresent(tasks::add); | ||
| 40 | if (outputRedirect != null) |
|
|||
| 41 | tasks.add(outputRedirect.redirect(proc.getInputStream())); |
|
|||
| 42 |
|
||||
| 43 | if (errorRedirect != null) |
|
|||
| 44 | tasks.add(errorRedirect.redirect(proc.getErrorStream())); |
|
|||
| 45 |
|
39 | |||
| 46 | return CompletableFuture |
|
40 | return CompletableFuture | |
| 47 | .allOf(tasks.toArray(new CompletableFuture<?>[0])) |
|
41 | .allOf(tasks.toArray(new CompletableFuture<?>[0])) | |
| 48 | .thenApply(t -> proc.exitValue()); |
|
42 | .thenApply(t -> proc.exitValue()); | |
| 49 | } |
|
43 | } | |
| 50 |
|
||||
| 51 | @Override |
|
|||
| 52 | public void directory(File workingDir) { |
|
|||
| 53 | builder.directory(workingDir); |
|
|||
| 54 | } |
|
|||
| 55 |
|
||||
| 56 | @Override |
|
|||
| 57 | public void stderr(RedirectTo to) { |
|
|||
| 58 | errorRedirect = to; |
|
|||
| 59 | } |
|
|||
| 60 |
|
||||
| 61 | @Override |
|
|||
| 62 | public void stdin(RedirectFrom from) { |
|
|||
| 63 | inputRedirect = from; |
|
|||
| 64 | } |
|
|||
| 65 |
|
||||
| 66 | @Override |
|
|||
| 67 | public void stdout(RedirectTo to) { |
|
|||
| 68 | outputRedirect = to; |
|
|||
| 69 | } |
|
|||
| 70 |
|
||||
| 71 | @Override |
|
|||
| 72 | public void argument(String arg) { |
|
|||
| 73 | builder.command().add(arg); |
|
|||
| 74 | } |
|
|||
| 75 |
|
||||
| 76 | @Override |
|
|||
| 77 | public void setEnvironment(String envVar, String value) { |
|
|||
| 78 | builder.environment().put(envVar, value); |
|
|||
| 79 |
|
||||
| 80 | } |
|
|||
| 81 |
|
||||
| 82 | @Override |
|
|||
| 83 | public void unsetEnvironment(String envVar) { |
|
|||
| 84 | builder.environment().remove(envVar); |
|
|||
| 85 | } |
|
|||
| 86 |
|
||||
| 87 | @Override |
|
|||
| 88 | public void command(String cmd, String... args) { |
|
|||
| 89 | var commandLine = new ArrayList<String>(); |
|
|||
| 90 |
|
||||
| 91 | commandLine.add(cmd); |
|
|||
| 92 | for (var arg : args) |
|
|||
| 93 | commandLine.add(arg); |
|
|||
| 94 |
|
||||
| 95 | builder.command(commandLine); |
|
|||
| 96 | } |
|
|||
| 97 |
|
||||
| 98 | } |
|
44 | } | |
| @@ -1,27 +1,40 | |||||
| 1 | package org.implab.gradle.common.utils; |
|
1 | package org.implab.gradle.common.utils; | |
| 2 |
|
2 | |||
| 3 | import java.util.function.Supplier; |
|
3 | import java.util.function.Supplier; | |
| 4 |
|
4 | |||
| 5 | import javax.inject.Inject; |
|
5 | import javax.inject.Inject; | |
| 6 |
|
6 | |||
|
|
7 | import org.gradle.api.NamedDomainObjectContainer; | |||
| 7 | import org.gradle.api.model.ObjectFactory; |
|
8 | import org.gradle.api.model.ObjectFactory; | |
| 8 | import org.gradle.api.provider.Provider; |
|
9 | import org.gradle.api.provider.Provider; | |
| 9 | import org.gradle.api.provider.ProviderFactory; |
|
10 | import org.gradle.api.provider.ProviderFactory; | |
| 10 |
|
11 | |||
| 11 | import groovy.lang.Closure; |
|
12 | import groovy.lang.Closure; | |
| 12 |
|
13 | |||
| 13 | public interface ObjectsMixin { |
|
14 | public interface ObjectsMixin { | |
| 14 | @Inject |
|
15 | @Inject | |
| 15 | ObjectFactory getObjects(); |
|
16 | ObjectFactory getObjects(); | |
| 16 |
|
17 | |||
| 17 | @Inject |
|
18 | @Inject | |
| 18 | ProviderFactory getProviders(); |
|
19 | ProviderFactory getProviders(); | |
| 19 |
|
20 | |||
| 20 | default <T> Provider<T> provider(Supplier<T> supplier) { |
|
21 | default <T> Provider<T> provider(Supplier<T> supplier) { | |
| 21 | return getProviders().provider(supplier::get); |
|
22 | return getProviders().provider(supplier::get); | |
| 22 | } |
|
23 | } | |
| 23 |
|
24 | |||
| 24 | default <T> Provider<T> provider(Closure<T> closure) { |
|
25 | default <T> Provider<T> provider(Closure<T> closure) { | |
| 25 | return getProviders().provider(closure); |
|
26 | return getProviders().provider(closure); | |
| 26 | } |
|
27 | } | |
|
|
28 | ||||
|
|
29 | default <T> T newInstance(Class<T> clazz) { | |||
|
|
30 | return getObjects().newInstance(clazz); | |||
|
|
31 | } | |||
|
|
32 | ||||
|
|
33 | default <T> T newInstance(Class<T> clazz, Object... params) { | |||
|
|
34 | return getObjects().newInstance(clazz, params); | |||
|
|
35 | } | |||
|
|
36 | ||||
|
|
37 | default <T> NamedDomainObjectContainer<T> newContainer(Class<T> clazz) { | |||
|
|
38 | return getObjects().domainObjectContainer(clazz); | |||
|
|
39 | } | |||
| 27 | } |
|
40 | } | |
General Comments 0
You need to be logged in to leave comments.
Login now
