| @@ -0,0 +1,52 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import static java.util.Objects.requireNonNull; | |||
|
|
4 | ||||
|
|
5 | import java.util.Optional; | |||
|
|
6 | ||||
|
|
7 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
8 | import org.implab.gradle.common.utils.Values; | |||
|
|
9 | ||||
|
|
10 | @NonNullByDefault | |||
|
|
11 | public interface CommandArgumentsBuilder<S extends CommandArgumentsBuilder<S>> { | |||
|
|
12 | ||||
|
|
13 | S self(); | |||
|
|
14 | ||||
|
|
15 | default S flag(String name, boolean value) { | |||
|
|
16 | requireNonNull(name, "Parameter name cannot be null"); | |||
|
|
17 | if (value) | |||
|
|
18 | addArguments(name); | |||
|
|
19 | return self(); | |||
|
|
20 | } | |||
|
|
21 | ||||
|
|
22 | default S param(String name, String value) { | |||
|
|
23 | requireNonNull(name, "Parameter name cannot be null"); | |||
|
|
24 | requireNonNull(value, "Parameter value cannot be null"); | |||
|
|
25 | if (value != null && value.length() > 0) | |||
|
|
26 | addArguments(name, value); | |||
|
|
27 | return self(); | |||
|
|
28 | } | |||
|
|
29 | ||||
|
|
30 | default S param(String name, Optional<String> value) { | |||
|
|
31 | value.ifPresent(v -> param(name, v)); | |||
|
|
32 | return self(); | |||
|
|
33 | } | |||
|
|
34 | ||||
|
|
35 | /** Adds the specified arguments to this builder */ | |||
|
|
36 | S addArguments(String... args); | |||
|
|
37 | ||||
|
|
38 | default S addArguments(Iterable<String> args) { | |||
|
|
39 | for (String arg : args) | |||
|
|
40 | addArguments(arg); | |||
|
|
41 | ||||
|
|
42 | return self(); | |||
|
|
43 | } | |||
|
|
44 | ||||
|
|
45 | /** Replaces arguments in the builder with the specified one. */ | |||
|
|
46 | default S arguments(String... args) { | |||
|
|
47 | return arguments(Values.iterable(args)); | |||
|
|
48 | } | |||
|
|
49 | ||||
|
|
50 | /** Replaces arguments in the builder with the specified one. */ | |||
|
|
51 | S arguments(Iterable<String> args); | |||
|
|
52 | } | |||
| @@ -0,0 +1,40 | |||||
|
|
1 | package org.implab.gradle.common.exec; | |||
|
|
2 | ||||
|
|
3 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
4 | import org.gradle.api.Action; | |||
|
|
5 | ||||
|
|
6 | @NonNullByDefault | |||
|
|
7 | public class ShellTool { | |||
|
|
8 | ||||
|
|
9 | private final Shell shell; | |||
|
|
10 | ||||
|
|
11 | private final String executable; | |||
|
|
12 | ||||
|
|
13 | ShellTool(String executable, Shell shell) { | |||
|
|
14 | this.shell = shell; | |||
|
|
15 | this.executable = executable; | |||
|
|
16 | } | |||
|
|
17 | ||||
|
|
18 | public ShellExec arguments(String... args) { | |||
|
|
19 | return shell.create(CommandSpec.builder() | |||
|
|
20 | .executable(executable) | |||
|
|
21 | .arguments(args) | |||
|
|
22 | .build()); | |||
|
|
23 | } | |||
|
|
24 | ||||
|
|
25 | public ShellExec arguments(Iterable<String> args) { | |||
|
|
26 | return shell.create(CommandSpec.builder() | |||
|
|
27 | .executable(executable) | |||
|
|
28 | .arguments(args) | |||
|
|
29 | .build()); | |||
|
|
30 | } | |||
|
|
31 | ||||
|
|
32 | public ShellExec arguments(Action<CommandArgumentsBuilder<?>> args) { | |||
|
|
33 | var builder = CommandSpec.builder() | |||
|
|
34 | .executable(executable); | |||
|
|
35 | args.execute(builder); | |||
|
|
36 | ||||
|
|
37 | return shell.create(builder.build()); | |||
|
|
38 | } | |||
|
|
39 | ||||
|
|
40 | } | |||
| @@ -0,0 +1,35 | |||||
|
|
1 | package org.implab.gradle.common.utils; | |||
|
|
2 | ||||
|
|
3 | import java.io.File; | |||
|
|
4 | import java.util.Optional; | |||
|
|
5 | ||||
|
|
6 | import org.implab.gradle.common.utils.os.SystemResolver; | |||
|
|
7 | ||||
|
|
8 | public interface OperatingSystem { | |||
|
|
9 | ||||
|
|
10 | public static OperatingSystem CURRENT = SystemResolver.current(); | |||
|
|
11 | ||||
|
|
12 | public static final String WINDOWS_FAMILY = "windows"; | |||
|
|
13 | ||||
|
|
14 | public static final String LINUX_FAMILY = "linux"; | |||
|
|
15 | ||||
|
|
16 | public static final String FREE_BSD_FAMILY = "freebsd"; | |||
|
|
17 | ||||
|
|
18 | public static final String MAC_OS_FAMILY = "os x"; | |||
|
|
19 | ||||
|
|
20 | public static final String UNKNOWN_FAMILY = "unknown"; | |||
|
|
21 | ||||
|
|
22 | String family(); | |||
|
|
23 | ||||
|
|
24 | String name(); | |||
|
|
25 | ||||
|
|
26 | String version(); | |||
|
|
27 | ||||
|
|
28 | Optional<File> which(String cmd); | |||
|
|
29 | ||||
|
|
30 | Optional<File> which(String cmd, Iterable<? extends File> paths); | |||
|
|
31 | ||||
|
|
32 | public static OperatingSystem current() { | |||
|
|
33 | return CURRENT; | |||
|
|
34 | } | |||
|
|
35 | } | |||
| @@ -0,0 +1,16 | |||||
|
|
1 | package org.implab.gradle.common.utils.os; | |||
|
|
2 | ||||
|
|
3 | import org.implab.gradle.common.utils.OperatingSystem; | |||
|
|
4 | ||||
|
|
5 | public class FreeBsd extends GenericSystem{ | |||
|
|
6 | ||||
|
|
7 | FreeBsd(String name, String version) { | |||
|
|
8 | super(name, version); | |||
|
|
9 | } | |||
|
|
10 | ||||
|
|
11 | @Override | |||
|
|
12 | public String family() { | |||
|
|
13 | return OperatingSystem.FREE_BSD_FAMILY; | |||
|
|
14 | } | |||
|
|
15 | ||||
|
|
16 | } | |||
| @@ -0,0 +1,64 | |||||
|
|
1 | package org.implab.gradle.common.utils.os; | |||
|
|
2 | ||||
|
|
3 | import java.io.File; | |||
|
|
4 | import java.util.Arrays; | |||
|
|
5 | import java.util.Optional; | |||
|
|
6 | import java.util.function.Function; | |||
|
|
7 | import java.util.regex.Pattern; | |||
|
|
8 | import java.util.stream.Stream; | |||
|
|
9 | ||||
|
|
10 | import org.implab.gradle.common.utils.OperatingSystem; | |||
|
|
11 | import org.implab.gradle.common.utils.Values; | |||
|
|
12 | ||||
|
|
13 | class GenericSystem implements OperatingSystem { | |||
|
|
14 | ||||
|
|
15 | private final String name; | |||
|
|
16 | ||||
|
|
17 | private final String version; | |||
|
|
18 | ||||
|
|
19 | GenericSystem(String name, String version) { | |||
|
|
20 | this.name = name; | |||
|
|
21 | this.version = version; | |||
|
|
22 | } | |||
|
|
23 | ||||
|
|
24 | public String getPathVar() { | |||
|
|
25 | return "PATH"; | |||
|
|
26 | } | |||
|
|
27 | ||||
|
|
28 | @Override | |||
|
|
29 | public String family() { | |||
|
|
30 | return OperatingSystem.UNKNOWN_FAMILY; | |||
|
|
31 | } | |||
|
|
32 | ||||
|
|
33 | @Override | |||
|
|
34 | public String name() { | |||
|
|
35 | return name; | |||
|
|
36 | } | |||
|
|
37 | ||||
|
|
38 | @Override | |||
|
|
39 | public String version() { | |||
|
|
40 | return version; | |||
|
|
41 | } | |||
|
|
42 | ||||
|
|
43 | protected Stream<File> getPath() { | |||
|
|
44 | String path = System.getenv(getPathVar()); | |||
|
|
45 | return path == null | |||
|
|
46 | ? Stream.empty() | |||
|
|
47 | : Arrays.stream(path.split(Pattern.quote(File.pathSeparator))) | |||
|
|
48 | .map(File::new); | |||
|
|
49 | } | |||
|
|
50 | ||||
|
|
51 | protected Function<File, Stream<File>> candidates(String cmd) { | |||
|
|
52 | return base -> Stream.of(new File(base, cmd)); | |||
|
|
53 | } | |||
|
|
54 | ||||
|
|
55 | @Override | |||
|
|
56 | public Optional<File> which(String cmd) { | |||
|
|
57 | return getPath().flatMap(candidates(cmd)).filter(File::isFile).findAny(); | |||
|
|
58 | } | |||
|
|
59 | ||||
|
|
60 | @Override | |||
|
|
61 | public Optional<File> which(String cmd, Iterable<? extends File> paths) { | |||
|
|
62 | return Values.stream(paths.iterator()).flatMap(candidates(cmd)).filter(File::isFile).findAny(); | |||
|
|
63 | } | |||
|
|
64 | } | |||
| @@ -0,0 +1,16 | |||||
|
|
1 | package org.implab.gradle.common.utils.os; | |||
|
|
2 | ||||
|
|
3 | import org.implab.gradle.common.utils.OperatingSystem; | |||
|
|
4 | ||||
|
|
5 | public class Linux extends GenericSystem { | |||
|
|
6 | ||||
|
|
7 | Linux(String name, String version) { | |||
|
|
8 | super(name, version); | |||
|
|
9 | } | |||
|
|
10 | ||||
|
|
11 | @Override | |||
|
|
12 | public String family() { | |||
|
|
13 | return OperatingSystem.LINUX_FAMILY; | |||
|
|
14 | } | |||
|
|
15 | ||||
|
|
16 | } | |||
| @@ -0,0 +1,15 | |||||
|
|
1 | package org.implab.gradle.common.utils.os; | |||
|
|
2 | ||||
|
|
3 | import org.implab.gradle.common.utils.OperatingSystem; | |||
|
|
4 | ||||
|
|
5 | public class MacOs extends GenericSystem { | |||
|
|
6 | ||||
|
|
7 | MacOs(String name, String version) { | |||
|
|
8 | super(name, version); | |||
|
|
9 | } | |||
|
|
10 | ||||
|
|
11 | @Override | |||
|
|
12 | public String family() { | |||
|
|
13 | return OperatingSystem.MAC_OS_FAMILY; | |||
|
|
14 | } | |||
|
|
15 | } | |||
| @@ -0,0 +1,29 | |||||
|
|
1 | package org.implab.gradle.common.utils.os; | |||
|
|
2 | ||||
|
|
3 | import org.implab.gradle.common.utils.OperatingSystem; | |||
|
|
4 | ||||
|
|
5 | public class SystemResolver { | |||
|
|
6 | public static OperatingSystem current() { | |||
|
|
7 | var osName = System.getProperty("os.name"); | |||
|
|
8 | var osVersion = System.getProperty("os.version"); | |||
|
|
9 | ||||
|
|
10 | return forName(osName, osVersion); | |||
|
|
11 | } | |||
|
|
12 | ||||
|
|
13 | public static OperatingSystem forName(String os, String version) { | |||
|
|
14 | var osName = os.toLowerCase(); | |||
|
|
15 | ||||
|
|
16 | if (osName.contains("windows")) { | |||
|
|
17 | return new Windows(osName, version); | |||
|
|
18 | } else if (osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx")) { | |||
|
|
19 | return new MacOs(osName, version); | |||
|
|
20 | } else if (osName.contains("linux")) { | |||
|
|
21 | return new Linux(osName, version); | |||
|
|
22 | } else if (osName.contains("freebsd")) { | |||
|
|
23 | return new FreeBsd(osName, version); | |||
|
|
24 | } else { | |||
|
|
25 | // Not strictly true | |||
|
|
26 | return new GenericSystem(osName, version); | |||
|
|
27 | } | |||
|
|
28 | } | |||
|
|
29 | } | |||
| @@ -0,0 +1,26 | |||||
|
|
1 | package org.implab.gradle.common.utils.os; | |||
|
|
2 | ||||
|
|
3 | import java.io.File; | |||
|
|
4 | import java.util.function.Function; | |||
|
|
5 | import java.util.stream.Stream; | |||
|
|
6 | ||||
|
|
7 | import org.implab.gradle.common.utils.OperatingSystem; | |||
|
|
8 | ||||
|
|
9 | class Windows extends GenericSystem { | |||
|
|
10 | ||||
|
|
11 | private Stream<String> exeSuffixes = Stream.of(".cmd", ".bat", ".exe"); | |||
|
|
12 | ||||
|
|
13 | Windows(String name, String version) { | |||
|
|
14 | super(name, version); | |||
|
|
15 | } | |||
|
|
16 | ||||
|
|
17 | @Override | |||
|
|
18 | public String family() { | |||
|
|
19 | return OperatingSystem.WINDOWS_FAMILY; | |||
|
|
20 | } | |||
|
|
21 | ||||
|
|
22 | @Override | |||
|
|
23 | protected Function<File, Stream<File>> candidates(String cmd) { | |||
|
|
24 | return base -> exeSuffixes.map(suffix -> new File(base, cmd + suffix)); | |||
|
|
25 | } | |||
|
|
26 | } | |||
| @@ -1,85 +1,63 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
| 3 | import java.util.function.Consumer; |
|
3 | import java.io.File; | |
| 4 |
|
4 | |||
| 5 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 6 | import org.implab.gradle.common.utils.Values; |
|
6 | import org.implab.gradle.common.utils.Values; | |
| 7 |
|
7 | |||
| 8 | /** Command builder interface, used to specify the executable and parameters */ |
|
8 | /** Command builder interface, used to specify the executable and parameters */ | |
| 9 | @NonNullByDefault |
|
9 | @NonNullByDefault | |
| 10 | public interface CommandBuilder { |
|
10 | public interface CommandBuilder extends CommandArgumentsBuilder<CommandBuilder> { | |
|
|
11 | ||||
|
|
12 | @Override | |||
|
|
13 | default CommandBuilder self() { | |||
|
|
14 | return this; | |||
|
|
15 | } | |||
| 11 |
|
16 | |||
| 12 | /** Sets the executable, the parameters are left intact. */ |
|
17 | /** Sets the executable, the parameters are left intact. */ | |
| 13 | CommandBuilder executable(String executable); |
|
18 | CommandBuilder executable(String executable); | |
| 14 |
|
19 | |||
|
|
20 | default CommandBuilder executable(File executable) { | |||
|
|
21 | executable(executable.toString()); | |||
|
|
22 | return this; | |||
|
|
23 | } | |||
|
|
24 | ||||
| 15 | /** |
|
25 | /** | |
| 16 | * Sets the specified executable and parameters, old executable and parameters |
|
26 | * Sets the specified executable and parameters, old executable and parameters | |
| 17 | * are discarded. |
|
27 | * are discarded. | |
| 18 | */ |
|
28 | */ | |
| 19 | default CommandBuilder commandLine(String executable, String... args) { |
|
29 | default CommandBuilder commandLine(String executable, String... args) { | |
| 20 | return executable(executable) |
|
30 | return executable(executable) | |
| 21 | .arguments(args); |
|
31 | .arguments(args); | |
| 22 | } |
|
32 | } | |
| 23 |
|
33 | |||
| 24 | /** |
|
34 | /** | |
| 25 | * Sets the specified executable and parameters, old executable and parameters |
|
35 | * Sets the specified executable and parameters, old executable and parameters | |
| 26 | * are discarded. |
|
36 | * are discarded. | |
| 27 | * |
|
37 | * | |
| 28 | * @param command The command line. Must contain at least one element |
|
38 | * @param command The command line. Must contain at least one element | |
| 29 | * (executable). |
|
39 | * (executable). | |
| 30 | * |
|
40 | * | |
| 31 | */ |
|
41 | */ | |
| 32 | default CommandBuilder commandLine(Iterable<? extends String> command) { |
|
42 | default CommandBuilder commandLine(Iterable<? extends String> command) { | |
| 33 | var iterator = command.iterator(); |
|
43 | var iterator = command.iterator(); | |
| 34 |
|
44 | |||
| 35 | // set executable |
|
45 | // set executable | |
| 36 | executable(Values.take(iterator).orElseThrow()); |
|
46 | executable(Values.take(iterator).orElseThrow()); | |
| 37 | // cleat arguments |
|
47 | // cleat arguments | |
| 38 | arguments(); |
|
48 | arguments(); | |
| 39 |
|
49 | |||
| 40 | // set new arguments |
|
50 | // set new arguments | |
| 41 | while (iterator.hasNext()) |
|
51 | while (iterator.hasNext()) | |
| 42 | addArguments(iterator.next()); |
|
52 | addArguments(iterator.next()); | |
| 43 |
|
53 | |||
| 44 | return this; |
|
54 | return this; | |
| 45 | } |
|
55 | } | |
| 46 |
|
56 | |||
| 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 |
|
||||
| 61 | /** Adds the specified arguments to this builder */ |
|
|||
| 62 | CommandBuilder addArguments(String... args); |
|
|||
| 63 |
|
||||
| 64 | default CommandBuilder addArguments(Iterable<String> args) { |
|
|||
| 65 | for (String arg : args) |
|
|||
| 66 | addArguments(arg); |
|
|||
| 67 |
|
||||
| 68 | return this; |
|
|||
| 69 | } |
|
|||
| 70 |
|
||||
| 71 | /** Replaces arguments in the builder with the specified one. */ |
|
|||
| 72 | default CommandBuilder arguments(String... args) { |
|
|||
| 73 | return arguments(Values.iterable(args)); |
|
|||
| 74 | } |
|
|||
| 75 |
|
||||
| 76 | /** Replaces arguments in the builder with the specified one. */ |
|
|||
| 77 | CommandBuilder arguments(Iterable<String> args); |
|
|||
| 78 |
|
||||
| 79 | default CommandBuilder from(CommandSpec commandSpec) { |
|
57 | default CommandBuilder from(CommandSpec commandSpec) { | |
| 80 | return executable(commandSpec.executable()) |
|
58 | return executable(commandSpec.executable()) | |
| 81 | .arguments(commandSpec.arguments()); |
|
59 | .arguments(commandSpec.arguments()); | |
| 82 | } |
|
60 | } | |
| 83 |
|
61 | |||
| 84 | CommandSpec build(); |
|
62 | CommandSpec build(); | |
| 85 | } |
|
63 | } | |
| @@ -1,20 +1,23 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
| 3 | import java.util.List; |
|
3 | import java.util.List; | |
| 4 | import java.util.stream.Stream; |
|
4 | import java.util.stream.Stream; | |
| 5 |
|
5 | |||
|
|
6 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
7 | ||||
|
|
8 | @NonNullByDefault | |||
| 6 | public interface CommandSpec { |
|
9 | public interface CommandSpec { | |
| 7 |
|
10 | |||
| 8 | String executable(); |
|
11 | String executable(); | |
| 9 |
|
12 | |||
| 10 | List<String> arguments(); |
|
13 | List<String> arguments(); | |
| 11 |
|
14 | |||
| 12 | default List<String> commandLine() { |
|
15 | default List<String> commandLine() { | |
| 13 | return Stream.concat(Stream.of(executable()), arguments().stream()).toList(); |
|
16 | return Stream.concat(Stream.of(executable()), arguments().stream()).toList(); | |
| 14 | } |
|
17 | } | |
| 15 |
|
18 | |||
| 16 | public static CommandBuilder builder() { |
|
19 | public static CommandBuilder builder() { | |
| 17 | return new CommandSpecRecord.Builder(); |
|
20 | return new CommandSpecRecord.Builder(); | |
| 18 | } |
|
21 | } | |
| 19 |
|
22 | |||
| 20 | } |
|
23 | } | |
| @@ -1,47 +1,51 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
| 3 | import java.util.List; |
|
3 | import java.util.List; | |
|
|
4 | ||||
|
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
6 | ||||
| 4 | import static java.util.Objects.requireNonNull; |
|
7 | import static java.util.Objects.requireNonNull; | |
| 5 |
|
8 | |||
| 6 | import java.util.ArrayList; |
|
9 | import java.util.ArrayList; | |
| 7 |
|
10 | |||
|
|
11 | @NonNullByDefault | |||
| 8 | public record CommandSpecRecord(String executable, List<String> arguments) implements CommandSpec { |
|
12 | public record CommandSpecRecord(String executable, List<String> arguments) implements CommandSpec { | |
| 9 |
|
13 | |||
| 10 | static class Builder implements CommandBuilder { |
|
14 | static class Builder implements CommandBuilder { | |
| 11 |
|
15 | |||
| 12 | private String executable; |
|
16 | private String executable; | |
| 13 |
|
17 | |||
| 14 | private List<String> arguments = new ArrayList<>(); |
|
18 | private List<String> arguments = new ArrayList<>(); | |
| 15 |
|
19 | |||
| 16 | @Override |
|
20 | @Override | |
| 17 | public CommandBuilder executable(String executable) { |
|
21 | public CommandBuilder executable(String executable) { | |
| 18 | requireNonNull(executable, "cmd can't be null"); |
|
22 | requireNonNull(executable, "cmd can't be null"); | |
| 19 | this.executable = executable; |
|
23 | this.executable = executable; | |
| 20 | return this; |
|
24 | return this; | |
| 21 | } |
|
25 | } | |
| 22 |
|
26 | |||
| 23 | @Override |
|
27 | @Override | |
| 24 | public CommandBuilder arguments(Iterable<String> args) { |
|
28 | public CommandBuilder arguments(Iterable<String> args) { | |
| 25 | requireNonNull(args, "Args must not be null"); |
|
29 | requireNonNull(args, "Args must not be null"); | |
| 26 | arguments.clear(); |
|
30 | arguments.clear(); | |
| 27 | for (var arg : args) |
|
31 | for (var arg : args) | |
| 28 | arguments.add(arg); |
|
32 | arguments.add(arg); | |
| 29 | return this; |
|
33 | return this; | |
| 30 | } |
|
34 | } | |
| 31 |
|
35 | |||
| 32 | @Override |
|
36 | @Override | |
| 33 | public CommandBuilder addArguments(String... args) { |
|
37 | public CommandBuilder addArguments(String... args) { | |
| 34 | for (var arg : args) |
|
38 | for (var arg : args) | |
| 35 | arguments.add(requireNonNull(arg, "arguments element shouldn't be null")); |
|
39 | arguments.add(requireNonNull(arg, "arguments element shouldn't be null")); | |
| 36 |
|
40 | |||
| 37 | return this; |
|
41 | return this; | |
| 38 | } |
|
42 | } | |
| 39 |
|
43 | |||
| 40 | @Override |
|
44 | @Override | |
| 41 | public CommandSpec build() { |
|
45 | public CommandSpec build() { | |
| 42 | requireNonNull(executable, "Executable must be specified"); |
|
46 | requireNonNull(executable, "Executable must be specified"); | |
| 43 | return new CommandSpecRecord(executable, arguments); |
|
47 | return new CommandSpecRecord(executable, arguments); | |
| 44 | } |
|
48 | } | |
| 45 |
|
49 | |||
| 46 | } |
|
50 | } | |
| 47 | } |
|
51 | } | |
| @@ -1,40 +1,43 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
| 3 | import java.io.ByteArrayInputStream; |
|
3 | import java.io.ByteArrayInputStream; | |
| 4 | import java.io.IOException; |
|
4 | import java.io.IOException; | |
| 5 | import java.nio.charset.StandardCharsets; |
|
5 | import java.nio.charset.StandardCharsets; | |
| 6 | import java.util.concurrent.CompletableFuture; |
|
6 | import java.util.concurrent.CompletableFuture; | |
| 7 | import java.util.stream.Collectors; |
|
7 | import java.util.stream.Collectors; | |
| 8 |
|
8 | |||
|
|
9 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
10 | ||||
|
|
11 | @NonNullByDefault | |||
| 9 | class EchoExecBuilder extends AbstractExecBuilder<CommandSpec> { |
|
12 | class EchoExecBuilder extends AbstractExecBuilder<CommandSpec> { | |
| 10 |
|
13 | |||
| 11 | private final boolean echoToStderr; |
|
14 | private final boolean echoToStderr; | |
| 12 |
|
15 | |||
| 13 | public EchoExecBuilder(CommandSpec command, boolean echoToStderr) { |
|
16 | public EchoExecBuilder(CommandSpec command, boolean echoToStderr) { | |
| 14 | super(command); |
|
17 | super(command); | |
| 15 | this.echoToStderr = echoToStderr; |
|
18 | this.echoToStderr = echoToStderr; | |
| 16 | } |
|
19 | } | |
| 17 |
|
20 | |||
| 18 | @Override |
|
21 | @Override | |
| 19 | protected CompletableFuture<Integer> startInternal( |
|
22 | protected CompletableFuture<Integer> startInternal( | |
| 20 | CommandSpec command, |
|
23 | CommandSpec command, | |
| 21 | EnvironmentSpec environment, |
|
24 | EnvironmentSpec environment, | |
| 22 | PipeSpec redirect) throws IOException { |
|
25 | PipeSpec redirect) throws IOException { | |
| 23 |
|
26 | |||
| 24 | var outputRedirect = echoToStderr ? redirect.stderr() : redirect.stdout(); |
|
27 | var outputRedirect = echoToStderr ? redirect.stderr() : redirect.stdout(); | |
| 25 |
|
28 | |||
| 26 | return outputRedirect |
|
29 | return outputRedirect | |
| 27 | .map(to -> { |
|
30 | .map(to -> { | |
| 28 | var bytes = String |
|
31 | var bytes = String | |
| 29 | .format( |
|
32 | .format( | |
| 30 | "exec: %s", |
|
33 | "exec: %s", | |
| 31 | command.commandLine().stream().collect(Collectors.joining(" "))) |
|
34 | command.commandLine().stream().collect(Collectors.joining(" "))) | |
| 32 | .getBytes(StandardCharsets.UTF_8); |
|
35 | .getBytes(StandardCharsets.UTF_8); | |
| 33 |
|
36 | |||
| 34 | return to.redirect(new ByteArrayInputStream(bytes)) |
|
37 | return to.redirect(new ByteArrayInputStream(bytes)) | |
| 35 | .thenApply((x) -> 0); |
|
38 | .thenApply((x) -> 0); | |
| 36 | }) |
|
39 | }) | |
| 37 | .orElse(CompletableFuture.completedFuture(0)); |
|
40 | .orElse(CompletableFuture.completedFuture(0)); | |
| 38 | } |
|
41 | } | |
| 39 |
|
42 | |||
| 40 | } |
|
43 | } | |
| @@ -1,14 +1,17 | |||||
| 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.util.Map; |
|
4 | import java.util.Map; | |
| 5 | import java.util.Optional; |
|
5 | import java.util.Optional; | |
| 6 |
|
6 | |||
|
|
7 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
8 | ||||
|
|
9 | @NonNullByDefault | |||
| 7 | public interface EnvironmentSpec { |
|
10 | public interface EnvironmentSpec { | |
| 8 |
|
11 | |||
| 9 | boolean inheritEnvironment(); |
|
12 | boolean inheritEnvironment(); | |
| 10 |
|
13 | |||
| 11 | Map<String,String> environment(); |
|
14 | Map<String,String> environment(); | |
| 12 |
|
15 | |||
| 13 | Optional<File> workingDirectory(); |
|
16 | Optional<File> workingDirectory(); | |
| 14 | } |
|
17 | } | |
| @@ -1,53 +1,56 | |||||
| 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.FileInputStream; |
|
4 | import java.io.FileInputStream; | |
| 5 | import java.io.InputStream; |
|
5 | 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 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
10 | ||||
| 9 | /** |
|
11 | /** | |
| 10 | * Describes how to redirect input streams. This interface is used to configure |
|
12 | * Describes how to redirect input streams. This interface is used to configure | |
| 11 | * lazy redirection. {@link #redirect(OutputStream)} is called when the process |
|
13 | * lazy redirection. {@link #redirect(OutputStream)} is called when the process | |
| 12 | * is started. Before the process is started the redirection isn't invoked and |
|
14 | * is started. Before the process is started the redirection isn't invoked and | |
| 13 | * no resources are allocated or used. |
|
15 | * no resources are allocated or used. | |
| 14 | */ |
|
16 | */ | |
|
|
17 | @NonNullByDefault | |||
| 15 | public interface RedirectFrom { |
|
18 | public interface RedirectFrom { | |
| 16 | CompletableFuture<Void> redirect(OutputStream to); |
|
19 | CompletableFuture<Void> redirect(OutputStream to); | |
| 17 |
|
20 | |||
| 18 | /** |
|
21 | /** | |
| 19 | * Read file contents and redirect it to the output stream. |
|
22 | * Read file contents and redirect it to the output stream. | |
| 20 | */ |
|
23 | */ | |
| 21 | public static RedirectFrom file(final File file) { |
|
24 | public static RedirectFrom file(final File file) { | |
| 22 | return to -> CompletableFuture.runAsync(() -> { |
|
25 | return to -> CompletableFuture.runAsync(() -> { | |
| 23 | try (var from = new FileInputStream(file); to) { |
|
26 | try (var from = new FileInputStream(file); to) { | |
| 24 | from.transferTo(to); |
|
27 | from.transferTo(to); | |
| 25 | } catch (Exception e) { |
|
28 | } catch (Exception e) { | |
| 26 | // silence! |
|
29 | // silence! | |
| 27 | } |
|
30 | } | |
| 28 | }); |
|
31 | }); | |
| 29 | } |
|
32 | } | |
| 30 |
|
33 | |||
| 31 | public static RedirectFrom stream(final InputStream from) { |
|
34 | public static RedirectFrom stream(final InputStream from) { | |
| 32 | return to -> CompletableFuture.runAsync(() -> { |
|
35 | return to -> CompletableFuture.runAsync(() -> { | |
| 33 | try (from; to) { |
|
36 | try (from; to) { | |
| 34 | from.transferTo(to); |
|
37 | from.transferTo(to); | |
| 35 | } catch (Exception e) { |
|
38 | } catch (Exception e) { | |
| 36 | // silence! |
|
39 | // silence! | |
| 37 | } |
|
40 | } | |
| 38 | }); |
|
41 | }); | |
| 39 | } |
|
42 | } | |
| 40 |
|
43 | |||
| 41 | public static RedirectFrom any(final Object output) { |
|
44 | public static RedirectFrom any(final Object output) { | |
| 42 | if (output instanceof File f) { |
|
45 | if (output instanceof File f) { | |
| 43 | return file(f); |
|
46 | return file(f); | |
| 44 | } else if (output instanceof InputStream stm) { |
|
47 | } else if (output instanceof InputStream stm) { | |
| 45 | return stream(stm); |
|
48 | return stream(stm); | |
| 46 | } else if (output instanceof RedirectFrom self) { |
|
49 | } else if (output instanceof RedirectFrom self) { | |
| 47 | return self; |
|
50 | return self; | |
| 48 | } else { |
|
51 | } else { | |
| 49 | throw new IllegalArgumentException("The specified argument type isn't supported: " + output.getClass()); |
|
52 | throw new IllegalArgumentException("The specified argument type isn't supported: " + output.getClass()); | |
| 50 | } |
|
53 | } | |
| 51 | } |
|
54 | } | |
| 52 |
|
55 | |||
| 53 | } |
|
56 | } | |
| @@ -1,22 +1,29 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
|
|
3 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
4 | ||||
|
|
5 | @NonNullByDefault | |||
| 3 | public interface Shell { |
|
6 | public interface Shell { | |
| 4 |
|
7 | |||
| 5 |
ShellExec |
|
8 | ShellExec create(CommandSpec spec); | |
|
|
9 | ||||
|
|
10 | default ShellTool tool(String executable) { | |||
|
|
11 | return new ShellTool(executable, this); | |||
|
|
12 | } | |||
| 6 |
|
13 | |||
| 7 | /** Creates a new shell to start processes using ProcessBuilder. */ |
|
14 | /** Creates a new shell to start processes using ProcessBuilder. */ | |
| 8 | static Shell system() { |
|
15 | static Shell system() { | |
| 9 | return spec -> new SystemExecBuilder(spec); |
|
16 | return spec -> new SystemExecBuilder(spec); | |
| 10 | } |
|
17 | } | |
| 11 |
|
18 | |||
| 12 | /** Creates a stub shell which echoes the specified command line. */ |
|
19 | /** Creates a stub shell which echoes the specified command line. */ | |
| 13 | static Shell echo() { |
|
20 | static Shell echo() { | |
| 14 | return spec -> new EchoExecBuilder(spec, false); |
|
21 | return spec -> new EchoExecBuilder(spec, false); | |
| 15 | } |
|
22 | } | |
| 16 |
|
23 | |||
| 17 | /** Creates a stub shell which echoes the specified command line. */ |
|
24 | /** Creates a stub shell which echoes the specified command line. */ | |
| 18 | static Shell echoStderr() { |
|
25 | static Shell echoStderr() { | |
| 19 | return spec -> new EchoExecBuilder(spec, false); |
|
26 | return spec -> new EchoExecBuilder(spec, false); | |
| 20 | } |
|
27 | } | |
| 21 |
|
28 | |||
| 22 | } |
|
29 | } | |
| @@ -1,36 +1,38 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
| 3 | import java.io.IOException; |
|
3 | import java.io.IOException; | |
| 4 | import java.util.ArrayList; |
|
4 | import java.util.ArrayList; | |
| 5 | import java.util.List; |
|
5 | import java.util.List; | |
| 6 | import java.util.concurrent.CompletableFuture; |
|
6 | import java.util.concurrent.CompletableFuture; | |
| 7 |
|
7 | |||
|
|
8 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
| 8 | import org.implab.gradle.common.utils.Exceptions; |
|
9 | import org.implab.gradle.common.utils.Exceptions; | |
| 9 |
|
10 | |||
|
|
11 | @NonNullByDefault | |||
| 10 | public interface ShellExec extends PipeBuilder, EnvironmentBuilder { |
|
12 | public interface ShellExec extends PipeBuilder, EnvironmentBuilder { | |
| 11 |
|
13 | |||
| 12 | default CompletableFuture<List<String>> readAllLines() throws IOException { |
|
14 | default CompletableFuture<List<String>> readAllLines() throws IOException { | |
| 13 | List<String> lines = new ArrayList<>(); |
|
15 | List<String> lines = new ArrayList<>(); | |
| 14 | stdout(RedirectTo.consumer(lines::add)); |
|
16 | stdout(RedirectTo.consumer(lines::add)); | |
| 15 |
|
17 | |||
| 16 | return exec() |
|
18 | return exec() | |
| 17 | .thenAccept(Exceptions.unchecked(this::assertExitCode)) |
|
19 | .thenAccept(Exceptions.unchecked(this::assertExitCode)) | |
| 18 | .thenApply(v -> lines); |
|
20 | .thenApply(v -> lines); | |
| 19 | } |
|
21 | } | |
| 20 |
|
22 | |||
| 21 | default CompletableFuture<String> readAllText() throws IOException { |
|
23 | default CompletableFuture<String> readAllText() throws IOException { | |
| 22 | List<String> lines = new ArrayList<>(); |
|
24 | List<String> lines = new ArrayList<>(); | |
| 23 | stdout(RedirectTo.consumer(lines::add)); |
|
25 | stdout(RedirectTo.consumer(lines::add)); | |
| 24 |
|
26 | |||
| 25 | return exec() |
|
27 | return exec() | |
| 26 | .thenAccept(Exceptions.unchecked(this::assertExitCode)) |
|
28 | .thenAccept(Exceptions.unchecked(this::assertExitCode)) | |
| 27 | .thenApply(v -> String.join("\n", lines)); |
|
29 | .thenApply(v -> String.join("\n", lines)); | |
| 28 | } |
|
30 | } | |
| 29 |
|
31 | |||
| 30 | default void assertExitCode(Integer code) throws IOException { |
|
32 | default void assertExitCode(Integer code) throws IOException { | |
| 31 | if (code != 0) |
|
33 | if (code != 0) | |
| 32 | throw new IOException(String.format("The process is terminated with code %d", code)); |
|
34 | throw new IOException(String.format("The process is terminated with code %d", code)); | |
| 33 | } |
|
35 | } | |
| 34 |
|
36 | |||
| 35 | CompletableFuture<Integer> exec() throws IOException; |
|
37 | CompletableFuture<Integer> exec() throws IOException; | |
| 36 | } |
|
38 | } | |
| @@ -1,49 +1,52 | |||||
| 1 | package org.implab.gradle.common.exec; |
|
1 | package org.implab.gradle.common.exec; | |
| 2 |
|
2 | |||
| 3 | import java.io.IOException; |
|
3 | import java.io.IOException; | |
| 4 | import java.lang.ProcessBuilder.Redirect; |
|
4 | import java.lang.ProcessBuilder.Redirect; | |
| 5 | import java.util.ArrayList; |
|
5 | import java.util.ArrayList; | |
| 6 | import java.util.concurrent.CompletableFuture; |
|
6 | import java.util.concurrent.CompletableFuture; | |
| 7 |
|
7 | |||
|
|
8 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
9 | ||||
|
|
10 | @NonNullByDefault | |||
| 8 | class SystemExecBuilder extends AbstractExecBuilder<CommandSpec> { |
|
11 | class SystemExecBuilder extends AbstractExecBuilder<CommandSpec> { | |
| 9 | SystemExecBuilder(CommandSpec command) { |
|
12 | SystemExecBuilder(CommandSpec command) { | |
| 10 | super(command); |
|
13 | super(command); | |
| 11 | } |
|
14 | } | |
| 12 |
|
15 | |||
| 13 | @Override |
|
16 | @Override | |
| 14 | protected CompletableFuture<Integer> startInternal( |
|
17 | protected CompletableFuture<Integer> startInternal( | |
| 15 | CommandSpec command, |
|
18 | CommandSpec command, | |
| 16 | EnvironmentSpec environment, |
|
19 | EnvironmentSpec environment, | |
| 17 | PipeSpec redirect) throws IOException { |
|
20 | PipeSpec redirect) throws IOException { | |
| 18 |
|
21 | |||
| 19 | var builder = new ProcessBuilder(command.commandLine()); |
|
22 | var builder = new ProcessBuilder(command.commandLine()); | |
| 20 |
|
23 | |||
| 21 | environment.workingDirectory().ifPresent(builder::directory); |
|
24 | environment.workingDirectory().ifPresent(builder::directory); | |
| 22 |
|
25 | |||
| 23 | // if the env isn't inherited we need to clear it |
|
26 | // if the env isn't inherited we need to clear it | |
| 24 | if (!environment.inheritEnvironment()) |
|
27 | if (!environment.inheritEnvironment()) | |
| 25 | builder.environment().clear(); |
|
28 | builder.environment().clear(); | |
| 26 |
|
29 | |||
| 27 | builder.environment().putAll(environment.environment()); |
|
30 | builder.environment().putAll(environment.environment()); | |
| 28 |
|
31 | |||
| 29 | var tasks = new ArrayList<CompletableFuture<?>>(); |
|
32 | var tasks = new ArrayList<CompletableFuture<?>>(); | |
| 30 |
|
33 | |||
| 31 | if (!redirect.stdout().isPresent()) |
|
34 | if (!redirect.stdout().isPresent()) | |
| 32 | builder.redirectOutput(Redirect.DISCARD); |
|
35 | builder.redirectOutput(Redirect.DISCARD); | |
| 33 | if (!redirect.stderr().isPresent()) |
|
36 | if (!redirect.stderr().isPresent()) | |
| 34 | builder.redirectError(Redirect.DISCARD); |
|
37 | builder.redirectError(Redirect.DISCARD); | |
| 35 |
|
38 | |||
| 36 | // run process |
|
39 | // run process | |
| 37 | var proc = builder.start(); |
|
40 | var proc = builder.start(); | |
| 38 |
|
41 | |||
| 39 | tasks.add(proc.onExit()); |
|
42 | tasks.add(proc.onExit()); | |
| 40 |
|
43 | |||
| 41 | redirect.stdin().map(from -> from.redirect(proc.getOutputStream())).ifPresent(tasks::add); |
|
44 | redirect.stdin().map(from -> from.redirect(proc.getOutputStream())).ifPresent(tasks::add); | |
| 42 | redirect.stdout().map(to -> to.redirect(proc.getInputStream())).ifPresent(tasks::add); |
|
45 | redirect.stdout().map(to -> to.redirect(proc.getInputStream())).ifPresent(tasks::add); | |
| 43 | redirect.stderr().map(to -> to.redirect(proc.getErrorStream())).ifPresent(tasks::add); |
|
46 | redirect.stderr().map(to -> to.redirect(proc.getErrorStream())).ifPresent(tasks::add); | |
| 44 |
|
47 | |||
| 45 | return CompletableFuture |
|
48 | return CompletableFuture | |
| 46 | .allOf(tasks.toArray(new CompletableFuture<?>[0])) |
|
49 | .allOf(tasks.toArray(new CompletableFuture<?>[0])) | |
| 47 | .thenApply(t -> proc.exitValue()); |
|
50 | .thenApply(t -> proc.exitValue()); | |
| 48 | } |
|
51 | } | |
| 49 | } |
|
52 | } | |
| @@ -1,31 +1,31 | |||||
| 1 | package org.implab.gradle.common.tasks; |
|
1 | package org.implab.gradle.common.tasks; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.provider.ListProperty; |
|
3 | import org.gradle.api.provider.ListProperty; | |
| 4 | import org.gradle.api.provider.Property; |
|
4 | import org.gradle.api.provider.Property; | |
| 5 | import org.gradle.api.tasks.Internal; |
|
5 | import org.gradle.api.tasks.Internal; | |
| 6 | import org.implab.gradle.common.dsl.TaskCommandSpecMixin; |
|
6 | import org.implab.gradle.common.dsl.TaskCommandSpecMixin; | |
| 7 | import org.implab.gradle.common.exec.CommandSpec; |
|
7 | import org.implab.gradle.common.exec.CommandSpec; | |
| 8 | import org.implab.gradle.common.exec.Shell; |
|
8 | import org.implab.gradle.common.exec.Shell; | |
| 9 | import org.implab.gradle.common.exec.ShellExec; |
|
9 | import org.implab.gradle.common.exec.ShellExec; | |
| 10 |
|
10 | |||
| 11 | public abstract class ShellExecTask |
|
11 | public abstract class ShellExecTask | |
| 12 | extends AbstractShellExecTask |
|
12 | extends AbstractShellExecTask | |
| 13 | implements TaskCommandSpecMixin { |
|
13 | implements TaskCommandSpecMixin { | |
| 14 |
|
14 | |||
| 15 | @Internal |
|
15 | @Internal | |
| 16 | public abstract Property<Shell> getShell(); |
|
16 | public abstract Property<Shell> getShell(); | |
| 17 |
|
17 | |||
| 18 | @Internal |
|
18 | @Internal | |
| 19 | @Override |
|
19 | @Override | |
| 20 | public abstract ListProperty<String> getCommandLine(); |
|
20 | public abstract ListProperty<String> getCommandLine(); | |
| 21 |
|
21 | |||
| 22 |
|
22 | |||
| 23 | @Override |
|
23 | @Override | |
| 24 | protected ShellExec execBuilder() { |
|
24 | protected ShellExec execBuilder() { | |
| 25 | return getShell().get() |
|
25 | return getShell().get() | |
| 26 |
. |
|
26 | .create(CommandSpec.builder() | |
| 27 | .commandLine(getCommandLine().get()) |
|
27 | .commandLine(getCommandLine().get()) | |
| 28 | .build()); |
|
28 | .build()); | |
| 29 | } |
|
29 | } | |
| 30 |
|
30 | |||
| 31 | } |
|
31 | } | |
| @@ -1,72 +1,87 | |||||
| 1 | package org.implab.gradle.common.utils; |
|
1 | package org.implab.gradle.common.utils; | |
| 2 |
|
2 | |||
|
|
3 | import java.text.MessageFormat; | |||
| 3 | import java.util.Iterator; |
|
4 | import java.util.Iterator; | |
| 4 | import java.util.Spliterators; |
|
5 | import java.util.Spliterators; | |
| 5 | import java.util.Optional; |
|
6 | import java.util.Optional; | |
|
|
7 | import java.util.Set; | |||
|
|
8 | import java.util.function.Function; | |||
| 6 | import java.util.function.Supplier; |
|
9 | import java.util.function.Supplier; | |
|
|
10 | import java.util.stream.Collectors; | |||
| 7 | import java.util.stream.Stream; |
|
11 | import java.util.stream.Stream; | |
| 8 | import java.util.stream.StreamSupport; |
|
12 | import java.util.stream.StreamSupport; | |
| 9 |
|
13 | |||
| 10 | import org.gradle.api.provider.Provider; |
|
14 | import org.gradle.api.provider.Provider; | |
| 11 |
|
15 | |||
| 12 | public final class Values { |
|
16 | public final class Values { | |
| 13 |
|
17 | |||
| 14 | private Values() { |
|
18 | private Values() { | |
| 15 | } |
|
19 | } | |
| 16 |
|
20 | |||
| 17 | /** |
|
21 | /** | |
| 18 | * Converts the supplied value to a string. |
|
22 | * Converts the supplied value to a string. | |
| 19 | */ |
|
23 | */ | |
| 20 | public static String toString(Object value) { |
|
24 | public static String toString(Object value) { | |
| 21 | if (value == null) { |
|
25 | if (value == null) { | |
| 22 | return null; |
|
26 | return null; | |
| 23 | } else if (value instanceof String string) { |
|
27 | } else if (value instanceof String string) { | |
| 24 | return string; |
|
28 | return string; | |
| 25 | } else if (value instanceof Provider<?> provider) { |
|
29 | } else if (value instanceof Provider<?> provider) { | |
| 26 | return toString(provider.getOrNull()); |
|
30 | return toString(provider.getOrNull()); | |
| 27 | } else if (value instanceof Supplier<?> supplier) { |
|
31 | } else if (value instanceof Supplier<?> supplier) { | |
| 28 | return toString(supplier.get()); |
|
32 | return toString(supplier.get()); | |
| 29 | } else { |
|
33 | } else { | |
| 30 | return value.toString(); |
|
34 | return value.toString(); | |
| 31 | } |
|
35 | } | |
| 32 | } |
|
36 | } | |
| 33 |
|
37 | |||
| 34 | public static <T> Stream<T> stream(Iterator<T> remaining) { |
|
38 | public static <T> Stream<T> stream(Iterator<T> remaining) { | |
| 35 | return StreamSupport.stream( |
|
39 | return StreamSupport.stream( | |
| 36 | Spliterators.spliteratorUnknownSize(remaining, 0), |
|
40 | Spliterators.spliteratorUnknownSize(remaining, 0), | |
| 37 | false); |
|
41 | false); | |
| 38 | } |
|
42 | } | |
| 39 |
|
43 | |||
| 40 | public static <T> Optional<T> take(Iterator<T> iterator) { |
|
44 | public static <T> Optional<T> take(Iterator<T> iterator) { | |
| 41 | return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty(); |
|
45 | return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty(); | |
| 42 | } |
|
46 | } | |
| 43 |
|
47 | |||
| 44 | public static <T> Iterable<T> iterable(T[] values) { |
|
48 | public static <T> Iterable<T> iterable(T[] values) { | |
| 45 | return () -> new ArrayIterator<>(values); |
|
49 | return () -> new ArrayIterator<>(values); | |
| 46 | } |
|
50 | } | |
| 47 |
|
51 | |||
| 48 | public static <T> Optional<T> optional(Provider<T> provider) { |
|
52 | public static <T> Optional<T> optional(Provider<T> provider) { | |
| 49 | return provider.isPresent() ? Optional.of(provider.get()) : Optional.empty(); |
|
53 | return provider.isPresent() ? Optional.of(provider.get()) : Optional.empty(); | |
| 50 | } |
|
54 | } | |
| 51 |
|
55 | |||
|
|
56 | public static <T> T required(Provider<T> provider, String providerName) { | |||
|
|
57 | if (!provider.isPresent()) | |||
|
|
58 | throw new IllegalStateException( | |||
|
|
59 | MessageFormat.format("The value for the '{0}' provider must be specified", providerName)); | |||
|
|
60 | return provider.get(); | |||
|
|
61 | } | |||
|
|
62 | ||||
|
|
63 | public static <U,V> Set<V> mapSet(Set<U> values, Function<U,V> mapper) { | |||
|
|
64 | return values.stream().map(mapper).collect(Collectors.toUnmodifiableSet()); | |||
|
|
65 | } | |||
|
|
66 | ||||
| 52 | private static class ArrayIterator<T> implements Iterator<T> { |
|
67 | private static class ArrayIterator<T> implements Iterator<T> { | |
| 53 | private final T[] data; |
|
68 | private final T[] data; | |
| 54 |
|
69 | |||
| 55 | private int pos = 0; |
|
70 | private int pos = 0; | |
| 56 |
|
71 | |||
| 57 | ArrayIterator(T[] data) { |
|
72 | ArrayIterator(T[] data) { | |
| 58 | this.data = data; |
|
73 | this.data = data; | |
| 59 | } |
|
74 | } | |
| 60 |
|
75 | |||
| 61 | @Override |
|
76 | @Override | |
| 62 | public boolean hasNext() { |
|
77 | public boolean hasNext() { | |
| 63 | return pos < data.length; |
|
78 | return pos < data.length; | |
| 64 | } |
|
79 | } | |
| 65 |
|
80 | |||
| 66 | @Override |
|
81 | @Override | |
| 67 | public T next() { |
|
82 | public T next() { | |
| 68 | return data[pos++]; |
|
83 | return data[pos++]; | |
| 69 | } |
|
84 | } | |
| 70 | } |
|
85 | } | |
| 71 |
|
86 | |||
| 72 | } |
|
87 | } | |
| 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
