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