| @@ -1,8 +1,9 | |||||
| 1 | { |
|
1 | { | |
| 2 | "java.configuration.updateBuildConfiguration": "automatic", |
|
2 | "java.configuration.updateBuildConfiguration": "automatic", | |
| 3 | "java.compile.nullAnalysis.mode": "automatic", |
|
3 | "java.compile.nullAnalysis.mode": "automatic", | |
| 4 | "cSpell.words": [ |
|
4 | "cSpell.words": [ | |
| 5 | "implab", |
|
5 | "implab", | |
|
|
6 | "materializer", | |||
| 6 | "rawtypes" |
|
7 | "rawtypes" | |
| 7 | ] |
|
8 | ] | |
| 8 | } No newline at end of file |
|
9 | } | |
| @@ -1,12 +1,42 | |||||
| 1 | # AGENTS.md |
|
1 | # AGENTS.md | |
| 2 |
|
2 | |||
| 3 | ## ΠΡΠΎΠ΅ΠΊΡΠ½ΡΠ΅ Π΄ΠΎΠ³ΠΎΠ²ΠΎΡΠ΅Π½Π½ΠΎΡΡΠΈ |
|
3 | ## ΠΡΠΎΠ΅ΠΊΡΠ½ΡΠ΅ Π΄ΠΎΠ³ΠΎΠ²ΠΎΡΠ΅Π½Π½ΠΎΡΡΠΈ | |
| 4 |
|
4 | |||
| 5 | ### ΠΡΠ±Π»ΠΈΡΠ½ΠΎΠ΅ API Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊ |
|
5 | ### ΠΡΠ±Π»ΠΈΡΠ½ΠΎΠ΅ API Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊ | |
| 6 |
|
6 | |||
| 7 | - ΠΡΠ΅Π΄ΠΏΠΎΡΡΠΈΡΠ΅Π»Π΅Π½ `non-null` ΠΏΠΎΠ΄Ρ ΠΎΠ΄. |
|
7 | - ΠΡΠ΅Π΄ΠΏΠΎΡΡΠΈΡΠ΅Π»Π΅Π½ `non-null` ΠΏΠΎΠ΄Ρ ΠΎΠ΄. | |
| 8 | - Π’Π°ΠΌ, Π³Π΄Π΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΆΠΈΠ²Π΅Ρ Π² Gradle Provider API, Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΡΡΡ `Provider<T>` (Π½Π΅ `null`). |
|
8 | - Π’Π°ΠΌ, Π³Π΄Π΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΆΠΈΠ²Π΅Ρ Π² Gradle Provider API, Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΡΡΡ `Provider<T>` (Π½Π΅ `null`). | |
| 9 | - Π’Π°ΠΌ, Π³Π΄Π΅ lookup ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΡΠΉ, Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΡΡΡ `Optional<T>` (Π½Π΅ `null`). |
|
9 | - Π’Π°ΠΌ, Π³Π΄Π΅ lookup ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΡΠΉ, Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΡΡΡ `Optional<T>` (Π½Π΅ `null`). | |
| 10 | - `find*` ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΡΡΡ ΠΊΠ°ΠΊ ΡΠΈΠ½ΠΎΠ½ΠΈΠΌ legacy `get*` (ΠΏΠΎΠΈΡΠΊ Π±Π΅Π· `fail-fast`). |
|
10 | - `find*` ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΡΡΡ ΠΊΠ°ΠΊ ΡΠΈΠ½ΠΎΠ½ΠΈΠΌ legacy `get*` (ΠΏΠΎΠΈΡΠΊ Π±Π΅Π· `fail-fast`). | |
| 11 | - `require*` ΡΡΠΎ `find*` + `fail-fast` Ρ ΠΏΠΎΠ½ΡΡΠ½ΠΎΠΉ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ Π² ΠΌΠ΅ΡΡΠ΅ Π²ΡΠ·ΠΎΠ²Π°. |
|
11 | - `require*` ΡΡΠΎ `find*` + `fail-fast` Ρ ΠΏΠΎΠ½ΡΡΠ½ΠΎΠΉ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ Π² ΠΌΠ΅ΡΡΠ΅ Π²ΡΠ·ΠΎΠ²Π°. | |
| 12 | - ΠΠ»Ρ Π½ΠΎΠ²ΠΎΠ³ΠΎ API ΠΏΡΠ΅Π΄ΠΏΠΎΡΡΠΈΡΠ΅Π»ΡΠ½Ρ ΡΠΎΡΠΌΡ `find/require`; Π½ΠΎΠ²ΡΠ΅ `get*` ΠΏΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ Π½Π΅ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ. |
|
12 | - ΠΠ»Ρ Π½ΠΎΠ²ΠΎΠ³ΠΎ API ΠΏΡΠ΅Π΄ΠΏΠΎΡΡΠΈΡΠ΅Π»ΡΠ½Ρ ΡΠΎΡΠΌΡ `find/require`; Π½ΠΎΠ²ΡΠ΅ `get*` ΠΏΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ Π½Π΅ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ. | |
|
|
13 | ||||
|
|
14 | ## Identity-first modeling | |||
|
|
15 | ||||
|
|
16 | Prefer an **identity-first** split between: | |||
|
|
17 | ||||
|
|
18 | - **identity objects** used for discovery and selection | |||
|
|
19 | - **stateful/materialized objects** obtained through separate API calls | |||
|
|
20 | ||||
|
|
21 | ### Rules | |||
|
|
22 | ||||
|
|
23 | - Objects intended for replayable observation (`all(...)`, similar collection APIs) should be **identity objects**. | |||
|
|
24 | - Identity objects must be: | |||
|
|
25 | - cheap to create | |||
|
|
26 | - effectively immutable | |||
|
|
27 | - limited to identity and cheap selection metadata | |||
|
|
28 | - Heavy, computed, provider-based, or runtime-bound state must be resolved separately. | |||
|
|
29 | - Aggregate content should be accessed through dedicated lookup/materialization APIs. | |||
|
|
30 | - Eager observation of identity is acceptable. | |||
|
|
31 | - Eager observation of computed state is not. | |||
|
|
32 | ||||
|
|
33 | ### Do not | |||
|
|
34 | ||||
|
|
35 | - Do not store heavy computed state inside identity objects. | |||
|
|
36 | - Do not store runtime references to foreign domains inside identity objects. | |||
|
|
37 | - Do not use custom events when replayable identity registries plus on-demand lookup are sufficient. | |||
|
|
38 | ||||
|
|
39 | ### Rule of thumb | |||
|
|
40 | ||||
|
|
41 | **Identity objects contain selection metadata. | |||
|
|
42 | Aggregate content is obtained separately, on demand.** | |||
| @@ -1,34 +1,35 | |||||
| 1 | package org.implab.gradle.common.core.lang; |
|
1 | package org.implab.gradle.common.core.lang; | |
| 2 |
|
2 | |||
| 3 | import java.util.Objects; |
|
3 | import java.util.Objects; | |
| 4 | import java.util.function.Supplier; |
|
4 | import java.util.function.Supplier; | |
| 5 |
|
5 | |||
| 6 | public class LazyValue<T> implements Supplier<T> { |
|
6 | public class LazyValue<T> implements Supplier<T> { | |
| 7 | private volatile T value; |
|
7 | private volatile T value; | |
|
|
8 | private volatile boolean initialized = false; | |||
| 8 |
|
9 | |||
| 9 | private final Supplier<T> innerSupplier; |
|
10 | private final Supplier<T> innerSupplier; | |
| 10 |
|
11 | |||
| 11 | public LazyValue(Supplier<T> supplier) { |
|
12 | public LazyValue(Supplier<T> supplier) { | |
| 12 | this.innerSupplier = supplier; |
|
13 | this.innerSupplier = supplier; | |
| 13 | } |
|
14 | } | |
| 14 |
|
15 | |||
| 15 | @Override |
|
16 | @Override | |
| 16 | public T get() { |
|
17 | public T get() { | |
| 17 | var v = value; |
|
18 | var v = value; | |
| 18 |
if ( |
|
19 | if (initialized) { | |
| 19 | return v; |
|
20 | return v; | |
| 20 | } |
|
21 | } | |
| 21 |
|
22 | |||
| 22 | synchronized (this) { |
|
23 | synchronized (this) { | |
| 23 | v = value; |
|
24 | v = value; | |
| 24 | if (v == null) { |
|
25 | if (v == null) { | |
| 25 | v = Objects.requireNonNull( |
|
26 | v = Objects.requireNonNull( | |
| 26 | innerSupplier.get(), |
|
27 | innerSupplier.get(), | |
| 27 | "LazyValue supplier returned null"); |
|
28 | "LazyValue supplier returned null"); | |
| 28 | value = v; |
|
29 | value = v; | |
| 29 | } |
|
30 | } | |
| 30 | return v; |
|
31 | return v; | |
| 31 | } |
|
32 | } | |
| 32 | } |
|
33 | } | |
| 33 |
|
34 | |||
| 34 | } |
|
35 | } | |
| @@ -1,65 +1,70 | |||||
| 1 | package org.implab.gradle.common.core.lang; |
|
1 | package org.implab.gradle.common.core.lang; | |
| 2 |
|
2 | |||
| 3 | import java.util.regex.Pattern; |
|
3 | import java.util.regex.Pattern; | |
| 4 |
|
4 | |||
| 5 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 6 | import org.gradle.api.provider.Provider; |
|
6 | import org.gradle.api.provider.Provider; | |
| 7 |
|
7 | |||
| 8 | @NonNullByDefault |
|
8 | @NonNullByDefault | |
| 9 | public class Strings { |
|
9 | public class Strings { | |
| 10 |
|
10 | |||
| 11 | private static final Pattern firstLetter = Pattern.compile("^\\w"); |
|
11 | private static final Pattern firstLetter = Pattern.compile("^\\w"); | |
| 12 |
|
12 | |||
| 13 | private static final Pattern INVALID_NAME_CHAR = Pattern.compile("[^A-Za-z0-9_.-]"); |
|
13 | private static final Pattern INVALID_NAME_CHAR = Pattern.compile("[^A-Za-z0-9_.-]"); | |
| 14 |
|
14 | |||
| 15 | public static String capitalize(String string) { |
|
15 | public static String capitalize(String string) { | |
| 16 | return string == null ? null |
|
16 | return string == null ? null | |
| 17 | : string.length() == 0 ? string |
|
17 | : string.length() == 0 ? string | |
| 18 | : firstLetter.matcher(string).replaceFirst(m -> m.group().toUpperCase()); |
|
18 | : firstLetter.matcher(string).replaceFirst(m -> m.group().toUpperCase()); | |
| 19 | } |
|
19 | } | |
| 20 |
|
20 | |||
| 21 | public static String toCamelCase(String name) { |
|
21 | public static String toCamelCase(String name) { | |
| 22 | if (name == null || name.isEmpty()) |
|
22 | if (name == null || name.isEmpty()) | |
| 23 | return name; |
|
23 | return name; | |
| 24 | StringBuilder out = new StringBuilder(name.length()); |
|
24 | StringBuilder out = new StringBuilder(name.length()); | |
| 25 | boolean up = false; |
|
25 | boolean up = false; | |
| 26 | boolean first = true; |
|
26 | boolean first = true; | |
| 27 | for (int i = 0; i < name.length(); i++) { |
|
27 | for (int i = 0; i < name.length(); i++) { | |
| 28 | char c = name.charAt(i); |
|
28 | char c = name.charAt(i); | |
| 29 | switch (c) { |
|
29 | switch (c) { | |
| 30 | case '-', '_', ' ', '.' -> up = true; |
|
30 | case '-', '_', ' ', '.' -> up = true; | |
| 31 | default -> { |
|
31 | default -> { | |
| 32 | out.append( |
|
32 | out.append( | |
| 33 | first ? Character.toLowerCase(c) |
|
33 | first ? Character.toLowerCase(c) | |
| 34 | : up ? Character.toUpperCase(c): c); |
|
34 | : up ? Character.toUpperCase(c): c); | |
| 35 | up = false; |
|
35 | up = false; | |
| 36 | first = false; |
|
36 | first = false; | |
| 37 | } |
|
37 | } | |
| 38 | } |
|
38 | } | |
| 39 | } |
|
39 | } | |
| 40 | return out.toString(); |
|
40 | return out.toString(); | |
| 41 | } |
|
41 | } | |
| 42 |
|
42 | |||
| 43 | public static void argumentNotNullOrEmpty(String value, String argumentName) { |
|
43 | public static void argumentNotNullOrEmpty(String value, String argumentName) { | |
| 44 | if (value == null || value.length() == 0) |
|
44 | if (value == null || value.length() == 0) | |
| 45 | throw new IllegalArgumentException(String.format("Argument %s can't be null or empty", argumentName)); |
|
45 | throw new IllegalArgumentException(String.format("Argument %s can't be null or empty", argumentName)); | |
| 46 | } |
|
46 | } | |
| 47 |
|
47 | |||
| 48 | public static void argumentNotNullOrBlank(String value, String argumentName) { |
|
48 | public static void argumentNotNullOrBlank(String value, String argumentName) { | |
| 49 | if (value == null || value.trim().length() == 0) |
|
49 | if (value == null || value.trim().length() == 0) | |
| 50 | throw new IllegalArgumentException(String.format("Argument %s can't be null or blank", argumentName)); |
|
50 | throw new IllegalArgumentException(String.format("Argument %s can't be null or blank", argumentName)); | |
| 51 | } |
|
51 | } | |
| 52 |
|
52 | |||
|
|
53 | public static String requireNonBlank(String value) { | |||
|
|
54 | argumentNotNullOrBlank(value, "value"); | |||
|
|
55 | return value; | |||
|
|
56 | } | |||
|
|
57 | ||||
| 53 | public static String sanitizeName(String value) { |
|
58 | public static String sanitizeName(String value) { | |
| 54 | return INVALID_NAME_CHAR.matcher(value).replaceAll("_"); |
|
59 | return INVALID_NAME_CHAR.matcher(value).replaceAll("_"); | |
| 55 | } |
|
60 | } | |
| 56 |
|
61 | |||
| 57 | public static String asString(Object value) { |
|
62 | public static String asString(Object value) { | |
| 58 | if (value == null) |
|
63 | if (value == null) | |
| 59 | return null; |
|
64 | return null; | |
| 60 | if (value instanceof Provider<?> provider) |
|
65 | if (value instanceof Provider<?> provider) | |
| 61 | return asString(provider.get()); |
|
66 | return asString(provider.get()); | |
| 62 | else |
|
67 | else | |
| 63 | return value.toString(); |
|
68 | return value.toString(); | |
| 64 | } |
|
69 | } | |
| 65 | } |
|
70 | } | |
| @@ -1,17 +1,15 | |||||
| 1 | package org.implab.gradle.variants; |
|
1 | package org.implab.gradle.variants; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Plugin; |
|
3 | import org.gradle.api.Plugin; | |
| 4 | import org.gradle.api.Project; |
|
4 | import org.gradle.api.Project; | |
| 5 | import org.implab.gradle.variants.model.VariantsExtension; |
|
5 | import org.implab.gradle.variants.model.VariantsExtension; | |
| 6 |
|
6 | |||
| 7 | public abstract class VariantsPlugin implements Plugin<Project> { |
|
7 | public abstract class VariantsPlugin implements Plugin<Project> { | |
| 8 | @Override |
|
8 | @Override | |
| 9 | public void apply(Project target) { |
|
9 | public void apply(Project target) { | |
| 10 | var extension = target.getExtensions().create("variants", VariantsExtension.class); |
|
|||
| 11 |
|
10 | |||
| 12 | target.afterEvaluate(project -> { |
|
11 | target.getExtensions().create("variants", VariantsExtension.class); | |
| 13 |
|
||||
| 14 | }); |
|
|||
| 15 |
|
12 | |||
| 16 | } |
|
13 | } | |
|
|
14 | ||||
| 17 | } |
|
15 | } | |
| @@ -1,35 +1,8 | |||||
| 1 | package org.implab.gradle.variants.model; |
|
1 | package org.implab.gradle.variants.model; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Named; |
|
3 | /** A binding between a role and a layer inside a specific variant. | |
| 4 | import org.gradle.api.provider.SetProperty; |
|
|||
| 5 |
|
||||
| 6 | /** |
|
|||
| 7 | * Binds a role to a set of layers inside a particular variant. |
|
|||
| 8 | * |
|
4 | * | |
| 9 | * The binding name is the role name, e.g. "production", "test", "tool". |
|
5 | * @see {@link VariantDefinition} for the context of this binding. | |
| 10 |
|
|
6 | */ | |
| 11 | public interface RoleBinding extends Named { |
|
7 | public record RoleLayerBinding(String name, String layerName) { | |
| 12 |
|
||||
| 13 | /** |
|
|||
| 14 | * Layer names participating in this (variant, role) selection. |
|
|||
| 15 | * |
|
|||
| 16 | * Core model keeps names here deliberately: |
|
|||
| 17 | * source/materialization semantics live elsewhere. |
|
|||
| 18 | */ |
|
|||
| 19 | SetProperty<String> getLayerNames(); |
|
|||
| 20 |
|
||||
| 21 | /** |
|
|||
| 22 | * Adds one layer to this binding. |
|
|||
| 23 | */ |
|
|||
| 24 | void layer(String name); |
|
|||
| 25 |
|
||||
| 26 | /** |
|
|||
| 27 | * Adds several layers to this binding. |
|
|||
| 28 | */ |
|
|||
| 29 | void layers(String... names); |
|
|||
| 30 |
|
||||
| 31 | /** |
|
|||
| 32 | * Adds several layers to this binding. |
|
|||
| 33 | */ |
|
|||
| 34 | void layers(Iterable<String> names); |
|
|||
| 35 | } No newline at end of file |
|
8 | } | |
| @@ -1,44 +1,12 | |||||
| 1 | package org.implab.gradle.variants.model; |
|
1 | package org.implab.gradle.variants.model; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Action; |
|
|||
| 4 | import org.gradle.api.Named; |
|
3 | import org.gradle.api.Named; | |
| 5 | import org.gradle.api.NamedDomainObjectContainer; |
|
|||
| 6 | import org.implab.gradle.common.core.lang.Closures; |
|
|||
| 7 |
|
||||
| 8 | import groovy.lang.Closure; |
|
|||
| 9 |
|
4 | |||
| 10 | /** |
|
5 | /** | |
| 11 | * A named variant, e.g. "browser", "electron". |
|
6 | * A named variant, e.g. "browser", "electron". | |
| 12 | * |
|
7 | * | |
| 13 | * A variant does not "have a role" directly. |
|
8 | * A variant does not "have a role" directly. | |
| 14 | * It owns a set of role bindings. |
|
9 | * It owns a set of role bindings. | |
| 15 | */ |
|
10 | */ | |
| 16 | public interface Variant extends Named { |
|
11 | public interface Variant extends Named { | |
| 17 |
|
||||
| 18 | /** |
|
|||
| 19 | * Role bindings declared inside this variant. |
|
|||
| 20 | * |
|
|||
| 21 | * The binding name is the role name. |
|
|||
| 22 | */ |
|
|||
| 23 | NamedDomainObjectContainer<RoleBinding> getRoleBindings(); |
|
|||
| 24 |
|
||||
| 25 | /** |
|
|||
| 26 | * Creates or returns an existing role binding and configures it. |
|
|||
| 27 | */ |
|
|||
| 28 | default RoleBinding role(String name) { |
|
|||
| 29 | return getRoleBindings().maybeCreate(name); |
|
|||
| 30 | } |
|
|||
| 31 |
|
||||
| 32 | /** |
|
|||
| 33 | * Creates or returns an existing role binding and configures it. |
|
|||
| 34 | */ |
|
|||
| 35 | default RoleBinding role(String name, Action<? super RoleBinding> action) { |
|
|||
| 36 | var role = role(name); |
|
|||
| 37 | action.execute(role); |
|
|||
| 38 | return role; |
|
|||
| 39 | } |
|
|||
| 40 |
|
||||
| 41 | default RoleBinding role(String name, Closure<?> closure) { |
|
|||
| 42 | return role(name, Closures.action(closure)); |
|
|||
| 43 | } |
|
|||
| 44 | } No newline at end of file |
|
12 | } | |
| @@ -1,59 +1,65 | |||||
| 1 | package org.implab.gradle.variants.model; |
|
1 | package org.implab.gradle.variants.model; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Action; |
|
3 | import org.gradle.api.Action; | |
| 4 | import org.gradle.api.NamedDomainObjectContainer; |
|
4 | import org.gradle.api.NamedDomainObjectContainer; | |
| 5 | import org.implab.gradle.common.core.lang.Closures; |
|
5 | import org.implab.gradle.common.core.lang.Closures; | |
| 6 |
|
6 | |||
| 7 | import groovy.lang.Closure; |
|
7 | import groovy.lang.Closure; | |
| 8 |
|
8 | |||
| 9 | /** |
|
9 | /** | |
| 10 | * Root extension: |
|
10 | * Root extension: | |
| 11 | * |
|
11 | * | |
| 12 | * variants { |
|
12 | * variants { | |
| 13 |
* |
|
13 | * layers { ... } | |
| 14 |
* |
|
14 | * roles { ... } | |
| 15 | * |
|
15 | * | |
| 16 |
* |
|
16 | * variant("browser") { | |
| 17 |
* |
|
17 | * role("production") { | |
| 18 |
* |
|
18 | * layers("main", "generated", "mainRjs") | |
| 19 | * } |
|
19 | * } | |
| 20 |
* |
|
20 | * } | |
| 21 | * } |
|
21 | * } | |
| 22 | */ |
|
22 | */ | |
| 23 | public interface VariantsExtension { |
|
23 | public interface VariantsExtension { | |
| 24 |
|
24 | |||
| 25 | /** |
|
25 | /** | |
| 26 | * Domain of layers. |
|
26 | * Domain of layers. | |
| 27 | */ |
|
27 | */ | |
| 28 | NamedDomainObjectContainer<Layer> getLayers(); |
|
28 | NamedDomainObjectContainer<Layer> getLayers(); | |
| 29 |
|
29 | |||
| 30 | /** |
|
30 | /** | |
| 31 | * Domain of roles. |
|
31 | * Domain of roles. | |
| 32 | */ |
|
32 | */ | |
| 33 | NamedDomainObjectContainer<Role> getRoles(); |
|
33 | NamedDomainObjectContainer<Role> getRoles(); | |
| 34 |
|
34 | |||
| 35 | /** |
|
35 | /** | |
|
|
36 | * Domain of variants. | |||
|
|
37 | */ | |||
|
|
38 | NamedDomainObjectContainer<Variant> getVariants(); | |||
|
|
39 | ||||
|
|
40 | /** | |||
| 36 | * Declared variants. |
|
41 | * Declared variants. | |
| 37 | */ |
|
42 | */ | |
| 38 | NamedDomainObjectContainer<Variant> getVariantDefinitions(); |
|
43 | NamedDomainObjectContainer<VariantDefinition> getVariantDefinitions(); | |
| 39 |
|
44 | |||
| 40 | /** |
|
45 | /** | |
| 41 | * Creates or returns an existing variant and configures it. |
|
46 | * Creates or returns an existing variant and configures it. | |
| 42 | */ |
|
47 | */ | |
| 43 | default Variant variant(String name) { |
|
48 | default VariantDefinition variant(String name) { | |
|
|
49 | ||||
| 44 | return getVariantDefinitions().maybeCreate(name); |
|
50 | return getVariantDefinitions().maybeCreate(name); | |
| 45 | } |
|
51 | } | |
| 46 |
|
52 | |||
| 47 | /** |
|
53 | /** | |
| 48 | * Creates or returns an existing variant and configures it. |
|
54 | * Creates or returns an existing variant and configures it. | |
| 49 | */ |
|
55 | */ | |
| 50 | default Variant variant(String name, Action<? super Variant> action) { |
|
56 | default VariantDefinition variant(String name, Action<? super VariantDefinition> action) { | |
| 51 | var variant = variant(name); |
|
57 | var variant = variant(name); | |
| 52 | action.execute(variant); |
|
58 | action.execute(variant); | |
| 53 | return variant; |
|
59 | return variant; | |
| 54 | } |
|
60 | } | |
| 55 |
|
61 | |||
| 56 | default Variant variant(String name, Closure<?> closure) { |
|
62 | default VariantDefinition variant(String name, Closure<?> closure) { | |
| 57 | return variant(name, Closures.action(closure)); |
|
63 | return variant(name, Closures.action(closure)); | |
| 58 | } |
|
64 | } | |
| 59 | } No newline at end of file |
|
65 | } | |
General Comments 0
You need to be logged in to leave comments.
Login now
