##// END OF EJS Templates
Set the project version to 0.1.0, add publication descriptions/license metadata, and keep module-level docs as compatibility pointers to the root documentation.
cin -
r60:e376d0cab00e default
parent child
Show More
@@ -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"
54 }
49 }
55 }
50 }
56 }
51 }
57 }
@@ -1,134 +1,18
1 # Gradle Common Sources Model
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 - `whenOutgoingVariant(...)`
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(...)`, and `unit(...)`
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 * it controls runtime behavior, not just a stored value
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 * the late action is applied as an imperative follow-up step
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 * actual observation order is the order in which late actions are registered
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 Three selectors are available:
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") {
36 declareOutputs("js", "dts")
58 sourceSet {
59 declareOutputs("js", "dts")
60 }
37 }
61 }
38 }
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 set("ts") {
84 sourceSet {
61 srcDir("src/main/ts")
85 sets.create("ts") {
86 srcDir("src/main/ts")
87 }
62 }
88 }
63 }
89 }
64 }
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 set("resources") {
112 sourceSet {
87 srcDir("src/browserMain/resources")
113 sets.create("resources") {
114 srcDir("src/browserMain/resources")
115 }
88 }
116 }
89 }
117 }
90 }
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. `variant(...)` actions are applied first
139 1. `configureEach(...)` actions are applied first
112 2. `layer(...)` actions are applied next
140 2. `variant(...)` actions are applied next
113 3. `unit(...)` actions are applied last
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(...)`, and `unit(...)`
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 `variant < layer < unit`
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.whenFinalized(...)`
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 `whenFinalized(...)` callbacks are replayed
270 `whenAvailable(...)` callbacks are replayed
241 - changing naming policy from inside a `whenFinalized(...)` callback is too late
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 set("ts") {
292 sourceSet {
255 srcDir("src/main/ts")
293 sets.create("ts") {
294 srcDir("src/main/ts")
295 }
256 }
296 }
257 }
297 }
258
298
259 unit("browser", "main") {
299 unit("browser", "main") {
260 set("resources") {
300 sourceSet {
261 srcDir("src/browserMain/resources")
301 sets.create("resources") {
302 srcDir("src/browserMain/resources")
303 }
262 }
304 }
263 }
305 }
264 }
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"
58 }
55 }
59 }
56 }
60 }
57 }
61 }
General Comments 0
You need to be logged in to leave comments. Login now