| @@ -0,0 +1,12 | |||
|
|
1 | # AGENTS.md | |
|
|
2 | ||
|
|
3 | ## Проектные договоренности | |
|
|
4 | ||
|
|
5 | ### Публичное API библиотек | |
|
|
6 | ||
|
|
7 | - Предпочтителен `non-null` подход. | |
|
|
8 | - Там, где значение живет в Gradle Provider API, возвращается `Provider<T>` (не `null`). | |
|
|
9 | - Там, где lookup синхронный, возвращается `Optional<T>` (не `null`). | |
|
|
10 | - `find*` рассматривается как синоним legacy `get*` (поиск без `fail-fast`). | |
|
|
11 | - `require*` это `find*` + `fail-fast` с понятной ошибкой в месте вызова. | |
|
|
12 | - Для нового API предпочтительны формы `find/require`; новые `get*` по возможности не добавлять. | |
| @@ -4,9 +4,8 import java.util.ArrayList; | |||
|
|
4 | 4 | import java.util.Collection; |
|
|
5 | 5 | import java.util.Collections; |
|
|
6 | 6 | import java.util.LinkedHashMap; |
|
|
7 | import java.util.LinkedHashSet; | |
|
|
8 | 7 | import java.util.List; |
|
|
9 |
import java.util. |
|
|
|
8 | import java.util.Optional; | |
|
|
10 | 9 | |
|
|
11 | 10 | import javax.inject.Inject; |
|
|
12 | 11 | |
| @@ -101,8 +100,14 public abstract class BuildVariant imple | |||
|
|
101 | 100 | }); |
|
|
102 | 101 | } |
|
|
103 | 102 | |
|
|
104 |
public BuildRole |
|
|
|
105 | return roles.get(name); | |
|
|
103 | public Optional<BuildRole> findRole(String name) { | |
|
|
104 | return Optional.ofNullable(roles.get(name)); | |
|
|
105 | } | |
|
|
106 | ||
|
|
107 | public BuildRole requireRole(String name) { | |
|
|
108 | return findRole(name) | |
|
|
109 | .orElseThrow(() -> new InvalidUserDataException( | |
|
|
110 | "Variant '" + this.name + "' doesn't define role '" + name + "'")); | |
|
|
106 | 111 | } |
|
|
107 | 112 | |
|
|
108 | 113 | public Collection<LayerLink> getLinks() { |
| @@ -157,17 +162,14 public abstract class BuildVariant imple | |||
|
|
157 | 162 | return artifactSlot(name, Closures.action(configure)); |
|
|
158 | 163 | } |
|
|
159 | 164 | |
|
|
160 |
public BuildArtifactSlot |
|
|
|
161 | return artifactSlots.get(name); | |
|
|
165 | public Optional<BuildArtifactSlot> findArtifactSlot(String name) { | |
|
|
166 | return Optional.ofNullable(artifactSlots.get(name)); | |
|
|
162 | 167 | } |
|
|
163 | 168 | |
|
|
164 | Set<String> declaredLayerNames() { | |
|
|
165 | var result = new LinkedHashSet<String>(); | |
|
|
166 | ||
|
|
167 | for (var role : roles.values()) | |
|
|
168 | result.addAll(role.getLayers().getOrElse(java.util.List.of())); | |
|
|
169 | ||
|
|
170 | return result; | |
|
|
169 | public BuildArtifactSlot requireArtifactSlot(String name) { | |
|
|
170 | return findArtifactSlot(name) | |
|
|
171 | .orElseThrow(() -> new InvalidUserDataException( | |
|
|
172 | "Variant '" + this.name + "' doesn't define artifact slot '" + name + "'")); | |
|
|
171 | 173 | } |
|
|
172 | 174 | |
|
|
173 | 175 | void finalizeModel() { |
| @@ -218,8 +220,12 public abstract class BuildVariant imple | |||
|
|
218 | 220 | return BuildVariant.this.getRoles(); |
|
|
219 | 221 | } |
|
|
220 | 222 | |
|
|
221 |
public BuildRole |
|
|
|
222 |
return BuildVariant.this. |
|
|
|
223 | public Optional<BuildRole> find(String name) { | |
|
|
224 | return BuildVariant.this.findRole(name); | |
|
|
225 | } | |
|
|
226 | ||
|
|
227 | public BuildRole require(String name) { | |
|
|
228 | return BuildVariant.this.requireRole(name); | |
|
|
223 | 229 | } |
|
|
224 | 230 | } |
|
|
225 | 231 | |
| @@ -250,8 +256,12 public abstract class BuildVariant imple | |||
|
|
250 | 256 | return BuildVariant.this.getArtifactSlots(); |
|
|
251 | 257 | } |
|
|
252 | 258 | |
|
|
253 |
public BuildArtifactSlot |
|
|
|
254 |
return BuildVariant.this. |
|
|
|
259 | public Optional<BuildArtifactSlot> find(String name) { | |
|
|
260 | return BuildVariant.this.findArtifactSlot(name); | |
|
|
261 | } | |
|
|
262 | ||
|
|
263 | public BuildArtifactSlot require(String name) { | |
|
|
264 | return BuildVariant.this.requireArtifactSlot(name); | |
|
|
255 | 265 | } |
|
|
256 | 266 | } |
|
|
257 | 267 | |
| @@ -9,6 +9,7 import java.util.LinkedHashMap; | |||
|
|
9 | 9 | import java.util.LinkedHashSet; |
|
|
10 | 10 | import java.util.List; |
|
|
11 | 11 | import java.util.Map; |
|
|
12 | import java.util.Optional; | |
|
|
12 | 13 | import java.util.Set; |
|
|
13 | 14 | |
|
|
14 | 15 | import javax.inject.Inject; |
| @@ -117,8 +118,13 public abstract class BuildVariantsExten | |||
|
|
117 | 118 | return Collections.unmodifiableList(all); |
|
|
118 | 119 | } |
|
|
119 | 120 | |
|
|
120 |
public BuildVariant |
|
|
|
121 | return variants.findByName(name); | |
|
|
121 | public Optional<BuildVariant> find(String name) { | |
|
|
122 | return Optional.ofNullable(variants.findByName(name)); | |
|
|
123 | } | |
|
|
124 | ||
|
|
125 | public BuildVariant require(String name) { | |
|
|
126 | return find(name) | |
|
|
127 | .orElseThrow(() -> new InvalidUserDataException("Variant '" + name + "' isn't defined")); | |
|
|
122 | 128 | } |
|
|
123 | 129 | |
|
|
124 | 130 | public void whenFinalized(Action<? super BuildVariantsExtension> action) { |
| @@ -15,10 +15,12 import org.gradle.api.provider.Provider; | |||
|
|
15 | 15 | public final class VariantAttributes { |
|
|
16 | 16 | private final ProviderFactory providers; |
|
|
17 | 17 | private final LinkedHashMap<Attribute<?>, Provider<?>> values = new LinkedHashMap<>(); |
|
|
18 | private final Provider<Object> emptyValueProvider; | |
|
|
18 | 19 | private boolean finalized; |
|
|
19 | 20 | |
|
|
20 | 21 | VariantAttributes(ProviderFactory providers) { |
|
|
21 | 22 | this.providers = providers; |
|
|
23 | this.emptyValueProvider = providers.provider(() -> null); | |
|
|
22 | 24 | } |
|
|
23 | 25 | |
|
|
24 | 26 | public <T> void attribute(Attribute<T> key, T value) { |
| @@ -32,8 +34,18 public final class VariantAttributes { | |||
|
|
32 | 34 | } |
|
|
33 | 35 | |
|
|
34 | 36 | @SuppressWarnings("unchecked") |
|
|
35 |
public <T> Provider<T> |
|
|
|
36 |
return |
|
|
|
37 | public <T> Provider<T> find(Attribute<T> key) { | |
|
|
38 | return providers | |
|
|
39 | .provider(() -> (Provider<T>) values.getOrDefault(key, emptyValueProvider)) | |
|
|
40 | .flatMap(provider -> provider); | |
|
|
41 | } | |
|
|
42 | ||
|
|
43 | public <T> Provider<T> require(Attribute<T> key) { | |
|
|
44 | var value = find(key); | |
|
|
45 | if (!value.isPresent()) | |
|
|
46 | throw new InvalidUserDataException("Attribute '" + key.getName() + "' doesn't have a value"); | |
|
|
47 | ||
|
|
48 | return value; | |
|
|
37 | 49 | } |
|
|
38 | 50 | |
|
|
39 | 51 | public boolean contains(Attribute<?> key) { |
| @@ -55,7 +55,7 class VariantsPluginFunctionalTest { | |||
|
|
55 | 55 | |
|
|
56 | 56 | tasks.register('probe') { |
|
|
57 | 57 | doLast { |
|
|
58 |
def browser = variants. |
|
|
|
58 | def browser = variants.require('browser') | |
|
|
59 | 59 | println('attributes=' + browser.attributes.size()) |
|
|
60 | 60 | println('roles=' + browser.roles.size()) |
|
|
61 | 61 | println('links=' + browser.links.size()) |
| @@ -277,7 +277,7 class VariantsPluginFunctionalTest { | |||
|
|
277 | 277 | } |
|
|
278 | 278 | |
|
|
279 | 279 | afterEvaluate { |
|
|
280 |
variants. |
|
|
|
280 | variants.require('browser').role('late') { layers('a') } | |
|
|
281 | 281 | } |
|
|
282 | 282 | """, "Variant 'browser' is finalized and cannot configure roles"); |
|
|
283 | 283 | } |
| @@ -99,7 +99,7 Typed-атрибуты (`Attribute<T> -> Provider<T>`) для передачи параметров в | |||
|
|
99 | 99 | - `variant(...)` — объявление или конфигурация `BuildVariant`. |
|
|
100 | 100 | - `layers { ... }`, `variants { ... }` — контейнерный DSL. |
|
|
101 | 101 | - `all(...)` — callback для всех вариантов. |
|
|
102 |
- `getAll()`, ` |
|
|
|
102 | - `getAll()`, `find(name)`, `require(name)` — доступ к вариантам. | |
|
|
103 | 103 | - `validate()` — явный запуск валидации. |
|
|
104 | 104 | - `finalizeModel()` — валидация + финализация модели. |
|
|
105 | 105 | - `whenFinalized(...)` — callback по завершенной модели (replayable). |
General Comments 0
You need to be logged in to leave comments.
Login now
