| @@ -0,0 +1,24 | |||||
|
|
1 | BSD 2-Clause License | |||
|
|
2 | ||||
|
|
3 | Copyright (c) 2026 gradle-common contributors. | |||
|
|
4 | ||||
|
|
5 | Redistribution and use in source and binary forms, with or without modification, | |||
|
|
6 | are permitted provided that the following conditions are met: | |||
|
|
7 | ||||
|
|
8 | 1. Redistributions of source code must retain the above copyright notice, this | |||
|
|
9 | list of conditions and the following disclaimer. | |||
|
|
10 | ||||
|
|
11 | 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
|
12 | this list of conditions and the following disclaimer in the documentation | |||
|
|
13 | and/or other materials provided with the distribution. | |||
|
|
14 | ||||
|
|
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
|
|
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
|
|
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
|
|
18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |||
|
|
19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
|
|
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
|
|
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |||
|
|
22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
|
|
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
|
|
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| @@ -0,0 +1,99 | |||||
|
|
1 | # Local Ivy Publishing | |||
|
|
2 | ||||
|
|
3 | This project currently publishes only to a local Ivy repository. Maven Central, | |||
|
|
4 | signing, and Gradle Plugin Portal publication are intentionally out of scope for | |||
|
|
5 | the current preparation step. | |||
|
|
6 | ||||
|
|
7 | Published Ivy descriptors include the BSD-2-Clause license metadata. | |||
|
|
8 | ||||
|
|
9 | ## Repository | |||
|
|
10 | ||||
|
|
11 | The configured Ivy repository is: | |||
|
|
12 | ||||
|
|
13 | ```text | |||
|
|
14 | ${user.home}/ivy-repo | |||
|
|
15 | ``` | |||
|
|
16 | ||||
|
|
17 | This is defined in: | |||
|
|
18 | ||||
|
|
19 | - `common/build.gradle` | |||
|
|
20 | - `variants/build.gradle` | |||
|
|
21 | ||||
|
|
22 | ## Verify Before Publishing | |||
|
|
23 | ||||
|
|
24 | Run a full clean verification: | |||
|
|
25 | ||||
|
|
26 | ```bash | |||
|
|
27 | ./gradlew clean check javadoc jar sourcesJar javadocJar --rerun-tasks | |||
|
|
28 | ``` | |||
|
|
29 | ||||
|
|
30 | Optional configuration-cache smoke check: | |||
|
|
31 | ||||
|
|
32 | ```bash | |||
|
|
33 | ./gradlew check --configuration-cache | |||
|
|
34 | ``` | |||
|
|
35 | ||||
|
|
36 | ## Publish | |||
|
|
37 | ||||
|
|
38 | Publish all modules: | |||
|
|
39 | ||||
|
|
40 | ```bash | |||
|
|
41 | ./gradlew publish | |||
|
|
42 | ``` | |||
|
|
43 | ||||
|
|
44 | Publish modules explicitly: | |||
|
|
45 | ||||
|
|
46 | ```bash | |||
|
|
47 | ./gradlew :common:publishIvyPublicationToIvyRepository \ | |||
|
|
48 | :variants:publishIvyPublicationToIvyRepository | |||
|
|
49 | ``` | |||
|
|
50 | ||||
|
|
51 | Safe smoke publish into a temporary repository: | |||
|
|
52 | ||||
|
|
53 | ```bash | |||
|
|
54 | ./gradlew -Duser.home=/tmp/gradle-common-ivy-smoke \ | |||
|
|
55 | :common:publishIvyPublicationToIvyRepository \ | |||
|
|
56 | :variants:publishIvyPublicationToIvyRepository \ | |||
|
|
57 | --rerun-tasks | |||
|
|
58 | ``` | |||
|
|
59 | ||||
|
|
60 | ## Consume Locally | |||
|
|
61 | ||||
|
|
62 | Use `buildscript` classpath for now: | |||
|
|
63 | ||||
|
|
64 | ```groovy | |||
|
|
65 | buildscript { | |||
|
|
66 | repositories { | |||
|
|
67 | ivy { | |||
|
|
68 | url "${System.properties['user.home']}/ivy-repo" | |||
|
|
69 | } | |||
|
|
70 | mavenCentral() | |||
|
|
71 | } | |||
|
|
72 | dependencies { | |||
|
|
73 | classpath 'org.implab.gradle:variants:0.1.0' | |||
|
|
74 | } | |||
|
|
75 | } | |||
|
|
76 | ||||
|
|
77 | apply plugin: 'org.implab.gradle-variants' | |||
|
|
78 | apply plugin: 'org.implab.gradle-variants-sources' | |||
|
|
79 | ``` | |||
|
|
80 | ||||
|
|
81 | The `plugins {}` DSL needs generated plugin marker artifacts and is not part of | |||
|
|
82 | the current local Ivy contract. | |||
|
|
83 | ||||
|
|
84 | ## Published Artifacts | |||
|
|
85 | ||||
|
|
86 | Each module publishes: | |||
|
|
87 | ||||
|
|
88 | - `<module>-<version>.jar` | |||
|
|
89 | - `<module>-<version>-sources.jar` | |||
|
|
90 | - `<module>-<version>-javadoc.jar` | |||
|
|
91 | - `ivy.xml` | |||
|
|
92 | - Gradle module metadata | |||
|
|
93 | ||||
|
|
94 | ## Current Coordinates | |||
|
|
95 | ||||
|
|
96 | ```text | |||
|
|
97 | org.implab.gradle:common:0.1.0 | |||
|
|
98 | org.implab.gradle:variants:0.1.0 | |||
|
|
99 | ``` | |||
| @@ -0,0 +1,296 | |||||
|
|
1 | # gradle-common | |||
|
|
2 | ||||
|
|
3 | Java 21 multi-project build with shared Gradle utilities and experimental | |||
|
|
4 | variant-oriented Gradle plugins. | |||
|
|
5 | ||||
|
|
6 | The repository currently publishes to a local Ivy repository only. Maven Central | |||
|
|
7 | and Gradle Plugin Portal publication are intentionally not configured yet. | |||
|
|
8 | ||||
|
|
9 | ## Modules | |||
|
|
10 | ||||
|
|
11 | - `common` - shared Gradle utilities, JSON helpers, shell execution helpers, and | |||
|
|
12 | small core value/util classes. | |||
|
|
13 | - `variants` - Gradle plugins for variant topology, source-set materialization, | |||
|
|
14 | and outgoing artifact slots. | |||
|
|
15 | ||||
|
|
16 | ## Requirements | |||
|
|
17 | ||||
|
|
18 | - JDK 21. | |||
|
|
19 | - Gradle Wrapper from this repository, currently Gradle 8.10.2. | |||
|
|
20 | ||||
|
|
21 | The produced bytecode targets Java 21. | |||
|
|
22 | ||||
|
|
23 | ## License | |||
|
|
24 | ||||
|
|
25 | This project is licensed under the BSD 2-Clause "Simplified" License | |||
|
|
26 | (`BSD-2-Clause`). See [LICENSE](LICENSE). | |||
|
|
27 | ||||
|
|
28 | ## Local Build | |||
|
|
29 | ||||
|
|
30 | ```bash | |||
|
|
31 | ./gradlew clean check javadoc jar sourcesJar javadocJar --rerun-tasks | |||
|
|
32 | ``` | |||
|
|
33 | ||||
|
|
34 | Configuration cache smoke check: | |||
|
|
35 | ||||
|
|
36 | ```bash | |||
|
|
37 | ./gradlew check --configuration-cache | |||
|
|
38 | ``` | |||
|
|
39 | ||||
|
|
40 | ## Local Ivy Publication | |||
|
|
41 | ||||
|
|
42 | The current publication target is: | |||
|
|
43 | ||||
|
|
44 | ```text | |||
|
|
45 | ${user.home}/ivy-repo | |||
|
|
46 | ``` | |||
|
|
47 | ||||
|
|
48 | Publish both modules locally: | |||
|
|
49 | ||||
|
|
50 | ```bash | |||
|
|
51 | ./gradlew :common:publishIvyPublicationToIvyRepository \ | |||
|
|
52 | :variants:publishIvyPublicationToIvyRepository | |||
|
|
53 | ``` | |||
|
|
54 | ||||
|
|
55 | or: | |||
|
|
56 | ||||
|
|
57 | ```bash | |||
|
|
58 | ./gradlew publish | |||
|
|
59 | ``` | |||
|
|
60 | ||||
|
|
61 | The publication includes: | |||
|
|
62 | ||||
|
|
63 | - main jar | |||
|
|
64 | - sources jar | |||
|
|
65 | - javadoc jar | |||
|
|
66 | - Ivy descriptor | |||
|
|
67 | - Gradle module metadata | |||
|
|
68 | ||||
|
|
69 | ## Local Consumption | |||
|
|
70 | ||||
|
|
71 | Current plugin ids are packaged as classic Gradle plugin marker resources inside | |||
|
|
72 | the `variants` jar: | |||
|
|
73 | ||||
|
|
74 | - `org.implab.gradle-variants` | |||
|
|
75 | - `org.implab.gradle-sources` | |||
|
|
76 | - `org.implab.gradle-variants-sources` | |||
|
|
77 | - `org.implab.gradle-variants-artifacts` | |||
|
|
78 | ||||
|
|
79 | Until Gradle Plugin Portal marker artifacts are configured, consume the plugin | |||
|
|
80 | through `buildscript` classpath: | |||
|
|
81 | ||||
|
|
82 | ```groovy | |||
|
|
83 | buildscript { | |||
|
|
84 | repositories { | |||
|
|
85 | ivy { | |||
|
|
86 | url "${System.properties['user.home']}/ivy-repo" | |||
|
|
87 | } | |||
|
|
88 | mavenCentral() | |||
|
|
89 | } | |||
|
|
90 | dependencies { | |||
|
|
91 | classpath 'org.implab.gradle:variants:0.1.0' | |||
|
|
92 | } | |||
|
|
93 | } | |||
|
|
94 | ||||
|
|
95 | apply plugin: 'org.implab.gradle-variants' | |||
|
|
96 | apply plugin: 'org.implab.gradle-variants-sources' | |||
|
|
97 | ``` | |||
|
|
98 | ||||
|
|
99 | The `plugins { id(...) version(...) }` DSL is not part of the current local Ivy | |||
|
|
100 | contract. | |||
|
|
101 | ||||
|
|
102 | ## Variants DSL | |||
|
|
103 | ||||
|
|
104 | `variants` defines the finalized build topology. It does not create compile | |||
|
|
105 | tasks, source directories, or outgoing publications by itself. | |||
|
|
106 | ||||
|
|
107 | ```groovy | |||
|
|
108 | apply plugin: 'org.implab.gradle-variants' | |||
|
|
109 | ||||
|
|
110 | variants.layers.create('main') | |||
|
|
111 | variants.layers.create('test') | |||
|
|
112 | variants.roles.create('main') | |||
|
|
113 | variants.roles.create('test') | |||
|
|
114 | ||||
|
|
115 | variants.variant('browser') { | |||
|
|
116 | role('main') { | |||
|
|
117 | layers('main') | |||
|
|
118 | } | |||
|
|
119 | role('test') { | |||
|
|
120 | layers('main', 'test') | |||
|
|
121 | } | |||
|
|
122 | } | |||
|
|
123 | ||||
|
|
124 | variants.whenFinalized { view -> | |||
|
|
125 | println view.entries.collect { | |||
|
|
126 | "${it.variant().name}:${it.role().name}:${it.layer().name}" | |||
|
|
127 | }.sort() | |||
|
|
128 | } | |||
|
|
129 | ``` | |||
|
|
130 | ||||
|
|
131 | The finalized model exposes cheap identity objects: `Variant`, `Role`, `Layer`, | |||
|
|
132 | and the normalized relation `(variant, role, layer)`. | |||
|
|
133 | ||||
|
|
134 | ## Sources DSL | |||
|
|
135 | ||||
|
|
136 | `sources` creates standalone `GenericSourceSet` objects. This is useful for | |||
|
|
137 | fallback workflows that do not need variant topology. | |||
|
|
138 | ||||
|
|
139 | ```groovy | |||
|
|
140 | apply plugin: 'org.implab.gradle-sources' | |||
|
|
141 | ||||
|
|
142 | sources.create('main') { | |||
|
|
143 | declareOutputs('js') | |||
|
|
144 | registerOutput('js', layout.projectDirectory.file('inputs/main.js')) | |||
|
|
145 | ||||
|
|
146 | sets.create('ts') { | |||
|
|
147 | srcDir 'src/main/ts' | |||
|
|
148 | } | |||
|
|
149 | } | |||
|
|
150 | ``` | |||
|
|
151 | ||||
|
|
152 | `SourcesPlugin` applies layout conventions: | |||
|
|
153 | ||||
|
|
154 | - `sourceSetDir = src/<sourceSet>` | |||
|
|
155 | - `outputsDir = build/out/<sourceSet>` | |||
|
|
156 | ||||
|
|
157 | The base `GenericSourceSet` model itself is convention-free. | |||
|
|
158 | ||||
|
|
159 | ## Variant Sources DSL | |||
|
|
160 | ||||
|
|
161 | `variantSources` derives compile units from finalized `variants`. | |||
|
|
162 | ||||
|
|
163 | A compile unit is: | |||
|
|
164 | ||||
|
|
165 | ```text | |||
|
|
166 | (variant, layer) | |||
|
|
167 | ``` | |||
|
|
168 | ||||
|
|
169 | Selectors configure materialized compile-unit source sets: | |||
|
|
170 | ||||
|
|
171 | ```groovy | |||
|
|
172 | apply plugin: 'org.implab.gradle-variants-sources' | |||
|
|
173 | ||||
|
|
174 | variants.layers.create('main') | |||
|
|
175 | variants.roles.create('main') | |||
|
|
176 | variants.variant('browser') { | |||
|
|
177 | role('main') { | |||
|
|
178 | layers('main') | |||
|
|
179 | } | |||
|
|
180 | } | |||
|
|
181 | ||||
|
|
182 | variantSources { | |||
|
|
183 | layer('main') { | |||
|
|
184 | sourceSet { | |||
|
|
185 | declareOutputs('js') | |||
|
|
186 | registerOutput('js', layout.projectDirectory.file('inputs/browser.js')) | |||
|
|
187 | } | |||
|
|
188 | } | |||
|
|
189 | ||||
|
|
190 | configureEach { | |||
|
|
191 | println "sourceSet=${sourceSet.name}, variant=${variant.name}, layer=${layer.name}" | |||
|
|
192 | } | |||
|
|
193 | } | |||
|
|
194 | ``` | |||
|
|
195 | ||||
|
|
196 | Selector order for future materialization is: | |||
|
|
197 | ||||
|
|
198 | ```text | |||
|
|
199 | configureEach -> variant -> layer -> unit | |||
|
|
200 | ``` | |||
|
|
201 | ||||
|
|
202 | Late selector registration is controlled by: | |||
|
|
203 | ||||
|
|
204 | ```groovy | |||
|
|
205 | variantSources { | |||
|
|
206 | lateConfigurationPolicy { | |||
|
|
207 | failOnLateConfiguration() | |||
|
|
208 | } | |||
|
|
209 | } | |||
|
|
210 | ``` | |||
|
|
211 | ||||
|
|
212 | Compile-unit source set names are generated by default as: | |||
|
|
213 | ||||
|
|
214 | ```text | |||
|
|
215 | <variant> + capitalize(<layer>) | |||
|
|
216 | ``` | |||
|
|
217 | ||||
|
|
218 | Name collisions fail by default and may be resolved deterministically: | |||
|
|
219 | ||||
|
|
220 | ```groovy | |||
|
|
221 | variantSources { | |||
|
|
222 | namingPolicy { | |||
|
|
223 | resolveNameCollision() | |||
|
|
224 | } | |||
|
|
225 | } | |||
|
|
226 | ``` | |||
|
|
227 | ||||
|
|
228 | ## Variant Artifacts DSL | |||
|
|
229 | ||||
|
|
230 | `variantArtifacts` is an experimental outgoing artifact layer over `variants` | |||
|
|
231 | and `variantSources`. | |||
|
|
232 | ||||
|
|
233 | The current model maps: | |||
|
|
234 | ||||
|
|
235 | - `Variant` to a variant-level consumable outgoing configuration. | |||
|
|
236 | - `Slot` to a Gradle outgoing artifact variant inside that configuration. | |||
|
|
237 | - `primarySlot` to the primary artifact set of the outgoing configuration. | |||
|
|
238 | ||||
|
|
239 | ```groovy | |||
|
|
240 | apply plugin: 'org.implab.gradle-variants-artifacts' | |||
|
|
241 | ||||
|
|
242 | variants.layers.create('main') | |||
|
|
243 | variants.roles.create('main') | |||
|
|
244 | variants.variant('browser') { | |||
|
|
245 | role('main') { | |||
|
|
246 | layers('main') | |||
|
|
247 | } | |||
|
|
248 | } | |||
|
|
249 | ||||
|
|
250 | variantSources.layer('main') { | |||
|
|
251 | sourceSet { | |||
|
|
252 | declareOutputs('types', 'js') | |||
|
|
253 | registerOutput('types', layout.projectDirectory.file('inputs/index.d.ts')) | |||
|
|
254 | registerOutput('js', layout.projectDirectory.file('inputs/index.js')) | |||
|
|
255 | } | |||
|
|
256 | } | |||
|
|
257 | ||||
|
|
258 | variantArtifacts { | |||
|
|
259 | variant('browser') { | |||
|
|
260 | primarySlot('typesPackage') { | |||
|
|
261 | fromVariant { | |||
|
|
262 | output('types') | |||
|
|
263 | } | |||
|
|
264 | } | |||
|
|
265 | slot('js') { | |||
|
|
266 | fromVariant { | |||
|
|
267 | output('js') | |||
|
|
268 | } | |||
|
|
269 | } | |||
|
|
270 | } | |||
|
|
271 | ||||
|
|
272 | whenOutgoingConfiguration { publication -> | |||
|
|
273 | publication.configuration { | |||
|
|
274 | description = "Outgoing contract for ${publication.variant.name}" | |||
|
|
275 | } | |||
|
|
276 | } | |||
|
|
277 | ||||
|
|
278 | whenOutgoingSlot { publication -> | |||
|
|
279 | println "slot=${publication.artifactSlot.slot.name}, primary=${publication.primary}" | |||
|
|
280 | } | |||
|
|
281 | } | |||
|
|
282 | ``` | |||
|
|
283 | ||||
|
|
284 | The artifact API is still considered pre-1.0 and may change. | |||
|
|
285 | ||||
|
|
286 | ## Publication Status | |||
|
|
287 | ||||
|
|
288 | Current status: | |||
|
|
289 | ||||
|
|
290 | - local Ivy publication only | |||
|
|
291 | - no Maven Central publication metadata | |||
|
|
292 | - no signing | |||
|
|
293 | - no Gradle Plugin Portal marker artifacts | |||
|
|
294 | - BSD-2-Clause license committed | |||
|
|
295 | ||||
|
|
296 | Before external publication, see [RELEASE_CHECKLIST.md](RELEASE_CHECKLIST.md). | |||
| @@ -0,0 +1,63 | |||||
|
|
1 | # Release Checklist | |||
|
|
2 | ||||
|
|
3 | This checklist tracks what should be true before publishing outside the local | |||
|
|
4 | Ivy repository. | |||
|
|
5 | ||||
|
|
6 | ## Current Scope | |||
|
|
7 | ||||
|
|
8 | For now the project is prepared for local Ivy publication only. | |||
|
|
9 | ||||
|
|
10 | ## Required Before External Publication | |||
|
|
11 | ||||
|
|
12 | - Add Maven publication (`maven-publish`) if publishing to Maven repositories. | |||
|
|
13 | - Add signing for Maven Central or any repository that requires signed | |||
|
|
14 | artifacts. | |||
|
|
15 | - Add complete POM metadata: project name, description, URL, license, | |||
|
|
16 | developers, and SCM coordinates. | |||
|
|
17 | - Keep Java 21 as the public baseline and document it for consumers. | |||
|
|
18 | - Decide whether `variants` artifact APIs are published as experimental or | |||
|
|
19 | split into a later module. | |||
|
|
20 | - Add Gradle plugin marker artifact generation if `plugins { id(...) version(...) }` | |||
|
|
21 | must work. | |||
|
|
22 | - Add a published-consumption smoke test that resolves artifacts from a | |||
|
|
23 | temporary local repository. | |||
|
|
24 | ||||
|
|
25 | ## Local Ivy Release Steps | |||
|
|
26 | ||||
|
|
27 | 1. Ensure the Mercurial working tree is clean. | |||
|
|
28 | 2. Run: | |||
|
|
29 | ||||
|
|
30 | ```bash | |||
|
|
31 | ./gradlew clean check javadoc jar sourcesJar javadocJar --rerun-tasks | |||
|
|
32 | ``` | |||
|
|
33 | ||||
|
|
34 | 3. Optionally run: | |||
|
|
35 | ||||
|
|
36 | ```bash | |||
|
|
37 | ./gradlew check --configuration-cache | |||
|
|
38 | ``` | |||
|
|
39 | ||||
|
|
40 | 4. Publish locally: | |||
|
|
41 | ||||
|
|
42 | ```bash | |||
|
|
43 | ./gradlew publish | |||
|
|
44 | ``` | |||
|
|
45 | ||||
|
|
46 | 5. Optionally smoke-publish into `/tmp` first: | |||
|
|
47 | ||||
|
|
48 | ```bash | |||
|
|
49 | ./gradlew -Duser.home=/tmp/gradle-common-ivy-smoke \ | |||
|
|
50 | :common:publishIvyPublicationToIvyRepository \ | |||
|
|
51 | :variants:publishIvyPublicationToIvyRepository \ | |||
|
|
52 | --rerun-tasks | |||
|
|
53 | ``` | |||
|
|
54 | ||||
|
|
55 | 6. Verify `${user.home}/ivy-repo/org.implab.gradle` contains `common` and | |||
|
|
56 | `variants` for the expected version. | |||
|
|
57 | ||||
|
|
58 | ## API Status | |||
|
|
59 | ||||
|
|
60 | - `common` is intended to be a shared utility library. | |||
|
|
61 | - `variants` core and source APIs are pre-1.0 and should be treated as | |||
|
|
62 | evolving. | |||
|
|
63 | - `variantArtifacts` is experimental and may change more aggressively. | |||
| @@ -1,7 +1,8 | |||||
| 1 | syntax: glob |
|
1 | syntax: glob | |
| 2 | .gradle/ |
|
2 | .gradle/ | |
| 3 | .codex/ |
|
3 | .codex/ | |
|
|
4 | build/ | |||
| 4 | common/build/ |
|
5 | common/build/ | |
| 5 | common/bin/ |
|
6 | common/bin/ | |
| 6 | variants/build/ |
|
7 | variants/build/ | |
| 7 | variants/bin/ |
|
8 | variants/bin/ | |
| @@ -1,51 +1,57 | |||||
| 1 | plugins { |
|
1 | plugins { | |
| 2 | id "java-library" |
|
2 | id "java-library" | |
| 3 | id "ivy-publish" |
|
3 | id "ivy-publish" | |
| 4 | } |
|
4 | } | |
| 5 |
|
5 | |||
|
|
6 | description = "Shared Gradle build utilities used by Implab plugins" | |||
|
|
7 | ||||
| 6 | java { |
|
8 | java { | |
| 7 | withJavadocJar() |
|
9 | withJavadocJar() | |
| 8 | withSourcesJar() |
|
10 | withSourcesJar() | |
| 9 | toolchain { |
|
11 | toolchain { | |
| 10 | languageVersion = JavaLanguageVersion.of(21) |
|
12 | languageVersion = JavaLanguageVersion.of(21) | |
| 11 | } |
|
13 | } | |
| 12 | } |
|
14 | } | |
| 13 |
|
15 | |||
| 14 | dependencies { |
|
16 | dependencies { | |
| 15 | compileOnly libs.jdt.annotations |
|
17 | compileOnly libs.jdt.annotations | |
| 16 |
|
18 | |||
| 17 | api gradleApi(), |
|
19 | api gradleApi(), | |
| 18 | libs.bundles.jackson |
|
20 | libs.bundles.jackson | |
| 19 |
|
21 | |||
| 20 | testImplementation gradleTestKit() |
|
22 | testImplementation gradleTestKit() | |
| 21 | testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4" |
|
23 | testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4" | |
| 22 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4" |
|
24 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4" | |
| 23 | testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4" |
|
25 | testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4" | |
| 24 | } |
|
26 | } | |
| 25 |
|
27 | |||
| 26 | task printVersion{ |
|
28 | task printVersion{ | |
| 27 | doLast { |
|
29 | doLast { | |
| 28 | println "project: $project.group:$project.name:$project.version" |
|
30 | println "project: $project.group:$project.name:$project.version" | |
| 29 | println "jar: ${->jar.archiveFileName.get()}" |
|
31 | println "jar: ${->jar.archiveFileName.get()}" | |
| 30 | } |
|
32 | } | |
| 31 | } |
|
33 | } | |
| 32 |
|
34 | |||
| 33 | test { |
|
35 | test { | |
| 34 | useJUnitPlatform() |
|
36 | useJUnitPlatform() | |
| 35 | } |
|
37 | } | |
| 36 |
|
38 | |||
| 37 | publishing { |
|
39 | publishing { | |
| 38 | repositories { |
|
40 | repositories { | |
| 39 | ivy { |
|
41 | ivy { | |
| 40 | url "${System.properties["user.home"]}/ivy-repo" |
|
42 | url "${System.properties["user.home"]}/ivy-repo" | |
| 41 | } |
|
43 | } | |
| 42 | } |
|
44 | } | |
| 43 | publications { |
|
45 | publications { | |
| 44 | ivy(IvyPublication) { |
|
46 | ivy(IvyPublication) { | |
| 45 | from components.java |
|
47 | from components.java | |
| 46 | descriptor.description { |
|
48 | descriptor.description { | |
| 47 | text = providers.provider({ description }) |
|
49 | text = providers.provider({ description }) | |
| 48 | } |
|
50 | } | |
|
|
51 | descriptor.license { | |||
|
|
52 | name = "BSD-2-Clause" | |||
|
|
53 | url = "https://spdx.org/licenses/BSD-2-Clause.html" | |||
| 49 | } |
|
54 | } | |
| 50 | } |
|
55 | } | |
| 51 | } |
|
56 | } | |
|
|
57 | } | |||
| @@ -1,134 +1,18 | |||||
| 1 |
# Gradle Common |
|
1 | # Gradle Common | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `gradle-common/common` β Π½Π°Π±ΠΎΡ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² Π΄Π»Ρ ΠΌΠΎΠ΄Π΅Π»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ² ΡΠ±ΠΎΡΠΊΠΈ, |
|
|||
| 6 | ΡΠ΅Π³ΠΈΡΡΡΠ°ΡΠΈΠΈ source sets ΠΈ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ ΡΡΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ Ρ toolchain-Π°Π΄Π°ΠΏΡΠ΅ΡΠ°ΠΌΠΈ. |
|
|||
| 7 |
|
||||
| 8 | ## SYNOPSIS |
|
|||
| 9 |
|
||||
| 10 | ```groovy |
|
|||
| 11 | plugins { |
|
|||
| 12 | id 'org.implab.gradle-variants-sources' |
|
|||
| 13 | } |
|
|||
| 14 |
|
||||
| 15 | variants { |
|
|||
| 16 | layer('mainBase') |
|
|||
| 17 | layer('mainAmd') |
|
|||
| 18 |
|
||||
| 19 | variant('browser') { |
|
|||
| 20 | role('main') { layers('mainBase', 'mainAmd') } |
|
|||
| 21 | } |
|
|||
| 22 | } |
|
|||
| 23 |
|
||||
| 24 | variantSources { |
|
|||
| 25 | bind('mainBase') { |
|
|||
| 26 | configureSourceSet { |
|
|||
| 27 | declareOutputs('compiled') |
|
|||
| 28 | } |
|
|||
| 29 | } |
|
|||
| 30 |
|
||||
| 31 | bind('mainAmd').sourceSetNamePattern = '{variant}{layerCap}' |
|
|||
| 32 |
|
2 | |||
| 33 | whenRegistered { sourceSetName() } |
|
3 | `common` is the shared utility module used by the Gradle plugins in this | |
| 34 |
|
4 | repository. | ||
| 35 | whenBound { ctx -> |
|
|||
| 36 | ctx.configureSourceSet { |
|
|||
| 37 | declareOutputs('typings') |
|
|||
| 38 | } |
|
|||
| 39 | } |
|
|||
| 40 | } |
|
|||
| 41 | ``` |
|
|||
| 42 |
|
||||
| 43 | ## DESCRIPTION |
|
|||
| 44 |
|
||||
| 45 | ΠΠΎΠ΄ΡΠ»Ρ ΡΠΎΡΡΠΎΠΈΡ ΠΈΠ· ΡΡΠ΅Ρ Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΠΈΡ ΡΠ°ΡΡΠ΅ΠΉ: |
|
|||
| 46 |
|
5 | |||
| 47 | - `variants` β Π΄Π΅ΠΊΠ»Π°ΡΠ°ΡΠΈΠ²Π½Π°Ρ Π΄ΠΎΠΌΠ΅Π½Π½Π°Ρ ΠΌΠΎΠ΄Π΅Π»Ρ ΡΠ±ΠΎΡΠΊΠΈ; |
|
6 | It contains: | |
| 48 | - `sources` β ΠΌΠΎΠ΄Π΅Π»Ρ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΈ ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅ΠΌΡΡ source sets; |
|
|||
| 49 | - `variantSources` β Π°Π΄Π°ΠΏΡΠ΅Ρ, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠ²ΡΠ·ΡΠ²Π°Π΅Ρ ΠΏΠ΅ΡΠ²ΡΠ΅ Π΄Π²Π΅ ΠΌΠΎΠ΄Π΅Π»ΠΈ. |
|
|||
| 50 |
|
||||
| 51 | ΠΠΈΠΆΠ΅ ΡΠ°ΡΠΊΡΡΡΠΈΠ΅ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΠ°ΡΡΠΈ. |
|
|||
| 52 |
|
||||
| 53 | ### variants |
|
|||
| 54 |
|
||||
| 55 | `variants` Π·Π°Π΄Π°Π΅Ρ ΡΡΡΡΠΊΡΡΡΡ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²Π° ΡΠ±ΠΎΡΠΊΠΈ: ΠΊΠ°ΠΊΠΈΠ΅ Π΅ΡΡΡ ΡΠ»ΠΎΠΈ, ΠΊΠ°ΠΊΠΈΠ΅ ΡΠΎΠ»ΠΈ |
|
|||
| 56 | ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ ΡΡΠΈ ΡΠ»ΠΎΠΈ Π² ΠΊΠ°ΠΆΠ΄ΠΎΠΌ Π²Π°ΡΠΈΠ°Π½ΡΠ΅, ΠΊΠ°ΠΊΠΈΠ΅ Π΅ΡΡΡ Π°ΡΡΠΈΠ±ΡΡΡ ΠΈ artifact slots. |
|
|||
| 57 | ΠΠΎΠ΄Π΅Π»Ρ Π½Π΅ ΡΠΎΠ·Π΄Π°Π΅Ρ Π·Π°Π΄Π°ΡΠΈ ΠΈ Π½Π΅ ΠΏΡΠΈΠ²ΡΠ·Π°Π½Π° ΠΊ TS/JS. |
|
|||
| 58 |
|
||||
| 59 | ΠΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΡΠΌΡΡΠ»: |
|
|||
| 60 |
|
||||
| 61 | - ΡΠΎΡΠΌΠ°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΡ ΡΠ±ΠΎΡΠΊΠΈ; |
|
|||
| 62 | - Π΄Π°ΡΡ Π°Π΄Π°ΠΏΡΠ΅ΡΠ°ΠΌ Π΅Π΄ΠΈΠ½ΡΠΉ ΠΈΡΡΠΎΡΠ½ΠΈΠΊ ΠΏΡΠ°Π²Π΄Ρ. |
|
|||
| 63 |
|
||||
| 64 | ### sources |
|
|||
| 65 |
|
7 | |||
| 66 | `sources` ΠΎΠΏΠΈΡΡΠ²Π°Π΅Ρ Π½Π΅Π·Π°Π²ΠΈΡΠΈΠΌΡΠ΅ source sets (`GenericSourceSet`) Ρ ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠΌΠΈ |
|
8 | - core Gradle helper utilities | |
| 67 | outputs. ΠΡΠΎ ΡΠΆΠ΅ "ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΈΠΉ" ΡΡΠΎΠ²Π΅Π½Ρ, ΠΊ ΠΊΠΎΡΠΎΡΠΎΠΌΡ ΡΠ΄ΠΎΠ±Π½ΠΎ ΠΏΡΠΈΠ²ΡΠ·ΡΠ²Π°ΡΡ Π·Π°Π΄Π°ΡΠΈ, |
|
9 | - small language/value helpers | |
| 68 | Π°ΡΡΠ΅ΡΠ°ΠΊΡΡ ΠΈ task inputs/outputs. |
|
10 | - shell execution helpers | |
| 69 |
|
11 | - JSON DSL and JSON-writing task support | ||
| 70 | ΠΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΡΠΌΡΡΠ»: |
|
|||
| 71 |
|
||||
| 72 | - ΡΠΎΠ·Π΄Π°ΡΡ Π΅Π΄ΠΈΠ½ΡΠΉ ΠΊΠΎΠ½ΡΡΠ°ΠΊΡ ΠΏΠΎ Π²Ρ ΠΎΠ΄Π°ΠΌ/Π²ΡΡ ΠΎΠ΄Π°ΠΌ; |
|
|||
| 73 | - ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°ΡΡ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ Π·Π°Π΄Π°Ρ ΠΊΠ°ΠΊ outputs source set; |
|
|||
| 74 | - ΠΌΠΈΠ½ΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΡΡΡΠ½ΡΠ΅ `dependsOn` Π·Π° ΡΡΠ΅Ρ ΠΌΠΎΠ΄Π΅Π»ΠΈ outputs. |
|
|||
| 75 |
|
||||
| 76 | ### variantSources |
|
|||
| 77 |
|
||||
| 78 | `variantSources` ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ source sets Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ `variants`, ΠΏΡΠΈΠΌΠ΅Π½ΡΠ΅Ρ |
|
|||
| 79 | ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ layer-bindings ΠΈ ΠΎΡΠ΄Π°Π΅Ρ ΡΠΎΠ±ΡΡΠΈΡ (`whenRegistered`, `whenBound`) Π΄Π»Ρ |
|
|||
| 80 | Π°Π΄Π°ΠΏΡΠ΅ΡΠΎΠ² Π΄ΡΡΠ³ΠΈΡ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ². |
|
|||
| 81 |
|
||||
| 82 | ΠΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΡΠΌΡΡΠ»: |
|
|||
| 83 |
|
||||
| 84 | - ΠΏΠ΅ΡΠ΅Π²ΠΎΠ΄ΠΈΡΡ Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ `variants` Π² executable-ΠΌΠΎΠ΄Π΅Π»Ρ `sources`; |
|
|||
| 85 | - Π½Π°Π²Π΅ΡΠΈΠ²Π°ΡΡ ΠΏΠΎΠ»ΠΈΡΠΈΠΊΠΈ toolchain Π½Π° Π·Π°ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ source sets; |
|
|||
| 86 | - ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΠΏΠ»Π°Π³ΠΈΠ½Ρ ΡΠ΅ΡΠ΅Π· replayable callback-ΠΊΠΎΠ½ΡΡΠ°ΠΊΡ. |
|
|||
| 87 |
|
||||
| 88 | ## DOMAIN MODEL |
|
|||
| 89 |
|
||||
| 90 | - `BuildLayer` β canonical identity-model ΠΎΠ±ΡΡΠ²Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΡΠ»ΠΎΡ. |
|
|||
| 91 | - `BuildVariant` β Π°Π³ΡΠ΅Π³Π°Ρ ΡΠΎΠ»Π΅ΠΉ, Π°ΡΡΠΈΠ±ΡΡΠΎΠ², Π°ΡΡΠ΅ΡΠ°ΠΊΡΠ½ΡΡ ΡΠ»ΠΎΡΠΎΠ². |
|
|||
| 92 | - `BuildRole` β ΡΠΎΠ»Ρ Π²Π½ΡΡΡΠΈ Π²Π°ΡΠΈΠ°Π½ΡΠ°, ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ ΡΡΡΠ»ΠΊΠΈ Π½Π° declared layer names. |
|
|||
| 93 | - `GenericSourceSet` β Π·Π°ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ Π½Π°Π±ΠΎΡ ΠΈΡΡ ΠΎΠ΄Π½ΠΈΠΊΠΎΠ² ΠΈ outputs. |
|
|||
| 94 | - `LayerBindingSpec` β ΠΏΡΠ±Π»ΠΈΡΠ½ΡΠΉ DSL-contract adapter policy/callbacks Π΄Π»Ρ ΡΠ»ΠΎΡ. |
|
|||
| 95 | - `SourceSetRegistration` β payload ΡΠΎΠ±ΡΡΠΈΡ ΡΠ΅Π³ΠΈΡΡΡΠ°ΡΠΈΠΈ source set. |
|
|||
| 96 | - `SourceSetUsageBinding` β payload ΡΠΎΠ±ΡΡΠΈΡ usage-binding. |
|
|||
| 97 |
|
||||
| 98 | ## EVENT CONTRACT |
|
|||
| 99 |
|
12 | |||
| 100 | - `whenRegistered`: |
|
13 | It no longer contains the variant/source/artifact plugin model. Those plugins | |
| 101 | - ΡΠΎΠ±ΡΡΠΈΠ΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΠΎΠ³ΠΎ source set name; |
|
14 | live in the `variants` module. | |
| 102 | - replayable. |
|
|||
| 103 | - `whenBound`: |
|
|||
| 104 | - ΡΠΎΠ±ΡΡΠΈΠ΅ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ usage-ΡΠ²ΡΠ·ΠΊΠΈ `variant/role/layer`; |
|
|||
| 105 | - replayable. |
|
|||
| 106 |
|
||||
| 107 | Closure callbacks ΡΠ°Π±ΠΎΡΠ°ΡΡ Π² delegate-first ΡΠ΅ΠΆΠΈΠΌΠ΅ (`@DelegatesTo`). ΠΠ»Ρ |
|
|||
| 108 | Π²Π»ΠΎΠΆΠ΅Π½Π½ΡΡ closure ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡΠ΅ΡΡΡ ΡΠ²Π½ΡΠΉ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ (`ctx -> ...`). |
|
|||
| 109 |
|
||||
| 110 | ## KEY CLASSES |
|
|||
| 111 |
|
15 | |||
| 112 | - `SourcesPlugin` β ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ extension `sources`. |
|
16 | See the root [README.md](../README.md) and [PUBLISHING.md](../PUBLISHING.md) for | |
| 113 | - `GenericSourceSet` β ΠΌΠΎΠ΄Π΅Π»Ρ ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠΎΠ²/outputs Π΄Π»Ρ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΈΠΌΠ΅Π½ΠΈ. |
|
17 | current build and local Ivy publication instructions. | |
| 114 | - `VariantsPlugin` β ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ extension `variants` ΠΈ lifecycle finalize. |
|
|||
| 115 | - `BuildVariantsExtension` β ΠΊΠΎΡΠ½Π΅Π²ΠΎΠΉ API ΠΌΠΎΠ΄Π΅Π»ΠΈ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ². |
|
|||
| 116 | - `BuildVariant` β API ΡΠΎΠ»Π΅ΠΉ, attributes ΠΈ artifact slots Π²Π°ΡΠΈΠ°Π½ΡΠ°. |
|
|||
| 117 | - `VariantsSourcesPlugin` β ΠΏΡΠΈΠΌΠ΅Π½ΡΠ΅Ρ `variants` + `sources` ΠΈ Π·Π°ΠΏΡΡΠΊΠ°Π΅Ρ Π°Π΄Π°ΠΏΡΠ΅Ρ. |
|
|||
| 118 | - `VariantSourcesExtension` β API bind/events registration. |
|
|||
| 119 | - `LayerBindingSpec` β ΡΠ»ΠΎΠΉ-ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΡΠΉ DSL Π΄Π»Ρ policy/configuration source set. |
|
|||
| 120 | - `SourceSetRegistration` β payload `whenRegistered(...)`. |
|
|||
| 121 | - `SourceSetUsageBinding` β payload `whenBound(...)`. |
|
|||
| 122 |
|
18 | |||
| 123 | ## NOTES |
|
|||
| 124 |
|
||||
| 125 | - Marker ids: |
|
|||
| 126 | - `org.implab.gradle-variants` |
|
|||
| 127 | - `org.implab.gradle-variants-sources` |
|
|||
| 128 | - `SourcesPlugin` ΠΏΠΎΠΊΠ° class-only (Π±Π΅Π· marker id). |
|
|||
| 129 |
|
||||
| 130 | ## SEE ALSO |
|
|||
| 131 |
|
||||
| 132 | - `sources-plugin.md` |
|
|||
| 133 | - `variants-plugin.md` |
|
|||
| 134 | - `variant-sources-plugin.md` |
|
|||
| @@ -1,83 +1,7 | |||||
| 1 | # Sources Plugin |
|
1 | # Moved: Sources Plugin | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `SourcesPlugin` ΠΈ extension `sources`. |
|
|||
| 6 |
|
||||
| 7 | ## SYNOPSIS |
|
|||
| 8 |
|
||||
| 9 | ```groovy |
|
|||
| 10 | // ΠΠ±ΡΡΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΡΡΡ ΡΡΠ°Π½Π·ΠΈΡΠΈΠ²Π½ΠΎ ΡΠ΅ΡΠ΅Π· org.implab.gradle-variants-sources |
|
|||
| 11 |
|
||||
| 12 | sources { |
|
|||
| 13 | register('main') { |
|
|||
| 14 | declareOutputs('compiled', 'typings') |
|
|||
| 15 |
|
||||
| 16 | sets { |
|
|||
| 17 | ts { srcDir 'src/main/ts' } |
|
|||
| 18 | js { srcDir 'src/main/js' } |
|
|||
| 19 | } |
|
|||
| 20 | } |
|
|||
| 21 | } |
|
|||
| 22 | ``` |
|
|||
| 23 |
|
||||
| 24 | ## DESCRIPTION |
|
|||
| 25 |
|
||||
| 26 | `SourcesPlugin` ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ extension `sources` ΡΠΈΠΏΠ° |
|
|||
| 27 | `NamedDomainObjectContainer<GenericSourceSet>`. |
|
|||
| 28 |
|
||||
| 29 | `GenericSourceSet` β ΡΡΠΎ Π°Π²ΡΠΎΠ½ΠΎΠΌΠ½ΡΠΉ source bundle Ρ ΡΠ΅ΡΠΊΠΈΠΌ ΠΊΠΎΠ½ΡΡΠ°ΠΊΡΠΎΠΌ outputs. |
|
|||
| 30 |
|
||||
| 31 | ### sourceSetDir |
|
|||
| 32 |
|
||||
| 33 | ΠΠ°Π·ΠΎΠ²ΡΠΉ ΠΊΠ°ΡΠ°Π»ΠΎΠ³ Π½Π°Π±ΠΎΡΠ°. ΠΠΎΠ½Π²Π΅Π½ΡΠΈΡ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ: `src/<name>`. |
|
|||
| 34 |
|
||||
| 35 | ### outputsDir |
|
|||
| 36 |
|
||||
| 37 | ΠΠ°Π·ΠΎΠ²ΡΠΉ ΠΊΠ°ΡΠ°Π»ΠΎΠ³ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ² Π½Π°Π±ΠΎΡΠ°. ΠΠΎΠ½Π²Π΅Π½ΡΠΈΡ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ: `build/<name>`. |
|
|||
| 38 |
|
||||
| 39 | ### sets |
|
|||
| 40 |
|
2 | |||
| 41 | ΠΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ `SourceDirectorySet` Π²Π½ΡΡΡΠΈ `GenericSourceSet`. ΠΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π΄Π»Ρ |
|
3 | The `SourcesPlugin` implementation is now part of the `variants` module, not | |
| 42 | Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ ΡΠ°Π·Π΄Π΅Π»Π΅Π½ΠΈΡ ΠΏΠΎΠ΄ΠΏΠ°ΠΏΠΎΠΊ (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ `ts`, `js`, `typings`). |
|
4 | the `common` module. | |
| 43 |
|
||||
| 44 | ### outputs contract |
|
|||
| 45 |
|
||||
| 46 | Outputs ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠ΅ ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ Π±ΡΡΡ ΠΎΠ±ΡΡΠ²Π»Π΅Π½Ρ Π·Π°ΡΠ°Π½Π΅Π΅: |
|
|||
| 47 |
|
||||
| 48 | - `declareOutputs(...)` β Π΄Π΅ΠΊΠ»Π°ΡΠ°ΡΠΈΡ Π΄ΠΎΡΡΡΠΏΠ½ΡΡ output keys; |
|
|||
| 49 | - `output(name)` β Π΄ΠΎΡΡΡΠΏ ΠΊ `ConfigurableFileCollection` Π΄Π»Ρ output key; |
|
|||
| 50 | - `registerOutput(...)` β ΡΠ΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ output ΠΈΠ· ΡΠ°ΠΉΠ»ΠΎΠ² ΠΈΠ»ΠΈ task provider. |
|
|||
| 51 |
|
||||
| 52 | Π’Π°ΠΊΠΎΠΉ ΠΊΠΎΠ½ΡΡΠ°ΠΊΡ ΡΠΏΡΠΎΡΠ°Π΅Ρ wiring Π·Π°Π΄Π°Ρ ΡΠ΅ΡΠ΅Π· inputs/outputs Π±Π΅Π· ΡΡΡΠ½ΠΎΠ³ΠΎ |
|
|||
| 53 | `dependsOn`. |
|
|||
| 54 |
|
||||
| 55 | ## API |
|
|||
| 56 |
|
||||
| 57 | ### SourcesPlugin |
|
|||
| 58 |
|
||||
| 59 | - `apply(Project)` β Π΄ΠΎΠ±Π°Π²Π»ΡΠ΅Ρ extension `sources` Π² ΠΏΡΠΎΠ΅ΠΊΡ. |
|
|||
| 60 | - `getSourcesExtension(Project)` β Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ `GenericSourceSet`. |
|
|||
| 61 |
|
5 | |||
| 62 | ### GenericSourceSet |
|
6 | Current documentation is maintained in the root [README.md](../README.md). | |
| 63 |
|
7 | |||
| 64 | - `getSourceSetDir()` β root directory ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠΎΠ² Π½Π°Π±ΠΎΡΠ°. |
|
|||
| 65 | - `getOutputsDir()` β root directory ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ² Π½Π°Π±ΠΎΡΠ°. |
|
|||
| 66 | - `getSets()` β ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ ΠΏΠΎΠ΄Π½Π°Π±ΠΎΡΠΎΠ² `SourceDirectorySet`. |
|
|||
| 67 | - `declareOutputs(...)` β ΠΎΠ±ΡΡΠ²Π»ΡΠ΅Ρ ΡΠ°Π·ΡΠ΅ΡΠ΅Π½Π½ΡΠ΅ output names. |
|
|||
| 68 | - `output(name)` β Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ `FileCollection` Π΄Π»Ρ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ output. |
|
|||
| 69 | - `registerOutput(name, files...)` β Π΄ΠΎΠ±Π°Π²Π»ΡΠ΅Ρ ΡΠ°ΠΉΠ»Ρ Π² output. |
|
|||
| 70 | - `registerOutput(name, task, mapper)` β ΡΠ²ΡΠ·ΡΠ²Π°Π΅Ρ output Ρ task provider. |
|
|||
| 71 | - `getAllOutputs()` β Π°Π³ΡΠ΅Π³ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ `FileCollection` Π²ΡΠ΅Ρ outputs. |
|
|||
| 72 | - `getAllSourceDirectories()` β Π°Π³ΡΠ΅Π³ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ `FileCollection` Π²ΡΠ΅Ρ source dirs. |
|
|||
| 73 |
|
||||
| 74 | ## KEY CLASSES |
|
|||
| 75 |
|
||||
| 76 | - `SourcesPlugin` β ΡΠ΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ extension `sources`. |
|
|||
| 77 | - `GenericSourceSet` β ΠΌΠΎΠ΄Π΅Π»Ρ ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠΎΠ² ΠΈ outputs. |
|
|||
| 78 |
|
||||
| 79 | ## NOTES |
|
|||
| 80 |
|
||||
| 81 | - ΠΠ±ΡΠ°ΡΠ΅Π½ΠΈΠ΅ ΠΊ `output(name)` Π±Π΅Π· ΠΏΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎΠ³ΠΎ `declareOutputs(name)` |
|
|||
| 82 | ΠΏΡΠΈΠ²ΠΎΠ΄ΠΈΡ ΠΊ ΠΎΡΠΈΠ±ΠΊΠ΅ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΠΈ. |
|
|||
| 83 | - ΠΠ»Π°Π³ΠΈΠ½ `sources` ΡΠ΅ΠΉΡΠ°Ρ Π±Π΅Π· marker id. |
|
|||
| @@ -1,354 +1,8 | |||||
| 1 | # Variant Artifacts Plugin |
|
1 | # Moved: Variant Artifacts Plugin | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `VariantsArtifactsPlugin` ΠΈ extension `variantArtifacts`. |
|
|||
| 6 |
|
||||
| 7 | ## SYNOPSIS |
|
|||
| 8 |
|
||||
| 9 | ```groovy |
|
|||
| 10 | import org.gradle.api.attributes.Attribute |
|
|||
| 11 |
|
||||
| 12 | plugins { |
|
|||
| 13 | id 'org.implab.gradle-variants-artifacts' |
|
|||
| 14 | } |
|
|||
| 15 |
|
||||
| 16 | def variantAttr = Attribute.of('test.variant', String) |
|
|||
| 17 | def slotAttr = Attribute.of('test.slot', String) |
|
|||
| 18 |
|
||||
| 19 | variants { |
|
|||
| 20 | layer('main') |
|
|||
| 21 |
|
||||
| 22 | variant('browser') { |
|
|||
| 23 | role('main') { layers('main') } |
|
|||
| 24 | } |
|
|||
| 25 | } |
|
|||
| 26 |
|
||||
| 27 | variantSources { |
|
|||
| 28 | bind('main') { |
|
|||
| 29 | configureSourceSet { |
|
|||
| 30 | declareOutputs('types', 'js', 'resources') |
|
|||
| 31 | } |
|
|||
| 32 | } |
|
|||
| 33 | } |
|
|||
| 34 |
|
||||
| 35 | variantArtifacts { |
|
|||
| 36 | variant('browser') { |
|
|||
| 37 | primarySlot('typesPackage') { |
|
|||
| 38 | fromVariant { |
|
|||
| 39 | output('types') |
|
|||
| 40 | } |
|
|||
| 41 | } |
|
|||
| 42 |
|
||||
| 43 | slot('js') { |
|
|||
| 44 | fromVariant { |
|
|||
| 45 | output('js') |
|
|||
| 46 | } |
|
|||
| 47 | } |
|
|||
| 48 |
|
||||
| 49 | slot('resources') { |
|
|||
| 50 | fromVariant { |
|
|||
| 51 | output('resources') |
|
|||
| 52 | } |
|
|||
| 53 | } |
|
|||
| 54 | } |
|
|||
| 55 |
|
||||
| 56 | whenOutgoingVariant { publication -> |
|
|||
| 57 | publication.configureConfiguration { |
|
|||
| 58 | attributes.attribute(variantAttr, publication.variantName()) |
|
|||
| 59 | } |
|
|||
| 60 |
|
||||
| 61 | publication.primarySlot().configureArtifactAttributes { |
|
|||
| 62 | attribute(slotAttr, publication.primarySlot().slotName()) |
|
|||
| 63 | } |
|
|||
| 64 |
|
||||
| 65 | publication.requireSlot('js').configureArtifactAttributes { |
|
|||
| 66 | attribute(slotAttr, 'js') |
|
|||
| 67 | } |
|
|||
| 68 |
|
||||
| 69 | publication.requireSlot('resources').configureArtifactAttributes { |
|
|||
| 70 | attribute(slotAttr, 'resources') |
|
|||
| 71 | } |
|
|||
| 72 | } |
|
|||
| 73 | } |
|
|||
| 74 | ``` |
|
|||
| 75 |
|
||||
| 76 | ## DESCRIPTION |
|
|||
| 77 |
|
||||
| 78 | `VariantsArtifactsPlugin` ΠΏΡΠΈΠΌΠ΅Π½ΡΠ΅Ρ `VariantsSourcesPlugin`, Π·Π°ΡΠ΅ΠΌ ΡΡΡΠΎΠΈΡ |
|
|||
| 79 | outgoing publication model ΠΏΠΎΠ²Π΅ΡΡ `variantSources`. |
|
|||
| 80 |
|
||||
| 81 | ### publication model |
|
|||
| 82 |
|
||||
| 83 | ΠΠ»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ `variantArtifacts.variant('<name>')` ΠΏΡΠ±Π»ΠΈΠΊΡΠ΅ΡΡΡ ΠΎΠ΄ΠΈΠ½ outgoing |
|
|||
| 84 | build variant: |
|
|||
| 85 |
|
||||
| 86 | - primary configuration `<variant>Elements`; |
|
|||
| 87 | - primary artifact slot Π½Π° ΡΠ°ΠΌΠΎΠΉ configuration; |
|
|||
| 88 | - secondary variants Π²Π½ΡΡΡΠΈ `configuration.outgoing.variants` Π΄Π»Ρ ΠΎΡΡΠ°Π»ΡΠ½ΡΡ slots. |
|
|||
| 89 |
|
||||
| 90 | ΠΡΠΈΠΌΠ΅Ρ: |
|
|||
| 91 |
|
||||
| 92 | - `browserElements` |
|
|||
| 93 | - primary slot: `typesPackage` |
|
|||
| 94 | - secondary variants: `js`, `resources` |
|
|||
| 95 |
|
||||
| 96 | ΠΡΠΎ ΡΠ°Π·Π΄Π΅Π»ΡΠ΅Ρ: |
|
|||
| 97 |
|
||||
| 98 | - graph selection build variant-Π°; |
|
|||
| 99 | - artifact selection Π²Π½ΡΡΡΠΈ ΡΠΆΠ΅ Π²ΡΠ±ΡΠ°Π½Π½ΠΎΠ³ΠΎ variant-Π°. |
|
|||
| 100 |
|
||||
| 101 | ### slot contributions ΠΈ DSL |
|
|||
| 102 |
|
||||
| 103 | `slot('<name>')` ΠΎΠΏΠΈΡΡΠ²Π°Π΅Ρ artifact representation Π½Π΅ ΠΊΠ°ΠΊ ΠΎΠ΄ΠΈΠ½ ΡΠ°ΠΉΠ» ΠΈΠ»ΠΈ ΠΎΠ΄Π½Ρ |
|
|||
| 104 | Π·Π°Π΄Π°ΡΡ, Π° ΠΊΠ°ΠΊ Π½Π°Π±ΠΎΡ contributions, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΠΎΡΠΎΠΌ materialize-ΡΡΡΡ Π² ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠΉ |
|
|||
| 105 | `ArtifactAssembly`. |
|
|||
| 106 |
|
||||
| 107 | Π’Π΅ΠΊΡΡΠΈΠΉ DSL ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ Π΄Π²Π° Π²ΠΈΠ΄Π° contributions: |
|
|||
| 108 |
|
||||
| 109 | - topology-aware: |
|
|||
| 110 | - `fromVariant { output(...) }` |
|
|||
| 111 | - `fromRole('<role>') { output(...) }` |
|
|||
| 112 | - `fromLayer('<layer>') { output(...) }` |
|
|||
| 113 | - direct: |
|
|||
| 114 | - `from(someFileOrProviderOrTaskOutput)` |
|
|||
| 115 |
|
||||
| 116 | Π‘ΠΌΡΡΠ» DSL ΠΏΠΎ ΡΠ»ΠΎΡΠΌ: |
|
|||
| 117 |
|
||||
| 118 | - `fromVariant/fromRole/fromLayer` Π²ΡΠ±ΠΈΡΠ°ΡΡ ΠΎΠ±Π»Π°ΡΡΡ topology model, Π² ΠΊΠΎΡΠΎΡΠΎΠΉ |
|
|||
| 119 | contribution Π°ΠΊΡΠΈΠ²Π΅Π½; |
|
|||
| 120 | - `output(...)` Π²ΡΠ±ΠΈΡΠ°Π΅Ρ named output ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠ΅Π³ΠΎ `GenericSourceSet`; |
|
|||
| 121 | - `from(Object)` Π΄ΠΎΠ±Π°Π²Π»ΡΠ΅Ρ direct contribution, Π½Π΅ Π·Π°Π²ΠΈΡΡΡΠΈΠΉ ΠΎΡ |
|
|||
| 122 | `variantSources` bindings; |
|
|||
| 123 | - ΠΈΡΠΎΠ³ΠΎΠ²ΡΠΉ contribution ΠΏΡΠΈ materialization: |
|
|||
| 124 | - ΠΏΡΠΎΠ²Π΅ΡΡΠ΅Ρ, ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΠΈΡ Π»ΠΈ ΡΠ΅ΠΊΡΡΠΈΠΉ `SourceSetUsageBinding`; |
|
|||
| 125 | - Π²ΡΠ΄Π°Π΅Ρ object Π΄Π»Ρ `files.from(...)`; |
|
|||
| 126 | - ΠΏΡΠΈ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎΡΡΠΈ Π²ΡΠ΄Π°Π΅Ρ `BindingKey`, Π΅ΡΠ»ΠΈ ΡΠ°ΠΊΠΎΠΉ contribution Π΄ΠΎΠ»ΠΆΠ΅Π½ |
|
|||
| 127 | ΡΡ Π»ΠΎΠΏΡΠ²Π°ΡΡΡΡ ΠΏΠΎ logical identity. |
|
|||
| 128 |
|
||||
| 129 | Π‘Π²ΡΠ·Ρ slot-Π° Ρ ΠΎΡΡΠ°Π»ΡΠ½ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΡΡ: |
|
|||
| 130 |
|
||||
| 131 | - `variants` Π·Π°Π΄Π°Π΅Ρ topology variant/role/layer; |
|
|||
| 132 | - `variantSources` ΠΏΡΠ΅Π²ΡΠ°ΡΠ°Π΅Ρ topology Π² concrete `SourceSetUsageBinding`; |
|
|||
| 133 | - `variantArtifacts.slot(...)` ΠΎΠΏΠΈΡΡΠ²Π°Π΅Ρ, ΠΊΠ°ΠΊΠΈΠ΅ bindings Π½Π°Π΄ΠΎ Π²ΠΊΠ»ΡΡΠΈΡΡ Π² slot; |
|
|||
| 134 | - `VariantArtifactsResolver` ΠΏΡΠ΅Π²ΡΠ°ΡΠ°Π΅Ρ contributions slot-Π° Π² `FileCollection`; |
|
|||
| 135 | - `VariantArtifactsPlugin` ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ Π΄Π»Ρ slot-Π° ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠΉ `ArtifactAssembly`; |
|
|||
| 136 | - `OutgoingVariantPublication` ΠΈ `OutgoingArtifactSlotPublication` ΠΏΡΠ±Π»ΠΈΠΊΡΡΡ |
|
|||
| 137 | ΡΠΆΠ΅ ΡΠΎΠ±ΡΠ°Π½Π½ΡΠ΅ slot artifacts Π½Π°ΡΡΠΆΡ. |
|
|||
| 138 |
|
||||
| 139 | ΠΠ°ΠΆΠ΄ΡΠΉ slot materialize-ΠΈΡΡΡ Π² ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠΉ `ArtifactAssembly`: |
|
|||
| 140 |
|
||||
| 141 | - task: `process<Variant><Slot>`; |
|
|||
| 142 | - output dir: `build/variant-artifacts/<variant>/<slot>`. |
|
|||
| 143 |
|
||||
| 144 | ### primary slot |
|
|||
| 145 |
|
||||
| 146 | Primary slot Π·Π°Π΄Π°Π΅Ρ artifact, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΡΠ±Π»ΠΈΠΊΡΠ΅ΡΡΡ ΠΊΠ°ΠΊ ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠΉ artifact |
|
|||
| 147 | configuration `<variant>Elements`. |
|
|||
| 148 |
|
||||
| 149 | Π€ΠΎΡΠΌΡ DSL: |
|
|||
| 150 |
|
||||
| 151 | ```groovy |
|
|||
| 152 | variant('browser') { |
|
|||
| 153 | primarySlot('typesPackage') |
|
|||
| 154 |
|
||||
| 155 | slot('typesPackage') { |
|
|||
| 156 | fromVariant { output('types') } |
|
|||
| 157 | } |
|
|||
| 158 | } |
|
|||
| 159 | ``` |
|
|||
| 160 |
|
||||
| 161 | ΠΈΠ»ΠΈ sugar: |
|
|||
| 162 |
|
||||
| 163 | ```groovy |
|
|||
| 164 | variant('browser') { |
|
|||
| 165 | primarySlot('typesPackage') { |
|
|||
| 166 | fromVariant { output('types') } |
|
|||
| 167 | } |
|
|||
| 168 | } |
|
|||
| 169 | ``` |
|
|||
| 170 |
|
||||
| 171 | ΠΡΠ°Π²ΠΈΠ»Π°: |
|
|||
| 172 |
|
||||
| 173 | - Π΅ΡΠ»ΠΈ slot ΠΎΠ΄ΠΈΠ½, ΠΎΠ½ ΡΡΠΈΡΠ°Π΅ΡΡΡ primary Π½Π΅ΡΠ²Π½ΠΎ; |
|
|||
| 174 | - Π΅ΡΠ»ΠΈ slots Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ, `primarySlot(...)` ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»Π΅Π½; |
|
|||
| 175 | - `primarySlot` Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΡΡΠ»Π°ΡΡΡΡ Π½Π° ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠΈΠΉ slot. |
|
|||
| 176 |
|
2 | |||
| 177 | ## LIFECYCLE |
|
3 | The `VariantArtifactsPlugin` implementation is now part of the `variants` | |
| 178 |
|
4 | module, not the `common` module. | ||
| 179 | - `VariantsArtifactsPlugin` ΠΆΠ΄Π΅Ρ `variants.whenFinalized(...)`; |
|
|||
| 180 | - ΠΏΠΎΡΠ»Π΅ ΡΡΠΎΠ³ΠΎ Π²Π°Π»ΠΈΠ΄ΠΈΡΡΠ΅Ρ `variantArtifacts`; |
|
|||
| 181 | - ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ `ArtifactAssembly` ΠΏΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡ slot; |
|
|||
| 182 | - materialize-ΠΈΡ outgoing publications; |
|
|||
| 183 | - Π²ΡΠ·ΡΠ²Π°Π΅Ρ `whenOutgoingVariant(...)`; |
|
|||
| 184 | - callbacks replayable. |
|
|||
| 185 |
|
||||
| 186 | ΠΠΎΡΠ»Π΅ finalize ΠΌΡΡΠ°ΡΠΈΠΈ `variantArtifacts` Π·Π°ΠΏΡΠ΅ΡΠ΅Π½Ρ. |
|
|||
| 187 |
|
||||
| 188 | ## EVENTS |
|
|||
| 189 |
|
||||
| 190 | ### whenOutgoingVariant |
|
|||
| 191 |
|
||||
| 192 | Replayable callback Π½Π° Π³ΠΎΡΠΎΠ²ΡΡ outgoing publication variant-Π°. |
|
|||
| 193 |
|
||||
| 194 | ΠΠΎΠ΄Ρ ΠΎΠ΄ΠΈΡ Π΄Π»Ρ: |
|
|||
| 195 |
|
||||
| 196 | - Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ ΠΎΠ±ΡΠΈΡ attributes build variant-Π° ΠΎΠ΄ΠΈΠ½ ΡΠ°Π·; |
|
|||
| 197 | - Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ per-slot artifact attributes; |
|
|||
| 198 | - Π΄ΠΎΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈ `ArtifactAssembly`. |
|
|||
| 199 |
|
||||
| 200 | ## PAYLOAD TYPES |
|
|||
| 201 |
|
||||
| 202 | ### OutgoingVariantPublication |
|
|||
| 203 |
|
||||
| 204 | Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΡ: |
|
|||
| 205 |
|
||||
| 206 | - `variantName()`; |
|
|||
| 207 | - `topologyVariant()`; |
|
|||
| 208 | - `variantArtifact()`; |
|
|||
| 209 | - `configuration()` β primary `<variant>Elements`; |
|
|||
| 210 | - `primarySlot()`; |
|
|||
| 211 | - `slots()` β Π²ΡΠ΅ slot publications; |
|
|||
| 212 | - `secondarySlots()`; |
|
|||
| 213 | - `findSlot(name)`, `requireSlot(name)`. |
|
|||
| 214 |
|
||||
| 215 | Sugar: |
|
|||
| 216 |
|
||||
| 217 | - `configureConfiguration(Action|Closure)`. |
|
|||
| 218 |
|
||||
| 219 | ### OutgoingArtifactSlotPublication |
|
|||
| 220 |
|
||||
| 221 | Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΡ: |
|
|||
| 222 |
|
||||
| 223 | - `slotName()`; |
|
|||
| 224 | - `primary()`; |
|
|||
| 225 | - `slot()` β ΠΌΠΎΠ΄Π΅Π»Ρ `VariantArtifactSlot`; |
|
|||
| 226 | - `assembly()`. |
|
|||
| 227 |
|
||||
| 228 | Sugar: |
|
|||
| 229 |
|
||||
| 230 | - `configureAssembly(Action|Closure)`; |
|
|||
| 231 | - `configureArtifactAttributes(Action|Closure)`. |
|
|||
| 232 |
|
||||
| 233 | `configureArtifactAttributes(...)` ΠΏΠΈΡΠ΅Ρ attributes: |
|
|||
| 234 |
|
||||
| 235 | - Π² `Configuration.attributes` Π΄Π»Ρ primary slot; |
|
|||
| 236 | - Π² `ConfigurationVariant.attributes` Π΄Π»Ρ secondary slot. |
|
|||
| 237 |
|
||||
| 238 | ## CONSUMER SIDE |
|
|||
| 239 |
|
||||
| 240 | ### primary resolution |
|
|||
| 241 |
|
||||
| 242 | ΠΠ±ΡΡΠ½ΠΎΠ΅ inter-project resolution Π²ΡΠ±ΠΈΡΠ°Π΅Ρ primary artifact `<variant>Elements`. |
|
|||
| 243 |
|
||||
| 244 | ΠΡΠΈΠΌΠ΅Ρ: |
|
|||
| 245 |
|
||||
| 246 | ```groovy |
|
|||
| 247 | configurations { |
|
|||
| 248 | compileView { |
|
|||
| 249 | canBeResolved = true |
|
|||
| 250 | canBeConsumed = false |
|
|||
| 251 | canBeDeclared = true |
|
|||
| 252 | attributes { |
|
|||
| 253 | attribute(variantAttr, 'browser') |
|
|||
| 254 | attribute(slotAttr, 'typesPackage') |
|
|||
| 255 | } |
|
|||
| 256 | } |
|
|||
| 257 | } |
|
|||
| 258 |
|
||||
| 259 | dependencies { |
|
|||
| 260 | compileView project(':producer') |
|
|||
| 261 | } |
|
|||
| 262 | ``` |
|
|||
| 263 |
|
||||
| 264 | ### artifact selection for secondary slots |
|
|||
| 265 |
|
5 | |||
| 266 | Secondary artifacts Π²ΡΠ±ΠΈΡΠ°ΡΡΡΡ ΡΠ΅ΡΠ΅Π· `artifactView`. |
|
6 | Current documentation is maintained in the root [README.md](../README.md) and | |
| 267 |
|
7 | [variant_artifacts.md](../variant_artifacts.md). | ||
| 268 | ```groovy |
|
|||
| 269 | def jsFiles = configurations.compileView.incoming.artifactView { |
|
|||
| 270 | attributes { |
|
|||
| 271 | attribute(slotAttr, 'js') |
|
|||
| 272 | } |
|
|||
| 273 | }.files |
|
|||
| 274 | ``` |
|
|||
| 275 |
|
||||
| 276 | ΠΠ΄Π΅ΡΡ graph variant ΡΠΆΠ΅ Π²ΡΠ±ΡΠ°Π½, Π° `artifactView` Π²ΡΠ±ΠΈΡΠ°Π΅Ρ Π½ΡΠΆΠ½ΡΠΉ secondary |
|
|||
| 277 | artifact representation. |
|
|||
| 278 |
|
||||
| 279 | ## VALIDATION |
|
|||
| 280 |
|
||||
| 281 | ΠΡΠΎΠ²Π΅ΡΡΠ΅ΡΡΡ: |
|
|||
| 282 |
|
||||
| 283 | - variant ΡΡΡΠ΅ΡΡΠ²ΡΠ΅Ρ Π² topology model; |
|
|||
| 284 | - slot contributions Π½Π΅ ΡΡΡΠ»Π°ΡΡΡΡ Π½Π° Π½Π΅ΠΈΠ·Π²Π΅ΡΡΠ½ΡΠ΅ role/layer; |
|
|||
| 285 | - ΠΏΡΠΈ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΈΡ slots ΡΠΊΠ°Π·Π°Π½ `primarySlot`; |
|
|||
| 286 | - `primarySlot` ΡΡΡΠ»Π°Π΅ΡΡΡ Π½Π° ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠΈΠΉ slot. |
|
|||
| 287 |
|
||||
| 288 | ## API |
|
|||
| 289 |
|
||||
| 290 | ### VariantArtifactsExtension |
|
|||
| 291 |
|
||||
| 292 | - `variant(String)` β ΠΏΠΎΠ»ΡΡΠΈΡΡ/ΡΠΎΠ·Π΄Π°ΡΡ variant artifact model; |
|
|||
| 293 | - `variant(String, Action|Closure)` β ΡΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠΎΠ²Π°ΡΡ variant artifact; |
|
|||
| 294 | - `getVariants()` β ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ variant artifacts; |
|
|||
| 295 | - `findVariant(name)`, `requireVariant(name)`; |
|
|||
| 296 | - `whenOutgoingVariant(...)`. |
|
|||
| 297 |
|
||||
| 298 | ### VariantArtifact |
|
|||
| 299 |
|
||||
| 300 | - `slot(String)` β ΠΏΠΎΠ»ΡΡΠΈΡΡ/ΡΠΎΠ·Π΄Π°ΡΡ slot; |
|
|||
| 301 | - `slot(String, Action|Closure)` β ΡΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠΎΠ²Π°ΡΡ slot; |
|
|||
| 302 | - `primarySlot(String)` β Π½Π°Π·Π½Π°ΡΠΈΡΡ primary slot; |
|
|||
| 303 | - `primarySlot(String, Action|Closure)` β sugar: configure slot + mark as primary; |
|
|||
| 304 | - `getSlots()`; |
|
|||
| 305 | - `findSlot(name)`, `requireSlot(name)`; |
|
|||
| 306 | - `findPrimarySlotName()`, `requirePrimarySlotName()`; |
|
|||
| 307 | - `findPrimarySlot()`, `requirePrimarySlot()`. |
|
|||
| 308 |
|
||||
| 309 | ### VariantArtifactSlot |
|
|||
| 310 |
|
8 | |||
| 311 | - `from(Object)`; |
|
|||
| 312 | - `fromVariant(...)`; |
|
|||
| 313 | - `fromRole(String, ...)`; |
|
|||
| 314 | - `fromLayer(String, ...)`. |
|
|||
| 315 |
|
||||
| 316 | ΠΠ½ΡΡΡΠ΅Π½Π½ΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ: |
|
|||
| 317 |
|
||||
| 318 | - slot Ρ ΡΠ°Π½ΠΈΡ contributions, Π° Π½Π΅ ΡΡΡΠΎΠΊΠΎΠ²ΡΠ΅ rules; |
|
|||
| 319 | - `fromVariant/fromRole/fromLayer` ΡΠΎΠ·Π΄Π°ΡΡ topology-aware contributions; |
|
|||
| 320 | - `from(Object)` ΡΠΎΠ·Π΄Π°Π΅Ρ direct contribution, ΠΊΠΎΡΠΎΡΡΠΉ materialize-ΠΈΡΡΡ Π΄Π°ΠΆΠ΅ |
|
|||
| 321 | Π΅ΡΠ»ΠΈ Ρ variant-Π° Π½Π΅Ρ Π½ΠΈ ΠΎΠ΄Π½ΠΎΠ³ΠΎ `SourceSetUsageBinding`; |
|
|||
| 322 | - slot ΠΎΡΠ΄Π΅Π»ΡΠ½ΠΎ Ρ ΡΠ°Π½ΠΈΡ topology references Π΄Π»Ρ validation: |
|
|||
| 323 | `referencedRoleNames()` ΠΈ `referencedLayerNames()`. |
|
|||
| 324 |
|
||||
| 325 | ### OutputSelectionSpec |
|
|||
| 326 |
|
||||
| 327 | - `output(name)`; |
|
|||
| 328 | - `output(name, extra...)`. |
|
|||
| 329 |
|
||||
| 330 | `OutputSelectionSpec` ΡΡΠΎ Π²Π½ΡΡΡΠ΅Π½Π½ΠΈΠΉ DSL-buffer Π΄Π»Ρ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Π±Π»ΠΎΠΊΠ° |
|
|||
| 331 | `fromVariant/fromRole/fromLayer`. ΠΠ½ Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎ Π½Π°ΠΊΠ°ΠΏΠ»ΠΈΠ²Π°Π΅Ρ contributions ΠΈ |
|
|||
| 332 | ΠΏΠ΅ΡΠ΅Π΄Π°Π΅Ρ ΠΈΡ Π² slot ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠ»Π΅ ΡΡΠΏΠ΅ΡΠ½ΠΎΠ³ΠΎ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ configure-Π±Π»ΠΎΠΊΠ°. |
|
|||
| 333 |
|
||||
| 334 | ## KEY CLASSES |
|
|||
| 335 |
|
||||
| 336 | - `VariantsArtifactsPlugin` β plugin adapter ΠΈ materialization outgoing variants. |
|
|||
| 337 | - `VariantArtifactsExtension` β root DSL ΠΈ lifecycle. |
|
|||
| 338 | - `VariantArtifact` β outgoing build variant model. |
|
|||
| 339 | - `VariantArtifactSlot` β artifact representation slot. |
|
|||
| 340 | - `VariantArtifactsResolver` β adapter ΠΌΠ΅ΠΆΠ΄Ρ `variantSources` bindings ΠΈ |
|
|||
| 341 | contribution model slot-Π°. |
|
|||
| 342 | - `OutgoingVariantPublication` β payload variant-level publication callback. |
|
|||
| 343 | - `OutgoingArtifactSlotPublication` β payload per-slot publication callback. |
|
|||
| 344 | - `ArtifactAssembly` β assembled files for a slot. |
|
|||
| 345 |
|
||||
| 346 | ## NOTES |
|
|||
| 347 |
|
||||
| 348 | - `common` Π½Π΅ Π½Π°Π²ΡΠ·ΡΠ²Π°Π΅Ρ Π΄ΠΎΠΌΠ΅Π½Π½ΡΡ Π»ΠΎΠ³ΠΈΠΊΡ Π²ΡΠ±ΠΎΡΠ° primary slot. |
|
|||
| 349 | - `common` Π½Π΅ ΡΠΈΠΊΡΠΈΡΡΠ΅Ρ Π·Π½Π°ΡΠ΅Π½ΠΈΡ `usage`, `libraryelements` ΠΈ ΠΏΡΠΎΡΠΈΡ |
|
|||
| 350 | slot-specific attributes. |
|
|||
| 351 | - `common` Π½Π΅ ΡΠΌΠ΅ΡΠΈΠ²Π°Π΅Ρ ΡΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ Ρ ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠΌΠΈ publish ΠΎΡΡΠΌΠΈ Π²ΡΠΎΠ΄Π΅ package |
|
|||
| 352 | metadata. |
|
|||
| 353 | - Closure callbacks ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ delegate-first; Π΄Π»Ρ Π²Π»ΠΎΠΆΠ΅Π½Π½ΡΡ closure ΡΠ΄ΠΎΠ±Π½Π΅Π΅ |
|
|||
| 354 | ΡΠ²Π½ΡΠΉ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ (`publication -> ...`, `slotPublication -> ...`). |
|
|||
| @@ -1,159 +1,9 | |||||
| 1 | # Variant Sources Plugin |
|
1 | # Moved: Variant Sources Plugin | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `VariantsSourcesPlugin` ΠΈ extension `variantSources`. |
|
|||
| 6 |
|
||||
| 7 | ## SYNOPSIS |
|
|||
| 8 |
|
||||
| 9 | ```groovy |
|
|||
| 10 | plugins { |
|
|||
| 11 | id 'org.implab.gradle-variants-sources' |
|
|||
| 12 | } |
|
|||
| 13 |
|
||||
| 14 | variants { |
|
|||
| 15 | layer('main') |
|
|||
| 16 |
|
||||
| 17 | variant('browser') { |
|
|||
| 18 | role('main') { layers('main') } |
|
|||
| 19 | } |
|
|||
| 20 |
|
||||
| 21 | variant('node') { |
|
|||
| 22 | role('main') { layers('main') } |
|
|||
| 23 | } |
|
|||
| 24 | } |
|
|||
| 25 |
|
||||
| 26 | variantSources { |
|
|||
| 27 | bind('main').sourceSetNamePattern = '{layer}' |
|
|||
| 28 |
|
||||
| 29 | bind('main') { |
|
|||
| 30 | configureSourceSet { |
|
|||
| 31 | declareOutputs('compiled') |
|
|||
| 32 | } |
|
|||
| 33 | } |
|
|||
| 34 |
|
||||
| 35 | whenRegistered { sourceSetName() } |
|
|||
| 36 | whenBound('browser') { roleName() } |
|
|||
| 37 | } |
|
|||
| 38 | ``` |
|
|||
| 39 |
|
2 | |||
| 40 | ## DESCRIPTION |
|
3 | The `VariantSourcesPlugin` implementation is now part of the `variants` module, | |
| 41 |
|
4 | not the `common` module. | ||
| 42 | `VariantsSourcesPlugin` ΠΏΡΠΈΠΌΠ΅Π½ΡΠ΅Ρ `VariantsPlugin` ΠΈ `SourcesPlugin`, Π·Π°ΡΠ΅ΠΌ |
|
|||
| 43 | ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ source sets ΠΈΠ· ΠΌΠΎΠ΄Π΅Π»ΠΈ `variants`. |
|
|||
| 44 |
|
||||
| 45 | Π’ΠΎΡΠΊΠ° Π·Π°ΠΏΡΡΠΊΠ° registration: |
|
|||
| 46 |
|
||||
| 47 | - `variants.whenFinalized(model -> registerSourceSets(...))` |
|
|||
| 48 |
|
||||
| 49 | ### registration |
|
|||
| 50 |
|
||||
| 51 | ΠΠ»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ usage-ΡΠ²ΡΠ·ΠΊΠΈ `variant/role/layer` Π²ΡΡΠΈΡΠ»ΡΠ΅ΡΡΡ ΠΈΠΌΡ source set, |
|
|||
| 52 | ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅ΡΡΡ `GenericSourceSet` (Π΅ΡΠ»ΠΈ ΠΎΠ½ Π΅ΡΠ΅ Π½Π΅ ΡΡΡΠ΅ΡΡΠ²ΡΠ΅Ρ), Π·Π°ΡΠ΅ΠΌ |
|
|||
| 53 | Π²ΡΠ·ΡΠ²Π°ΡΡΡΡ callbacks. |
|
|||
| 54 |
|
||||
| 55 | ### binding |
|
|||
| 56 |
|
||||
| 57 | `bind('<layer>')` Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ `LayerBindingSpec` ΠΈ Π·Π°Π΄Π°Π΅Ρ policy Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ |
|
|||
| 58 | ΡΠ»ΠΎΡ: |
|
|||
| 59 |
|
||||
| 60 | - ΠΊΠ°ΠΊ ΠΈΠΌΠ΅Π½ΠΎΠ²Π°ΡΡ source set; |
|
|||
| 61 | - ΠΊΠ°ΠΊ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠΎΠ²Π°ΡΡ source set; |
|
|||
| 62 | - ΠΊΠ°ΠΊΠΈΠ΅ callbacks Π²ΡΠ·Π²Π°ΡΡ Π½Π° registration/binding. |
|
|||
| 63 |
|
||||
| 64 | ### sourceSetNamePattern |
|
|||
| 65 |
|
||||
| 66 | `sourceSetNamePattern` ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅Ρ naming policy Π·Π°ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ source set. |
|
|||
| 67 |
|
||||
| 68 | Default: |
|
|||
| 69 |
|
||||
| 70 | - `{variant}{layerCap}` |
|
|||
| 71 |
|
||||
| 72 | Tokens: |
|
|||
| 73 |
|
||||
| 74 | - `{variant}`, `{variantCap}` |
|
|||
| 75 | - `{role}`, `{roleCap}` |
|
|||
| 76 | - `{layer}`, `{layerCap}` |
|
|||
| 77 |
|
||||
| 78 | ΠΠΌΡ ΡΠ°Π½ΠΈΡΠΈΠ·ΠΈΡΡΠ΅ΡΡΡ (`[^A-Za-z0-9_.-] -> _`). |
|
|||
| 79 |
|
5 | |||
| 80 | ΠΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΠ΅: |
|
6 | Current documentation is maintained in the root [README.md](../README.md), | |
| 81 |
|
7 | [variant_sources.md](../variant_sources.md), and | ||
| 82 | - ΠΎΠ΄ΠΈΠ½ `sourceSetName` Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΏΠΎΡΠΎΠΆΠ΄Π΅Π½ ΡΠ°Π·Π½ΡΠΌΠΈ ΡΠ»ΠΎΡΠΌΠΈ. |
|
8 | [variant_sources_precedence.md](../variant_sources_precedence.md). | |
| 83 |
|
||||
| 84 | ## EVENTS |
|
|||
| 85 |
|
||||
| 86 | ### whenRegistered |
|
|||
| 87 |
|
||||
| 88 | - callback Π½Π° Π½ΠΎΠ²ΡΠΉ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ source set; |
|
|||
| 89 | - replayable; |
|
|||
| 90 | - ΠΏΡΠΈ shared source set ΡΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ ΠΎΠ΄ΠΈΠ½ ΡΠ°Π·. |
|
|||
| 91 |
|
||||
| 92 | ### whenBound |
|
|||
| 93 |
|
||||
| 94 | - callback Π½Π° ΠΊΠ°ΠΆΠ΄ΡΡ usage-ΡΠ²ΡΠ·ΠΊΡ `variant/role/layer`; |
|
|||
| 95 | - replayable; |
|
|||
| 96 | - ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΠΈΡ Π΄Π»Ρ per-usage Π»ΠΎΠ³ΠΈΠΊΠΈ. |
|
|||
| 97 |
|
||||
| 98 | ### variant filter |
|
|||
| 99 |
|
||||
| 100 | Π€ΠΈΠ»ΡΡΡ ΠΏΠΎ Π²Π°ΡΠΈΠ°Π½ΡΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΡΠΎΠ»ΡΠΊΠΎ usage-binding: |
|
|||
| 101 |
|
||||
| 102 | - `whenBound(String variantName, ...)` |
|
|||
| 103 |
|
||||
| 104 | ## PAYLOAD TYPES |
|
|||
| 105 |
|
||||
| 106 | `SourceSetRegistration` ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ: |
|
|||
| 107 |
|
||||
| 108 | - `layerName`, `sourceSetName`; |
|
|||
| 109 | - `sourceSet` (`NamedDomainObjectProvider<GenericSourceSet>`). |
|
|||
| 110 |
|
||||
| 111 | Sugar: |
|
|||
| 112 |
|
||||
| 113 | - `configureSourceSet(Action|Closure)`. |
|
|||
| 114 |
|
||||
| 115 | `SourceSetUsageBinding` ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ: |
|
|||
| 116 |
|
||||
| 117 | - `variantName`, `roleName`, `layerName`, `sourceSetName`; |
|
|||
| 118 | - `sourceSet` (`NamedDomainObjectProvider<GenericSourceSet>`). |
|
|||
| 119 |
|
9 | |||
| 120 | Sugar: |
|
|||
| 121 |
|
||||
| 122 | - `configureSourceSet(Action|Closure)`. |
|
|||
| 123 |
|
||||
| 124 | ## API |
|
|||
| 125 |
|
||||
| 126 | ### VariantSourcesExtension |
|
|||
| 127 |
|
||||
| 128 | - `bind(BuildLayer)` β ΠΏΠΎΠ»ΡΡΠΈΡΡ/ΡΠΎΠ·Π΄Π°ΡΡ binding Π΄Π»Ρ canonical layer identity. |
|
|||
| 129 | - `bind(String)` β ΠΏΠΎΠ»ΡΡΠΈΡΡ/ΡΠΎΠ·Π΄Π°ΡΡ binding ΠΏΠΎ ΠΈΠΌΠ΅Π½ΠΈ ΡΠ»ΠΎΡ. |
|
|||
| 130 | - `bind(String, Action|Closure)` β ΡΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠΎΠ²Π°ΡΡ binding. |
|
|||
| 131 | - `bind(BuildLayer, Action|Closure)` β ΡΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠΎΠ²Π°ΡΡ binding ΠΏΠΎ `BuildLayer`. |
|
|||
| 132 | - `getBindings()` β read-only snapshot ΡΠ΅ΠΊΡΡΠΈΡ bindings. |
|
|||
| 133 | - `whenRegistered(...)` β Π³Π»ΠΎΠ±Π°Π»ΡΠ½ΡΠ΅ callbacks ΡΠ΅Π³ΠΈΡΡΡΠ°ΡΠΈΠΈ source set. |
|
|||
| 134 | - `whenBound(...)` β Π³Π»ΠΎΠ±Π°Π»ΡΠ½ΡΠ΅ callbacks usage-binding. |
|
|||
| 135 | - `whenBound(String variantName, ...)` β usage-binding callbacks Ρ variant-filter. |
|
|||
| 136 |
|
||||
| 137 | ### LayerBindingSpec |
|
|||
| 138 |
|
||||
| 139 | - `sourceSetNamePattern` β naming policy Π΄Π»Ρ source set ΡΠ»ΠΎΡ. |
|
|||
| 140 | - `configureSourceSet(...)` β ΡΠ»ΠΎΠΉΠ½Π°Ρ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ `GenericSourceSet`. |
|
|||
| 141 | - `whenRegistered(...)` β callbacks ΡΠ΅Π³ΠΈΡΡΡΠ°ΡΠΈΠΈ Π² ΡΠ°ΠΌΠΊΠ°Ρ ΡΠ»ΠΎΡ. |
|
|||
| 142 | - `whenBound(...)` β callbacks usage-binding Π² ΡΠ°ΠΌΠΊΠ°Ρ ΡΠ»ΠΎΡ. |
|
|||
| 143 |
|
||||
| 144 | ## KEY CLASSES |
|
|||
| 145 |
|
||||
| 146 | - `VariantsSourcesPlugin` β ΡΠΎΡΠΊΠ° Π²Ρ ΠΎΠ΄Π° plugin adapter. |
|
|||
| 147 | - `VariantSourcesExtension` β Π³Π»ΠΎΠ±Π°Π»ΡΠ½ΡΠΉ DSL bind/events. |
|
|||
| 148 | - `LayerBindingSpec` β ΠΏΡΠ±Π»ΠΈΡΠ½ΡΠΉ DSL-contract layer-local policy/callbacks. |
|
|||
| 149 | - `SourceSetRegistration` β payload ΡΠ΅Π³ΠΈΡΡΡΠ°ΡΠΈΠΈ source set. |
|
|||
| 150 | - `SourceSetUsageBinding` β payload usage-binding. |
|
|||
| 151 |
|
||||
| 152 | ## NOTES |
|
|||
| 153 |
|
||||
| 154 | - `sourceSetNamePattern` ΡΠΈΠΊΡΠΈΡΡΠ΅ΡΡΡ ΠΏΡΠΈ ΠΏΠ΅ΡΠ²ΠΎΠΌ ΡΡΠ΅Π½ΠΈΠΈ Π² registration |
|
|||
| 155 | (`finalizeValueOnRead`). |
|
|||
| 156 | - runtime state bindings ΡΠΊΡΡΡ Π²Π½ΡΡΡΠΈ adapter implementation (`LayerBinding`). |
|
|||
| 157 | - name-based bindings ΡΠ΅Π·ΠΎΠ»Π²ΡΡΡΡ ΠΊ canonical `BuildLayer` ΡΠ΅ΡΠ΅Π· registry `variants`. |
|
|||
| 158 | - Closure callbacks ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ delegate-first. |
|
|||
| 159 | - ΠΠ»Ρ Π²Π»ΠΎΠΆΠ΅Π½Π½ΡΡ closure Π»ΡΡΡΠ΅ ΡΠ²Π½ΡΠΉ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ (`ctx -> ...`). |
|
|||
| @@ -1,112 +1,8 | |||||
| 1 | # Variants Plugin |
|
1 | # Moved: Variants Plugin | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `VariantsPlugin` ΠΈ extension `variants`. |
|
|||
| 6 |
|
||||
| 7 | ## SYNOPSIS |
|
|||
| 8 |
|
||||
| 9 | ```groovy |
|
|||
| 10 | plugins { |
|
|||
| 11 | id 'org.implab.gradle-variants' |
|
|||
| 12 | } |
|
|||
| 13 |
|
||||
| 14 | variants { |
|
|||
| 15 | layer('mainBase') |
|
|||
| 16 | layer('mainAmd') |
|
|||
| 17 |
|
||||
| 18 | variant('browser') { |
|
|||
| 19 | attributes { |
|
|||
| 20 | string('jsRuntime', 'browser') |
|
|||
| 21 | string('jsModule', 'amd') |
|
|||
| 22 | } |
|
|||
| 23 |
|
||||
| 24 | role('main') { |
|
|||
| 25 | layers('mainBase', 'mainAmd') |
|
|||
| 26 | } |
|
|||
| 27 |
|
||||
| 28 | artifactSlot('mainCompiled') |
|
|||
| 29 | } |
|
|||
| 30 | } |
|
|||
| 31 | ``` |
|
|||
| 32 |
|
||||
| 33 | ## DESCRIPTION |
|
|||
| 34 |
|
||||
| 35 | `VariantsPlugin` Π·Π°Π΄Π°Π΅Ρ Π΄ΠΎΠΌΠ΅Π½Π½ΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ ΡΠ±ΠΎΡΠΊΠΈ ΠΈ Π΅Π΅ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ. ΠΠ»Π°Π³ΠΈΠ½ Π½Π΅ |
|
|||
| 36 | ΡΠ΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ compile/copy/bundle Π·Π°Π΄Π°ΡΠΈ Π½Π°ΠΏΡΡΠΌΡΡ. |
|
|||
| 37 |
|
||||
| 38 | ### layers |
|
|||
| 39 |
|
||||
| 40 | ΠΠ»ΠΎΠ±Π°Π»ΡΠ½ΡΠ΅ Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΡΠ»ΠΎΠΈ. Π‘Π»ΡΠΆΠ°Ρ Π΅Π΄ΠΈΠ½ΡΠΌ ΡΠ»ΠΎΠ²Π°ΡΠ΅ΠΌ ΠΈΠΌΠ΅Π½, Π½Π° ΠΊΠΎΡΠΎΡΡΠ΅ Π·Π°ΡΠ΅ΠΌ |
|
|||
| 41 | ΡΡΡΠ»Π°ΡΡΡΡ ΡΠΎΠ»ΠΈ. |
|
|||
| 42 |
|
||||
| 43 | ### variants |
|
|||
| 44 |
|
||||
| 45 | ΠΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠ΅ Π²Π°ΡΠΈΠ°Π½ΡΡ ΠΈΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ/ΠΏΠ°ΠΊΠ΅ΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ (`browser`, `node`, ΠΈ Ρ.Π΄.). |
|
|||
| 46 | ΠΠ°ΡΠΈΠ°Π½Ρ Π°Π³ΡΠ΅Π³ΠΈΡΡΠ΅Ρ ΡΠΎΠ»ΠΈ, Π°ΡΡΠΈΠ±ΡΡΡ ΠΈ artifact slots. |
|
|||
| 47 |
|
||||
| 48 | ### roles |
|
|||
| 49 |
|
||||
| 50 | Π ΠΎΠ»Ρ ΠΎΠΏΠΈΡΡΠ²Π°Π΅Ρ Π½Π°Π±ΠΎΡ ΡΠ»ΠΎΠ΅Π² Π² ΠΏΡΠ΅Π΄Π΅Π»Π°Ρ Π²Π°ΡΠΈΠ°Π½ΡΠ° (`main`, `test`, `tools`). |
|
|||
| 51 | ΠΠ΄Π½Π° ΡΠΎΠ»Ρ ΠΌΠΎΠΆΠ΅Ρ ΡΡΡΠ»Π°ΡΡΡΡ Π½Π° Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΠ»ΠΎΠ΅Π². |
|
|||
| 52 |
|
||||
| 53 | ### attributes |
|
|||
| 54 |
|
2 | |||
| 55 | Typed-Π°ΡΡΠΈΠ±ΡΡΡ (`Attribute<T> -> Provider<T>`) Π΄Π»Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² Π² |
|
3 | The `VariantsPlugin` implementation is now part of the `variants` module, not | |
| 56 | Π°Π΄Π°ΠΏΡΠ΅ΡΡ ΠΈ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΡ Π°ΡΡΠ΅ΡΠ°ΠΊΡΠΎΠ². |
|
4 | the `common` module. | |
| 57 |
|
||||
| 58 | ### artifact slots |
|
|||
| 59 |
|
||||
| 60 | ΠΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠ΅ ΡΠ»ΠΎΡΡ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΡΡ Π°ΡΡΠ΅ΡΠ°ΠΊΡΠΎΠ² Π²Π°ΡΠΈΠ°Π½ΡΠ°. ΠΡΠΏΠΎΠ»ΡΠ·ΡΡΡΡΡ ΠΊΠ°ΠΊ ΠΊΠΎΠ½ΡΡΠ°ΠΊΡ |
|
|||
| 61 | ΠΌΠ΅ΠΆΠ΄Ρ ΠΌΠΎΠ΄Π΅Π»ΡΡ Π²Π°ΡΠΈΠ°Π½ΡΠ° ΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°ΠΌΠΈ, ΡΠΎΠ·Π΄Π°ΡΡΠΈΠΌΠΈ/ΠΏΡΠ±Π»ΠΈΠΊΡΡΡΠΈΠΌΠΈ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ. |
|
|||
| 62 |
|
||||
| 63 | ## VALIDATION |
|
|||
| 64 |
|
||||
| 65 | Π `finalizeModel()` Π²ΡΠΏΠΎΠ»Π½ΡΠ΅ΡΡΡ ΠΏΡΠΎΠ²Π΅ΡΠΊΠ°: |
|
|||
| 66 |
|
||||
| 67 | - ΡΠΎΠ»Ρ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ ΡΡΡΠ»Π°ΡΡΡΡ Π½Π° Π½Π΅ΠΈΠ·Π²Π΅ΡΡΠ½ΡΠΉ layer; |
|
|||
| 68 | - ΠΏΡΡΡΡΠ΅ ΠΈΠΌΠ΅Π½Π° layer Π·Π°ΠΏΡΠ΅ΡΠ΅Π½Ρ; |
|
|||
| 69 | - ΠΈΠΌΠ΅Π½Π° ΡΠΎΠ»Π΅ΠΉ Π² Π²Π°ΡΠΈΠ°Π½ΡΠ΅ Π΄ΠΎΠ»ΠΆΠ½Ρ Π±ΡΡΡ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½Ρ; |
|
|||
| 70 | - ΠΈΠΌΠ΅Π½Π° artifact slots Π² Π²Π°ΡΠΈΠ°Π½ΡΠ΅ Π΄ΠΎΠ»ΠΆΠ½Ρ Π±ΡΡΡ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½Ρ. |
|
|||
| 71 |
|
||||
| 72 | ## LIFECYCLE |
|
|||
| 73 |
|
||||
| 74 | - `VariantsPlugin` Π²ΡΠ·ΡΠ²Π°Π΅Ρ `variants.finalizeModel()` Π½Π° `afterEvaluate`. |
|
|||
| 75 | - ΠΏΠΎΡΠ»Π΅ `finalizeModel()` ΠΌΡΡΠ°ΡΠΈΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π·Π°ΠΏΡΠ΅ΡΠ΅Π½Ρ. |
|
|||
| 76 | - `whenFinalized(...)` replayable. |
|
|||
| 77 |
|
||||
| 78 | ## API |
|
|||
| 79 |
|
||||
| 80 | ### BuildVariantsExtension |
|
|||
| 81 |
|
5 | |||
| 82 | - `layer(...)` β ΠΎΠ±ΡΡΠ²Π»Π΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ `BuildLayer`. |
|
6 | Current documentation is maintained in the root [README.md](../README.md) and | |
| 83 | - `variant(...)` β ΠΎΠ±ΡΡΠ²Π»Π΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ `BuildVariant`. |
|
7 | the design notes in [variant_sources.md](../variant_sources.md). | |
| 84 | - `layers { layer(...) }`, `variants { ... }` β grouped DSL Π±Π΅Π· ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΠΈ container API Π½Π°ΡΡΠΆΡ. |
|
|||
| 85 | - `all(...)` β callback Π΄Π»Ρ Π²ΡΠ΅Ρ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ². |
|
|||
| 86 | - `findLayer(name)`, `requireLayer(name)`, `getAllLayers()` β Π΄ΠΎΡΡΡΠΏ ΠΊ registry ΡΠ»ΠΎΠ΅Π². |
|
|||
| 87 | - `getAll()`, `find(name)`, `require(name)` β Π΄ΠΎΡΡΡΠΏ ΠΊ Π²Π°ΡΠΈΠ°Π½ΡΠ°ΠΌ. |
|
|||
| 88 | - `validate()` β ΡΠ²Π½ΡΠΉ Π·Π°ΠΏΡΡΠΊ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΠΈ. |
|
|||
| 89 | - `finalizeModel()` β Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ + ΡΠΈΠ½Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ. |
|
|||
| 90 | - `whenFinalized(...)` β callback ΠΏΠΎ Π·Π°Π²Π΅ΡΡΠ΅Π½Π½ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ (replayable). |
|
|||
| 91 |
|
||||
| 92 | ### BuildVariant |
|
|||
| 93 |
|
||||
| 94 | - `attributes { ... }` β Π°ΡΡΠΈΠ±ΡΡΡ Π²Π°ΡΠΈΠ°Π½ΡΠ° (+ sugar `string/bool/integer`). |
|
|||
| 95 | - `role(...)`, `roles { ... }` β ΡΠΎΠ»ΠΈ Π²Π°ΡΠΈΠ°Π½ΡΠ°. |
|
|||
| 96 | - `artifactSlot(...)`, `artifactSlots { ... }` β Π°ΡΡΠ΅ΡΠ°ΠΊΡΠ½ΡΠ΅ ΡΠ»ΠΎΡΡ. |
|
|||
| 97 |
|
8 | |||
| 98 | ## KEY CLASSES |
|
|||
| 99 |
|
||||
| 100 | - `VariantsPlugin` β ΡΠΎΡΠΊΠ° Π²Ρ ΠΎΠ΄Π° ΠΏΠ»Π°Π³ΠΈΠ½Π°. |
|
|||
| 101 | - `BuildVariantsExtension` β root extension ΠΈ lifecycle. |
|
|||
| 102 | - `BuildVariant` β Π°Π³ΡΠ΅Π³Π°ΡΠ½Π°Ρ ΠΌΠΎΠ΄Π΅Π»Ρ Π²Π°ΡΠΈΠ°Π½ΡΠ°. |
|
|||
| 103 | - `BuildLayer` β canonical identity-model ΡΠ»ΠΎΡ. |
|
|||
| 104 | - `BuildRole` β ΠΌΠΎΠ΄Π΅Π»Ρ ΡΠΎΠ»ΠΈ. |
|
|||
| 105 | - `BuildArtifactSlot` β ΠΌΠΎΠ΄Π΅Π»Ρ Π°ΡΡΠ΅ΡΠ°ΠΊΡΠ½ΠΎΠ³ΠΎ ΡΠ»ΠΎΡΠ°. |
|
|||
| 106 | - `VariantAttributes` β typed wrapper Π΄Π»Ρ variant attributes. |
|
|||
| 107 |
|
||||
| 108 | ## NOTES |
|
|||
| 109 |
|
||||
| 110 | - ΠΠΎΠ΄Π΅Π»Ρ `variants` intentionally agnostic ΠΊ toolchain. |
|
|||
| 111 | - Layer registry Ρ ΡΠ°Π½ΠΈΡΡΡ ΠΊΠ°ΠΊ ΡΠ²Π½Π°Ρ identity-map, Π° Π½Π΅ ΠΊΠ°ΠΊ ΠΏΡΠ±Π»ΠΈΡΠ½ΡΠΉ `NamedDomainObjectContainer`. |
|
|||
| 112 | - ΠΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Ρ Π·Π°Π΄Π°ΡΠ°ΠΌΠΈ Π²ΡΠΏΠΎΠ»Π½ΡΠ΅ΡΡΡ ΡΠ΅ΡΠ΅Π· `variantSources` ΠΈ Π°Π΄Π°ΠΏΡΠ΅ΡΡ. |
|
|||
| @@ -1,2 +1,2 | |||||
| 1 | group=org.implab.gradle |
|
1 | group=org.implab.gradle | |
| 2 | version=1.0 No newline at end of file |
|
2 | version=0.1.0 | |
| @@ -1,694 +1,698 | |||||
| 1 | # Variants and Variant Artifacts |
|
1 | # Variants and Variant Artifacts | |
| 2 |
|
2 | |||
|
|
3 | > Design note. The current user-facing DSL and local publication workflow are | |||
|
|
4 | > documented in [README.md](README.md). Some snippets below are conceptual and | |||
|
|
5 | > describe model direction rather than exact public API. | |||
|
|
6 | ||||
| 3 | ## Overview |
|
7 | ## Overview | |
| 4 |
|
8 | |||
| 5 | This document describes the artifact model built on top of `variants` and |
|
9 | This document describes the artifact model built on top of `variants` and | |
| 6 | `variantSources`. |
|
10 | `variantSources`. | |
| 7 |
|
11 | |||
| 8 | The goal is to define: |
|
12 | The goal is to define: | |
| 9 |
|
13 | |||
| 10 | - a stable artifact-facing model for outgoing contracts; |
|
14 | - a stable artifact-facing model for outgoing contracts; | |
| 11 | - a DSL for declaring slots and their inputs; |
|
15 | - a DSL for declaring slots and their inputs; | |
| 12 | - a resolver bridge between `variantArtifacts` and `variantSources`; |
|
16 | - a resolver bridge between `variantArtifacts` and `variantSources`; | |
| 13 | - extension points for deduplication and similar policies; |
|
17 | - extension points for deduplication and similar policies; | |
| 14 | - a model that remains live during configuration and does not require an |
|
18 | - a model that remains live during configuration and does not require an | |
| 15 | artificial freeze of slot content. |
|
19 | artificial freeze of slot content. | |
| 16 |
|
20 | |||
| 17 | The design follows the same split already used elsewhere: |
|
21 | The design follows the same split already used elsewhere: | |
| 18 |
|
22 | |||
| 19 | - `variants` defines the closed domain topology; |
|
23 | - `variants` defines the closed domain topology; | |
| 20 | - `variantSources` defines source materialization semantics over that topology; |
|
24 | - `variantSources` defines source materialization semantics over that topology; | |
| 21 | - `variantArtifacts` defines outgoing artifact contracts over that topology. |
|
25 | - `variantArtifacts` defines outgoing artifact contracts over that topology. | |
| 22 |
|
26 | |||
| 23 | --- |
|
27 | --- | |
| 24 |
|
28 | |||
| 25 | ## Core idea |
|
29 | ## Core idea | |
| 26 |
|
30 | |||
| 27 | `variantArtifacts` is not the owner of the variant model and not the owner of |
|
31 | `variantArtifacts` is not the owner of the variant model and not the owner of | |
| 28 | source-set materialization. |
|
32 | source-set materialization. | |
| 29 |
|
33 | |||
| 30 | Its purpose is narrower: |
|
34 | Its purpose is narrower: | |
| 31 |
|
35 | |||
| 32 | - decide which variants participate in outgoing publication; |
|
36 | - decide which variants participate in outgoing publication; | |
| 33 | - define artifact slots for those outgoing variants; |
|
37 | - define artifact slots for those outgoing variants; | |
| 34 | - declare how each slot gathers its inputs. |
|
38 | - declare how each slot gathers its inputs. | |
| 35 |
|
39 | |||
| 36 | This makes `variantArtifacts` an outgoing-contract layer, not a compilation or |
|
40 | This makes `variantArtifacts` an outgoing-contract layer, not a compilation or | |
| 37 | source-materialization layer. |
|
41 | source-materialization layer. | |
| 38 |
|
42 | |||
| 39 | --- |
|
43 | --- | |
| 40 |
|
44 | |||
| 41 | ## Model boundaries |
|
45 | ## Model boundaries | |
| 42 |
|
46 | |||
| 43 | ### What belongs to `variants` |
|
47 | ### What belongs to `variants` | |
| 44 |
|
48 | |||
| 45 | - identities: `Variant`, `Role`, `Layer`; |
|
49 | - identities: `Variant`, `Role`, `Layer`; | |
| 46 | - normalized topology relation `(variant, role, layer)`; |
|
50 | - normalized topology relation `(variant, role, layer)`; | |
| 47 | - finalization of the core domain model; |
|
51 | - finalization of the core domain model; | |
| 48 | - `VariantsView` and derived topology views. |
|
52 | - `VariantsView` and derived topology views. | |
| 49 |
|
53 | |||
| 50 | ### What belongs to `variantSources` |
|
54 | ### What belongs to `variantSources` | |
| 51 |
|
55 | |||
| 52 | - compile units and role projections derived from finalized `variants`; |
|
56 | - compile units and role projections derived from finalized `variants`; | |
| 53 | - source-set naming policy; |
|
57 | - source-set naming policy; | |
| 54 | - source-set materialization; |
|
58 | - source-set materialization; | |
| 55 | - lazy access to `GenericSourceSet` providers and their named outputs. |
|
59 | - lazy access to `GenericSourceSet` providers and their named outputs. | |
| 56 |
|
60 | |||
| 57 | ### What belongs to `variantArtifacts` |
|
61 | ### What belongs to `variantArtifacts` | |
| 58 |
|
62 | |||
| 59 | - selection of outgoing variants; |
|
63 | - selection of outgoing variants; | |
| 60 | - slot identities inside an outgoing variant; |
|
64 | - slot identities inside an outgoing variant; | |
| 61 | - slot assembly declarations; |
|
65 | - slot assembly declarations; | |
| 62 | - root outgoing configurations for outgoing variants; |
|
66 | - root outgoing configurations for outgoing variants; | |
| 63 | - slot-level assembly bodies; |
|
67 | - slot-level assembly bodies; | |
| 64 | - publication-facing hooks. |
|
68 | - publication-facing hooks. | |
| 65 |
|
69 | |||
| 66 | ### What does not belong to `variantArtifacts` |
|
70 | ### What does not belong to `variantArtifacts` | |
| 67 |
|
71 | |||
| 68 | - ownership of variant existence; |
|
72 | - ownership of variant existence; | |
| 69 | - ownership of source-set naming; |
|
73 | - ownership of source-set naming; | |
| 70 | - direct mutation of source materialization internals; |
|
74 | - direct mutation of source materialization internals; | |
| 71 | - compiler- or toolchain-specific logic; |
|
75 | - compiler- or toolchain-specific logic; | |
| 72 | - eager flattening of source inputs into files during DSL declaration. |
|
76 | - eager flattening of source inputs into files during DSL declaration. | |
| 73 |
|
77 | |||
| 74 | --- |
|
78 | --- | |
| 75 |
|
79 | |||
| 76 | ## Outgoing subset |
|
80 | ## Outgoing subset | |
| 77 |
|
81 | |||
| 78 | Not every declared `Variant` must become outgoing. |
|
82 | Not every declared `Variant` must become outgoing. | |
| 79 |
|
83 | |||
| 80 | `variantArtifacts` defines an outgoing subset of variants. |
|
84 | `variantArtifacts` defines an outgoing subset of variants. | |
| 81 |
|
85 | |||
| 82 | For each outgoing variant there is one root outgoing aggregate: |
|
86 | For each outgoing variant there is one root outgoing aggregate: | |
| 83 |
|
87 | |||
| 84 | - one root consumable `Configuration`; |
|
88 | - one root consumable `Configuration`; | |
| 85 | - one or more artifact slots; |
|
89 | - one or more artifact slots; | |
| 86 | - one primary slot; |
|
90 | - one primary slot; | |
| 87 | - optional secondary slots. |
|
91 | - optional secondary slots. | |
| 88 |
|
92 | |||
| 89 | This is why `OutgoingConfiguration` is a real model object and not merely a |
|
93 | This is why `OutgoingConfiguration` is a real model object and not merely a | |
| 90 | publication event payload. |
|
94 | publication event payload. | |
| 91 |
|
95 | |||
| 92 | It represents a live build-facing aggregate: |
|
96 | It represents a live build-facing aggregate: | |
| 93 |
|
97 | |||
| 94 | - it has its own attributes; |
|
98 | - it has its own attributes; | |
| 95 | - it is visible to other build logic as soon as registered; |
|
99 | - it is visible to other build logic as soon as registered; | |
| 96 | - it contains lazy handles rather than eagerly materialized state; |
|
100 | - it contains lazy handles rather than eagerly materialized state; | |
| 97 | - it is distinct from slot assembly state. |
|
101 | - it is distinct from slot assembly state. | |
| 98 |
|
102 | |||
| 99 | --- |
|
103 | --- | |
| 100 |
|
104 | |||
| 101 | ## Identity-first split |
|
105 | ## Identity-first split | |
| 102 |
|
106 | |||
| 103 | The artifact model should preserve the same identity-first principle used for |
|
107 | The artifact model should preserve the same identity-first principle used for | |
| 104 | the rest of the project. |
|
108 | the rest of the project. | |
| 105 |
|
109 | |||
| 106 | ### Identity objects |
|
110 | ### Identity objects | |
| 107 |
|
111 | |||
| 108 | - `Variant` |
|
112 | - `Variant` | |
| 109 | - `Slot` |
|
113 | - `Slot` | |
| 110 | - `ArtifactSlot = (variant, slot)` |
|
114 | - `ArtifactSlot = (variant, slot)` | |
| 111 |
|
115 | |||
| 112 | These objects are: |
|
116 | These objects are: | |
| 113 |
|
117 | |||
| 114 | - cheap; |
|
118 | - cheap; | |
| 115 | - replayable; |
|
119 | - replayable; | |
| 116 | - suitable for discovery and selection. |
|
120 | - suitable for discovery and selection. | |
| 117 |
|
121 | |||
| 118 | ### Stateful objects |
|
122 | ### Stateful objects | |
| 119 |
|
123 | |||
| 120 | - `OutgoingConfiguration` |
|
124 | - `OutgoingConfiguration` | |
| 121 | - `ArtifactAssembly` |
|
125 | - `ArtifactAssembly` | |
| 122 |
|
126 | |||
| 123 | These objects are: |
|
127 | These objects are: | |
| 124 |
|
128 | |||
| 125 | - build-facing; |
|
129 | - build-facing; | |
| 126 | - allowed to contain Gradle lazy handles; |
|
130 | - allowed to contain Gradle lazy handles; | |
| 127 | - obtained through dedicated APIs rather than embedded into identity objects. |
|
131 | - obtained through dedicated APIs rather than embedded into identity objects. | |
| 128 |
|
132 | |||
| 129 | ### Rule of thumb |
|
133 | ### Rule of thumb | |
| 130 |
|
134 | |||
| 131 | - slot identity is cheap and replayable; |
|
135 | - slot identity is cheap and replayable; | |
| 132 | - inside one `OutgoingConfiguration`, `Slot` is the natural local identity; |
|
136 | - inside one `OutgoingConfiguration`, `Slot` is the natural local identity; | |
| 133 | - `ArtifactSlot` is useful when slot identity must be referenced outside the |
|
137 | - `ArtifactSlot` is useful when slot identity must be referenced outside the | |
| 134 | parent outgoing configuration; |
|
138 | parent outgoing configuration; | |
| 135 | - slot body is stateful and resolved separately; |
|
139 | - slot body is stateful and resolved separately; | |
| 136 | - outgoing configuration is a live aggregate, not a mere snapshot. |
|
140 | - outgoing configuration is a live aggregate, not a mere snapshot. | |
| 137 |
|
141 | |||
| 138 | --- |
|
142 | --- | |
| 139 |
|
143 | |||
| 140 | ## Artifact model |
|
144 | ## Artifact model | |
| 141 |
|
145 | |||
| 142 | Conceptually: |
|
146 | Conceptually: | |
| 143 |
|
147 | |||
| 144 | ```java |
|
148 | ```java | |
| 145 | interface VariantArtifactsContext { |
|
149 | interface VariantArtifactsContext { | |
| 146 | VariantsView getVariants(); |
|
150 | VariantsView getVariants(); | |
| 147 | void all(Action<? super OutgoingConfiguration> action); |
|
151 | void all(Action<? super OutgoingConfiguration> action); | |
| 148 | Optional<OutgoingConfiguration> findArtifacts(Variant variant); |
|
152 | Optional<OutgoingConfiguration> findArtifacts(Variant variant); | |
| 149 | OutgoingConfiguration requireArtifacts(Variant variant); |
|
153 | OutgoingConfiguration requireArtifacts(Variant variant); | |
| 150 | ArtifactAssemblies getAssemblies(); |
|
154 | ArtifactAssemblies getAssemblies(); | |
| 151 | } |
|
155 | } | |
| 152 | ``` |
|
156 | ``` | |
| 153 |
|
157 | |||
| 154 | ```java |
|
158 | ```java | |
| 155 | interface OutgoingConfiguration { |
|
159 | interface OutgoingConfiguration { | |
| 156 | Variant getVariant(); |
|
160 | Variant getVariant(); | |
| 157 | NamedDomainObjectProvider<Configuration> getOutgoingConfiguration(); |
|
161 | NamedDomainObjectProvider<Configuration> getOutgoingConfiguration(); | |
| 158 | NamedDomainObjectContainer<Slot> getSlots(); |
|
162 | NamedDomainObjectContainer<Slot> getSlots(); | |
| 159 | Property<Slot> getPrimarySlot(); |
|
163 | Property<Slot> getPrimarySlot(); | |
| 160 | } |
|
164 | } | |
| 161 | ``` |
|
165 | ``` | |
| 162 |
|
166 | |||
| 163 | ```java |
|
167 | ```java | |
| 164 | interface ArtifactAssemblies { |
|
168 | interface ArtifactAssemblies { | |
| 165 | ArtifactAssembly resolveSlot(ArtifactSlot slot); |
|
169 | ArtifactAssembly resolveSlot(ArtifactSlot slot); | |
| 166 | } |
|
170 | } | |
| 167 | ``` |
|
171 | ``` | |
| 168 |
|
172 | |||
| 169 | This intentionally uses a Gradle-style local slot container rather than a |
|
173 | This intentionally uses a Gradle-style local slot container rather than a | |
| 170 | separate `ArtifactSlotsView`. |
|
174 | separate `ArtifactSlotsView`. | |
| 171 |
|
175 | |||
| 172 | The reason is simple: |
|
176 | The reason is simple: | |
| 173 |
|
177 | |||
| 174 | - inside one `OutgoingConfiguration`, slot identity is local and naturally |
|
178 | - inside one `OutgoingConfiguration`, slot identity is local and naturally | |
| 175 | expressed as `Slot`; |
|
179 | expressed as `Slot`; | |
| 176 | - a dedicated `ArtifactSlotsView` would suggest a detached readonly projection |
|
180 | - a dedicated `ArtifactSlotsView` would suggest a detached readonly projection | |
| 177 | without clearly owning mutation/configuration semantics; |
|
181 | without clearly owning mutation/configuration semantics; | |
| 178 | - `NamedDomainObjectContainer<Slot>` better matches the live configuration model |
|
182 | - `NamedDomainObjectContainer<Slot>` better matches the live configuration model | |
| 179 | and keeps the parent aggregate as the owner of slot structure. |
|
183 | and keeps the parent aggregate as the owner of slot structure. | |
| 180 |
|
184 | |||
| 181 | `ArtifactSlot` remains useful, but only as a fully qualified identity outside |
|
185 | `ArtifactSlot` remains useful, but only as a fully qualified identity outside | |
| 182 | the parent aggregate: |
|
186 | the parent aggregate: | |
| 183 |
|
187 | |||
| 184 | - resolver APIs; |
|
188 | - resolver APIs; | |
| 185 | - global payloads; |
|
189 | - global payloads; | |
| 186 | - cross-variant references. |
|
190 | - cross-variant references. | |
| 187 |
|
191 | |||
| 188 | Important distinction: |
|
192 | Important distinction: | |
| 189 |
|
193 | |||
| 190 | - `OutgoingConfiguration` describes outgoing publication structure; |
|
194 | - `OutgoingConfiguration` describes outgoing publication structure; | |
| 191 | - `ArtifactAssembly` describes how one slot artifact is assembled. |
|
195 | - `ArtifactAssembly` describes how one slot artifact is assembled. | |
| 192 |
|
196 | |||
| 193 | An `ArtifactAssembly` does not create the root outgoing configuration. It serves |
|
197 | An `ArtifactAssembly` does not create the root outgoing configuration. It serves | |
| 194 | one already declared slot inside that configuration. |
|
198 | one already declared slot inside that configuration. | |
| 195 |
|
199 | |||
| 196 | ### Primary slot ownership |
|
200 | ### Primary slot ownership | |
| 197 |
|
201 | |||
| 198 | Primary status belongs to the parent outgoing configuration, not to the slot |
|
202 | Primary status belongs to the parent outgoing configuration, not to the slot | |
| 199 | itself. |
|
203 | itself. | |
| 200 |
|
204 | |||
| 201 | This is why the preferred container-level contract is: |
|
205 | This is why the preferred container-level contract is: | |
| 202 |
|
206 | |||
| 203 | ```java |
|
207 | ```java | |
| 204 | Property<Slot> getPrimarySlot(); |
|
208 | Property<Slot> getPrimarySlot(); | |
| 205 | ``` |
|
209 | ``` | |
| 206 |
|
210 | |||
| 207 | and not a slot-local boolean or a derived `ArtifactSlot` reference. |
|
211 | and not a slot-local boolean or a derived `ArtifactSlot` reference. | |
| 208 |
|
212 | |||
| 209 | Reasons: |
|
213 | Reasons: | |
| 210 |
|
214 | |||
| 211 | - the primary role is assigned by the parent aggregate; |
|
215 | - the primary role is assigned by the parent aggregate; | |
| 212 | - within one `OutgoingConfiguration`, the variant identity is already known, so |
|
216 | - within one `OutgoingConfiguration`, the variant identity is already known, so | |
| 213 | `Slot` is sufficient and avoids redundant `(variant, slot)` duplication; |
|
217 | `Slot` is sufficient and avoids redundant `(variant, slot)` duplication; | |
| 214 | - `Property` matches the rest of the Gradle-facing live model better than a |
|
218 | - `Property` matches the rest of the Gradle-facing live model better than a | |
| 215 | custom `findPrimarySlot()` style API; |
|
219 | custom `findPrimarySlot()` style API; | |
| 216 | - `Property` gives useful write/configure/finalize semantics without inventing a |
|
220 | - `Property` gives useful write/configure/finalize semantics without inventing a | |
| 217 | separate special lifecycle abstraction. |
|
221 | separate special lifecycle abstraction. | |
| 218 |
|
222 | |||
| 219 | Expected usage: |
|
223 | Expected usage: | |
| 220 |
|
224 | |||
| 221 | - DSL or adapters may assign the primary slot through `set(...)`; |
|
225 | - DSL or adapters may assign the primary slot through `set(...)`; | |
| 222 | - adapters that want to provide a default may use `convention(...)`; |
|
226 | - adapters that want to provide a default may use `convention(...)`; | |
| 223 | - the property may remain unset while the model is still incomplete; |
|
227 | - the property may remain unset while the model is still incomplete; | |
| 224 | - at materialization time the property may be finalized; |
|
228 | - at materialization time the property may be finalized; | |
| 225 | - if more than one slot exists and `primarySlot` is still unset at the |
|
229 | - if more than one slot exists and `primarySlot` is still unset at the | |
| 226 | materialization point, that is a model error. |
|
230 | materialization point, that is a model error. | |
| 227 |
|
231 | |||
| 228 | The model should still enforce that the selected primary slot belongs to the |
|
232 | The model should still enforce that the selected primary slot belongs to the | |
| 229 | same `OutgoingConfiguration`. |
|
233 | same `OutgoingConfiguration`. | |
| 230 |
|
234 | |||
| 231 | ### Proposed public shape |
|
235 | ### Proposed public shape | |
| 232 |
|
236 | |||
| 233 | With these constraints, the preferred public structure is: |
|
237 | With these constraints, the preferred public structure is: | |
| 234 |
|
238 | |||
| 235 | ```java |
|
239 | ```java | |
| 236 | interface VariantArtifactsContext { |
|
240 | interface VariantArtifactsContext { | |
| 237 | VariantsView getVariants(); |
|
241 | VariantsView getVariants(); | |
| 238 | void all(Action<? super OutgoingConfiguration> action); |
|
242 | void all(Action<? super OutgoingConfiguration> action); | |
| 239 | Optional<OutgoingConfiguration> findArtifacts(Variant variant); |
|
243 | Optional<OutgoingConfiguration> findArtifacts(Variant variant); | |
| 240 | OutgoingConfiguration requireArtifacts(Variant variant); |
|
244 | OutgoingConfiguration requireArtifacts(Variant variant); | |
| 241 | ArtifactAssemblies getAssemblies(); |
|
245 | ArtifactAssemblies getAssemblies(); | |
| 242 | } |
|
246 | } | |
| 243 |
|
247 | |||
| 244 | interface OutgoingConfiguration { |
|
248 | interface OutgoingConfiguration { | |
| 245 | Variant getVariant(); |
|
249 | Variant getVariant(); | |
| 246 | NamedDomainObjectProvider<Configuration> getOutgoingConfiguration(); |
|
250 | NamedDomainObjectProvider<Configuration> getOutgoingConfiguration(); | |
| 247 | NamedDomainObjectContainer<Slot> getSlots(); |
|
251 | NamedDomainObjectContainer<Slot> getSlots(); | |
| 248 | Property<Slot> getPrimarySlot(); |
|
252 | Property<Slot> getPrimarySlot(); | |
| 249 | } |
|
253 | } | |
| 250 |
|
254 | |||
| 251 | interface ArtifactAssemblies { |
|
255 | interface ArtifactAssemblies { | |
| 252 | ArtifactAssembly resolveSlot(ArtifactSlot slot); |
|
256 | ArtifactAssembly resolveSlot(ArtifactSlot slot); | |
| 253 | } |
|
257 | } | |
| 254 |
|
258 | |||
| 255 | record ArtifactSlot(Variant variant, Slot slot) {} |
|
259 | record ArtifactSlot(Variant variant, Slot slot) {} | |
| 256 | ``` |
|
260 | ``` | |
| 257 |
|
261 | |||
| 258 | This gives: |
|
262 | This gives: | |
| 259 |
|
263 | |||
| 260 | - one global registry of outgoing variants; |
|
264 | - one global registry of outgoing variants; | |
| 261 | - one local slot container per outgoing variant; |
|
265 | - one local slot container per outgoing variant; | |
| 262 | - one fully qualified slot identity for resolver and cross-aggregate use; |
|
266 | - one fully qualified slot identity for resolver and cross-aggregate use; | |
| 263 | - one explicit service for slot assembly materialization. |
|
267 | - one explicit service for slot assembly materialization. | |
| 264 |
|
268 | |||
| 265 | ### Minimal internal shape |
|
269 | ### Minimal internal shape | |
| 266 |
|
270 | |||
| 267 | The preferred minimal internal structure is: |
|
271 | The preferred minimal internal structure is: | |
| 268 |
|
272 | |||
| 269 | ```java |
|
273 | ```java | |
| 270 | final class VariantArtifactsRegistry implements VariantArtifactsContext { |
|
274 | final class VariantArtifactsRegistry implements VariantArtifactsContext { | |
| 271 | OutgoingConfiguration outgoingConfiguration(Variant variant); |
|
275 | OutgoingConfiguration outgoingConfiguration(Variant variant); | |
| 272 | ArtifactAssemblyRules slotRules(ArtifactSlot slot); |
|
276 | ArtifactAssemblyRules slotRules(ArtifactSlot slot); | |
| 273 | ArtifactAssemblies assemblies(); |
|
277 | ArtifactAssemblies assemblies(); | |
| 274 | } |
|
278 | } | |
| 275 |
|
279 | |||
| 276 | interface ArtifactAssemblyRules { |
|
280 | interface ArtifactAssemblyRules { | |
| 277 | void from(Object input); |
|
281 | void from(Object input); | |
| 278 | void fromVariant(Action<? super OutputSelectionSpec> action); |
|
282 | void fromVariant(Action<? super OutputSelectionSpec> action); | |
| 279 | void fromRole(String roleName, Action<? super OutputSelectionSpec> action); |
|
283 | void fromRole(String roleName, Action<? super OutputSelectionSpec> action); | |
| 280 | void fromLayer(String layerName, Action<? super OutputSelectionSpec> action); |
|
284 | void fromLayer(String layerName, Action<? super OutputSelectionSpec> action); | |
| 281 | } |
|
285 | } | |
| 282 | ``` |
|
286 | ``` | |
| 283 |
|
287 | |||
| 284 | Responsibility split: |
|
288 | Responsibility split: | |
| 285 |
|
289 | |||
| 286 | - `VariantArtifactsRegistry` owns the whole artifact model; |
|
290 | - `VariantArtifactsRegistry` owns the whole artifact model; | |
| 287 | - `OutgoingConfiguration` owns only the structural variant-local aggregate; |
|
291 | - `OutgoingConfiguration` owns only the structural variant-local aggregate; | |
| 288 | - `ArtifactAssemblyRules` owns the content declaration of one slot; |
|
292 | - `ArtifactAssemblyRules` owns the content declaration of one slot; | |
| 289 | - `ArtifactAssemblies` materializes `ArtifactAssembly` from |
|
293 | - `ArtifactAssemblies` materializes `ArtifactAssembly` from | |
| 290 | `ArtifactSlot -> ArtifactAssemblyRules`. |
|
294 | `ArtifactSlot -> ArtifactAssemblyRules`. | |
| 291 |
|
295 | |||
| 292 | This keeps `OutgoingConfiguration` focused on structure and avoids overloading it |
|
296 | This keeps `OutgoingConfiguration` focused on structure and avoids overloading it | |
| 293 | with slot-content APIs such as `rules(slot)`. |
|
297 | with slot-content APIs such as `rules(slot)`. | |
| 294 |
|
298 | |||
| 295 | ### DSL binding |
|
299 | ### DSL binding | |
| 296 |
|
300 | |||
| 297 | The DSL should be connected through the registry, not by making |
|
301 | The DSL should be connected through the registry, not by making | |
| 298 | `OutgoingConfiguration` responsible for content rules. |
|
302 | `OutgoingConfiguration` responsible for content rules. | |
| 299 |
|
303 | |||
| 300 | Conceptually: |
|
304 | Conceptually: | |
| 301 |
|
305 | |||
| 302 | ```java |
|
306 | ```java | |
| 303 | variantArtifacts.variant("browser", spec -> { |
|
307 | variantArtifacts.variant("browser", spec -> { | |
| 304 | spec.slot("runtime", assembly -> { |
|
308 | spec.slot("runtime", assembly -> { | |
| 305 | assembly.fromRole("production", out -> out.output("js")); |
|
309 | assembly.fromRole("production", out -> out.output("js")); | |
| 306 | }); |
|
310 | }); | |
| 307 | }); |
|
311 | }); | |
| 308 | ``` |
|
312 | ``` | |
| 309 |
|
313 | |||
| 310 | Operationally this means: |
|
314 | Operationally this means: | |
| 311 |
|
315 | |||
| 312 | 1. registry creates or returns `OutgoingConfiguration` for the variant; |
|
316 | 1. registry creates or returns `OutgoingConfiguration` for the variant; | |
| 313 | 2. slot declaration creates or returns `Slot` inside that outgoing configuration; |
|
317 | 2. slot declaration creates or returns `Slot` inside that outgoing configuration; | |
| 314 | 3. registry forms `ArtifactSlot(variant, slot)`; |
|
318 | 3. registry forms `ArtifactSlot(variant, slot)`; | |
| 315 | 4. registry resolves `slotRules(artifactSlot)`; |
|
319 | 4. registry resolves `slotRules(artifactSlot)`; | |
| 316 | 5. bound `ArtifactAssemblySpec` writes into those rules. |
|
320 | 5. bound `ArtifactAssemblySpec` writes into those rules. | |
| 317 |
|
321 | |||
| 318 | So the DSL writes: |
|
322 | So the DSL writes: | |
| 319 |
|
323 | |||
| 320 | - structure into `OutgoingConfiguration`; |
|
324 | - structure into `OutgoingConfiguration`; | |
| 321 | - slot content into registry-owned `ArtifactAssemblyRules`. |
|
325 | - slot content into registry-owned `ArtifactAssemblyRules`. | |
| 322 |
|
326 | |||
| 323 | This is the intended bridge point between the public DSL and the internal |
|
327 | This is the intended bridge point between the public DSL and the internal | |
| 324 | resolver/materialization model. |
|
328 | resolver/materialization model. | |
| 325 |
|
329 | |||
| 326 | --- |
|
330 | --- | |
| 327 |
|
331 | |||
| 328 | ## Live model and monotonic structure |
|
332 | ## Live model and monotonic structure | |
| 329 |
|
333 | |||
| 330 | `variantArtifacts` should be treated as a live configuration model during the |
|
334 | `variantArtifacts` should be treated as a live configuration model during the | |
| 331 | whole configuration phase. |
|
335 | whole configuration phase. | |
| 332 |
|
336 | |||
| 333 | This means: |
|
337 | This means: | |
| 334 |
|
338 | |||
| 335 | - slot inputs remain live; |
|
339 | - slot inputs remain live; | |
| 336 | - `from(...)`, `fromVariant(...)`, `fromRole(...)`, `fromLayer(...)` may keep |
|
340 | - `from(...)`, `fromVariant(...)`, `fromRole(...)`, `fromLayer(...)` may keep | |
| 337 | contributing inputs until task execution; |
|
341 | contributing inputs until task execution; | |
| 338 | - `ArtifactAssembly` may expose live `FileCollection`, `Provider`, and task |
|
342 | - `ArtifactAssembly` may expose live `FileCollection`, `Provider`, and task | |
| 339 | wiring; |
|
343 | wiring; | |
| 340 | - external task outputs remain outside the control of this model and must be |
|
344 | - external task outputs remain outside the control of this model and must be | |
| 341 | accepted as live inputs. |
|
345 | accepted as live inputs. | |
| 342 |
|
346 | |||
| 343 | The model should therefore avoid a mandatory freeze phase for slot content. |
|
347 | The model should therefore avoid a mandatory freeze phase for slot content. | |
| 344 |
|
348 | |||
| 345 | Instead, it should follow a monotonic rule: |
|
349 | Instead, it should follow a monotonic rule: | |
| 346 |
|
350 | |||
| 347 | - outgoing variant existence may grow; |
|
351 | - outgoing variant existence may grow; | |
| 348 | - slot existence may grow; |
|
352 | - slot existence may grow; | |
| 349 | - slot content may grow; |
|
353 | - slot content may grow; | |
| 350 | - publication-visible identity should not be retroactively redefined. |
|
354 | - publication-visible identity should not be retroactively redefined. | |
| 351 |
|
355 | |||
| 352 | In practice this means: |
|
356 | In practice this means: | |
| 353 |
|
357 | |||
| 354 | - slot names are stable once declared; |
|
358 | - slot names are stable once declared; | |
| 355 | - primary slot designation is structural; |
|
359 | - primary slot designation is structural; | |
| 356 | - slot input content remains live. |
|
360 | - slot input content remains live. | |
| 357 |
|
361 | |||
| 358 | This also means that the model does not need a dedicated freeze phase for slot |
|
362 | This also means that the model does not need a dedicated freeze phase for slot | |
| 359 | content merely because the root outgoing configuration was registered earlier. |
|
363 | content merely because the root outgoing configuration was registered earlier. | |
| 360 |
|
364 | |||
| 361 | Early registration of the root `Configuration` and live evolution of slot input |
|
365 | Early registration of the root `Configuration` and live evolution of slot input | |
| 362 | content are compatible concerns. |
|
366 | content are compatible concerns. | |
| 363 |
|
367 | |||
| 364 | --- |
|
368 | --- | |
| 365 |
|
369 | |||
| 366 | ## DSL principles |
|
370 | ## DSL principles | |
| 367 |
|
371 | |||
| 368 | The DSL should remain declarative and symbolic. |
|
372 | The DSL should remain declarative and symbolic. | |
| 369 |
|
373 | |||
| 370 | It should describe: |
|
374 | It should describe: | |
| 371 |
|
375 | |||
| 372 | - which variant is outgoing; |
|
376 | - which variant is outgoing; | |
| 373 | - which slots exist; |
|
377 | - which slots exist; | |
| 374 | - which slot is primary; |
|
378 | - which slot is primary; | |
| 375 | - which selectors contribute inputs to each slot. |
|
379 | - which selectors contribute inputs to each slot. | |
| 376 |
|
380 | |||
| 377 | It should not directly expose: |
|
381 | It should not directly expose: | |
| 378 |
|
382 | |||
| 379 | - `GenericSourceSet`; |
|
383 | - `GenericSourceSet`; | |
| 380 | - `FileCollection`; |
|
384 | - `FileCollection`; | |
| 381 | - concrete resolved files from `variantSources`; |
|
385 | - concrete resolved files from `variantSources`; | |
| 382 | - internal resolver state. |
|
386 | - internal resolver state. | |
| 383 |
|
387 | |||
| 384 | ### DSL shape |
|
388 | ### DSL shape | |
| 385 |
|
389 | |||
| 386 | Conceptually: |
|
390 | Conceptually: | |
| 387 |
|
391 | |||
| 388 | ```groovy |
|
392 | ```groovy | |
| 389 | variantArtifacts { |
|
393 | variantArtifacts { | |
| 390 | variant("browser") { |
|
394 | variant("browser") { | |
| 391 | primarySlot("runtime") { |
|
395 | primarySlot("runtime") { | |
| 392 | fromRole("production") { |
|
396 | fromRole("production") { | |
| 393 | output("js") |
|
397 | output("js") | |
| 394 | output("resources") |
|
398 | output("resources") | |
| 395 | } |
|
399 | } | |
| 396 | } |
|
400 | } | |
| 397 |
|
401 | |||
| 398 | slot("types") { |
|
402 | slot("types") { | |
| 399 | fromVariant { |
|
403 | fromVariant { | |
| 400 | output("dts") |
|
404 | output("dts") | |
| 401 | } |
|
405 | } | |
| 402 | } |
|
406 | } | |
| 403 |
|
407 | |||
| 404 | slot("sources") { |
|
408 | slot("sources") { | |
| 405 | fromLayer("main") { |
|
409 | fromLayer("main") { | |
| 406 | output("sources") |
|
410 | output("sources") | |
| 407 | } |
|
411 | } | |
| 408 | } |
|
412 | } | |
| 409 |
|
413 | |||
| 410 | slot("bundleMetadata") { |
|
414 | slot("bundleMetadata") { | |
| 411 | from(someTask) |
|
415 | from(someTask) | |
| 412 | from(layout.buildDirectory.file("generated/meta.json")) |
|
416 | from(layout.buildDirectory.file("generated/meta.json")) | |
| 413 | } |
|
417 | } | |
| 414 | } |
|
418 | } | |
| 415 | } |
|
419 | } | |
| 416 | ``` |
|
420 | ``` | |
| 417 |
|
421 | |||
| 418 | ### Meaning of contribution forms |
|
422 | ### Meaning of contribution forms | |
| 419 |
|
423 | |||
| 420 | - `from(Object)` adds a direct input independent from `variantSources`; |
|
424 | - `from(Object)` adds a direct input independent from `variantSources`; | |
| 421 | - `fromVariant { output(...) }` selects named outputs from all compile units of |
|
425 | - `fromVariant { output(...) }` selects named outputs from all compile units of | |
| 422 | the current variant; |
|
426 | the current variant; | |
| 423 | - `fromRole(role) { output(...) }` selects named outputs from compile units that |
|
427 | - `fromRole(role) { output(...) }` selects named outputs from compile units that | |
| 424 | belong to the given role projection; |
|
428 | belong to the given role projection; | |
| 425 | - `fromLayer(layer) { output(...) }` selects named outputs from the compile unit |
|
429 | - `fromLayer(layer) { output(...) }` selects named outputs from the compile unit | |
| 426 | of the current variant and the given layer, if such unit exists. |
|
430 | of the current variant and the given layer, if such unit exists. | |
| 427 |
|
431 | |||
| 428 | The DSL stores declarations, not resolved file collections. |
|
432 | The DSL stores declarations, not resolved file collections. | |
| 429 |
|
433 | |||
| 430 | --- |
|
434 | --- | |
| 431 |
|
435 | |||
| 432 | ## Contribution model |
|
436 | ## Contribution model | |
| 433 |
|
437 | |||
| 434 | Internally the DSL should compile to slot contributions. |
|
438 | Internally the DSL should compile to slot contributions. | |
| 435 |
|
439 | |||
| 436 | Conceptually: |
|
440 | Conceptually: | |
| 437 |
|
441 | |||
| 438 | - `DirectContribution` |
|
442 | - `DirectContribution` | |
| 439 | - `VariantOutputContribution` |
|
443 | - `VariantOutputContribution` | |
| 440 | - `RoleOutputContribution` |
|
444 | - `RoleOutputContribution` | |
| 441 | - `LayerOutputContribution` |
|
445 | - `LayerOutputContribution` | |
| 442 |
|
446 | |||
| 443 | These contributions should remain symbolic for as long as possible. |
|
447 | These contributions should remain symbolic for as long as possible. | |
| 444 |
|
448 | |||
| 445 | They should not resolve source sets or files at declaration time. |
|
449 | They should not resolve source sets or files at declaration time. | |
| 446 |
|
450 | |||
| 447 | Each contribution is expected to provide: |
|
451 | Each contribution is expected to provide: | |
| 448 |
|
452 | |||
| 449 | - its selection scope; |
|
453 | - its selection scope; | |
| 450 | - the requested output names; |
|
454 | - the requested output names; | |
| 451 | - enough symbolic identity for later validation and resolver policies. |
|
455 | - enough symbolic identity for later validation and resolver policies. | |
| 452 |
|
456 | |||
| 453 | --- |
|
457 | --- | |
| 454 |
|
458 | |||
| 455 | ## Resolver bridge between `variantSources` and `variantArtifacts` |
|
459 | ## Resolver bridge between `variantSources` and `variantArtifacts` | |
| 456 |
|
460 | |||
| 457 | This is the central integration point. |
|
461 | This is the central integration point. | |
| 458 |
|
462 | |||
| 459 | `variantArtifacts` should not access mutable internals of `variantSources`. |
|
463 | `variantArtifacts` should not access mutable internals of `variantSources`. | |
| 460 |
|
464 | |||
| 461 | Instead, it should resolve slot inputs through the public finalized |
|
465 | Instead, it should resolve slot inputs through the public finalized | |
| 462 | `VariantSourcesContext`. |
|
466 | `VariantSourcesContext`. | |
| 463 |
|
467 | |||
| 464 | ### Bridge responsibilities |
|
468 | ### Bridge responsibilities | |
| 465 |
|
469 | |||
| 466 | The bridge: |
|
470 | The bridge: | |
| 467 |
|
471 | |||
| 468 | - takes slot contribution declarations; |
|
472 | - takes slot contribution declarations; | |
| 469 | - expands them against finalized variant topology; |
|
473 | - expands them against finalized variant topology; | |
| 470 | - maps logical selectors to compile units and role projections; |
|
474 | - maps logical selectors to compile units and role projections; | |
| 471 | - obtains source sets lazily through `VariantSourcesContext`; |
|
475 | - obtains source sets lazily through `VariantSourcesContext`; | |
| 472 | - resolves named outputs from those source sets; |
|
476 | - resolves named outputs from those source sets; | |
| 473 | - builds the live input model for an `ArtifactAssembly`. |
|
477 | - builds the live input model for an `ArtifactAssembly`. | |
| 474 |
|
478 | |||
| 475 | ### Bridge input |
|
479 | ### Bridge input | |
| 476 |
|
480 | |||
| 477 | - current outgoing variant identity; |
|
481 | - current outgoing variant identity; | |
| 478 | - slot contribution declarations; |
|
482 | - slot contribution declarations; | |
| 479 | - `VariantSourcesContext`. |
|
483 | - `VariantSourcesContext`. | |
| 480 |
|
484 | |||
| 481 | ### Bridge output |
|
485 | ### Bridge output | |
| 482 |
|
486 | |||
| 483 | - a live collection of logical slot inputs; |
|
487 | - a live collection of logical slot inputs; | |
| 484 | - later adapted to `FileCollection` or other assembly-facing input models. |
|
488 | - later adapted to `FileCollection` or other assembly-facing input models. | |
| 485 |
|
489 | |||
| 486 | ### Resolution semantics |
|
490 | ### Resolution semantics | |
| 487 |
|
491 | |||
| 488 | For one outgoing variant: |
|
492 | For one outgoing variant: | |
| 489 |
|
493 | |||
| 490 | - `fromVariant { output(x) }` |
|
494 | - `fromVariant { output(x) }` | |
| 491 | - expands to all `CompileUnit` of that variant; |
|
495 | - expands to all `CompileUnit` of that variant; | |
| 492 | - `fromRole(role) { output(x) }` |
|
496 | - `fromRole(role) { output(x) }` | |
| 493 | - expands to `RoleProjection(variant, role)` and then to its compile units; |
|
497 | - expands to `RoleProjection(variant, role)` and then to its compile units; | |
| 494 | - `fromLayer(layer) { output(x) }` |
|
498 | - `fromLayer(layer) { output(x) }` | |
| 495 | - expands to one compile unit `(variant, layer)` when it exists; |
|
499 | - expands to one compile unit `(variant, layer)` when it exists; | |
| 496 | - `from(Object)` |
|
500 | - `from(Object)` | |
| 497 | - bypasses `variantSources` completely. |
|
501 | - bypasses `variantSources` completely. | |
| 498 |
|
502 | |||
| 499 | After compile units are known, the bridge asks |
|
503 | After compile units are known, the bridge asks | |
| 500 | `ctx.getSourceSets().getSourceSet(unit)` for each selected unit and resolves the |
|
504 | `ctx.getSourceSets().getSourceSet(unit)` for each selected unit and resolves the | |
| 501 | requested named output. |
|
505 | requested named output. | |
| 502 |
|
506 | |||
| 503 | This keeps `variantArtifacts` independent from source-set naming internals and |
|
507 | This keeps `variantArtifacts` independent from source-set naming internals and | |
| 504 | other materialization details. |
|
508 | other materialization details. | |
| 505 |
|
509 | |||
| 506 | --- |
|
510 | --- | |
| 507 |
|
511 | |||
| 508 | ## Validation |
|
512 | ## Validation | |
| 509 |
|
513 | |||
| 510 | Validation should be structural and symbolic. |
|
514 | Validation should be structural and symbolic. | |
| 511 |
|
515 | |||
| 512 | It should validate: |
|
516 | It should validate: | |
| 513 |
|
517 | |||
| 514 | - outgoing variant refers to an existing `Variant`; |
|
518 | - outgoing variant refers to an existing `Variant`; | |
| 515 | - referenced `Role` exists in that variant projection space; |
|
519 | - referenced `Role` exists in that variant projection space; | |
| 516 | - referenced `Layer` exists in that variant compile-unit space; |
|
520 | - referenced `Layer` exists in that variant compile-unit space; | |
| 517 | - primary slot is defined when needed; |
|
521 | - primary slot is defined when needed; | |
| 518 | - primary slot refers to a slot declared in the same outgoing configuration. |
|
522 | - primary slot refers to a slot declared in the same outgoing configuration. | |
| 519 |
|
523 | |||
| 520 | Validation should not require eager materialization of source sets or eager |
|
524 | Validation should not require eager materialization of source sets or eager | |
| 521 | resolution of files. |
|
525 | resolution of files. | |
| 522 |
|
526 | |||
| 523 | --- |
|
527 | --- | |
| 524 |
|
528 | |||
| 525 | ## Deduplication and policy extension points |
|
529 | ## Deduplication and policy extension points | |
| 526 |
|
530 | |||
| 527 | Deduplication is important, but it should not be baked into the DSL itself. |
|
531 | Deduplication is important, but it should not be baked into the DSL itself. | |
| 528 |
|
532 | |||
| 529 | The correct place for it is the resolver bridge, after symbolic contributions |
|
533 | The correct place for it is the resolver bridge, after symbolic contributions | |
| 530 | have been expanded to logical inputs but before they are finally adapted to |
|
534 | have been expanded to logical inputs but before they are finally adapted to | |
| 531 | assembly-facing file collections. |
|
535 | assembly-facing file collections. | |
| 532 |
|
536 | |||
| 533 | ### Why not in the DSL |
|
537 | ### Why not in the DSL | |
| 534 |
|
538 | |||
| 535 | At declaration time it is still unknown whether selectors overlap: |
|
539 | At declaration time it is still unknown whether selectors overlap: | |
| 536 |
|
540 | |||
| 537 | - `fromVariant` |
|
541 | - `fromVariant` | |
| 538 | - `fromRole` |
|
542 | - `fromRole` | |
| 539 | - `fromLayer` |
|
543 | - `fromLayer` | |
| 540 |
|
544 | |||
| 541 | may all describe the same logical source output. |
|
545 | may all describe the same logical source output. | |
| 542 |
|
546 | |||
| 543 | ### Why not rely only on `FileCollection` |
|
547 | ### Why not rely only on `FileCollection` | |
| 544 |
|
548 | |||
| 545 | `FileCollection` may still provide useful physical deduplication, but it is too |
|
549 | `FileCollection` may still provide useful physical deduplication, but it is too | |
| 546 | late and too file-oriented to serve as the only semantic mechanism. |
|
550 | late and too file-oriented to serve as the only semantic mechanism. | |
| 547 |
|
551 | |||
| 548 | The artifact model should first deduplicate logical inputs, then let Gradle |
|
552 | The artifact model should first deduplicate logical inputs, then let Gradle | |
| 549 | perform any additional physical deduplication. |
|
553 | perform any additional physical deduplication. | |
| 550 |
|
554 | |||
| 551 | ### Default expectation |
|
555 | ### Default expectation | |
| 552 |
|
556 | |||
| 553 | The default resolver should support: |
|
557 | The default resolver should support: | |
| 554 |
|
558 | |||
| 555 | - deduplication of topology-aware inputs by logical identity; |
|
559 | - deduplication of topology-aware inputs by logical identity; | |
| 556 | - no implicit deduplication of direct `from(Object)` inputs. |
|
560 | - no implicit deduplication of direct `from(Object)` inputs. | |
| 557 |
|
561 | |||
| 558 | Logical identity should be based on domain meaning, for example: |
|
562 | Logical identity should be based on domain meaning, for example: | |
| 559 |
|
563 | |||
| 560 | - `(CompileUnit, outputName)` |
|
564 | - `(CompileUnit, outputName)` | |
| 561 |
|
565 | |||
| 562 | and not on projected source-set names. |
|
566 | and not on projected source-set names. | |
| 563 |
|
567 | |||
| 564 | This is important because source-set naming policy belongs to `variantSources` |
|
568 | This is important because source-set naming policy belongs to `variantSources` | |
| 565 | and must not silently redefine artifact semantics. |
|
569 | and must not silently redefine artifact semantics. | |
| 566 |
|
570 | |||
| 567 | ### Extension points |
|
571 | ### Extension points | |
| 568 |
|
572 | |||
| 569 | The model should provide explicit internal extension points for: |
|
573 | The model should provide explicit internal extension points for: | |
| 570 |
|
574 | |||
| 571 | - deduplication policy; |
|
575 | - deduplication policy; | |
| 572 | - logical input identity; |
|
576 | - logical input identity; | |
| 573 | - adaptation of resolved logical inputs to assembly-facing objects. |
|
577 | - adaptation of resolved logical inputs to assembly-facing objects. | |
| 574 |
|
578 | |||
| 575 | Conceptually: |
|
579 | Conceptually: | |
| 576 |
|
580 | |||
| 577 | ```java |
|
581 | ```java | |
| 578 | interface SlotInputDedupPolicy { ... } |
|
582 | interface SlotInputDedupPolicy { ... } | |
| 579 | interface LogicalSlotInputIdentity { ... } |
|
583 | interface LogicalSlotInputIdentity { ... } | |
| 580 | interface SlotInputAdapter { ... } |
|
584 | interface SlotInputAdapter { ... } | |
| 581 | ``` |
|
585 | ``` | |
| 582 |
|
586 | |||
| 583 | The default implementation may remain simple, but these seams should exist from |
|
587 | The default implementation may remain simple, but these seams should exist from | |
| 584 | the start. |
|
588 | the start. | |
| 585 |
|
589 | |||
| 586 | --- |
|
590 | --- | |
| 587 |
|
591 | |||
| 588 | ## Publication hooks |
|
592 | ## Publication hooks | |
| 589 |
|
593 | |||
| 590 | Publication hooks remain useful, but they should observe the live structural |
|
594 | Publication hooks remain useful, but they should observe the live structural | |
| 591 | model rather than define it. |
|
595 | model rather than define it. | |
| 592 |
|
596 | |||
| 593 | Examples: |
|
597 | Examples: | |
| 594 |
|
598 | |||
| 595 |
- `whenOutgoing |
|
599 | - `whenOutgoingConfiguration(...)` | |
| 596 | - `whenOutgoingSlot(...)` |
|
600 | - `whenOutgoingSlot(...)` | |
| 597 |
|
601 | |||
| 598 | These hooks are adapter-facing customization points over already declared |
|
602 | These hooks are adapter-facing customization points over already declared | |
| 599 | outgoing structure: |
|
603 | outgoing structure: | |
| 600 |
|
604 | |||
| 601 | - root configuration attributes; |
|
605 | - root configuration attributes; | |
| 602 | - slot artifact attributes; |
|
606 | - slot artifact attributes; | |
| 603 | - assembly task tweaks. |
|
607 | - assembly task tweaks. | |
| 604 |
|
608 | |||
| 605 | The recommended way to connect publication-facing `Spec` objects to the |
|
609 | The recommended way to connect publication-facing `Spec` objects to the | |
| 606 | structural model is by backlink, not by moving slot rules into publication |
|
610 | structural model is by backlink, not by moving slot rules into publication | |
| 607 | types. |
|
611 | types. | |
| 608 |
|
612 | |||
| 609 | Conceptually: |
|
613 | Conceptually: | |
| 610 |
|
614 | |||
| 611 | ```java |
|
615 | ```java | |
| 612 | interface OutgoingConfigurationSpec { |
|
616 | interface OutgoingConfigurationSpec { | |
| 613 | OutgoingConfiguration getOutgoingArtifacts(); |
|
617 | OutgoingConfiguration getOutgoingArtifacts(); | |
| 614 | Variant getVariant(); |
|
618 | Variant getVariant(); | |
| 615 | Configuration getConfiguration(); |
|
619 | Configuration getConfiguration(); | |
| 616 | } |
|
620 | } | |
| 617 |
|
621 | |||
| 618 | interface OutgoingArtifactSlotSpec { |
|
622 | interface OutgoingArtifactSlotSpec { | |
| 619 | ArtifactSlot getArtifactSlot(); |
|
623 | ArtifactSlot getArtifactSlot(); | |
| 620 | ArtifactAssembly getAssembly(); |
|
624 | ArtifactAssembly getAssembly(); | |
| 621 | boolean isPrimary(); |
|
625 | boolean isPrimary(); | |
| 622 | } |
|
626 | } | |
| 623 | ``` |
|
627 | ``` | |
| 624 |
|
628 | |||
| 625 | In this arrangement: |
|
629 | In this arrangement: | |
| 626 |
|
630 | |||
| 627 | - `OutgoingConfigurationSpec` remains a publication-facing facade; |
|
631 | - `OutgoingConfigurationSpec` remains a publication-facing facade; | |
| 628 | - `OutgoingConfigurationSpec` may expose the structural aggregate when an |
|
632 | - `OutgoingConfigurationSpec` may expose the structural aggregate when an | |
| 629 | adapter needs it; |
|
633 | adapter needs it; | |
| 630 | - slot rules still belong to `VariantArtifactsRegistry`; |
|
634 | - slot rules still belong to `VariantArtifactsRegistry`; | |
| 631 | - publication specs do not become owners of declaration or resolver state. |
|
635 | - publication specs do not become owners of declaration or resolver state. | |
| 632 |
|
636 | |||
| 633 | They should not become the primary structural API for the artifact model. |
|
637 | They should not become the primary structural API for the artifact model. | |
| 634 |
|
638 | |||
| 635 | This is why a separate phase-oriented `OutgoingPublicationsContext` is not |
|
639 | This is why a separate phase-oriented `OutgoingPublicationsContext` is not | |
| 636 | required. |
|
640 | required. | |
| 637 |
|
641 | |||
| 638 | The live `OutgoingConfiguration` aggregate is sufficient. |
|
642 | The live `OutgoingConfiguration` aggregate is sufficient. | |
| 639 |
|
643 | |||
| 640 | --- |
|
644 | --- | |
| 641 |
|
645 | |||
| 642 | ## Design principles |
|
646 | ## Design principles | |
| 643 |
|
647 | |||
| 644 | ### 1. Keep topology ownership in `variants` |
|
648 | ### 1. Keep topology ownership in `variants` | |
| 645 |
|
649 | |||
| 646 | `variantArtifacts` selects from the topology model. It does not own it. |
|
650 | `variantArtifacts` selects from the topology model. It does not own it. | |
| 647 |
|
651 | |||
| 648 | ### 2. Keep source ownership in `variantSources` |
|
652 | ### 2. Keep source ownership in `variantSources` | |
| 649 |
|
653 | |||
| 650 | `variantArtifacts` consumes source materialization through a resolver bridge. It |
|
654 | `variantArtifacts` consumes source materialization through a resolver bridge. It | |
| 651 | does not own source-set semantics. |
|
655 | does not own source-set semantics. | |
| 652 |
|
656 | |||
| 653 | ### 3. Keep the DSL symbolic |
|
657 | ### 3. Keep the DSL symbolic | |
| 654 |
|
658 | |||
| 655 | The DSL declares intent and selection rules, not materialized files. |
|
659 | The DSL declares intent and selection rules, not materialized files. | |
| 656 |
|
660 | |||
| 657 | ### 4. Keep slot content live |
|
661 | ### 4. Keep slot content live | |
| 658 |
|
662 | |||
| 659 | Do not introduce an artificial finalize phase for slot content unless a real |
|
663 | Do not introduce an artificial finalize phase for slot content unless a real | |
| 660 | semantic need appears. |
|
664 | semantic need appears. | |
| 661 |
|
665 | |||
| 662 | ### 5. Fix only structural identity |
|
666 | ### 5. Fix only structural identity | |
| 663 |
|
667 | |||
| 664 | Slot name, primary designation, and outgoing shape are structural. Slot inputs |
|
668 | Slot name, primary designation, and outgoing shape are structural. Slot inputs | |
| 665 | remain live. |
|
669 | remain live. | |
| 666 |
|
670 | |||
| 667 | ### 6. Resolve through dedicated bridges |
|
671 | ### 6. Resolve through dedicated bridges | |
| 668 |
|
672 | |||
| 669 | Cross-model integration belongs in a resolver service, not in DSL classes. |
|
673 | Cross-model integration belongs in a resolver service, not in DSL classes. | |
| 670 |
|
674 | |||
| 671 | ### 7. Add policy seams early |
|
675 | ### 7. Add policy seams early | |
| 672 |
|
676 | |||
| 673 | Deduplication and similar concerns should have extension points from the start, |
|
677 | Deduplication and similar concerns should have extension points from the start, | |
| 674 | even if the initial implementation is conservative. |
|
678 | even if the initial implementation is conservative. | |
| 675 |
|
679 | |||
| 676 | --- |
|
680 | --- | |
| 677 |
|
681 | |||
| 678 | ## Summary |
|
682 | ## Summary | |
| 679 |
|
683 | |||
| 680 | `variantArtifacts` should be modeled as a live outgoing-contract layer over |
|
684 | `variantArtifacts` should be modeled as a live outgoing-contract layer over | |
| 681 | `variants`, with source input resolution delegated to a dedicated bridge over |
|
685 | `variants`, with source input resolution delegated to a dedicated bridge over | |
| 682 | `variantSources`. |
|
686 | `variantSources`. | |
| 683 |
|
687 | |||
| 684 | The resulting shape is: |
|
688 | The resulting shape is: | |
| 685 |
|
689 | |||
| 686 | - `variants` owns topology; |
|
690 | - `variants` owns topology; | |
| 687 | - `variantSources` owns source materialization; |
|
691 | - `variantSources` owns source materialization; | |
| 688 | - `variantArtifacts` owns outgoing contract structure; |
|
692 | - `variantArtifacts` owns outgoing contract structure; | |
| 689 | - a resolver bridge connects symbolic slot declarations to live source-derived |
|
693 | - a resolver bridge connects symbolic slot declarations to live source-derived | |
| 690 | inputs; |
|
694 | inputs; | |
| 691 | - deduplication and similar concerns are policies of that bridge, not of the |
|
695 | - deduplication and similar concerns are policies of that bridge, not of the | |
| 692 | DSL itself; |
|
696 | DSL itself; | |
| 693 | - slot content stays live during configuration; |
|
697 | - slot content stays live during configuration; | |
| 694 | - only publication-visible structure is treated as stable identity. |
|
698 | - only publication-visible structure is treated as stable identity. | |
| @@ -1,872 +1,877 | |||||
| 1 | # Variants and Variant Sources |
|
1 | # Variants and Variant Sources | |
| 2 |
|
2 | |||
|
|
3 | > Design note. The current user-facing DSL and local publication workflow are | |||
|
|
4 | > documented in [README.md](README.md). Some snippets below are conceptual and | |||
|
|
5 | > describe model direction rather than exact public API. | |||
|
|
6 | ||||
| 3 | ## Overview |
|
7 | ## Overview | |
| 4 |
|
8 | |||
| 5 | This document describes a two-layer model for build variants: |
|
9 | This document describes a two-layer model for build variants: | |
| 6 |
|
10 | |||
| 7 | - `variants` defines the **core domain model** |
|
11 | - `variants` defines the **core domain model** | |
| 8 | - `variantSources` defines **source materialization semantics** for that model |
|
12 | - `variantSources` defines **source materialization semantics** for that model | |
| 9 |
|
13 | |||
| 10 | The main goal is to keep the core model small, explicit, and stable, while allowing source-related behavior to remain flexible and adapter-friendly. |
|
14 | The main goal is to keep the core model small, explicit, and stable, while allowing source-related behavior to remain flexible and adapter-friendly. | |
| 11 |
|
15 | |||
| 12 | The model is intentionally split into: |
|
16 | The model is intentionally split into: | |
| 13 |
|
17 | |||
| 14 | 1. a **closed, finalized domain model** |
|
18 | 1. a **closed, finalized domain model** | |
| 15 | 2. an **open, runtime-oriented source materialization model** |
|
19 | 2. an **open, runtime-oriented source materialization model** | |
| 16 |
|
20 | |||
| 17 | This separation is important because compilation, source aggregation, publication, and adapter-specific behavior do not belong to the same abstraction layer. |
|
21 | This separation is important because compilation, source aggregation, publication, and adapter-specific behavior do not belong to the same abstraction layer. | |
| 18 |
|
22 | |||
| 19 | --- |
|
23 | --- | |
| 20 |
|
24 | |||
| 21 | ## Core idea |
|
25 | ## Core idea | |
| 22 |
|
26 | |||
| 23 | The `variants` model is based on three independent domains: |
|
27 | The `variants` model is based on three independent domains: | |
| 24 |
|
28 | |||
| 25 | - `Layer` |
|
29 | - `Layer` | |
| 26 | - `Role` |
|
30 | - `Role` | |
| 27 | - `Variant` |
|
31 | - `Variant` | |
| 28 |
|
32 | |||
| 29 | A finalized `VariantsView` contains the normalized relation: |
|
33 | A finalized `VariantsView` contains the normalized relation: | |
| 30 |
|
34 | |||
| 31 | - `(variant, role, layer)` |
|
35 | - `(variant, role, layer)` | |
| 32 |
|
36 | |||
| 33 | This relation is the source of truth. |
|
37 | This relation is the source of truth. | |
| 34 |
|
38 | |||
| 35 | Everything else is derived from it. |
|
39 | Everything else is derived from it. | |
| 36 |
|
40 | |||
| 37 | --- |
|
41 | --- | |
| 38 |
|
42 | |||
| 39 | ## `variants`: the core domain model |
|
43 | ## `variants`: the core domain model | |
| 40 |
|
44 | |||
| 41 | ### Purpose |
|
45 | ### Purpose | |
| 42 |
|
46 | |||
| 43 | `variants` describes: |
|
47 | `variants` describes: | |
| 44 |
|
48 | |||
| 45 | - what layers exist |
|
49 | - what layers exist | |
| 46 | - what roles exist |
|
50 | - what roles exist | |
| 47 | - what variants exist |
|
51 | - what variants exist | |
| 48 | - which `(variant, role, layer)` combinations are valid |
|
52 | - which `(variant, role, layer)` combinations are valid | |
| 49 |
|
53 | |||
| 50 | It does **not** describe: |
|
54 | It does **not** describe: | |
| 51 |
|
55 | |||
| 52 | - source directories |
|
56 | - source directories | |
| 53 | - source roots |
|
57 | - source roots | |
| 54 | - source set materialization |
|
58 | - source set materialization | |
| 55 | - compilation tasks |
|
59 | - compilation tasks | |
| 56 | - publication mechanics |
|
60 | - publication mechanics | |
| 57 | - source set inheritance |
|
61 | - source set inheritance | |
| 58 | - layer merge behavior for a concrete toolchain |
|
62 | - layer merge behavior for a concrete toolchain | |
| 59 |
|
63 | |||
| 60 | Those concerns are intentionally outside the core model. |
|
64 | Those concerns are intentionally outside the core model. | |
| 61 |
|
65 | |||
| 62 | --- |
|
66 | --- | |
| 63 |
|
67 | |||
| 64 | ## Core DSL example |
|
68 | ## Core DSL example | |
| 65 |
|
69 | |||
| 66 | ```groovy |
|
70 | ```groovy | |
| 67 | variants { |
|
71 | variants { | |
| 68 | layers { |
|
72 | layers { | |
| 69 | main() |
|
73 | main() | |
| 70 | test() |
|
74 | test() | |
| 71 | generated() |
|
75 | generated() | |
| 72 | rjs() |
|
76 | rjs() | |
| 73 | cjs() |
|
77 | cjs() | |
| 74 | } |
|
78 | } | |
| 75 |
|
79 | |||
| 76 | roles { |
|
80 | roles { | |
| 77 | production() |
|
81 | production() | |
| 78 | test() |
|
82 | test() | |
| 79 | tool() |
|
83 | tool() | |
| 80 | } |
|
84 | } | |
| 81 |
|
85 | |||
| 82 | variant("browser") { |
|
86 | variant("browser") { | |
| 83 | role("production") { |
|
87 | role("production") { | |
| 84 | layers("main", "generated", "rjs") |
|
88 | layers("main", "generated", "rjs") | |
| 85 | } |
|
89 | } | |
| 86 | role("test") { |
|
90 | role("test") { | |
| 87 | layers("main", "test", "generated", "rjs") |
|
91 | layers("main", "test", "generated", "rjs") | |
| 88 | } |
|
92 | } | |
| 89 | } |
|
93 | } | |
| 90 |
|
94 | |||
| 91 | variant("nodejs") { |
|
95 | variant("nodejs") { | |
| 92 | role("production") { |
|
96 | role("production") { | |
| 93 | layers("main", "generated", "cjs") |
|
97 | layers("main", "generated", "cjs") | |
| 94 | } |
|
98 | } | |
| 95 | role("test") { |
|
99 | role("test") { | |
| 96 | layers("main", "test", "generated", "cjs") |
|
100 | layers("main", "test", "generated", "cjs") | |
| 97 | } |
|
101 | } | |
| 98 | role("tool") { |
|
102 | role("tool") { | |
| 99 | layers("main", "generated", "cjs") |
|
103 | layers("main", "generated", "cjs") | |
| 100 | } |
|
104 | } | |
| 101 | } |
|
105 | } | |
| 102 | } |
|
106 | } | |
| 103 | ``` |
|
107 | ``` | |
| 104 |
|
108 | |||
| 105 | ### Interpretation |
|
109 | ### Interpretation | |
| 106 |
|
110 | |||
| 107 | This example means: |
|
111 | This example means: | |
| 108 |
|
112 | |||
| 109 | * `browser` production uses `main`, `generated`, `rjs` |
|
113 | * `browser` production uses `main`, `generated`, `rjs` | |
| 110 | * `browser` test uses `main`, `test`, `generated`, `rjs` |
|
114 | * `browser` test uses `main`, `test`, `generated`, `rjs` | |
| 111 | * `nodejs` production uses `main`, `generated`, `cjs` |
|
115 | * `nodejs` production uses `main`, `generated`, `cjs` | |
| 112 | * `nodejs` test uses `main`, `test`, `generated`, `cjs` |
|
116 | * `nodejs` test uses `main`, `test`, `generated`, `cjs` | |
| 113 | * `nodejs` tool uses `main`, `generated`, `cjs` |
|
117 | * `nodejs` tool uses `main`, `generated`, `cjs` | |
| 114 |
|
118 | |||
| 115 | The model is purely declarative. |
|
119 | The model is purely declarative. | |
| 116 |
|
120 | |||
| 117 | --- |
|
121 | --- | |
| 118 |
|
122 | |||
| 119 | ## Identity and references |
|
123 | ## Identity and references | |
| 120 |
|
124 | |||
| 121 | `Layer`, `Role`, and `Variant` are identity objects. |
|
125 | `Layer`, `Role`, and `Variant` are identity objects. | |
| 122 |
|
126 | |||
| 123 | They exist as declared domain values. |
|
127 | They exist as declared domain values. | |
| 124 |
|
128 | |||
| 125 | References between model elements are symbolic: |
|
129 | References between model elements are symbolic: | |
| 126 |
|
130 | |||
| 127 | * layers are referenced by layer name |
|
131 | * layers are referenced by layer name | |
| 128 | * roles are referenced by role name |
|
132 | * roles are referenced by role name | |
| 129 | * variants are referenced by variant name |
|
133 | * variants are referenced by variant name | |
| 130 |
|
134 | |||
| 131 | This is intentional. |
|
135 | This is intentional. | |
| 132 |
|
136 | |||
| 133 | The core model is declarative, not navigation-oriented. |
|
137 | The core model is declarative, not navigation-oriented. | |
| 134 |
|
138 | |||
| 135 | It is acceptable for aggregates to hold symbolic references to foreign domain values, as long as identity is clearly defined and validated later. |
|
139 | It is acceptable for aggregates to hold symbolic references to foreign domain values, as long as identity is clearly defined and validated later. | |
| 136 |
|
140 | |||
| 137 | --- |
|
141 | --- | |
| 138 |
|
142 | |||
| 139 | ## Finalization |
|
143 | ## Finalization | |
| 140 |
|
144 | |||
| 141 | The `variants` model is finalized once. |
|
145 | The `variants` model is finalized once. | |
| 142 |
|
146 | |||
| 143 | Finalization is an internal lifecycle transition. It is typically triggered privately, for example from `afterEvaluate`, but that mechanism is not part of the public API contract. |
|
147 | Finalization is an internal lifecycle transition. It is typically triggered privately, for example from `afterEvaluate`, but that mechanism is not part of the public API contract. | |
| 144 |
|
148 | |||
| 145 | The public contract is: |
|
149 | The public contract is: | |
| 146 |
|
150 | |||
| 147 | * `variants.whenFinalized(...)` |
|
151 | * `variants.whenFinalized(...)` | |
| 148 |
|
152 | |||
| 149 | This callback is **replayable**: |
|
153 | This callback is **replayable**: | |
| 150 |
|
154 | |||
| 151 | * if called before finalization, the action is queued |
|
155 | * if called before finalization, the action is queued | |
| 152 | * if called after finalization, the action is invoked immediately |
|
156 | * if called after finalization, the action is invoked immediately | |
| 153 |
|
157 | |||
| 154 | The callback receives a finalized, read-only view of the model. |
|
158 | The callback receives a finalized, read-only view of the model. | |
| 155 |
|
159 | |||
| 156 | Example: |
|
160 | Example: | |
| 157 |
|
161 | |||
| 158 | ```java |
|
162 | ```java | |
| 159 | variants.whenFinalized(view -> { |
|
163 | variants.whenFinalized(view -> { | |
| 160 | // use finalized VariantsView here |
|
164 | // use finalized VariantsView here | |
| 161 | }); |
|
165 | }); | |
| 162 | ``` |
|
166 | ``` | |
| 163 |
|
167 | |||
| 164 | --- |
|
168 | --- | |
| 165 |
|
169 | |||
| 166 | ## `VariantsView` |
|
170 | ## `VariantsView` | |
| 167 |
|
171 | |||
| 168 | `VariantsView` is the finalized representation of the core model. |
|
172 | `VariantsView` is the finalized representation of the core model. | |
| 169 |
|
173 | |||
| 170 | It contains: |
|
174 | It contains: | |
| 171 |
|
175 | |||
| 172 | * all declared `Layer` |
|
176 | * all declared `Layer` | |
| 173 | * all declared `Role` |
|
177 | * all declared `Role` | |
| 174 | * all declared `Variant` |
|
178 | * all declared `Variant` | |
| 175 | * all normalized entries `(variant, role, layer)` |
|
179 | * all normalized entries `(variant, role, layer)` | |
| 176 |
|
180 | |||
| 177 | Conceptually: |
|
181 | Conceptually: | |
| 178 |
|
182 | |||
| 179 | ```java |
|
183 | ```java | |
| 180 | interface VariantsView { |
|
184 | interface VariantsView { | |
| 181 | Set<Layer> getLayers(); |
|
185 | Set<Layer> getLayers(); | |
| 182 | Set<Role> getRoles(); |
|
186 | Set<Role> getRoles(); | |
| 183 | Set<Variant> getVariants(); |
|
187 | Set<Variant> getVariants(); | |
| 184 | Set<VariantRoleLayer> getEntries(); |
|
188 | Set<VariantRoleLayer> getEntries(); | |
| 185 | } |
|
189 | } | |
| 186 | ``` |
|
190 | ``` | |
| 187 |
|
191 | |||
| 188 | Where: |
|
192 | Where: | |
| 189 |
|
193 | |||
| 190 | ```java |
|
194 | ```java | |
| 191 | record VariantRoleLayer(Variant variant, Role role, Layer layer) {} |
|
195 | record VariantRoleLayer(Variant variant, Role role, Layer layer) {} | |
| 192 | ``` |
|
196 | ``` | |
| 193 |
|
197 | |||
| 194 | This view is: |
|
198 | This view is: | |
| 195 |
|
199 | |||
| 196 | * immutable |
|
200 | * immutable | |
| 197 | * normalized |
|
201 | * normalized | |
| 198 | * validated |
|
202 | * validated | |
| 199 | * independent from DSL internals |
|
203 | * independent from DSL internals | |
| 200 |
|
204 | |||
| 201 | --- |
|
205 | --- | |
| 202 |
|
206 | |||
| 203 | ## Derived views |
|
207 | ## Derived views | |
| 204 |
|
208 | |||
| 205 | Two important views can be derived from `VariantsView`: |
|
209 | Two important views can be derived from `VariantsView`: | |
| 206 |
|
210 | |||
| 207 | * `CompileUnitsView` |
|
211 | * `CompileUnitsView` | |
| 208 | * `RoleProjectionsView` |
|
212 | * `RoleProjectionsView` | |
| 209 |
|
213 | |||
| 210 | These views are not part of the raw core model itself, but they are naturally derived from it. |
|
214 | These views are not part of the raw core model itself, but they are naturally derived from it. | |
| 211 |
|
215 | |||
| 212 | --- |
|
216 | --- | |
| 213 |
|
217 | |||
| 214 | ## `CompileUnitsView` |
|
218 | ## `CompileUnitsView` | |
| 215 |
|
219 | |||
| 216 | ### Purpose |
|
220 | ### Purpose | |
| 217 |
|
221 | |||
| 218 | A compile unit is defined as: |
|
222 | A compile unit is defined as: | |
| 219 |
|
223 | |||
| 220 | * `(variant, layer)` |
|
224 | * `(variant, layer)` | |
| 221 |
|
225 | |||
| 222 | This is based on the following rationale: |
|
226 | This is based on the following rationale: | |
| 223 |
|
227 | |||
| 224 | * `variant` defines compilation semantics |
|
228 | * `variant` defines compilation semantics | |
| 225 | * `layer` partitions a variant into separate compilation units |
|
229 | * `layer` partitions a variant into separate compilation units | |
| 226 | * `role` is not a compilation boundary |
|
230 | * `role` is not a compilation boundary | |
| 227 |
|
231 | |||
| 228 | This is especially useful for toolchains such as TypeScript, where compilation is often more practical or more correct per layer than for the whole variant at once. |
|
232 | This is especially useful for toolchains such as TypeScript, where compilation is often more practical or more correct per layer than for the whole variant at once. | |
| 229 |
|
233 | |||
| 230 | ### Example |
|
234 | ### Example | |
| 231 |
|
235 | |||
| 232 | From: |
|
236 | From: | |
| 233 |
|
237 | |||
| 234 | * `(browser, production, main)` |
|
238 | * `(browser, production, main)` | |
| 235 | * `(browser, production, rjs)` |
|
239 | * `(browser, production, rjs)` | |
| 236 | * `(browser, test, main)` |
|
240 | * `(browser, test, main)` | |
| 237 | * `(browser, test, test)` |
|
241 | * `(browser, test, test)` | |
| 238 | * `(browser, test, rjs)` |
|
242 | * `(browser, test, rjs)` | |
| 239 |
|
243 | |||
| 240 | we derive compile units: |
|
244 | we derive compile units: | |
| 241 |
|
245 | |||
| 242 | * `(browser, main)` |
|
246 | * `(browser, main)` | |
| 243 | * `(browser, rjs)` |
|
247 | * `(browser, rjs)` | |
| 244 | * `(browser, test)` |
|
248 | * `(browser, test)` | |
| 245 |
|
249 | |||
| 246 | ### Conceptual API |
|
250 | ### Conceptual API | |
| 247 |
|
251 | |||
| 248 | ```java |
|
252 | ```java | |
| 249 | interface CompileUnitsView { |
|
253 | interface CompileUnitsView { | |
| 250 | Set<CompileUnit> getUnits(); |
|
254 | Set<CompileUnit> getUnits(); | |
| 251 | Set<CompileUnit> getUnitsForVariant(Variant variant); |
|
255 | Set<CompileUnit> getUnitsForVariant(Variant variant); | |
| 252 | boolean contains(Variant variant, Layer layer); |
|
256 | boolean contains(Variant variant, Layer layer); | |
| 253 | Set<Role> getRoles(CompileUnit unit); |
|
257 | Set<Role> getRoles(CompileUnit unit); | |
| 254 | } |
|
258 | } | |
| 255 |
|
259 | |||
| 256 | record CompileUnit(Variant variant, Layer layer) {} |
|
260 | record CompileUnit(Variant variant, Layer layer) {} | |
| 257 | ``` |
|
261 | ``` | |
| 258 |
|
262 | |||
| 259 | ### Meaning |
|
263 | ### Meaning | |
| 260 |
|
264 | |||
| 261 | `CompileUnitsView` answers: |
|
265 | `CompileUnitsView` answers: | |
| 262 |
|
266 | |||
| 263 | * what can be compiled |
|
267 | * what can be compiled | |
| 264 | * how a variant is partitioned into compile units |
|
268 | * how a variant is partitioned into compile units | |
| 265 | * which logical roles include a given compile unit |
|
269 | * which logical roles include a given compile unit | |
| 266 |
|
270 | |||
| 267 | --- |
|
271 | --- | |
| 268 |
|
272 | |||
| 269 | ## `RoleProjectionsView` |
|
273 | ## `RoleProjectionsView` | |
| 270 |
|
274 | |||
| 271 | ### Purpose |
|
275 | ### Purpose | |
| 272 |
|
276 | |||
| 273 | A role projection is defined as: |
|
277 | A role projection is defined as: | |
| 274 |
|
278 | |||
| 275 | * `(variant, role)` |
|
279 | * `(variant, role)` | |
| 276 |
|
280 | |||
| 277 | This is based on the following rationale: |
|
281 | This is based on the following rationale: | |
| 278 |
|
282 | |||
| 279 | * `role` is not about compilation |
|
283 | * `role` is not about compilation | |
| 280 | * `role` groups compile units by purpose |
|
284 | * `role` groups compile units by purpose | |
| 281 | * roles are more closely related to publication, aggregation, assembly, or result grouping |
|
285 | * roles are more closely related to publication, aggregation, assembly, or result grouping | |
| 282 |
|
286 | |||
| 283 | ### Example |
|
287 | ### Example | |
| 284 |
|
288 | |||
| 285 | For `browser`: |
|
289 | For `browser`: | |
| 286 |
|
290 | |||
| 287 | * `production` includes compile units: |
|
291 | * `production` includes compile units: | |
| 288 |
|
292 | |||
| 289 | * `(browser, main)` |
|
293 | * `(browser, main)` | |
| 290 | * `(browser, rjs)` |
|
294 | * `(browser, rjs)` | |
| 291 |
|
295 | |||
| 292 | * `test` includes compile units: |
|
296 | * `test` includes compile units: | |
| 293 |
|
297 | |||
| 294 | * `(browser, main)` |
|
298 | * `(browser, main)` | |
| 295 | * `(browser, test)` |
|
299 | * `(browser, test)` | |
| 296 | * `(browser, rjs)` |
|
300 | * `(browser, rjs)` | |
| 297 |
|
301 | |||
| 298 | ### Conceptual API |
|
302 | ### Conceptual API | |
| 299 |
|
303 | |||
| 300 | ```java |
|
304 | ```java | |
| 301 | interface RoleProjectionsView { |
|
305 | interface RoleProjectionsView { | |
| 302 | Set<RoleProjection> getProjections(); |
|
306 | Set<RoleProjection> getProjections(); | |
| 303 | Set<RoleProjection> getProjectionsForVariant(Variant variant); |
|
307 | Set<RoleProjection> getProjectionsForVariant(Variant variant); | |
| 304 | Set<RoleProjection> getProjectionsForRole(Role role); |
|
308 | Set<RoleProjection> getProjectionsForRole(Role role); | |
| 305 | Set<CompileUnit> getUnits(RoleProjection projection); |
|
309 | Set<CompileUnit> getUnits(RoleProjection projection); | |
| 306 | } |
|
310 | } | |
| 307 |
|
311 | |||
| 308 | record RoleProjection(Variant variant, Role role) {} |
|
312 | record RoleProjection(Variant variant, Role role) {} | |
| 309 | ``` |
|
313 | ``` | |
| 310 |
|
314 | |||
| 311 | ### Meaning |
|
315 | ### Meaning | |
| 312 |
|
316 | |||
| 313 | `RoleProjectionsView` answers: |
|
317 | `RoleProjectionsView` answers: | |
| 314 |
|
318 | |||
| 315 | * how compile units are grouped by purpose |
|
319 | * how compile units are grouped by purpose | |
| 316 | * what belongs to `production`, `test`, `tool`, etc. |
|
320 | * what belongs to `production`, `test`, `tool`, etc. | |
| 317 | * what should be aggregated or published together |
|
321 | * what should be aggregated or published together | |
| 318 |
|
322 | |||
| 319 | --- |
|
323 | --- | |
| 320 |
|
324 | |||
| 321 | ## Why `CompileUnitsView` and `RoleProjectionsView` are not part of `VariantsView` |
|
325 | ## Why `CompileUnitsView` and `RoleProjectionsView` are not part of `VariantsView` | |
| 322 |
|
326 | |||
| 323 | `VariantsView` is intentionally minimal. |
|
327 | `VariantsView` is intentionally minimal. | |
| 324 |
|
328 | |||
| 325 | It expresses the domain relation: |
|
329 | It expresses the domain relation: | |
| 326 |
|
330 | |||
| 327 | * `(variant, role, layer)` |
|
331 | * `(variant, role, layer)` | |
| 328 |
|
332 | |||
| 329 | `CompileUnitsView` and `RoleProjectionsView` are **derived interpretations** of that relation. |
|
333 | `CompileUnitsView` and `RoleProjectionsView` are **derived interpretations** of that relation. | |
| 330 |
|
334 | |||
| 331 | They are natural and useful, but they are still interpretations: |
|
335 | They are natural and useful, but they are still interpretations: | |
| 332 |
|
336 | |||
| 333 | * `CompileUnit = (variant, layer)` |
|
337 | * `CompileUnit = (variant, layer)` | |
| 334 | * `RoleProjection = (variant, role)` |
|
338 | * `RoleProjection = (variant, role)` | |
| 335 |
|
339 | |||
| 336 | This is why they are better treated as derived views rather than direct core model primitives. |
|
340 | This is why they are better treated as derived views rather than direct core model primitives. | |
| 337 |
|
341 | |||
| 338 | --- |
|
342 | --- | |
| 339 |
|
343 | |||
| 340 | ## `variantSources`: source semantics for layers |
|
344 | ## `variantSources`: source semantics for layers | |
| 341 |
|
345 | |||
| 342 | ### Purpose |
|
346 | ### Purpose | |
| 343 |
|
347 | |||
| 344 | `variantSources` does **not** define variants. |
|
348 | `variantSources` does **not** define variants. | |
| 345 |
|
349 | |||
| 346 | It defines how a declared `Layer` contributes sources. |
|
350 | It defines how a declared `Layer` contributes sources. | |
| 347 |
|
351 | |||
| 348 | In other words: |
|
352 | In other words: | |
| 349 |
|
353 | |||
| 350 | * `variants` defines **what exists** |
|
354 | * `variants` defines **what exists** | |
| 351 | * `variantSources` defines **how layers become source inputs** |
|
355 | * `variantSources` defines **how layers become source inputs** | |
| 352 |
|
356 | |||
| 353 | This distinction is important. |
|
357 | This distinction is important. | |
| 354 |
|
358 | |||
| 355 | `variantSources` does not own the variant model. It interprets it. |
|
359 | `variantSources` does not own the variant model. It interprets it. | |
| 356 |
|
360 | |||
| 357 | --- |
|
361 | --- | |
| 358 |
|
362 | |||
| 359 | ## Main idea |
|
363 | ## Main idea | |
| 360 |
|
364 | |||
| 361 | A layer source rule describes the source contribution of a layer. |
|
365 | A layer source rule describes the source contribution of a layer. | |
| 362 |
|
366 | |||
| 363 | This is independent of any concrete variant or role. |
|
367 | This is independent of any concrete variant or role. | |
| 364 |
|
368 | |||
| 365 | Conceptually: |
|
369 | Conceptually: | |
| 366 |
|
370 | |||
| 367 | * `Layer -> source contribution rule` |
|
371 | * `Layer -> source contribution rule` | |
| 368 |
|
372 | |||
| 369 | Examples of source contribution semantics: |
|
373 | Examples of source contribution semantics: | |
| 370 |
|
374 | |||
| 371 | * base directory |
|
375 | * base directory | |
| 372 | * source directories |
|
376 | * source directories | |
| 373 | * logical source kinds (`ts`, `js`, `resources`) |
|
377 | * logical source kinds (`ts`, `js`, `resources`) | |
| 374 | * declared outputs (`js`, `dts`, `resources`) |
|
378 | * declared outputs (`js`, `dts`, `resources`) | |
| 375 |
|
379 | |||
| 376 | --- |
|
380 | --- | |
| 377 |
|
381 | |||
| 378 | ## `variantSources` DSL example |
|
382 | ## `variantSources` DSL example | |
| 379 |
|
383 | |||
| 380 | ```groovy |
|
384 | ```groovy | |
| 381 | variantSources { |
|
385 | variantSources { | |
| 382 | layerRule("main") { |
|
386 | layerRule("main") { | |
| 383 | from("src/main") |
|
387 | from("src/main") | |
| 384 |
|
388 | |||
| 385 | set("ts") { |
|
389 | set("ts") { | |
| 386 | srcDir("ts") |
|
390 | srcDir("ts") | |
| 387 | } |
|
391 | } | |
| 388 | set("js") { |
|
392 | set("js") { | |
| 389 | srcDir("js") |
|
393 | srcDir("js") | |
| 390 | } |
|
394 | } | |
| 391 | set("resources") { |
|
395 | set("resources") { | |
| 392 | srcDir("resources") |
|
396 | srcDir("resources") | |
| 393 | } |
|
397 | } | |
| 394 |
|
398 | |||
| 395 | outputs("js", "dts", "resources") |
|
399 | outputs("js", "dts", "resources") | |
| 396 | } |
|
400 | } | |
| 397 |
|
401 | |||
| 398 | layerRule("test") { |
|
402 | layerRule("test") { | |
| 399 | from("src/test") |
|
403 | from("src/test") | |
| 400 |
|
404 | |||
| 401 | set("ts") { |
|
405 | set("ts") { | |
| 402 | srcDir("ts") |
|
406 | srcDir("ts") | |
| 403 | } |
|
407 | } | |
| 404 | set("resources") { |
|
408 | set("resources") { | |
| 405 | srcDir("resources") |
|
409 | srcDir("resources") | |
| 406 | } |
|
410 | } | |
| 407 |
|
411 | |||
| 408 | outputs("js", "dts", "resources") |
|
412 | outputs("js", "dts", "resources") | |
| 409 | } |
|
413 | } | |
| 410 |
|
414 | |||
| 411 | layerRule("rjs") { |
|
415 | layerRule("rjs") { | |
| 412 | from("src/rjs") |
|
416 | from("src/rjs") | |
| 413 |
|
417 | |||
| 414 | set("ts") { |
|
418 | set("ts") { | |
| 415 | srcDir("ts") |
|
419 | srcDir("ts") | |
| 416 | } |
|
420 | } | |
| 417 |
|
421 | |||
| 418 | outputs("js", "dts") |
|
422 | outputs("js", "dts") | |
| 419 | } |
|
423 | } | |
| 420 |
|
424 | |||
| 421 | layerRule("cjs") { |
|
425 | layerRule("cjs") { | |
| 422 | from("src/cjs") |
|
426 | from("src/cjs") | |
| 423 |
|
427 | |||
| 424 | set("ts") { |
|
428 | set("ts") { | |
| 425 | srcDir("ts") |
|
429 | srcDir("ts") | |
| 426 | } |
|
430 | } | |
| 427 |
|
431 | |||
| 428 | outputs("js", "dts") |
|
432 | outputs("js", "dts") | |
| 429 | } |
|
433 | } | |
| 430 | } |
|
434 | } | |
| 431 | ``` |
|
435 | ``` | |
| 432 |
|
436 | |||
| 433 | ### Interpretation |
|
437 | ### Interpretation | |
| 434 |
|
438 | |||
| 435 | This means: |
|
439 | This means: | |
| 436 |
|
440 | |||
| 437 | * `main` contributes `ts`, `js`, and `resources` |
|
441 | * `main` contributes `ts`, `js`, and `resources` | |
| 438 | * `test` contributes `ts` and `resources` |
|
442 | * `test` contributes `ts` and `resources` | |
| 439 | * `rjs` contributes `ts` |
|
443 | * `rjs` contributes `ts` | |
| 440 | * `cjs` contributes `ts` |
|
444 | * `cjs` contributes `ts` | |
| 441 |
|
445 | |||
| 442 | These are layer rules only. |
|
446 | These are layer rules only. | |
| 443 |
|
447 | |||
| 444 | They do not yet say which variant consumes them. |
|
448 | They do not yet say which variant consumes them. | |
| 445 |
|
449 | |||
| 446 | --- |
|
450 | --- | |
| 447 |
|
451 | |||
| 448 | ## Why `variantSources` remains open |
|
452 | ## Why `variantSources` remains open | |
| 449 |
|
453 | |||
| 450 | Unlike `variants`, `variantSources` does not need to be closed in the same way. |
|
454 | Unlike `variants`, `variantSources` does not need to be closed in the same way. | |
| 451 |
|
455 | |||
| 452 | Reasons: |
|
456 | Reasons: | |
| 453 |
|
457 | |||
| 454 | * the DSL is internal to source materialization |
|
458 | * the DSL is internal to source materialization | |
| 455 | * the source of truth for unit existence is already finalized in `VariantsView` |
|
459 | * the source of truth for unit existence is already finalized in `VariantsView` | |
| 456 | * `SourceSetMaterializer` returns `NamedDomainObjectProvider<GenericSourceSet>` |
|
460 | * `SourceSetMaterializer` returns `NamedDomainObjectProvider<GenericSourceSet>` | |
| 457 | * adapters may need to refine source-related behavior after `variants` is finalized |
|
461 | * adapters may need to refine source-related behavior after `variants` is finalized | |
| 458 |
|
462 | |||
| 459 | Therefore: |
|
463 | Therefore: | |
| 460 |
|
464 | |||
| 461 | * `variants` is finalized |
|
465 | * `variants` is finalized | |
| 462 | * `variantSources` may remain open |
|
466 | * `variantSources` may remain open | |
| 463 |
|
467 | |||
| 464 | This is not a contradiction. |
|
468 | This is not a contradiction. | |
| 465 |
|
469 | |||
| 466 | It reflects the difference between: |
|
470 | It reflects the difference between: | |
| 467 |
|
471 | |||
| 468 | * a closed domain model |
|
472 | * a closed domain model | |
| 469 | * an open infrastructure/materialization model |
|
473 | * an open infrastructure/materialization model | |
| 470 |
|
474 | |||
| 471 | This openness is still constrained by explicit policy fixation points: |
|
475 | This openness is still constrained by explicit policy fixation points: | |
| 472 |
|
476 | |||
| 473 | * late-configuration policy is fixed when the first selector rule is registered |
|
477 | * late-configuration policy is fixed when the first selector rule is registered | |
| 474 | * naming policy is fixed when the finalized `VariantSourcesContext` is created |
|
478 | * naming policy is fixed when the finalized `VariantSourcesContext` is created | |
| 475 |
|
479 | |||
| 476 | --- |
|
480 | --- | |
| 477 |
|
481 | |||
| 478 | ## Late configuration policy |
|
482 | ## Late configuration policy | |
| 479 |
|
483 | |||
| 480 | Openness of `variantSources` does not mean that late configuration is |
|
484 | Openness of `variantSources` does not mean that late configuration is | |
| 481 | semantically neutral. |
|
485 | semantically neutral. | |
| 482 |
|
486 | |||
| 483 | Selector rules may be added after the finalized context becomes available, but |
|
487 | Selector rules may be added after the finalized context becomes available, but | |
| 484 | their behavior against already materialized `GenericSourceSet` objects must be |
|
488 | their behavior against already materialized `GenericSourceSet` objects must be | |
| 485 | controlled explicitly. |
|
489 | controlled explicitly. | |
| 486 |
|
490 | |||
| 487 | Conceptually, `variantSources` exposes a policy choice such as: |
|
491 | Conceptually, `variantSources` exposes a policy choice such as: | |
| 488 |
|
492 | |||
| 489 | ```groovy |
|
493 | ```groovy | |
| 490 | variantSources { |
|
494 | variantSources { | |
| 491 | lateConfigurationPolicy { |
|
495 | lateConfigurationPolicy { | |
| 492 | failOnLateConfiguration() |
|
496 | failOnLateConfiguration() | |
| 493 | } |
|
497 | } | |
| 494 | } |
|
498 | } | |
| 495 | ``` |
|
499 | ``` | |
| 496 |
|
500 | |||
| 497 | Available modes are: |
|
501 | Available modes are: | |
| 498 |
|
502 | |||
| 499 | * `failOnLateConfiguration()` |
|
503 | * `failOnLateConfiguration()` | |
| 500 | * `warnOnLateConfiguration()` |
|
504 | * `warnOnLateConfiguration()` | |
| 501 | * `allowLateConfiguration()` |
|
505 | * `allowLateConfiguration()` | |
| 502 |
|
506 | |||
| 503 | Meaning: |
|
507 | Meaning: | |
| 504 |
|
508 | |||
| 505 | * `fail` rejects selector rules that target already materialized source sets |
|
509 | * `fail` rejects selector rules that target already materialized source sets | |
| 506 | * `warn` allows them but emits a warning |
|
510 | * `warn` allows them but emits a warning | |
| 507 | * `allow` allows them silently |
|
511 | * `allow` allows them silently | |
| 508 |
|
512 | |||
| 509 | This policy is intentionally modeled as an imperative choice, not as a mutable |
|
513 | This policy is intentionally modeled as an imperative choice, not as a mutable | |
| 510 | property: |
|
514 | property: | |
| 511 |
|
515 | |||
| 512 | * it must be chosen before the first selector rule is added |
|
516 | * it must be chosen before the first selector rule is added | |
| 513 |
* selector rules here mean `variant(...)`, `layer(...)`, |
|
517 | * selector rules here mean `configureEach(...)`, `variant(...)`, `layer(...)`, | |
|
|
518 | and `unit(...)` | |||
| 514 | * once chosen, it cannot be changed later |
|
519 | * once chosen, it cannot be changed later | |
| 515 |
|
|
520 | * it controls runtime behavior, not just a stored value | |
| 516 | * the enforcement point is the first selector registration itself, not variants |
|
521 | * the enforcement point is the first selector registration itself, not variants | |
| 517 | finalization in isolation |
|
522 | finalization in isolation | |
| 518 |
|
|
523 | ||
| 519 | For source sets configured before materialization, selector precedence remains: |
|
524 | For source sets configured before materialization, selector precedence remains: | |
| 520 |
|
|
525 | ||
| 521 | ```text |
|
526 | ```text | |
| 522 | variant < layer < unit |
|
527 | configureEach < variant < layer < unit | |
| 523 |
|
|
528 | ``` | |
| 524 |
|
|
529 | ||
| 525 | For already materialized source sets in `warn` and `allow` modes: |
|
530 | For already materialized source sets in `warn` and `allow` modes: | |
| 526 |
|
|
531 | ||
| 527 |
|
|
532 | * the late action is applied as an imperative follow-up step | |
| 528 | * selector precedence is not reconstructed retroactively |
|
533 | * selector precedence is not reconstructed retroactively | |
| 529 |
|
|
534 | * actual observation order is the order in which late actions are registered | |
| 530 |
|
535 | |||
| 531 | --- |
|
536 | --- | |
| 532 |
|
537 | |||
| 533 | ## Compile-unit naming policy |
|
538 | ## Compile-unit naming policy | |
| 534 |
|
539 | |||
| 535 | Source-set naming is treated as a separate policy concern from selector |
|
540 | Source-set naming is treated as a separate policy concern from selector | |
| 536 | registration. |
|
541 | registration. | |
| 537 |
|
542 | |||
| 538 | Conceptually, `variantSources` exposes: |
|
543 | Conceptually, `variantSources` exposes: | |
| 539 |
|
544 | |||
| 540 | ```groovy |
|
545 | ```groovy | |
| 541 | variantSources { |
|
546 | variantSources { | |
| 542 | namingPolicy { |
|
547 | namingPolicy { | |
| 543 | failOnNameCollision() |
|
548 | failOnNameCollision() | |
| 544 | } |
|
549 | } | |
| 545 | } |
|
550 | } | |
| 546 | ``` |
|
551 | ``` | |
| 547 |
|
552 | |||
| 548 | The base projected name of a compile unit is: |
|
553 | The base projected name of a compile unit is: | |
| 549 |
|
554 | |||
| 550 | ```text |
|
555 | ```text | |
| 551 | variantName + capitalize(layerName) |
|
556 | variantName + capitalize(layerName) | |
| 552 | ``` |
|
557 | ``` | |
| 553 |
|
558 | |||
| 554 | Examples: |
|
559 | Examples: | |
| 555 |
|
560 | |||
| 556 | * `(browser, main)` -> `browserMain` |
|
561 | * `(browser, main)` -> `browserMain` | |
| 557 | * `(browser, rjs)` -> `browserRjs` |
|
562 | * `(browser, rjs)` -> `browserRjs` | |
| 558 |
|
563 | |||
| 559 | Available modes are: |
|
564 | Available modes are: | |
| 560 |
|
565 | |||
| 561 | * `failOnNameCollision()` - reject finalized compile-unit models that project |
|
566 | * `failOnNameCollision()` - reject finalized compile-unit models that project | |
| 562 | the same source-set name for different compile units |
|
567 | the same source-set name for different compile units | |
| 563 | * `resolveNameCollision()` - resolve such conflicts deterministically |
|
568 | * `resolveNameCollision()` - resolve such conflicts deterministically | |
| 564 |
|
569 | |||
| 565 | ### `resolveNameCollision()` semantics |
|
570 | ### `resolveNameCollision()` semantics | |
| 566 |
|
571 | |||
| 567 | Conflicting compile units are ordered canonically by: |
|
572 | Conflicting compile units are ordered canonically by: | |
| 568 |
|
573 | |||
| 569 | ```text |
|
574 | ```text | |
| 570 | (variant.name, layer.name) |
|
575 | (variant.name, layer.name) | |
| 571 | ``` |
|
576 | ``` | |
| 572 |
|
577 | |||
| 573 | Within one conflicting group: |
|
578 | Within one conflicting group: | |
| 574 |
|
579 | |||
| 575 | * the first compile unit keeps the base name |
|
580 | * the first compile unit keeps the base name | |
| 576 | * the second gets suffix `2` |
|
581 | * the second gets suffix `2` | |
| 577 | * the third gets suffix `3` |
|
582 | * the third gets suffix `3` | |
| 578 | * and so on |
|
583 | * and so on | |
| 579 |
|
584 | |||
| 580 | For example, if: |
|
585 | For example, if: | |
| 581 |
|
586 | |||
| 582 | * `(foo, variantBar)` projects to `fooVariantBar` |
|
587 | * `(foo, variantBar)` projects to `fooVariantBar` | |
| 583 | * `(fooVariant, bar)` also projects to `fooVariantBar` |
|
588 | * `(fooVariant, bar)` also projects to `fooVariantBar` | |
| 584 |
|
589 | |||
| 585 | then canonical ordering yields: |
|
590 | then canonical ordering yields: | |
| 586 |
|
591 | |||
| 587 | * `(foo, variantBar)` -> `fooVariantBar` |
|
592 | * `(foo, variantBar)` -> `fooVariantBar` | |
| 588 | * `(fooVariant, bar)` -> `fooVariantBar2` |
|
593 | * `(fooVariant, bar)` -> `fooVariantBar2` | |
| 589 |
|
594 | |||
| 590 | ### Fixation point |
|
595 | ### Fixation point | |
| 591 |
|
596 | |||
| 592 | Naming policy is fixed when the finalized `VariantSourcesContext` is created. |
|
597 | Naming policy is fixed when the finalized `VariantSourcesContext` is created. | |
| 593 |
|
598 | |||
| 594 | Operationally this means: |
|
599 | Operationally this means: | |
| 595 |
|
600 | |||
| 596 | * naming policy must be selected before `variantSources.whenFinalized(...)` |
|
601 | * naming policy must be selected before `variantSources.whenFinalized(...)` | |
| 597 | becomes observable |
|
602 | becomes observable | |
| 598 | * compile-unit names are projected and validated before queued |
|
603 | * compile-unit names are projected and validated before queued | |
| 599 | `whenFinalized(...)` callbacks are replayed |
|
604 | `whenFinalized(...)` callbacks are replayed | |
| 600 | * changing naming policy from inside a `whenFinalized(...)` callback is too late |
|
605 | * changing naming policy from inside a `whenFinalized(...)` callback is too late | |
| 601 |
|
606 | |||
| 602 | This differs intentionally from late-configuration policy: |
|
607 | This differs intentionally from late-configuration policy: | |
| 603 |
|
608 | |||
| 604 | * late-configuration policy is fixed by the first selector rule |
|
609 | * late-configuration policy is fixed by the first selector rule | |
| 605 | * naming policy is fixed by finalized-context creation |
|
610 | * naming policy is fixed by finalized-context creation | |
| 606 |
|
611 | |||
| 607 | --- |
|
612 | --- | |
| 608 |
|
613 | |||
| 609 | ## `VariantSourcesContext` |
|
614 | ## `VariantSourcesContext` | |
| 610 |
|
615 | |||
| 611 | `variantSources.whenFinalized(...)` remains useful, but not because `variantSources` itself is frozen. |
|
616 | `variantSources.whenFinalized(...)` remains useful, but not because `variantSources` itself is frozen. | |
| 612 |
|
617 | |||
| 613 | Its purpose is to provide access to a finalized context derived from `variants`. |
|
618 | Its purpose is to provide access to a finalized context derived from `variants`. | |
| 614 |
|
619 | |||
| 615 | This context contains: |
|
620 | This context contains: | |
| 616 |
|
621 | |||
| 617 | * `CompileUnitsView` |
|
622 | * `CompileUnitsView` | |
| 618 | * `RoleProjectionsView` |
|
623 | * `RoleProjectionsView` | |
| 619 | * `SourceSetMaterializer` |
|
624 | * `SourceSetMaterializer` | |
| 620 |
|
625 | |||
| 621 | By the time the context becomes observable: |
|
626 | By the time the context becomes observable: | |
| 622 |
|
627 | |||
| 623 | * compile-unit naming policy is already fixed |
|
628 | * compile-unit naming policy is already fixed | |
| 624 | * symbolic source-set names for finalized compile units are already determined |
|
629 | * symbolic source-set names for finalized compile units are already determined | |
| 625 |
|
630 | |||
| 626 | Conceptually: |
|
631 | Conceptually: | |
| 627 |
|
632 | |||
| 628 | ```java |
|
633 | ```java | |
| 629 | interface VariantSourcesContext { |
|
634 | interface VariantSourcesContext { | |
| 630 | CompileUnitsView getCompileUnits(); |
|
635 | CompileUnitsView getCompileUnits(); | |
| 631 | RoleProjectionsView getRoleProjections(); |
|
636 | RoleProjectionsView getRoleProjections(); | |
| 632 | SourceSetMaterializer getSourceSets(); |
|
637 | SourceSetMaterializer getSourceSets(); | |
| 633 | } |
|
638 | } | |
| 634 | ``` |
|
639 | ``` | |
| 635 |
|
640 | |||
| 636 | This callback is also replayable. |
|
641 | This callback is also replayable. | |
| 637 |
|
642 | |||
| 638 | Example: |
|
643 | Example: | |
| 639 |
|
644 | |||
| 640 | ```java |
|
645 | ```java | |
| 641 | variantSources.whenFinalized(ctx -> { |
|
646 | variantSources.whenFinalized(ctx -> { | |
| 642 | var units = ctx.getCompileUnits(); |
|
647 | var units = ctx.getCompileUnits(); | |
| 643 | var roles = ctx.getRoleProjections(); |
|
648 | var roles = ctx.getRoleProjections(); | |
| 644 | var sourceSets = ctx.getSourceSets(); |
|
649 | var sourceSets = ctx.getSourceSets(); | |
| 645 | }); |
|
650 | }); | |
| 646 | ``` |
|
651 | ``` | |
| 647 |
|
652 | |||
| 648 | --- |
|
653 | --- | |
| 649 |
|
654 | |||
| 650 | ## `SourceSetMaterializer` |
|
655 | ## `SourceSetMaterializer` | |
| 651 |
|
656 | |||
| 652 | ### Purpose |
|
657 | ### Purpose | |
| 653 |
|
658 | |||
| 654 | `SourceSetMaterializer` is the official source of truth for materialized source sets. |
|
659 | `SourceSetMaterializer` is the official source of truth for materialized source sets. | |
| 655 |
|
660 | |||
| 656 | It is responsible for: |
|
661 | It is responsible for: | |
| 657 |
|
662 | |||
| 658 | * lazy creation of `GenericSourceSet` |
|
663 | * lazy creation of `GenericSourceSet` | |
| 659 | * projecting finalized compile units to symbolic source-set names |
|
664 | * projecting finalized compile units to symbolic source-set names | |
| 660 | * validating or resolving name collisions according to naming policy |
|
665 | * validating or resolving name collisions according to naming policy | |
| 661 | * applying `layerRule` |
|
666 | * applying `layerRule` | |
| 662 | * connecting a compile unit to a source set provider |
|
667 | * connecting a compile unit to a source set provider | |
| 663 | * exposing source sets to adapters |
|
668 | * exposing source sets to adapters | |
| 664 |
|
669 | |||
| 665 | This is the correct place to apply `layerRule`. |
|
670 | This is the correct place to apply `layerRule`. | |
| 666 |
|
671 | |||
| 667 | Adapters should not apply layer rules themselves. |
|
672 | Adapters should not apply layer rules themselves. | |
| 668 |
|
673 | |||
| 669 | ### Conceptual API |
|
674 | ### Conceptual API | |
| 670 |
|
675 | |||
| 671 | ```java |
|
676 | ```java | |
| 672 | interface SourceSetMaterializer { |
|
677 | interface SourceSetMaterializer { | |
| 673 | NamedDomainObjectProvider<GenericSourceSet> getSourceSet(CompileUnit unit); |
|
678 | NamedDomainObjectProvider<GenericSourceSet> getSourceSet(CompileUnit unit); | |
| 674 | } |
|
679 | } | |
| 675 | ``` |
|
680 | ``` | |
| 676 |
|
681 | |||
| 677 | --- |
|
682 | --- | |
| 678 |
|
683 | |||
| 679 | ## Why `SourceSetMaterializer` should own `layerRule` application |
|
684 | ## Why `SourceSetMaterializer` should own `layerRule` application | |
| 680 |
|
685 | |||
| 681 | If adapters applied `layerRule` directly, responsibility would leak across multiple layers: |
|
686 | If adapters applied `layerRule` directly, responsibility would leak across multiple layers: | |
| 682 |
|
687 | |||
| 683 | * one component would know compile units |
|
688 | * one component would know compile units | |
| 684 | * another would know source semantics |
|
689 | * another would know source semantics | |
| 685 | * another would know how to configure `GenericSourceSet` |
|
690 | * another would know how to configure `GenericSourceSet` | |
| 686 |
|
691 | |||
| 687 | This would make the model harder to reason about. |
|
692 | This would make the model harder to reason about. | |
| 688 |
|
693 | |||
| 689 | Instead: |
|
694 | Instead: | |
| 690 |
|
695 | |||
| 691 | * `layerRule` is DSL/spec-level |
|
696 | * `layerRule` is DSL/spec-level | |
| 692 | * `SourceSetMaterializer` is execution/materialization-level |
|
697 | * `SourceSetMaterializer` is execution/materialization-level | |
| 693 | * adapters are consumption-level |
|
698 | * adapters are consumption-level | |
| 694 |
|
699 | |||
| 695 | This gives a much cleaner separation. |
|
700 | This gives a much cleaner separation. | |
| 696 |
|
701 | |||
| 697 | --- |
|
702 | --- | |
| 698 |
|
703 | |||
| 699 | ## `GenericSourceSet` as materialization target |
|
704 | ## `GenericSourceSet` as materialization target | |
| 700 |
|
705 | |||
| 701 | `GenericSourceSet` is the materialized source aggregation object. |
|
706 | `GenericSourceSet` is the materialized source aggregation object. | |
| 702 |
|
707 | |||
| 703 | It is a good fit because it can represent: |
|
708 | It is a good fit because it can represent: | |
| 704 |
|
709 | |||
| 705 | * multiple logical source sets |
|
710 | * multiple logical source sets | |
| 706 | * aggregated source directories |
|
711 | * aggregated source directories | |
| 707 | * declared outputs |
|
712 | * declared outputs | |
| 708 | * lazy registration through providers |
|
713 | * lazy registration through providers | |
| 709 |
|
714 | |||
| 710 | The materializer is therefore the owner of: |
|
715 | The materializer is therefore the owner of: | |
| 711 |
|
716 | |||
| 712 | * creating `GenericSourceSet` |
|
717 | * creating `GenericSourceSet` | |
| 713 | * populating its source sets |
|
718 | * populating its source sets | |
| 714 | * declaring outputs |
|
719 | * declaring outputs | |
| 715 | * returning a provider for later use |
|
720 | * returning a provider for later use | |
| 716 |
|
721 | |||
| 717 | --- |
|
722 | --- | |
| 718 |
|
723 | |||
| 719 | ## How an adapter should use the model |
|
724 | ## How an adapter should use the model | |
| 720 |
|
725 | |||
| 721 | Example: |
|
726 | Example: | |
| 722 |
|
727 | |||
| 723 | ```java |
|
728 | ```java | |
| 724 | variantSources.whenFinalized(ctx -> { |
|
729 | variantSources.whenFinalized(ctx -> { | |
| 725 | for (CompileUnit unit : ctx.getCompileUnits().getUnits()) { |
|
730 | for (CompileUnit unit : ctx.getCompileUnits().getUnits()) { | |
| 726 | var sourceSetProvider = ctx.getSourceSets().getSourceSet(unit); |
|
731 | var sourceSetProvider = ctx.getSourceSets().getSourceSet(unit); | |
| 727 |
|
732 | |||
| 728 | var variant = unit.variant(); |
|
733 | var variant = unit.variant(); | |
| 729 | var layer = unit.layer(); |
|
734 | var layer = unit.layer(); | |
| 730 |
|
735 | |||
| 731 | // create compile task for this compile unit |
|
736 | // create compile task for this compile unit | |
| 732 | // configure compiler options from variant semantics |
|
737 | // configure compiler options from variant semantics | |
| 733 | // use sourceSetProvider as task input |
|
738 | // use sourceSetProvider as task input | |
| 734 | } |
|
739 | } | |
| 735 |
|
740 | |||
| 736 | for (RoleProjection projection : ctx.getRoleProjections().getProjections()) { |
|
741 | for (RoleProjection projection : ctx.getRoleProjections().getProjections()) { | |
| 737 | var units = ctx.getRoleProjections().getUnits(projection); |
|
742 | var units = ctx.getRoleProjections().getUnits(projection); | |
| 738 |
|
743 | |||
| 739 | // aggregate outputs of included compile units |
|
744 | // aggregate outputs of included compile units | |
| 740 | // use for publication or assembly |
|
745 | // use for publication or assembly | |
| 741 | } |
|
746 | } | |
| 742 | }); |
|
747 | }); | |
| 743 | ``` |
|
748 | ``` | |
| 744 |
|
749 | |||
| 745 | --- |
|
750 | --- | |
| 746 |
|
751 | |||
| 747 | ## Why compile unit is `(variant, layer)` and not `(variant, role)` or `(variant, role, layer)` |
|
752 | ## Why compile unit is `(variant, layer)` and not `(variant, role)` or `(variant, role, layer)` | |
| 748 |
|
753 | |||
| 749 | ### Not `(variant, role)` |
|
754 | ### Not `(variant, role)` | |
| 750 |
|
755 | |||
| 751 | Because role is not a compilation boundary. |
|
756 | Because role is not a compilation boundary. | |
| 752 |
|
757 | |||
| 753 | Role is a logical grouping of results. |
|
758 | Role is a logical grouping of results. | |
| 754 |
|
759 | |||
| 755 | ### Not `(variant, role, layer)` |
|
760 | ### Not `(variant, role, layer)` | |
| 756 |
|
761 | |||
| 757 | Because role does not define the compile unit itself. |
|
762 | Because role does not define the compile unit itself. | |
| 758 |
|
763 | |||
| 759 | A compile unit is a unit of compilation, not a unit of publication grouping. |
|
764 | A compile unit is a unit of compilation, not a unit of publication grouping. | |
| 760 |
|
765 | |||
| 761 | ### Correct interpretation |
|
766 | ### Correct interpretation | |
| 762 |
|
767 | |||
| 763 | * `(variant, layer)` = compile unit |
|
768 | * `(variant, layer)` = compile unit | |
| 764 | * `(variant, role)` = logical result group |
|
769 | * `(variant, role)` = logical result group | |
| 765 | * `(variant, role, layer)` = membership relation between them |
|
770 | * `(variant, role, layer)` = membership relation between them | |
| 766 |
|
771 | |||
| 767 | This is the most coherent separation. |
|
772 | This is the most coherent separation. | |
| 768 |
|
773 | |||
| 769 | --- |
|
774 | --- | |
| 770 |
|
775 | |||
| 771 | ## Model boundaries |
|
776 | ## Model boundaries | |
| 772 |
|
777 | |||
| 773 | ### What belongs to `variants` |
|
778 | ### What belongs to `variants` | |
| 774 |
|
779 | |||
| 775 | * declared domains: `Layer`, `Role`, `Variant` |
|
780 | * declared domains: `Layer`, `Role`, `Variant` | |
| 776 | * normalized relation `(variant, role, layer)` |
|
781 | * normalized relation `(variant, role, layer)` | |
| 777 | * finalization lifecycle |
|
782 | * finalization lifecycle | |
| 778 | * finalized `VariantsView` |
|
783 | * finalized `VariantsView` | |
| 779 |
|
784 | |||
| 780 | ### What belongs to derived views |
|
785 | ### What belongs to derived views | |
| 781 |
|
786 | |||
| 782 | * compile units: `(variant, layer)` |
|
787 | * compile units: `(variant, layer)` | |
| 783 | * role projections: `(variant, role)` |
|
788 | * role projections: `(variant, role)` | |
| 784 |
|
789 | |||
| 785 | ### What belongs to `variantSources` |
|
790 | ### What belongs to `variantSources` | |
| 786 |
|
791 | |||
| 787 | * source semantics of layers |
|
792 | * source semantics of layers | |
| 788 | * source materialization rules |
|
793 | * source materialization rules | |
| 789 | * lazy `GenericSourceSet` provisioning |
|
794 | * lazy `GenericSourceSet` provisioning | |
| 790 | * source adapter integration |
|
795 | * source adapter integration | |
| 791 |
|
796 | |||
| 792 | ### What does not belong to `variants` |
|
797 | ### What does not belong to `variants` | |
| 793 |
|
798 | |||
| 794 | * source directories |
|
799 | * source directories | |
| 795 | * base paths |
|
800 | * base paths | |
| 796 | * output declarations |
|
801 | * output declarations | |
| 797 | * source set layout |
|
802 | * source set layout | |
| 798 | * task registration |
|
803 | * task registration | |
| 799 | * compiler-specific assumptions |
|
804 | * compiler-specific assumptions | |
| 800 |
|
805 | |||
| 801 | --- |
|
806 | --- | |
| 802 |
|
807 | |||
| 803 | ## Design principles |
|
808 | ## Design principles | |
| 804 |
|
809 | |||
| 805 | ### 1. Keep the core model small |
|
810 | ### 1. Keep the core model small | |
| 806 |
|
811 | |||
| 807 | The core model should only contain domain facts. |
|
812 | The core model should only contain domain facts. | |
| 808 |
|
813 | |||
| 809 | ### 2. Separate domain truth from materialization |
|
814 | ### 2. Separate domain truth from materialization | |
| 810 |
|
815 | |||
| 811 | The existence of compile units comes from `VariantsView`, not from source rules. |
|
816 | The existence of compile units comes from `VariantsView`, not from source rules. | |
| 812 |
|
817 | |||
| 813 | ### 3. Treat source materialization as infrastructure |
|
818 | ### 3. Treat source materialization as infrastructure | |
| 814 |
|
819 | |||
| 815 | `variantSources` is an interpretation layer, not the source of truth. |
|
820 | `variantSources` is an interpretation layer, not the source of truth. | |
| 816 |
|
821 | |||
| 817 | ### 4. Prefer replayable finalized hooks |
|
822 | ### 4. Prefer replayable finalized hooks | |
| 818 |
|
823 | |||
| 819 | Adapters should not depend on raw Gradle lifecycle callbacks such as `afterEvaluate`. |
|
824 | Adapters should not depend on raw Gradle lifecycle callbacks such as `afterEvaluate`. | |
| 820 |
|
825 | |||
| 821 | ### 5. Make late behavior explicit |
|
826 | ### 5. Make late behavior explicit | |
| 822 |
|
827 | |||
| 823 | Late configuration after materialization is a policy decision, not an implicit |
|
828 | Late configuration after materialization is a policy decision, not an implicit | |
| 824 | guarantee. |
|
829 | guarantee. | |
| 825 |
|
830 | |||
| 826 | ### 6. Keep heavy runtime objects behind providers |
|
831 | ### 6. Keep heavy runtime objects behind providers | |
| 827 |
|
832 | |||
| 828 | Materialized `GenericSourceSet` objects should remain behind a lazy API. |
|
833 | Materialized `GenericSourceSet` objects should remain behind a lazy API. | |
| 829 |
|
834 | |||
| 830 | ### 7. Make name-collision behavior explicit |
|
835 | ### 7. Make name-collision behavior explicit | |
| 831 |
|
836 | |||
| 832 | Compile-unit naming must be governed by an explicit policy, not by incidental |
|
837 | Compile-unit naming must be governed by an explicit policy, not by incidental | |
| 833 | materialization order. |
|
838 | materialization order. | |
| 834 |
|
839 | |||
| 835 | --- |
|
840 | --- | |
| 836 |
|
841 | |||
| 837 | ## Summary |
|
842 | ## Summary | |
| 838 |
|
843 | |||
| 839 | The model is intentionally split into two layers. |
|
844 | The model is intentionally split into two layers. | |
| 840 |
|
845 | |||
| 841 | ### `variants` |
|
846 | ### `variants` | |
| 842 |
|
847 | |||
| 843 | A closed, finalized domain model: |
|
848 | A closed, finalized domain model: | |
| 844 |
|
849 | |||
| 845 | * `Layer` |
|
850 | * `Layer` | |
| 846 | * `Role` |
|
851 | * `Role` | |
| 847 | * `Variant` |
|
852 | * `Variant` | |
| 848 | * `(variant, role, layer)` |
|
853 | * `(variant, role, layer)` | |
| 849 |
|
854 | |||
| 850 | ### `variantSources` |
|
855 | ### `variantSources` | |
| 851 |
|
856 | |||
| 852 | An open, source-materialization layer: |
|
857 | An open, source-materialization layer: | |
| 853 |
|
858 | |||
| 854 | * layer source rules |
|
859 | * layer source rules | |
| 855 | * compile-unit source set materialization |
|
860 | * compile-unit source set materialization | |
| 856 | * compile-unit naming policy |
|
861 | * compile-unit naming policy | |
| 857 | * adapter-facing `GenericSourceSet` providers |
|
862 | * adapter-facing `GenericSourceSet` providers | |
| 858 |
|
863 | |||
| 859 | ### Derived views |
|
864 | ### Derived views | |
| 860 |
|
865 | |||
| 861 | From the finalized variant model: |
|
866 | From the finalized variant model: | |
| 862 |
|
867 | |||
| 863 | * `CompileUnitsView`: `(variant, layer)` |
|
868 | * `CompileUnitsView`: `(variant, layer)` | |
| 864 | * `RoleProjectionsView`: `(variant, role)` |
|
869 | * `RoleProjectionsView`: `(variant, role)` | |
| 865 |
|
870 | |||
| 866 | ### Operational interpretation |
|
871 | ### Operational interpretation | |
| 867 |
|
872 | |||
| 868 | * `variant` defines compilation semantics |
|
873 | * `variant` defines compilation semantics | |
| 869 | * `layer` partitions compilation |
|
874 | * `layer` partitions compilation | |
| 870 | * `role` groups results by purpose |
|
875 | * `role` groups results by purpose | |
| 871 |
|
876 | |||
| 872 | This keeps the core model stable and minimal, while allowing source handling and adapter integration to remain flexible. |
|
877 | This keeps the core model stable and minimal, while allowing source handling and adapter integration to remain flexible. | |
| @@ -1,337 +1,382 | |||||
| 1 | # `variantSources`: selectors and precedence |
|
1 | # `variantSources`: selectors and precedence | |
| 2 |
|
2 | |||
| 3 | `variantSources` configures source-set materialization over the compile-unit space. |
|
3 | `variantSources` configures source-set materialization over the compile-unit space. | |
| 4 |
|
4 | |||
| 5 | A compile unit is defined as: |
|
5 | A compile unit is defined as: | |
| 6 |
|
6 | |||
| 7 | - `(variant, layer)` |
|
7 | - `(variant, layer)` | |
| 8 |
|
8 | |||
| 9 | This means: |
|
9 | This means: | |
| 10 |
|
10 | |||
| 11 | - `variant` defines compilation semantics |
|
11 | - `variant` defines compilation semantics | |
| 12 | - `layer` defines compilation partitioning |
|
12 | - `layer` defines compilation partitioning | |
| 13 |
|
13 | |||
| 14 | The `variantSources` DSL does not introduce a separate source model. |
|
14 | The `variantSources` DSL does not introduce a separate source model. | |
| 15 | Instead, it provides configuration selectors over the existing compile-unit space. |
|
15 | Instead, it provides configuration selectors over the existing compile-unit space. | |
| 16 |
|
16 | |||
| 17 | ## Selectors |
|
17 | ## Selectors | |
| 18 |
|
18 | |||
| 19 |
|
|
19 | Four selectors are available: | |
| 20 |
|
20 | |||
|
|
21 | - `configureEach(...)` | |||
| 21 | - `variant(...)` |
|
22 | - `variant(...)` | |
| 22 | - `layer(...)` |
|
23 | - `layer(...)` | |
| 23 | - `unit(...)` |
|
24 | - `unit(...)` | |
| 24 |
|
25 | |||
| 25 | They all target the same set of compile units, but at different levels of specificity. |
|
26 | They all target the same set of compile units, but at different levels of specificity. | |
| 26 |
|
27 | |||
|
|
28 | ### `configureEach(...)` | |||
|
|
29 | ||||
|
|
30 | `configureEach(...)` applies configuration to every materialized compile-unit | |||
|
|
31 | source set. | |||
|
|
32 | ||||
|
|
33 | Example: | |||
|
|
34 | ||||
|
|
35 | ```groovy | |||
|
|
36 | variantSources { | |||
|
|
37 | configureEach { | |||
|
|
38 | sourceSet { | |||
|
|
39 | declareOutputs("js") | |||
|
|
40 | } | |||
|
|
41 | } | |||
|
|
42 | } | |||
|
|
43 | ``` | |||
|
|
44 | ||||
|
|
45 | Use this selector for global source-set conventions. | |||
|
|
46 | ||||
|
|
47 | --- | |||
|
|
48 | ||||
| 27 | ### `variant(...)` |
|
49 | ### `variant(...)` | |
| 28 |
|
50 | |||
| 29 | `variant(...)` applies configuration to all compile units that belong to the given variant. |
|
51 | `variant(...)` applies configuration to all compile units that belong to the given variant. | |
| 30 |
|
52 | |||
| 31 | Example: |
|
53 | Example: | |
| 32 |
|
54 | |||
| 33 | ```groovy |
|
55 | ```groovy | |
| 34 | variantSources { |
|
56 | variantSources { | |
| 35 | variant("browser") { |
|
57 | variant("browser") { | |
|
|
58 | sourceSet { | |||
| 36 | declareOutputs("js", "dts") |
|
59 | declareOutputs("js", "dts") | |
| 37 | } |
|
60 | } | |
| 38 | } |
|
61 | } | |
|
|
62 | } | |||
| 39 | ``` |
|
63 | ``` | |
| 40 |
|
64 | |||
| 41 | This affects all compile units of `browser`, for example: |
|
65 | This affects all compile units of `browser`, for example: | |
| 42 |
|
66 | |||
| 43 | - `(browser, main)` |
|
67 | - `(browser, main)` | |
| 44 | - `(browser, rjs)` |
|
68 | - `(browser, rjs)` | |
| 45 | - `(browser, test)` |
|
69 | - `(browser, test)` | |
| 46 |
|
70 | |||
| 47 | Use this selector for variant-wide conventions. |
|
71 | Use this selector for variant-wide conventions. | |
| 48 |
|
72 | |||
| 49 | --- |
|
73 | --- | |
| 50 |
|
74 | |||
| 51 | ### `layer(...)` |
|
75 | ### `layer(...)` | |
| 52 |
|
76 | |||
| 53 | `layer(...)` applies configuration to all compile units that use the given layer. |
|
77 | `layer(...)` applies configuration to all compile units that use the given layer. | |
| 54 |
|
78 | |||
| 55 | Example: |
|
79 | Example: | |
| 56 |
|
80 | |||
| 57 | ```groovy |
|
81 | ```groovy | |
| 58 | variantSources { |
|
82 | variantSources { | |
| 59 | layer("main") { |
|
83 | layer("main") { | |
| 60 |
s |
|
84 | sourceSet { | |
|
|
85 | sets.create("ts") { | |||
| 61 | srcDir("src/main/ts") |
|
86 | srcDir("src/main/ts") | |
| 62 | } |
|
87 | } | |
| 63 | } |
|
88 | } | |
| 64 | } |
|
89 | } | |
|
|
90 | } | |||
| 65 | ``` |
|
91 | ``` | |
| 66 |
|
92 | |||
| 67 | This affects all compile units with layer `main`, for example: |
|
93 | This affects all compile units with layer `main`, for example: | |
| 68 |
|
94 | |||
| 69 | - `(browser, main)` |
|
95 | - `(browser, main)` | |
| 70 | - `(nodejs, main)` |
|
96 | - `(nodejs, main)` | |
| 71 | - `(electron, main)` |
|
97 | - `(electron, main)` | |
| 72 |
|
98 | |||
| 73 | Use this selector for cross-variant layer conventions. |
|
99 | Use this selector for cross-variant layer conventions. | |
| 74 |
|
100 | |||
| 75 | --- |
|
101 | --- | |
| 76 |
|
102 | |||
| 77 | ### `unit(...)` |
|
103 | ### `unit(...)` | |
| 78 |
|
104 | |||
| 79 | `unit(...)` applies configuration to one exact compile unit. |
|
105 | `unit(...)` applies configuration to one exact compile unit. | |
| 80 |
|
106 | |||
| 81 | Example: |
|
107 | Example: | |
| 82 |
|
108 | |||
| 83 | ```groovy |
|
109 | ```groovy | |
| 84 | variantSources { |
|
110 | variantSources { | |
| 85 | unit("browser", "main") { |
|
111 | unit("browser", "main") { | |
| 86 |
|
|
112 | sourceSet { | |
|
|
113 | sets.create("resources") { | |||
| 87 | srcDir("src/browserMain/resources") |
|
114 | srcDir("src/browserMain/resources") | |
| 88 | } |
|
115 | } | |
| 89 | } |
|
116 | } | |
| 90 | } |
|
117 | } | |
|
|
118 | } | |||
| 91 | ``` |
|
119 | ``` | |
| 92 |
|
120 | |||
| 93 | This affects only: |
|
121 | This affects only: | |
| 94 |
|
122 | |||
| 95 | - `(browser, main)` |
|
123 | - `(browser, main)` | |
| 96 |
|
124 | |||
| 97 | Use this selector for the most specific adjustments. |
|
125 | Use this selector for the most specific adjustments. | |
| 98 |
|
126 | |||
| 99 | --- |
|
127 | --- | |
| 100 |
|
128 | |||
| 101 | ## Precedence |
|
129 | ## Precedence | |
| 102 |
|
130 | |||
| 103 | For each compile unit, source-set configuration is applied in the following order: |
|
131 | For each compile unit, source-set configuration is applied in the following order: | |
| 104 |
|
132 | |||
| 105 | ```text |
|
133 | ```text | |
| 106 | variant < layer < unit |
|
134 | configureEach < variant < layer < unit | |
| 107 | ``` |
|
135 | ``` | |
| 108 |
|
136 | |||
| 109 | This means: |
|
137 | This means: | |
| 110 |
|
138 | |||
| 111 |
1. ` |
|
139 | 1. `configureEach(...)` actions are applied first | |
| 112 |
2. ` |
|
140 | 2. `variant(...)` actions are applied next | |
| 113 |
3. ` |
|
141 | 3. `layer(...)` actions are applied next | |
|
|
142 | 4. `unit(...)` actions are applied last | |||
| 114 |
|
143 | |||
| 115 | Each next level is allowed to refine or override the previous one. |
|
144 | Each next level is allowed to refine or override the previous one. | |
| 116 |
|
145 | |||
| 117 | ### Within the same level |
|
146 | ### Within the same level | |
| 118 |
|
147 | |||
| 119 | Within the same selector level, actions are applied in registration order. |
|
148 | Within the same selector level, actions are applied in registration order. | |
| 120 |
|
149 | |||
| 121 | For example, if two plugins both configure `layer("main")`, their actions are applied in the same order in which they were registered. |
|
150 | For example, if two plugins both configure `layer("main")`, their actions are applied in the same order in which they were registered. | |
| 122 |
|
151 | |||
| 123 | ### Scope of this guarantee |
|
152 | ### Scope of this guarantee | |
| 124 |
|
153 | |||
| 125 | This precedence describes the normal materialization order used by the source-set |
|
154 | This precedence describes the normal materialization order used by the source-set | |
| 126 | materializer. |
|
155 | materializer. | |
| 127 |
|
156 | |||
| 128 | It is stable for source sets that are configured before they are materialized. |
|
157 | It is stable for source sets that are configured before they are materialized. | |
| 129 |
|
158 | |||
| 130 | If a selector rule is added after a target source set has already been |
|
159 | If a selector rule is added after a target source set has already been | |
| 131 | materialized, the behavior depends on the selected late-configuration policy. |
|
160 | materialized, the behavior depends on the selected late-configuration policy. | |
| 132 |
|
161 | |||
| 133 | - in `fail` mode, such late configuration is rejected |
|
162 | - in `fail` mode, such late configuration is rejected | |
| 134 | - in `warn` and `allow` modes, the late action is applied as an imperative |
|
163 | - in `warn` and `allow` modes, the late action is applied as an imperative | |
| 135 | follow-up step |
|
164 | follow-up step | |
| 136 | - in `warn` and `allow` modes, selector precedence is not reconstructed |
|
165 | - in `warn` and `allow` modes, selector precedence is not reconstructed | |
| 137 | retroactively for already materialized targets |
|
166 | retroactively for already materialized targets | |
| 138 |
|
167 | |||
| 139 | --- |
|
168 | --- | |
| 140 |
|
169 | |||
| 141 | ## Late Configuration Policy |
|
170 | ## Late Configuration Policy | |
| 142 |
|
171 | |||
| 143 | `variantSources` exposes a policy switch for selector rules that target already |
|
172 | `variantSources` exposes a policy switch for selector rules that target already | |
| 144 | materialized source sets: |
|
173 | materialized source sets: | |
| 145 |
|
174 | |||
| 146 | ```groovy |
|
175 | ```groovy | |
| 147 | variantSources { |
|
176 | variantSources { | |
| 148 | lateConfigurationPolicy { |
|
177 | lateConfigurationPolicy { | |
| 149 | failOnLateConfiguration() |
|
178 | failOnLateConfiguration() | |
| 150 | } |
|
179 | } | |
| 151 | } |
|
180 | } | |
| 152 | ``` |
|
181 | ``` | |
| 153 |
|
182 | |||
| 154 | Available modes: |
|
183 | Available modes: | |
| 155 |
|
184 | |||
| 156 | - `failOnLateConfiguration()` rejects such rules |
|
185 | - `failOnLateConfiguration()` rejects such rules | |
| 157 | - `warnOnLateConfiguration()` allows them and emits a warning |
|
186 | - `warnOnLateConfiguration()` allows them and emits a warning | |
| 158 | - `allowLateConfiguration()` allows them silently |
|
187 | - `allowLateConfiguration()` allows them silently | |
| 159 |
|
188 | |||
| 160 | Policy rules: |
|
189 | Policy rules: | |
| 161 |
|
190 | |||
| 162 | - the policy must be chosen before the first selector rule is added |
|
191 | - the policy must be chosen before the first selector rule is added | |
| 163 |
- selector rules here mean `variant(...)`, `layer(...)`, |
|
192 | - selector rules here mean `configureEach(...)`, `variant(...)`, `layer(...)`, | |
|
|
193 | and `unit(...)` | |||
| 164 | - once chosen, the policy cannot be changed later |
|
194 | - once chosen, the policy cannot be changed later | |
| 165 | - the policy is single-valued; it is not intended to be switched during further |
|
195 | - the policy is single-valued; it is not intended to be switched during further | |
| 166 | configuration |
|
196 | configuration | |
| 167 | - the enforcement point is the first selector registration itself; finalization |
|
197 | - the enforcement point is the first selector registration itself; finalization | |
| 168 | of `variants` alone does not freeze this policy |
|
198 | of `variants` alone does not freeze this policy | |
| 169 |
|
199 | |||
| 170 | Operationally: |
|
200 | Operationally: | |
| 171 |
|
201 | |||
| 172 | - `fail` preserves the strict precedence contract by rejecting late mutation of |
|
202 | - `fail` preserves the strict precedence contract by rejecting late mutation of | |
| 173 | already materialized targets |
|
203 | already materialized targets | |
| 174 | - `warn` and `allow` keep compatibility with imperative late mutation |
|
204 | - `warn` and `allow` keep compatibility with imperative late mutation | |
| 175 | - in `warn` and `allow`, already materialized targets observe the late action in |
|
205 | - in `warn` and `allow`, already materialized targets observe the late action in | |
| 176 |
actual registration order, not in reconstructed |
|
206 | actual registration order, not in reconstructed | |
| 177 | order |
|
207 | `configureEach < variant < layer < unit` order | |
| 178 |
|
208 | |||
| 179 | --- |
|
209 | --- | |
| 180 |
|
210 | |||
| 181 | ## Compile-Unit Naming Policy |
|
211 | ## Compile-Unit Naming Policy | |
| 182 |
|
212 | |||
| 183 | `variantSources` also exposes a policy for projecting compile units to symbolic |
|
213 | `variantSources` also exposes a policy for projecting compile units to symbolic | |
| 184 | source-set names: |
|
214 | source-set names: | |
| 185 |
|
215 | |||
| 186 | ```groovy |
|
216 | ```groovy | |
| 187 | variantSources { |
|
217 | variantSources { | |
| 188 | namingPolicy { |
|
218 | namingPolicy { | |
| 189 | failOnNameCollision() |
|
219 | failOnNameCollision() | |
| 190 | } |
|
220 | } | |
| 191 | } |
|
221 | } | |
| 192 | ``` |
|
222 | ``` | |
| 193 |
|
223 | |||
| 194 | Base projected name: |
|
224 | Base projected name: | |
| 195 |
|
225 | |||
| 196 | - `sourceSetName = variantName + capitalize(layerName)` |
|
226 | - `sourceSetName = variantName + capitalize(layerName)` | |
| 197 |
|
227 | |||
| 198 | Example: |
|
228 | Example: | |
| 199 |
|
229 | |||
| 200 | - `(browser, main)` -> `browserMain` |
|
230 | - `(browser, main)` -> `browserMain` | |
| 201 | - `(browser, rjs)` -> `browserRjs` |
|
231 | - `(browser, rjs)` -> `browserRjs` | |
| 202 |
|
232 | |||
| 203 | Available modes: |
|
233 | Available modes: | |
| 204 |
|
234 | |||
| 205 | - `failOnNameCollision()` rejects finalized compile-unit models that project the |
|
235 | - `failOnNameCollision()` rejects finalized compile-unit models that project the | |
| 206 | same base name for different compile units |
|
236 | same base name for different compile units | |
| 207 | - `resolveNameCollision()` resolves such collisions deterministically |
|
237 | - `resolveNameCollision()` resolves such collisions deterministically | |
| 208 |
|
238 | |||
| 209 | ### `resolveNameCollision()` semantics |
|
239 | ### `resolveNameCollision()` semantics | |
| 210 |
|
240 | |||
| 211 | Conflicting compile units are ordered canonically by: |
|
241 | Conflicting compile units are ordered canonically by: | |
| 212 |
|
242 | |||
| 213 | ```text |
|
243 | ```text | |
| 214 | (variant.name, layer.name) |
|
244 | (variant.name, layer.name) | |
| 215 | ``` |
|
245 | ``` | |
| 216 |
|
246 | |||
| 217 | Name assignment in a conflicting group is: |
|
247 | Name assignment in a conflicting group is: | |
| 218 |
|
248 | |||
| 219 | - the first compile unit keeps the base name |
|
249 | - the first compile unit keeps the base name | |
| 220 | - the second gets suffix `2` |
|
250 | - the second gets suffix `2` | |
| 221 | - the third gets suffix `3` |
|
251 | - the third gets suffix `3` | |
| 222 | - and so on |
|
252 | - and so on | |
| 223 |
|
253 | |||
| 224 | Example: |
|
254 | Example: | |
| 225 |
|
255 | |||
| 226 | - `(foo, variantBar)` and `(fooVariant, bar)` both project to `fooVariantBar` |
|
256 | - `(foo, variantBar)` and `(fooVariant, bar)` both project to `fooVariantBar` | |
| 227 | - after canonical ordering: |
|
257 | - after canonical ordering: | |
| 228 | - `(foo, variantBar)` -> `fooVariantBar` |
|
258 | - `(foo, variantBar)` -> `fooVariantBar` | |
| 229 | - `(fooVariant, bar)` -> `fooVariantBar2` |
|
259 | - `(fooVariant, bar)` -> `fooVariantBar2` | |
| 230 |
|
260 | |||
| 231 | ### Fixation Point |
|
261 | ### Fixation Point | |
| 232 |
|
262 | |||
| 233 | Naming policy is fixed when the finalized `VariantSourcesContext` is created. |
|
263 | Naming policy is fixed when the finalized `VariantSourcesContext` is created. | |
| 234 |
|
264 | |||
| 235 | Operationally this means: |
|
265 | Operationally this means: | |
| 236 |
|
266 | |||
| 237 |
- policy selection must happen before `variantSources.when |
|
267 | - policy selection must happen before `variantSources.whenAvailable(...)` | |
| 238 | becomes observable |
|
268 | becomes observable | |
| 239 | - compile-unit names are projected and validated before queued |
|
269 | - compile-unit names are projected and validated before queued | |
| 240 |
`when |
|
270 | `whenAvailable(...)` callbacks are replayed | |
| 241 |
- changing naming policy from inside a `when |
|
271 | - changing naming policy from inside a `whenAvailable(...)` callback is too late | |
| 242 |
|
272 | |||
| 243 | --- |
|
273 | --- | |
| 244 |
|
274 | |||
| 245 | ## Example |
|
275 | ## Example | |
| 246 |
|
276 | |||
| 247 | ```groovy |
|
277 | ```groovy | |
| 248 | variantSources { |
|
278 | variantSources { | |
|
|
279 | configureEach { | |||
|
|
280 | sourceSet { | |||
|
|
281 | declareOutputs("js", "dts") | |||
|
|
282 | } | |||
|
|
283 | } | |||
|
|
284 | ||||
| 249 | variant("browser") { |
|
285 | variant("browser") { | |
| 250 | declareOutputs("js", "dts") |
|
286 | sourceSet { | |
|
|
287 | registerOutput("js", layout.projectDirectory.file("inputs/browser.js")) | |||
|
|
288 | } | |||
| 251 | } |
|
289 | } | |
| 252 |
|
290 | |||
| 253 | layer("main") { |
|
291 | layer("main") { | |
| 254 |
s |
|
292 | sourceSet { | |
|
|
293 | sets.create("ts") { | |||
| 255 | srcDir("src/main/ts") |
|
294 | srcDir("src/main/ts") | |
| 256 | } |
|
295 | } | |
| 257 | } |
|
296 | } | |
|
|
297 | } | |||
| 258 |
|
298 | |||
| 259 | unit("browser", "main") { |
|
299 | unit("browser", "main") { | |
| 260 |
|
|
300 | sourceSet { | |
|
|
301 | sets.create("resources") { | |||
| 261 | srcDir("src/browserMain/resources") |
|
302 | srcDir("src/browserMain/resources") | |
| 262 | } |
|
303 | } | |
| 263 | } |
|
304 | } | |
| 264 | } |
|
305 | } | |
|
|
306 | } | |||
| 265 | ``` |
|
307 | ``` | |
| 266 |
|
308 | |||
| 267 | For compile unit `(browser, main)` the effective configuration is built in this order: |
|
309 | For compile unit `(browser, main)` the effective configuration is built in this order: | |
| 268 |
|
310 | |||
| 269 | 1. `variant("browser")` |
|
311 | 1. `variant("browser")` | |
| 270 | 2. `layer("main")` |
|
312 | 2. `layer("main")` | |
| 271 | 3. `unit("browser", "main")` |
|
313 | 3. `unit("browser", "main")` | |
| 272 |
|
314 | |||
|
|
315 | The global `configureEach(...)` selector is applied before the listed | |||
|
|
316 | variant/layer/unit selectors for every compile unit. | |||
|
|
317 | ||||
| 273 | For compile unit `(browser, rjs)` the effective configuration is built in this order: |
|
318 | For compile unit `(browser, rjs)` the effective configuration is built in this order: | |
| 274 |
|
319 | |||
| 275 | 1. `variant("browser")` |
|
320 | 1. `variant("browser")` | |
| 276 | 2. `layer("rjs")` if present |
|
321 | 2. `layer("rjs")` if present | |
| 277 | 3. `unit("browser", "rjs")` if present |
|
322 | 3. `unit("browser", "rjs")` if present | |
| 278 |
|
323 | |||
| 279 | For compile unit `(nodejs, main)` the effective configuration is built in this order: |
|
324 | For compile unit `(nodejs, main)` the effective configuration is built in this order: | |
| 280 |
|
325 | |||
| 281 | 1. `variant("nodejs")` if present |
|
326 | 1. `variant("nodejs")` if present | |
| 282 | 2. `layer("main")` |
|
327 | 2. `layer("main")` | |
| 283 | 3. `unit("nodejs", "main")` if present |
|
328 | 3. `unit("nodejs", "main")` if present | |
| 284 |
|
329 | |||
| 285 | --- |
|
330 | --- | |
| 286 |
|
331 | |||
| 287 | ## Model boundary |
|
332 | ## Model boundary | |
| 288 |
|
333 | |||
| 289 | These selectors do not define compile units. |
|
334 | These selectors do not define compile units. | |
| 290 | Compile units are derived from finalized `variants`. |
|
335 | Compile units are derived from finalized `variants`. | |
| 291 |
|
336 | |||
| 292 | `variantSources` only configures how source sets are materialized for those units. |
|
337 | `variantSources` only configures how source sets are materialized for those units. | |
| 293 |
|
338 | |||
| 294 | This means: |
|
339 | This means: | |
| 295 |
|
340 | |||
| 296 | - `variants` is the source of truth for compile-unit existence |
|
341 | - `variants` is the source of truth for compile-unit existence | |
| 297 | - `variantSources` is the source of truth for compile-unit source-set configuration |
|
342 | - `variantSources` is the source of truth for compile-unit source-set configuration | |
| 298 |
|
343 | |||
| 299 | --- |
|
344 | --- | |
| 300 |
|
345 | |||
| 301 | ## Operational semantics |
|
346 | ## Operational semantics | |
| 302 |
|
347 | |||
| 303 | The `variantSources` API is exposed through a finalized context. |
|
348 | The `variantSources` API is exposed through a finalized context. | |
| 304 |
|
349 | |||
| 305 | Conceptually, configuration is registered against finalized model objects, while DSL sugar may still use names for convenience. |
|
350 | Conceptually, configuration is registered against finalized model objects, while DSL sugar may still use names for convenience. | |
| 306 |
|
351 | |||
| 307 | Internally, selector-based configuration is accumulated and later applied by the |
|
352 | Internally, selector-based configuration is accumulated and later applied by the | |
| 308 | source-set materializer when a `GenericSourceSet` is created for a compile unit. |
|
353 | source-set materializer when a `GenericSourceSet` is created for a compile unit. | |
| 309 |
|
354 | |||
| 310 | This guarantees that: |
|
355 | This guarantees that: | |
| 311 |
|
356 | |||
| 312 | - selector precedence is stable before materialization |
|
357 | - selector precedence is stable before materialization | |
| 313 | - registration order is preserved |
|
358 | - registration order is preserved | |
| 314 | - configuration of already materialized targets is governed by the selected |
|
359 | - configuration of already materialized targets is governed by the selected | |
| 315 | late-configuration policy |
|
360 | late-configuration policy | |
| 316 | - adapters do not need to depend on raw Gradle lifecycle timing |
|
361 | - adapters do not need to depend on raw Gradle lifecycle timing | |
| 317 |
|
362 | |||
| 318 | --- |
|
363 | --- | |
| 319 |
|
364 | |||
| 320 | ## Summary |
|
365 | ## Summary | |
| 321 |
|
366 | |||
| 322 | - compile unit space is `(variant, layer)` |
|
367 | - compile unit space is `(variant, layer)` | |
| 323 | - `variant(...)`, `layer(...)`, and `unit(...)` are selectors over that space |
|
368 | - `variant(...)`, `layer(...)`, and `unit(...)` are selectors over that space | |
| 324 | - precedence is: |
|
369 | - precedence is: | |
| 325 |
|
370 | |||
| 326 | ```text |
|
371 | ```text | |
| 327 | variant < layer < unit |
|
372 | configureEach < variant < layer < unit | |
| 328 | ``` |
|
373 | ``` | |
| 329 |
|
374 | |||
| 330 | - registration order is preserved within the same selector level |
|
375 | - registration order is preserved within the same selector level | |
| 331 | - already materialized targets are handled by `lateConfigurationPolicy(...)` |
|
376 | - already materialized targets are handled by `lateConfigurationPolicy(...)` | |
| 332 | - the late-configuration policy must be selected before the first selector rule |
|
377 | - the late-configuration policy must be selected before the first selector rule | |
| 333 | and cannot be changed later |
|
378 | and cannot be changed later | |
| 334 | - compile-unit naming is governed by `namingPolicy(...)` |
|
379 | - compile-unit naming is governed by `namingPolicy(...)` | |
| 335 | - by default, name collisions fail fast during finalized context creation |
|
380 | - by default, name collisions fail fast during finalized context creation | |
| 336 | - `variants` defines what exists |
|
381 | - `variants` defines what exists | |
| 337 | - `variantSources` defines how those compile units are materialized as source sets |
|
382 | - `variantSources` defines how those compile units are materialized as source sets | |
| @@ -1,57 +1,61 | |||||
| 1 | plugins { |
|
1 | plugins { | |
| 2 | id "java-library" |
|
2 | id "java-library" | |
| 3 | id "ivy-publish" |
|
3 | id "ivy-publish" | |
| 4 | } |
|
4 | } | |
| 5 |
|
5 | |||
|
|
6 | description = "Variant, source-set, and outgoing artifact model plugins for Gradle builds" | |||
|
|
7 | ||||
| 6 | java { |
|
8 | java { | |
| 7 | withJavadocJar() |
|
9 | withJavadocJar() | |
| 8 | withSourcesJar() |
|
10 | withSourcesJar() | |
| 9 | toolchain { |
|
11 | toolchain { | |
| 10 | languageVersion = JavaLanguageVersion.of(21) |
|
12 | languageVersion = JavaLanguageVersion.of(21) | |
| 11 | } |
|
13 | } | |
| 12 | } |
|
14 | } | |
| 13 |
|
15 | |||
| 14 | dependencies { |
|
16 | dependencies { | |
| 15 | compileOnly libs.jdt.annotations |
|
17 | compileOnly libs.jdt.annotations | |
| 16 |
|
18 | |||
| 17 | api gradleApi(), |
|
19 | api gradleApi(), | |
| 18 | libs.bundles.jackson |
|
20 | project(":common") | |
| 19 |
|
||||
| 20 | implementation project(":common") |
|
|||
| 21 |
|
21 | |||
| 22 | testImplementation gradleTestKit() |
|
22 | testImplementation gradleTestKit() | |
| 23 | testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4" |
|
23 | testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4" | |
| 24 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4" |
|
24 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4" | |
| 25 | testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4" |
|
25 | testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4" | |
| 26 | } |
|
26 | } | |
| 27 |
|
27 | |||
| 28 | task printVersion{ |
|
28 | task printVersion{ | |
| 29 | doLast { |
|
29 | doLast { | |
| 30 | println "project: $project.group:$project.name:$project.version" |
|
30 | println "project: $project.group:$project.name:$project.version" | |
| 31 | println "jar: ${->jar.archiveFileName.get()}" |
|
31 | println "jar: ${->jar.archiveFileName.get()}" | |
| 32 | } |
|
32 | } | |
| 33 | } |
|
33 | } | |
| 34 |
|
34 | |||
| 35 | test { |
|
35 | test { | |
| 36 | useJUnitPlatform() |
|
36 | useJUnitPlatform() | |
| 37 | } |
|
37 | } | |
| 38 |
|
38 | |||
| 39 | javadoc { |
|
39 | javadoc { | |
| 40 | exclude "**/internal/**" |
|
40 | exclude "**/internal/**" | |
| 41 | } |
|
41 | } | |
| 42 |
|
42 | |||
| 43 | publishing { |
|
43 | publishing { | |
| 44 | repositories { |
|
44 | repositories { | |
| 45 | ivy { |
|
45 | ivy { | |
| 46 | url "${System.properties["user.home"]}/ivy-repo" |
|
46 | url "${System.properties["user.home"]}/ivy-repo" | |
| 47 | } |
|
47 | } | |
| 48 | } |
|
48 | } | |
| 49 | publications { |
|
49 | publications { | |
| 50 | ivy(IvyPublication) { |
|
50 | ivy(IvyPublication) { | |
| 51 | from components.java |
|
51 | from components.java | |
| 52 | descriptor.description { |
|
52 | descriptor.description { | |
| 53 | text = providers.provider({ description }) |
|
53 | text = providers.provider({ description }) | |
| 54 | } |
|
54 | } | |
|
|
55 | descriptor.license { | |||
|
|
56 | name = "BSD-2-Clause" | |||
|
|
57 | url = "https://spdx.org/licenses/BSD-2-Clause.html" | |||
| 55 | } |
|
58 | } | |
| 56 | } |
|
59 | } | |
| 57 | } |
|
60 | } | |
|
|
61 | } | |||
General Comments 0
You need to be logged in to leave comments.
Login now
