| @@ -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,6 +1,7 | |||||
| 1 | syntax: glob |
|
1 | syntax: glob | |
| 2 | .gradle/ |
|
2 | .gradle/ | |
| 3 | .codex/ |
|
3 | .codex/ | |
|
|
4 | build/ | |||
| 4 | common/build/ |
|
5 | common/build/ | |
| 5 | common/bin/ |
|
6 | common/bin/ | |
| 6 | variants/build/ |
|
7 | variants/build/ | |
| @@ -3,6 +3,8 plugins { | |||||
| 3 | id "ivy-publish" |
|
3 | id "ivy-publish" | |
| 4 | } |
|
4 | } | |
| 5 |
|
5 | |||
|
|
6 | description = "Shared Gradle build utilities used by Implab plugins" | |||
|
|
7 | ||||
| 6 | java { |
|
8 | java { | |
| 7 | withJavadocJar() |
|
9 | withJavadocJar() | |
| 8 | withSourcesJar() |
|
10 | withSourcesJar() | |
| @@ -46,6 +48,10 publishing { | |||||
| 46 | descriptor.description { |
|
48 | descriptor.description { | |
| 47 | text = providers.provider({ description }) |
|
49 | text = providers.provider({ description }) | |
| 48 | } |
|
50 | } | |
|
|
51 | descriptor.license { | |||
|
|
52 | name = "BSD-2-Clause" | |||
|
|
53 | url = "https://spdx.org/licenses/BSD-2-Clause.html" | |||
| 49 | } |
|
54 | } | |
| 50 | } |
|
55 | } | |
| 51 | } |
|
56 | } | |
|
|
57 | } | |||
| @@ -1,134 +1,18 | |||||
| 1 |
# Gradle Common |
|
1 | # Gradle Common | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `gradle-common/common` — набор плагинов для моделирования вариантов сборки, |
|
|||
| 6 | регистрации source sets и интеграции этой модели с toolchain-адаптерами. |
|
|||
| 7 |
|
||||
| 8 | ## SYNOPSIS |
|
|||
| 9 |
|
||||
| 10 | ```groovy |
|
|||
| 11 | plugins { |
|
|||
| 12 | id 'org.implab.gradle-variants-sources' |
|
|||
| 13 | } |
|
|||
| 14 |
|
||||
| 15 | variants { |
|
|||
| 16 | layer('mainBase') |
|
|||
| 17 | layer('mainAmd') |
|
|||
| 18 |
|
||||
| 19 | variant('browser') { |
|
|||
| 20 | role('main') { layers('mainBase', 'mainAmd') } |
|
|||
| 21 | } |
|
|||
| 22 | } |
|
|||
| 23 |
|
||||
| 24 | variantSources { |
|
|||
| 25 | bind('mainBase') { |
|
|||
| 26 | configureSourceSet { |
|
|||
| 27 | declareOutputs('compiled') |
|
|||
| 28 | } |
|
|||
| 29 | } |
|
|||
| 30 |
|
||||
| 31 | bind('mainAmd').sourceSetNamePattern = '{variant}{layerCap}' |
|
|||
| 32 |
|
2 | |||
| 33 | whenRegistered { sourceSetName() } |
|
3 | `common` is the shared utility module used by the Gradle plugins in this | |
| 34 |
|
4 | repository. | ||
| 35 | whenBound { ctx -> |
|
|||
| 36 | ctx.configureSourceSet { |
|
|||
| 37 | declareOutputs('typings') |
|
|||
| 38 | } |
|
|||
| 39 | } |
|
|||
| 40 | } |
|
|||
| 41 | ``` |
|
|||
| 42 |
|
||||
| 43 | ## DESCRIPTION |
|
|||
| 44 |
|
||||
| 45 | Модуль состоит из трех логических частей: |
|
|||
| 46 |
|
5 | |||
| 47 | - `variants` — декларативная доменная модель сборки; |
|
6 | It contains: | |
| 48 | - `sources` — модель физически регистрируемых source sets; |
|
|||
| 49 | - `variantSources` — адаптер, который связывает первые две модели. |
|
|||
| 50 |
|
||||
| 51 | Ниже раскрытие каждой части. |
|
|||
| 52 |
|
||||
| 53 | ### variants |
|
|||
| 54 |
|
||||
| 55 | `variants` задает структуру пространства сборки: какие есть слои, какие роли |
|
|||
| 56 | используют эти слои в каждом варианте, какие есть атрибуты и artifact slots. |
|
|||
| 57 | Модель не создает задачи и не привязана к TS/JS. |
|
|||
| 58 |
|
||||
| 59 | Практический смысл: |
|
|||
| 60 |
|
||||
| 61 | - формализовать архитектуру сборки; |
|
|||
| 62 | - дать адаптерам единый источник правды. |
|
|||
| 63 |
|
||||
| 64 | ### sources |
|
|||
| 65 |
|
7 | |||
| 66 | `sources` описывает независимые source sets (`GenericSourceSet`) с именованными |
|
8 | - core Gradle helper utilities | |
| 67 | outputs. Это уже "физический" уровень, к которому удобно привязывать задачи, |
|
9 | - small language/value helpers | |
| 68 | артефакты и task inputs/outputs. |
|
10 | - shell execution helpers | |
| 69 |
|
11 | - JSON DSL and JSON-writing task support | ||
| 70 | Практический смысл: |
|
|||
| 71 |
|
||||
| 72 | - создать единый контракт по входам/выходам; |
|
|||
| 73 | - регистрировать результаты задач как outputs source set; |
|
|||
| 74 | - минимизировать ручные `dependsOn` за счет модели outputs. |
|
|||
| 75 |
|
||||
| 76 | ### variantSources |
|
|||
| 77 |
|
||||
| 78 | `variantSources` регистрирует source sets на основе `variants`, применяет |
|
|||
| 79 | конфигурацию layer-bindings и отдает события (`whenRegistered`, `whenBound`) для |
|
|||
| 80 | адаптеров других плагинов. |
|
|||
| 81 |
|
||||
| 82 | Практический смысл: |
|
|||
| 83 |
|
||||
| 84 | - переводить логическую модель `variants` в executable-модель `sources`; |
|
|||
| 85 | - навешивать политики toolchain на зарегистрированные source sets; |
|
|||
| 86 | - синхронизировать плагины через replayable callback-контракт. |
|
|||
| 87 |
|
||||
| 88 | ## DOMAIN MODEL |
|
|||
| 89 |
|
||||
| 90 | - `BuildLayer` — canonical identity-model объявленного слоя. |
|
|||
| 91 | - `BuildVariant` — агрегат ролей, атрибутов, артефактных слотов. |
|
|||
| 92 | - `BuildRole` — роль внутри варианта, содержит ссылки на declared layer names. |
|
|||
| 93 | - `GenericSourceSet` — зарегистрированный набор исходников и outputs. |
|
|||
| 94 | - `LayerBindingSpec` — публичный DSL-contract adapter policy/callbacks для слоя. |
|
|||
| 95 | - `SourceSetRegistration` — payload события регистрации source set. |
|
|||
| 96 | - `SourceSetUsageBinding` — payload события usage-binding. |
|
|||
| 97 |
|
||||
| 98 | ## EVENT CONTRACT |
|
|||
| 99 |
|
12 | |||
| 100 | - `whenRegistered`: |
|
13 | It no longer contains the variant/source/artifact plugin model. Those plugins | |
| 101 | - событие нового уникального source set name; |
|
14 | live in the `variants` module. | |
| 102 | - replayable. |
|
|||
| 103 | - `whenBound`: |
|
|||
| 104 | - событие каждой usage-связки `variant/role/layer`; |
|
|||
| 105 | - replayable. |
|
|||
| 106 |
|
||||
| 107 | Closure callbacks работают в delegate-first режиме (`@DelegatesTo`). Для |
|
|||
| 108 | вложенных closure рекомендуется явный параметр (`ctx -> ...`). |
|
|||
| 109 |
|
||||
| 110 | ## KEY CLASSES |
|
|||
| 111 |
|
15 | |||
| 112 | - `SourcesPlugin` — регистрирует extension `sources`. |
|
16 | See the root [README.md](../README.md) and [PUBLISHING.md](../PUBLISHING.md) for | |
| 113 | - `GenericSourceSet` — модель источников/outputs для конкретного имени. |
|
17 | current build and local Ivy publication instructions. | |
| 114 | - `VariantsPlugin` — регистрирует extension `variants` и lifecycle finalize. |
|
|||
| 115 | - `BuildVariantsExtension` — корневой API модели вариантов. |
|
|||
| 116 | - `BuildVariant` — API ролей, attributes и artifact slots варианта. |
|
|||
| 117 | - `VariantsSourcesPlugin` — применяет `variants` + `sources` и запускает адаптер. |
|
|||
| 118 | - `VariantSourcesExtension` — API bind/events registration. |
|
|||
| 119 | - `LayerBindingSpec` — слой-конкретный DSL для policy/configuration source set. |
|
|||
| 120 | - `SourceSetRegistration` — payload `whenRegistered(...)`. |
|
|||
| 121 | - `SourceSetUsageBinding` — payload `whenBound(...)`. |
|
|||
| 122 |
|
18 | |||
| 123 | ## NOTES |
|
|||
| 124 |
|
||||
| 125 | - Marker ids: |
|
|||
| 126 | - `org.implab.gradle-variants` |
|
|||
| 127 | - `org.implab.gradle-variants-sources` |
|
|||
| 128 | - `SourcesPlugin` пока class-only (без marker id). |
|
|||
| 129 |
|
||||
| 130 | ## SEE ALSO |
|
|||
| 131 |
|
||||
| 132 | - `sources-plugin.md` |
|
|||
| 133 | - `variants-plugin.md` |
|
|||
| 134 | - `variant-sources-plugin.md` |
|
|||
| @@ -1,83 +1,7 | |||||
| 1 | # Sources Plugin |
|
1 | # Moved: Sources Plugin | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `SourcesPlugin` и extension `sources`. |
|
|||
| 6 |
|
||||
| 7 | ## SYNOPSIS |
|
|||
| 8 |
|
||||
| 9 | ```groovy |
|
|||
| 10 | // Обычно подключается транзитивно через org.implab.gradle-variants-sources |
|
|||
| 11 |
|
||||
| 12 | sources { |
|
|||
| 13 | register('main') { |
|
|||
| 14 | declareOutputs('compiled', 'typings') |
|
|||
| 15 |
|
||||
| 16 | sets { |
|
|||
| 17 | ts { srcDir 'src/main/ts' } |
|
|||
| 18 | js { srcDir 'src/main/js' } |
|
|||
| 19 | } |
|
|||
| 20 | } |
|
|||
| 21 | } |
|
|||
| 22 | ``` |
|
|||
| 23 |
|
||||
| 24 | ## DESCRIPTION |
|
|||
| 25 |
|
||||
| 26 | `SourcesPlugin` регистрирует extension `sources` типа |
|
|||
| 27 | `NamedDomainObjectContainer<GenericSourceSet>`. |
|
|||
| 28 |
|
||||
| 29 | `GenericSourceSet` — это автономный source bundle с четким контрактом outputs. |
|
|||
| 30 |
|
||||
| 31 | ### sourceSetDir |
|
|||
| 32 |
|
||||
| 33 | Базовый каталог набора. Конвенция по умолчанию: `src/<name>`. |
|
|||
| 34 |
|
||||
| 35 | ### outputsDir |
|
|||
| 36 |
|
||||
| 37 | Базовый каталог результатов набора. Конвенция по умолчанию: `build/<name>`. |
|
|||
| 38 |
|
||||
| 39 | ### sets |
|
|||
| 40 |
|
2 | |||
| 41 | Контейнер `SourceDirectorySet` внутри `GenericSourceSet`. Используется для |
|
3 | The `SourcesPlugin` implementation is now part of the `variants` module, not | |
| 42 | логического разделения подпапок (например `ts`, `js`, `typings`). |
|
4 | the `common` module. | |
| 43 |
|
||||
| 44 | ### outputs contract |
|
|||
| 45 |
|
||||
| 46 | Outputs именованные и должны быть объявлены заранее: |
|
|||
| 47 |
|
||||
| 48 | - `declareOutputs(...)` — декларация доступных output keys; |
|
|||
| 49 | - `output(name)` — доступ к `ConfigurableFileCollection` для output key; |
|
|||
| 50 | - `registerOutput(...)` — регистрация output из файлов или task provider. |
|
|||
| 51 |
|
||||
| 52 | Такой контракт упрощает wiring задач через inputs/outputs без ручного |
|
|||
| 53 | `dependsOn`. |
|
|||
| 54 |
|
||||
| 55 | ## API |
|
|||
| 56 |
|
||||
| 57 | ### SourcesPlugin |
|
|||
| 58 |
|
||||
| 59 | - `apply(Project)` — добавляет extension `sources` в проект. |
|
|||
| 60 | - `getSourcesExtension(Project)` — возвращает контейнер `GenericSourceSet`. |
|
|||
| 61 |
|
5 | |||
| 62 | ### GenericSourceSet |
|
6 | Current documentation is maintained in the root [README.md](../README.md). | |
| 63 |
|
7 | |||
| 64 | - `getSourceSetDir()` — root directory источников набора. |
|
|||
| 65 | - `getOutputsDir()` — root directory результатов набора. |
|
|||
| 66 | - `getSets()` — контейнер поднаборов `SourceDirectorySet`. |
|
|||
| 67 | - `declareOutputs(...)` — объявляет разрешенные output names. |
|
|||
| 68 | - `output(name)` — возвращает `FileCollection` для конкретного output. |
|
|||
| 69 | - `registerOutput(name, files...)` — добавляет файлы в output. |
|
|||
| 70 | - `registerOutput(name, task, mapper)` — связывает output с task provider. |
|
|||
| 71 | - `getAllOutputs()` — агрегированный `FileCollection` всех outputs. |
|
|||
| 72 | - `getAllSourceDirectories()` — агрегированный `FileCollection` всех source dirs. |
|
|||
| 73 |
|
||||
| 74 | ## KEY CLASSES |
|
|||
| 75 |
|
||||
| 76 | - `SourcesPlugin` — регистрация extension `sources`. |
|
|||
| 77 | - `GenericSourceSet` — модель источников и outputs. |
|
|||
| 78 |
|
||||
| 79 | ## NOTES |
|
|||
| 80 |
|
||||
| 81 | - Обращение к `output(name)` без предварительного `declareOutputs(name)` |
|
|||
| 82 | приводит к ошибке валидации. |
|
|||
| 83 | - Плагин `sources` сейчас без marker id. |
|
|||
| @@ -1,354 +1,8 | |||||
| 1 | # Variant Artifacts Plugin |
|
1 | # Moved: Variant Artifacts Plugin | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `VariantsArtifactsPlugin` и extension `variantArtifacts`. |
|
|||
| 6 |
|
||||
| 7 | ## SYNOPSIS |
|
|||
| 8 |
|
||||
| 9 | ```groovy |
|
|||
| 10 | import org.gradle.api.attributes.Attribute |
|
|||
| 11 |
|
||||
| 12 | plugins { |
|
|||
| 13 | id 'org.implab.gradle-variants-artifacts' |
|
|||
| 14 | } |
|
|||
| 15 |
|
||||
| 16 | def variantAttr = Attribute.of('test.variant', String) |
|
|||
| 17 | def slotAttr = Attribute.of('test.slot', String) |
|
|||
| 18 |
|
||||
| 19 | variants { |
|
|||
| 20 | layer('main') |
|
|||
| 21 |
|
||||
| 22 | variant('browser') { |
|
|||
| 23 | role('main') { layers('main') } |
|
|||
| 24 | } |
|
|||
| 25 | } |
|
|||
| 26 |
|
||||
| 27 | variantSources { |
|
|||
| 28 | bind('main') { |
|
|||
| 29 | configureSourceSet { |
|
|||
| 30 | declareOutputs('types', 'js', 'resources') |
|
|||
| 31 | } |
|
|||
| 32 | } |
|
|||
| 33 | } |
|
|||
| 34 |
|
||||
| 35 | variantArtifacts { |
|
|||
| 36 | variant('browser') { |
|
|||
| 37 | primarySlot('typesPackage') { |
|
|||
| 38 | fromVariant { |
|
|||
| 39 | output('types') |
|
|||
| 40 | } |
|
|||
| 41 | } |
|
|||
| 42 |
|
||||
| 43 | slot('js') { |
|
|||
| 44 | fromVariant { |
|
|||
| 45 | output('js') |
|
|||
| 46 | } |
|
|||
| 47 | } |
|
|||
| 48 |
|
||||
| 49 | slot('resources') { |
|
|||
| 50 | fromVariant { |
|
|||
| 51 | output('resources') |
|
|||
| 52 | } |
|
|||
| 53 | } |
|
|||
| 54 | } |
|
|||
| 55 |
|
||||
| 56 | whenOutgoingVariant { publication -> |
|
|||
| 57 | publication.configureConfiguration { |
|
|||
| 58 | attributes.attribute(variantAttr, publication.variantName()) |
|
|||
| 59 | } |
|
|||
| 60 |
|
||||
| 61 | publication.primarySlot().configureArtifactAttributes { |
|
|||
| 62 | attribute(slotAttr, publication.primarySlot().slotName()) |
|
|||
| 63 | } |
|
|||
| 64 |
|
||||
| 65 | publication.requireSlot('js').configureArtifactAttributes { |
|
|||
| 66 | attribute(slotAttr, 'js') |
|
|||
| 67 | } |
|
|||
| 68 |
|
||||
| 69 | publication.requireSlot('resources').configureArtifactAttributes { |
|
|||
| 70 | attribute(slotAttr, 'resources') |
|
|||
| 71 | } |
|
|||
| 72 | } |
|
|||
| 73 | } |
|
|||
| 74 | ``` |
|
|||
| 75 |
|
||||
| 76 | ## DESCRIPTION |
|
|||
| 77 |
|
||||
| 78 | `VariantsArtifactsPlugin` применяет `VariantsSourcesPlugin`, затем строит |
|
|||
| 79 | outgoing publication model поверх `variantSources`. |
|
|||
| 80 |
|
||||
| 81 | ### publication model |
|
|||
| 82 |
|
||||
| 83 | Для каждого `variantArtifacts.variant('<name>')` публикуется один outgoing |
|
|||
| 84 | build variant: |
|
|||
| 85 |
|
||||
| 86 | - primary configuration `<variant>Elements`; |
|
|||
| 87 | - primary artifact slot на самой configuration; |
|
|||
| 88 | - secondary variants внутри `configuration.outgoing.variants` для остальных slots. |
|
|||
| 89 |
|
||||
| 90 | Пример: |
|
|||
| 91 |
|
||||
| 92 | - `browserElements` |
|
|||
| 93 | - primary slot: `typesPackage` |
|
|||
| 94 | - secondary variants: `js`, `resources` |
|
|||
| 95 |
|
||||
| 96 | Это разделяет: |
|
|||
| 97 |
|
||||
| 98 | - graph selection build variant-а; |
|
|||
| 99 | - artifact selection внутри уже выбранного variant-а. |
|
|||
| 100 |
|
||||
| 101 | ### slot contributions и DSL |
|
|||
| 102 |
|
||||
| 103 | `slot('<name>')` описывает artifact representation не как один файл или одну |
|
|||
| 104 | задачу, а как набор contributions, которые потом materialize-ятся в отдельный |
|
|||
| 105 | `ArtifactAssembly`. |
|
|||
| 106 |
|
||||
| 107 | Текущий DSL поддерживает два вида contributions: |
|
|||
| 108 |
|
||||
| 109 | - topology-aware: |
|
|||
| 110 | - `fromVariant { output(...) }` |
|
|||
| 111 | - `fromRole('<role>') { output(...) }` |
|
|||
| 112 | - `fromLayer('<layer>') { output(...) }` |
|
|||
| 113 | - direct: |
|
|||
| 114 | - `from(someFileOrProviderOrTaskOutput)` |
|
|||
| 115 |
|
||||
| 116 | Смысл DSL по слоям: |
|
|||
| 117 |
|
||||
| 118 | - `fromVariant/fromRole/fromLayer` выбирают область topology model, в которой |
|
|||
| 119 | contribution активен; |
|
|||
| 120 | - `output(...)` выбирает named output соответствующего `GenericSourceSet`; |
|
|||
| 121 | - `from(Object)` добавляет direct contribution, не зависящий от |
|
|||
| 122 | `variantSources` bindings; |
|
|||
| 123 | - итоговый contribution при materialization: |
|
|||
| 124 | - проверяет, подходит ли текущий `SourceSetUsageBinding`; |
|
|||
| 125 | - выдает object для `files.from(...)`; |
|
|||
| 126 | - при необходимости выдает `BindingKey`, если такой contribution должен |
|
|||
| 127 | схлопываться по logical identity. |
|
|||
| 128 |
|
||||
| 129 | Связь slot-а с остальной моделью: |
|
|||
| 130 |
|
||||
| 131 | - `variants` задает topology variant/role/layer; |
|
|||
| 132 | - `variantSources` превращает topology в concrete `SourceSetUsageBinding`; |
|
|||
| 133 | - `variantArtifacts.slot(...)` описывает, какие bindings надо включить в slot; |
|
|||
| 134 | - `VariantArtifactsResolver` превращает contributions slot-а в `FileCollection`; |
|
|||
| 135 | - `VariantArtifactsPlugin` регистрирует для slot-а отдельный `ArtifactAssembly`; |
|
|||
| 136 | - `OutgoingVariantPublication` и `OutgoingArtifactSlotPublication` публикуют |
|
|||
| 137 | уже собранные slot artifacts наружу. |
|
|||
| 138 |
|
||||
| 139 | Каждый slot materialize-ится в отдельный `ArtifactAssembly`: |
|
|||
| 140 |
|
||||
| 141 | - task: `process<Variant><Slot>`; |
|
|||
| 142 | - output dir: `build/variant-artifacts/<variant>/<slot>`. |
|
|||
| 143 |
|
||||
| 144 | ### primary slot |
|
|||
| 145 |
|
||||
| 146 | Primary slot задает artifact, который публикуется как основной artifact |
|
|||
| 147 | configuration `<variant>Elements`. |
|
|||
| 148 |
|
||||
| 149 | Формы DSL: |
|
|||
| 150 |
|
||||
| 151 | ```groovy |
|
|||
| 152 | variant('browser') { |
|
|||
| 153 | primarySlot('typesPackage') |
|
|||
| 154 |
|
||||
| 155 | slot('typesPackage') { |
|
|||
| 156 | fromVariant { output('types') } |
|
|||
| 157 | } |
|
|||
| 158 | } |
|
|||
| 159 | ``` |
|
|||
| 160 |
|
||||
| 161 | или sugar: |
|
|||
| 162 |
|
||||
| 163 | ```groovy |
|
|||
| 164 | variant('browser') { |
|
|||
| 165 | primarySlot('typesPackage') { |
|
|||
| 166 | fromVariant { output('types') } |
|
|||
| 167 | } |
|
|||
| 168 | } |
|
|||
| 169 | ``` |
|
|||
| 170 |
|
||||
| 171 | Правила: |
|
|||
| 172 |
|
||||
| 173 | - если slot один, он считается primary неявно; |
|
|||
| 174 | - если slots несколько, `primarySlot(...)` обязателен; |
|
|||
| 175 | - `primarySlot` должен ссылаться на существующий slot. |
|
|||
| 176 |
|
2 | |||
| 177 | ## LIFECYCLE |
|
3 | The `VariantArtifactsPlugin` implementation is now part of the `variants` | |
| 178 |
|
4 | module, not the `common` module. | ||
| 179 | - `VariantsArtifactsPlugin` ждет `variants.whenFinalized(...)`; |
|
|||
| 180 | - после этого валидирует `variantArtifacts`; |
|
|||
| 181 | - регистрирует `ArtifactAssembly` по каждому slot; |
|
|||
| 182 | - materialize-ит outgoing publications; |
|
|||
| 183 | - вызывает `whenOutgoingVariant(...)`; |
|
|||
| 184 | - callbacks replayable. |
|
|||
| 185 |
|
||||
| 186 | После finalize мутации `variantArtifacts` запрещены. |
|
|||
| 187 |
|
||||
| 188 | ## EVENTS |
|
|||
| 189 |
|
||||
| 190 | ### whenOutgoingVariant |
|
|||
| 191 |
|
||||
| 192 | Replayable callback на готовую outgoing publication variant-а. |
|
|||
| 193 |
|
||||
| 194 | Подходит для: |
|
|||
| 195 |
|
||||
| 196 | - настройки общих attributes build variant-а один раз; |
|
|||
| 197 | - настройки per-slot artifact attributes; |
|
|||
| 198 | - доконфигурации `ArtifactAssembly`. |
|
|||
| 199 |
|
||||
| 200 | ## PAYLOAD TYPES |
|
|||
| 201 |
|
||||
| 202 | ### OutgoingVariantPublication |
|
|||
| 203 |
|
||||
| 204 | Содержит: |
|
|||
| 205 |
|
||||
| 206 | - `variantName()`; |
|
|||
| 207 | - `topologyVariant()`; |
|
|||
| 208 | - `variantArtifact()`; |
|
|||
| 209 | - `configuration()` — primary `<variant>Elements`; |
|
|||
| 210 | - `primarySlot()`; |
|
|||
| 211 | - `slots()` — все slot publications; |
|
|||
| 212 | - `secondarySlots()`; |
|
|||
| 213 | - `findSlot(name)`, `requireSlot(name)`. |
|
|||
| 214 |
|
||||
| 215 | Sugar: |
|
|||
| 216 |
|
||||
| 217 | - `configureConfiguration(Action|Closure)`. |
|
|||
| 218 |
|
||||
| 219 | ### OutgoingArtifactSlotPublication |
|
|||
| 220 |
|
||||
| 221 | Содержит: |
|
|||
| 222 |
|
||||
| 223 | - `slotName()`; |
|
|||
| 224 | - `primary()`; |
|
|||
| 225 | - `slot()` — модель `VariantArtifactSlot`; |
|
|||
| 226 | - `assembly()`. |
|
|||
| 227 |
|
||||
| 228 | Sugar: |
|
|||
| 229 |
|
||||
| 230 | - `configureAssembly(Action|Closure)`; |
|
|||
| 231 | - `configureArtifactAttributes(Action|Closure)`. |
|
|||
| 232 |
|
||||
| 233 | `configureArtifactAttributes(...)` пишет attributes: |
|
|||
| 234 |
|
||||
| 235 | - в `Configuration.attributes` для primary slot; |
|
|||
| 236 | - в `ConfigurationVariant.attributes` для secondary slot. |
|
|||
| 237 |
|
||||
| 238 | ## CONSUMER SIDE |
|
|||
| 239 |
|
||||
| 240 | ### primary resolution |
|
|||
| 241 |
|
||||
| 242 | Обычное inter-project resolution выбирает primary artifact `<variant>Elements`. |
|
|||
| 243 |
|
||||
| 244 | Пример: |
|
|||
| 245 |
|
||||
| 246 | ```groovy |
|
|||
| 247 | configurations { |
|
|||
| 248 | compileView { |
|
|||
| 249 | canBeResolved = true |
|
|||
| 250 | canBeConsumed = false |
|
|||
| 251 | canBeDeclared = true |
|
|||
| 252 | attributes { |
|
|||
| 253 | attribute(variantAttr, 'browser') |
|
|||
| 254 | attribute(slotAttr, 'typesPackage') |
|
|||
| 255 | } |
|
|||
| 256 | } |
|
|||
| 257 | } |
|
|||
| 258 |
|
||||
| 259 | dependencies { |
|
|||
| 260 | compileView project(':producer') |
|
|||
| 261 | } |
|
|||
| 262 | ``` |
|
|||
| 263 |
|
||||
| 264 | ### artifact selection for secondary slots |
|
|||
| 265 |
|
5 | |||
| 266 | Secondary artifacts выбираются через `artifactView`. |
|
6 | Current documentation is maintained in the root [README.md](../README.md) and | |
| 267 |
|
7 | [variant_artifacts.md](../variant_artifacts.md). | ||
| 268 | ```groovy |
|
|||
| 269 | def jsFiles = configurations.compileView.incoming.artifactView { |
|
|||
| 270 | attributes { |
|
|||
| 271 | attribute(slotAttr, 'js') |
|
|||
| 272 | } |
|
|||
| 273 | }.files |
|
|||
| 274 | ``` |
|
|||
| 275 |
|
||||
| 276 | Здесь graph variant уже выбран, а `artifactView` выбирает нужный secondary |
|
|||
| 277 | artifact representation. |
|
|||
| 278 |
|
||||
| 279 | ## VALIDATION |
|
|||
| 280 |
|
||||
| 281 | Проверяется: |
|
|||
| 282 |
|
||||
| 283 | - variant существует в topology model; |
|
|||
| 284 | - slot contributions не ссылаются на неизвестные role/layer; |
|
|||
| 285 | - при нескольких slots указан `primarySlot`; |
|
|||
| 286 | - `primarySlot` ссылается на существующий slot. |
|
|||
| 287 |
|
||||
| 288 | ## API |
|
|||
| 289 |
|
||||
| 290 | ### VariantArtifactsExtension |
|
|||
| 291 |
|
||||
| 292 | - `variant(String)` — получить/создать variant artifact model; |
|
|||
| 293 | - `variant(String, Action|Closure)` — сконфигурировать variant artifact; |
|
|||
| 294 | - `getVariants()` — контейнер variant artifacts; |
|
|||
| 295 | - `findVariant(name)`, `requireVariant(name)`; |
|
|||
| 296 | - `whenOutgoingVariant(...)`. |
|
|||
| 297 |
|
||||
| 298 | ### VariantArtifact |
|
|||
| 299 |
|
||||
| 300 | - `slot(String)` — получить/создать slot; |
|
|||
| 301 | - `slot(String, Action|Closure)` — сконфигурировать slot; |
|
|||
| 302 | - `primarySlot(String)` — назначить primary slot; |
|
|||
| 303 | - `primarySlot(String, Action|Closure)` — sugar: configure slot + mark as primary; |
|
|||
| 304 | - `getSlots()`; |
|
|||
| 305 | - `findSlot(name)`, `requireSlot(name)`; |
|
|||
| 306 | - `findPrimarySlotName()`, `requirePrimarySlotName()`; |
|
|||
| 307 | - `findPrimarySlot()`, `requirePrimarySlot()`. |
|
|||
| 308 |
|
||||
| 309 | ### VariantArtifactSlot |
|
|||
| 310 |
|
8 | |||
| 311 | - `from(Object)`; |
|
|||
| 312 | - `fromVariant(...)`; |
|
|||
| 313 | - `fromRole(String, ...)`; |
|
|||
| 314 | - `fromLayer(String, ...)`. |
|
|||
| 315 |
|
||||
| 316 | Внутренняя модель: |
|
|||
| 317 |
|
||||
| 318 | - slot хранит contributions, а не строковые rules; |
|
|||
| 319 | - `fromVariant/fromRole/fromLayer` создают topology-aware contributions; |
|
|||
| 320 | - `from(Object)` создает direct contribution, который materialize-ится даже |
|
|||
| 321 | если у variant-а нет ни одного `SourceSetUsageBinding`; |
|
|||
| 322 | - slot отдельно хранит topology references для validation: |
|
|||
| 323 | `referencedRoleNames()` и `referencedLayerNames()`. |
|
|||
| 324 |
|
||||
| 325 | ### OutputSelectionSpec |
|
|||
| 326 |
|
||||
| 327 | - `output(name)`; |
|
|||
| 328 | - `output(name, extra...)`. |
|
|||
| 329 |
|
||||
| 330 | `OutputSelectionSpec` это внутренний DSL-buffer для одного блока |
|
|||
| 331 | `fromVariant/fromRole/fromLayer`. Он локально накапливает contributions и |
|
|||
| 332 | передает их в slot только после успешного завершения configure-блока. |
|
|||
| 333 |
|
||||
| 334 | ## KEY CLASSES |
|
|||
| 335 |
|
||||
| 336 | - `VariantsArtifactsPlugin` — plugin adapter и materialization outgoing variants. |
|
|||
| 337 | - `VariantArtifactsExtension` — root DSL и lifecycle. |
|
|||
| 338 | - `VariantArtifact` — outgoing build variant model. |
|
|||
| 339 | - `VariantArtifactSlot` — artifact representation slot. |
|
|||
| 340 | - `VariantArtifactsResolver` — adapter между `variantSources` bindings и |
|
|||
| 341 | contribution model slot-а. |
|
|||
| 342 | - `OutgoingVariantPublication` — payload variant-level publication callback. |
|
|||
| 343 | - `OutgoingArtifactSlotPublication` — payload per-slot publication callback. |
|
|||
| 344 | - `ArtifactAssembly` — assembled files for a slot. |
|
|||
| 345 |
|
||||
| 346 | ## NOTES |
|
|||
| 347 |
|
||||
| 348 | - `common` не навязывает доменную логику выбора primary slot. |
|
|||
| 349 | - `common` не фиксирует значения `usage`, `libraryelements` и прочих |
|
|||
| 350 | slot-specific attributes. |
|
|||
| 351 | - `common` не смешивает эту модель с отдельными publish осями вроде package |
|
|||
| 352 | metadata. |
|
|||
| 353 | - Closure callbacks используют delegate-first; для вложенных closure удобнее |
|
|||
| 354 | явный параметр (`publication -> ...`, `slotPublication -> ...`). |
|
|||
| @@ -1,159 +1,9 | |||||
| 1 | # Variant Sources Plugin |
|
1 | # Moved: Variant Sources Plugin | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `VariantsSourcesPlugin` и extension `variantSources`. |
|
|||
| 6 |
|
||||
| 7 | ## SYNOPSIS |
|
|||
| 8 |
|
||||
| 9 | ```groovy |
|
|||
| 10 | plugins { |
|
|||
| 11 | id 'org.implab.gradle-variants-sources' |
|
|||
| 12 | } |
|
|||
| 13 |
|
||||
| 14 | variants { |
|
|||
| 15 | layer('main') |
|
|||
| 16 |
|
||||
| 17 | variant('browser') { |
|
|||
| 18 | role('main') { layers('main') } |
|
|||
| 19 | } |
|
|||
| 20 |
|
||||
| 21 | variant('node') { |
|
|||
| 22 | role('main') { layers('main') } |
|
|||
| 23 | } |
|
|||
| 24 | } |
|
|||
| 25 |
|
||||
| 26 | variantSources { |
|
|||
| 27 | bind('main').sourceSetNamePattern = '{layer}' |
|
|||
| 28 |
|
||||
| 29 | bind('main') { |
|
|||
| 30 | configureSourceSet { |
|
|||
| 31 | declareOutputs('compiled') |
|
|||
| 32 | } |
|
|||
| 33 | } |
|
|||
| 34 |
|
||||
| 35 | whenRegistered { sourceSetName() } |
|
|||
| 36 | whenBound('browser') { roleName() } |
|
|||
| 37 | } |
|
|||
| 38 | ``` |
|
|||
| 39 |
|
2 | |||
| 40 | ## DESCRIPTION |
|
3 | The `VariantSourcesPlugin` implementation is now part of the `variants` module, | |
| 41 |
|
4 | not the `common` module. | ||
| 42 | `VariantsSourcesPlugin` применяет `VariantsPlugin` и `SourcesPlugin`, затем |
|
|||
| 43 | регистрирует source sets из модели `variants`. |
|
|||
| 44 |
|
||||
| 45 | Точка запуска registration: |
|
|||
| 46 |
|
||||
| 47 | - `variants.whenFinalized(model -> registerSourceSets(...))` |
|
|||
| 48 |
|
||||
| 49 | ### registration |
|
|||
| 50 |
|
||||
| 51 | Для каждой usage-связки `variant/role/layer` вычисляется имя source set, |
|
|||
| 52 | регистрируется `GenericSourceSet` (если он еще не существует), затем |
|
|||
| 53 | вызываются callbacks. |
|
|||
| 54 |
|
||||
| 55 | ### binding |
|
|||
| 56 |
|
||||
| 57 | `bind('<layer>')` возвращает `LayerBindingSpec` и задает policy для этого |
|
|||
| 58 | слоя: |
|
|||
| 59 |
|
||||
| 60 | - как именовать source set; |
|
|||
| 61 | - как конфигурировать source set; |
|
|||
| 62 | - какие callbacks вызвать на registration/binding. |
|
|||
| 63 |
|
||||
| 64 | ### sourceSetNamePattern |
|
|||
| 65 |
|
||||
| 66 | `sourceSetNamePattern` определяет naming policy зарегистрированного source set. |
|
|||
| 67 |
|
||||
| 68 | Default: |
|
|||
| 69 |
|
||||
| 70 | - `{variant}{layerCap}` |
|
|||
| 71 |
|
||||
| 72 | Tokens: |
|
|||
| 73 |
|
||||
| 74 | - `{variant}`, `{variantCap}` |
|
|||
| 75 | - `{role}`, `{roleCap}` |
|
|||
| 76 | - `{layer}`, `{layerCap}` |
|
|||
| 77 |
|
||||
| 78 | Имя санитизируется (`[^A-Za-z0-9_.-] -> _`). |
|
|||
| 79 |
|
5 | |||
| 80 | Ограничение: |
|
6 | Current documentation is maintained in the root [README.md](../README.md), | |
| 81 |
|
7 | [variant_sources.md](../variant_sources.md), and | ||
| 82 | - один `sourceSetName` не может быть порожден разными слоями. |
|
8 | [variant_sources_precedence.md](../variant_sources_precedence.md). | |
| 83 |
|
||||
| 84 | ## EVENTS |
|
|||
| 85 |
|
||||
| 86 | ### whenRegistered |
|
|||
| 87 |
|
||||
| 88 | - callback на новый уникальный source set; |
|
|||
| 89 | - replayable; |
|
|||
| 90 | - при shared source set срабатывает один раз. |
|
|||
| 91 |
|
||||
| 92 | ### whenBound |
|
|||
| 93 |
|
||||
| 94 | - callback на каждую usage-связку `variant/role/layer`; |
|
|||
| 95 | - replayable; |
|
|||
| 96 | - подходит для per-usage логики. |
|
|||
| 97 |
|
||||
| 98 | ### variant filter |
|
|||
| 99 |
|
||||
| 100 | Фильтр по варианту поддерживает только usage-binding: |
|
|||
| 101 |
|
||||
| 102 | - `whenBound(String variantName, ...)` |
|
|||
| 103 |
|
||||
| 104 | ## PAYLOAD TYPES |
|
|||
| 105 |
|
||||
| 106 | `SourceSetRegistration` содержит: |
|
|||
| 107 |
|
||||
| 108 | - `layerName`, `sourceSetName`; |
|
|||
| 109 | - `sourceSet` (`NamedDomainObjectProvider<GenericSourceSet>`). |
|
|||
| 110 |
|
||||
| 111 | Sugar: |
|
|||
| 112 |
|
||||
| 113 | - `configureSourceSet(Action|Closure)`. |
|
|||
| 114 |
|
||||
| 115 | `SourceSetUsageBinding` содержит: |
|
|||
| 116 |
|
||||
| 117 | - `variantName`, `roleName`, `layerName`, `sourceSetName`; |
|
|||
| 118 | - `sourceSet` (`NamedDomainObjectProvider<GenericSourceSet>`). |
|
|||
| 119 |
|
9 | |||
| 120 | Sugar: |
|
|||
| 121 |
|
||||
| 122 | - `configureSourceSet(Action|Closure)`. |
|
|||
| 123 |
|
||||
| 124 | ## API |
|
|||
| 125 |
|
||||
| 126 | ### VariantSourcesExtension |
|
|||
| 127 |
|
||||
| 128 | - `bind(BuildLayer)` — получить/создать binding для canonical layer identity. |
|
|||
| 129 | - `bind(String)` — получить/создать binding по имени слоя. |
|
|||
| 130 | - `bind(String, Action|Closure)` — сконфигурировать binding. |
|
|||
| 131 | - `bind(BuildLayer, Action|Closure)` — сконфигурировать binding по `BuildLayer`. |
|
|||
| 132 | - `getBindings()` — read-only snapshot текущих bindings. |
|
|||
| 133 | - `whenRegistered(...)` — глобальные callbacks регистрации source set. |
|
|||
| 134 | - `whenBound(...)` — глобальные callbacks usage-binding. |
|
|||
| 135 | - `whenBound(String variantName, ...)` — usage-binding callbacks с variant-filter. |
|
|||
| 136 |
|
||||
| 137 | ### LayerBindingSpec |
|
|||
| 138 |
|
||||
| 139 | - `sourceSetNamePattern` — naming policy для source set слоя. |
|
|||
| 140 | - `configureSourceSet(...)` — слойная конфигурация `GenericSourceSet`. |
|
|||
| 141 | - `whenRegistered(...)` — callbacks регистрации в рамках слоя. |
|
|||
| 142 | - `whenBound(...)` — callbacks usage-binding в рамках слоя. |
|
|||
| 143 |
|
||||
| 144 | ## KEY CLASSES |
|
|||
| 145 |
|
||||
| 146 | - `VariantsSourcesPlugin` — точка входа plugin adapter. |
|
|||
| 147 | - `VariantSourcesExtension` — глобальный DSL bind/events. |
|
|||
| 148 | - `LayerBindingSpec` — публичный DSL-contract layer-local policy/callbacks. |
|
|||
| 149 | - `SourceSetRegistration` — payload регистрации source set. |
|
|||
| 150 | - `SourceSetUsageBinding` — payload usage-binding. |
|
|||
| 151 |
|
||||
| 152 | ## NOTES |
|
|||
| 153 |
|
||||
| 154 | - `sourceSetNamePattern` фиксируется при первом чтении в registration |
|
|||
| 155 | (`finalizeValueOnRead`). |
|
|||
| 156 | - runtime state bindings скрыт внутри adapter implementation (`LayerBinding`). |
|
|||
| 157 | - name-based bindings резолвятся к canonical `BuildLayer` через registry `variants`. |
|
|||
| 158 | - Closure callbacks используют delegate-first. |
|
|||
| 159 | - Для вложенных closure лучше явный параметр (`ctx -> ...`). |
|
|||
| @@ -1,112 +1,8 | |||||
| 1 | # Variants Plugin |
|
1 | # Moved: Variants Plugin | |
| 2 |
|
||||
| 3 | ## NAME |
|
|||
| 4 |
|
||||
| 5 | `VariantsPlugin` и extension `variants`. |
|
|||
| 6 |
|
||||
| 7 | ## SYNOPSIS |
|
|||
| 8 |
|
||||
| 9 | ```groovy |
|
|||
| 10 | plugins { |
|
|||
| 11 | id 'org.implab.gradle-variants' |
|
|||
| 12 | } |
|
|||
| 13 |
|
||||
| 14 | variants { |
|
|||
| 15 | layer('mainBase') |
|
|||
| 16 | layer('mainAmd') |
|
|||
| 17 |
|
||||
| 18 | variant('browser') { |
|
|||
| 19 | attributes { |
|
|||
| 20 | string('jsRuntime', 'browser') |
|
|||
| 21 | string('jsModule', 'amd') |
|
|||
| 22 | } |
|
|||
| 23 |
|
||||
| 24 | role('main') { |
|
|||
| 25 | layers('mainBase', 'mainAmd') |
|
|||
| 26 | } |
|
|||
| 27 |
|
||||
| 28 | artifactSlot('mainCompiled') |
|
|||
| 29 | } |
|
|||
| 30 | } |
|
|||
| 31 | ``` |
|
|||
| 32 |
|
||||
| 33 | ## DESCRIPTION |
|
|||
| 34 |
|
||||
| 35 | `VariantsPlugin` задает доменную модель сборки и ее валидацию. Плагин не |
|
|||
| 36 | регистрирует compile/copy/bundle задачи напрямую. |
|
|||
| 37 |
|
||||
| 38 | ### layers |
|
|||
| 39 |
|
||||
| 40 | Глобальные логические слои. Служат единым словарем имен, на которые затем |
|
|||
| 41 | ссылаются роли. |
|
|||
| 42 |
|
||||
| 43 | ### variants |
|
|||
| 44 |
|
||||
| 45 | Именованные варианты исполнения/пакетирования (`browser`, `node`, и т.д.). |
|
|||
| 46 | Вариант агрегирует роли, атрибуты и artifact slots. |
|
|||
| 47 |
|
||||
| 48 | ### roles |
|
|||
| 49 |
|
||||
| 50 | Роль описывает набор слоев в пределах варианта (`main`, `test`, `tools`). |
|
|||
| 51 | Одна роль может ссылаться на несколько слоев. |
|
|||
| 52 |
|
||||
| 53 | ### attributes |
|
|||
| 54 |
|
2 | |||
| 55 | Typed-атрибуты (`Attribute<T> -> Provider<T>`) для передачи параметров в |
|
3 | The `VariantsPlugin` implementation is now part of the `variants` module, not | |
| 56 | адаптеры и публикацию артефактов. |
|
4 | the `common` module. | |
| 57 |
|
||||
| 58 | ### artifact slots |
|
|||
| 59 |
|
||||
| 60 | Именованные слоты ожидаемых артефактов варианта. Используются как контракт |
|
|||
| 61 | между моделью варианта и плагинами, создающими/публикующими результаты. |
|
|||
| 62 |
|
||||
| 63 | ## VALIDATION |
|
|||
| 64 |
|
||||
| 65 | В `finalizeModel()` выполняется проверка: |
|
|||
| 66 |
|
||||
| 67 | - роль не может ссылаться на неизвестный layer; |
|
|||
| 68 | - пустые имена layer запрещены; |
|
|||
| 69 | - имена ролей в варианте должны быть уникальны; |
|
|||
| 70 | - имена artifact slots в варианте должны быть уникальны. |
|
|||
| 71 |
|
||||
| 72 | ## LIFECYCLE |
|
|||
| 73 |
|
||||
| 74 | - `VariantsPlugin` вызывает `variants.finalizeModel()` на `afterEvaluate`. |
|
|||
| 75 | - после `finalizeModel()` мутации модели запрещены. |
|
|||
| 76 | - `whenFinalized(...)` replayable. |
|
|||
| 77 |
|
||||
| 78 | ## API |
|
|||
| 79 |
|
||||
| 80 | ### BuildVariantsExtension |
|
|||
| 81 |
|
5 | |||
| 82 | - `layer(...)` — объявление или конфигурация `BuildLayer`. |
|
6 | Current documentation is maintained in the root [README.md](../README.md) and | |
| 83 | - `variant(...)` — объявление или конфигурация `BuildVariant`. |
|
7 | the design notes in [variant_sources.md](../variant_sources.md). | |
| 84 | - `layers { layer(...) }`, `variants { ... }` — grouped DSL без публикации container API наружу. |
|
|||
| 85 | - `all(...)` — callback для всех вариантов. |
|
|||
| 86 | - `findLayer(name)`, `requireLayer(name)`, `getAllLayers()` — доступ к registry слоев. |
|
|||
| 87 | - `getAll()`, `find(name)`, `require(name)` — доступ к вариантам. |
|
|||
| 88 | - `validate()` — явный запуск валидации. |
|
|||
| 89 | - `finalizeModel()` — валидация + финализация модели. |
|
|||
| 90 | - `whenFinalized(...)` — callback по завершенной модели (replayable). |
|
|||
| 91 |
|
||||
| 92 | ### BuildVariant |
|
|||
| 93 |
|
||||
| 94 | - `attributes { ... }` — атрибуты варианта (+ sugar `string/bool/integer`). |
|
|||
| 95 | - `role(...)`, `roles { ... }` — роли варианта. |
|
|||
| 96 | - `artifactSlot(...)`, `artifactSlots { ... }` — артефактные слоты. |
|
|||
| 97 |
|
8 | |||
| 98 | ## KEY CLASSES |
|
|||
| 99 |
|
||||
| 100 | - `VariantsPlugin` — точка входа плагина. |
|
|||
| 101 | - `BuildVariantsExtension` — root extension и lifecycle. |
|
|||
| 102 | - `BuildVariant` — агрегатная модель варианта. |
|
|||
| 103 | - `BuildLayer` — canonical identity-model слоя. |
|
|||
| 104 | - `BuildRole` — модель роли. |
|
|||
| 105 | - `BuildArtifactSlot` — модель артефактного слота. |
|
|||
| 106 | - `VariantAttributes` — typed wrapper для variant attributes. |
|
|||
| 107 |
|
||||
| 108 | ## NOTES |
|
|||
| 109 |
|
||||
| 110 | - Модель `variants` intentionally agnostic к toolchain. |
|
|||
| 111 | - Layer registry хранится как явная identity-map, а не как публичный `NamedDomainObjectContainer`. |
|
|||
| 112 | - Интеграция с задачами выполняется через `variantSources` и адаптеры. |
|
|||
| @@ -1,2 +1,2 | |||||
| 1 | group=org.implab.gradle |
|
1 | group=org.implab.gradle | |
| 2 | version=1.0 No newline at end of file |
|
2 | version=0.1.0 | |
| @@ -1,5 +1,9 | |||||
| 1 | # Variants and Variant Artifacts |
|
1 | # Variants and Variant Artifacts | |
| 2 |
|
2 | |||
|
|
3 | > Design note. The current user-facing DSL and local publication workflow are | |||
|
|
4 | > documented in [README.md](README.md). Some snippets below are conceptual and | |||
|
|
5 | > describe model direction rather than exact public API. | |||
|
|
6 | ||||
| 3 | ## Overview |
|
7 | ## Overview | |
| 4 |
|
8 | |||
| 5 | This document describes the artifact model built on top of `variants` and |
|
9 | This document describes the artifact model built on top of `variants` and | |
| @@ -592,7 +596,7 model rather than define it. | |||||
| 592 |
|
596 | |||
| 593 | Examples: |
|
597 | Examples: | |
| 594 |
|
598 | |||
| 595 |
- `whenOutgoing |
|
599 | - `whenOutgoingConfiguration(...)` | |
| 596 | - `whenOutgoingSlot(...)` |
|
600 | - `whenOutgoingSlot(...)` | |
| 597 |
|
601 | |||
| 598 | These hooks are adapter-facing customization points over already declared |
|
602 | These hooks are adapter-facing customization points over already declared | |
| @@ -1,5 +1,9 | |||||
| 1 | # Variants and Variant Sources |
|
1 | # Variants and Variant Sources | |
| 2 |
|
2 | |||
|
|
3 | > Design note. The current user-facing DSL and local publication workflow are | |||
|
|
4 | > documented in [README.md](README.md). Some snippets below are conceptual and | |||
|
|
5 | > describe model direction rather than exact public API. | |||
|
|
6 | ||||
| 3 | ## Overview |
|
7 | ## Overview | |
| 4 |
|
8 | |||
| 5 | This document describes a two-layer model for build variants: |
|
9 | This document describes a two-layer model for build variants: | |
| @@ -510,7 +514,8 This policy is intentionally modeled as | |||||
| 510 | property: |
|
514 | property: | |
| 511 |
|
515 | |||
| 512 | * it must be chosen before the first selector rule is added |
|
516 | * it must be chosen before the first selector rule is added | |
| 513 |
* selector rules here mean `variant(...)`, `layer(...)`, |
|
517 | * selector rules here mean `configureEach(...)`, `variant(...)`, `layer(...)`, | |
|
|
518 | and `unit(...)` | |||
| 514 | * once chosen, it cannot be changed later |
|
519 | * once chosen, it cannot be changed later | |
| 515 |
|
|
520 | * it controls runtime behavior, not just a stored value | |
| 516 | * the enforcement point is the first selector registration itself, not variants |
|
521 | * the enforcement point is the first selector registration itself, not variants | |
| @@ -519,7 +524,7 property: | |||||
| 519 | For source sets configured before materialization, selector precedence remains: |
|
524 | For source sets configured before materialization, selector precedence remains: | |
| 520 |
|
|
525 | ||
| 521 | ```text |
|
526 | ```text | |
| 522 | variant < layer < unit |
|
527 | configureEach < variant < layer < unit | |
| 523 |
|
|
528 | ``` | |
| 524 |
|
|
529 | ||
| 525 | For already materialized source sets in `warn` and `allow` modes: |
|
530 | For already materialized source sets in `warn` and `allow` modes: | |
| @@ -16,14 +16,36 Instead, it provides configuration selec | |||||
| 16 |
|
16 | |||
| 17 | ## Selectors |
|
17 | ## Selectors | |
| 18 |
|
18 | |||
| 19 |
|
|
19 | Four selectors are available: | |
| 20 |
|
20 | |||
|
|
21 | - `configureEach(...)` | |||
| 21 | - `variant(...)` |
|
22 | - `variant(...)` | |
| 22 | - `layer(...)` |
|
23 | - `layer(...)` | |
| 23 | - `unit(...)` |
|
24 | - `unit(...)` | |
| 24 |
|
25 | |||
| 25 | They all target the same set of compile units, but at different levels of specificity. |
|
26 | They all target the same set of compile units, but at different levels of specificity. | |
| 26 |
|
27 | |||
|
|
28 | ### `configureEach(...)` | |||
|
|
29 | ||||
|
|
30 | `configureEach(...)` applies configuration to every materialized compile-unit | |||
|
|
31 | source set. | |||
|
|
32 | ||||
|
|
33 | Example: | |||
|
|
34 | ||||
|
|
35 | ```groovy | |||
|
|
36 | variantSources { | |||
|
|
37 | configureEach { | |||
|
|
38 | sourceSet { | |||
|
|
39 | declareOutputs("js") | |||
|
|
40 | } | |||
|
|
41 | } | |||
|
|
42 | } | |||
|
|
43 | ``` | |||
|
|
44 | ||||
|
|
45 | Use this selector for global source-set conventions. | |||
|
|
46 | ||||
|
|
47 | --- | |||
|
|
48 | ||||
| 27 | ### `variant(...)` |
|
49 | ### `variant(...)` | |
| 28 |
|
50 | |||
| 29 | `variant(...)` applies configuration to all compile units that belong to the given variant. |
|
51 | `variant(...)` applies configuration to all compile units that belong to the given variant. | |
| @@ -33,9 +55,11 Example: | |||||
| 33 | ```groovy |
|
55 | ```groovy | |
| 34 | variantSources { |
|
56 | variantSources { | |
| 35 | variant("browser") { |
|
57 | variant("browser") { | |
|
|
58 | sourceSet { | |||
| 36 | declareOutputs("js", "dts") |
|
59 | declareOutputs("js", "dts") | |
| 37 | } |
|
60 | } | |
| 38 | } |
|
61 | } | |
|
|
62 | } | |||
| 39 | ``` |
|
63 | ``` | |
| 40 |
|
64 | |||
| 41 | This affects all compile units of `browser`, for example: |
|
65 | This affects all compile units of `browser`, for example: | |
| @@ -57,11 +81,13 Example: | |||||
| 57 | ```groovy |
|
81 | ```groovy | |
| 58 | variantSources { |
|
82 | variantSources { | |
| 59 | layer("main") { |
|
83 | layer("main") { | |
| 60 |
s |
|
84 | sourceSet { | |
|
|
85 | sets.create("ts") { | |||
| 61 | srcDir("src/main/ts") |
|
86 | srcDir("src/main/ts") | |
| 62 | } |
|
87 | } | |
| 63 | } |
|
88 | } | |
| 64 | } |
|
89 | } | |
|
|
90 | } | |||
| 65 | ``` |
|
91 | ``` | |
| 66 |
|
92 | |||
| 67 | This affects all compile units with layer `main`, for example: |
|
93 | This affects all compile units with layer `main`, for example: | |
| @@ -83,11 +109,13 Example: | |||||
| 83 | ```groovy |
|
109 | ```groovy | |
| 84 | variantSources { |
|
110 | variantSources { | |
| 85 | unit("browser", "main") { |
|
111 | unit("browser", "main") { | |
| 86 |
|
|
112 | sourceSet { | |
|
|
113 | sets.create("resources") { | |||
| 87 | srcDir("src/browserMain/resources") |
|
114 | srcDir("src/browserMain/resources") | |
| 88 | } |
|
115 | } | |
| 89 | } |
|
116 | } | |
| 90 | } |
|
117 | } | |
|
|
118 | } | |||
| 91 | ``` |
|
119 | ``` | |
| 92 |
|
120 | |||
| 93 | This affects only: |
|
121 | This affects only: | |
| @@ -103,14 +131,15 Use this selector for the most specific | |||||
| 103 | For each compile unit, source-set configuration is applied in the following order: |
|
131 | For each compile unit, source-set configuration is applied in the following order: | |
| 104 |
|
132 | |||
| 105 | ```text |
|
133 | ```text | |
| 106 | variant < layer < unit |
|
134 | configureEach < variant < layer < unit | |
| 107 | ``` |
|
135 | ``` | |
| 108 |
|
136 | |||
| 109 | This means: |
|
137 | This means: | |
| 110 |
|
138 | |||
| 111 |
1. ` |
|
139 | 1. `configureEach(...)` actions are applied first | |
| 112 |
2. ` |
|
140 | 2. `variant(...)` actions are applied next | |
| 113 |
3. ` |
|
141 | 3. `layer(...)` actions are applied next | |
|
|
142 | 4. `unit(...)` actions are applied last | |||
| 114 |
|
143 | |||
| 115 | Each next level is allowed to refine or override the previous one. |
|
144 | Each next level is allowed to refine or override the previous one. | |
| 116 |
|
145 | |||
| @@ -160,7 +189,8 Available modes: | |||||
| 160 | Policy rules: |
|
189 | Policy rules: | |
| 161 |
|
190 | |||
| 162 | - the policy must be chosen before the first selector rule is added |
|
191 | - the policy must be chosen before the first selector rule is added | |
| 163 |
- selector rules here mean `variant(...)`, `layer(...)`, |
|
192 | - selector rules here mean `configureEach(...)`, `variant(...)`, `layer(...)`, | |
|
|
193 | and `unit(...)` | |||
| 164 | - once chosen, the policy cannot be changed later |
|
194 | - once chosen, the policy cannot be changed later | |
| 165 | - the policy is single-valued; it is not intended to be switched during further |
|
195 | - the policy is single-valued; it is not intended to be switched during further | |
| 166 | configuration |
|
196 | configuration | |
| @@ -173,8 +203,8 Operationally: | |||||
| 173 | already materialized targets |
|
203 | already materialized targets | |
| 174 | - `warn` and `allow` keep compatibility with imperative late mutation |
|
204 | - `warn` and `allow` keep compatibility with imperative late mutation | |
| 175 | - in `warn` and `allow`, already materialized targets observe the late action in |
|
205 | - in `warn` and `allow`, already materialized targets observe the late action in | |
| 176 |
actual registration order, not in reconstructed |
|
206 | actual registration order, not in reconstructed | |
| 177 | order |
|
207 | `configureEach < variant < layer < unit` order | |
| 178 |
|
208 | |||
| 179 | --- |
|
209 | --- | |
| 180 |
|
210 | |||
| @@ -234,11 +264,11 Naming policy is fixed when the finalize | |||||
| 234 |
|
264 | |||
| 235 | Operationally this means: |
|
265 | Operationally this means: | |
| 236 |
|
266 | |||
| 237 |
- policy selection must happen before `variantSources.when |
|
267 | - policy selection must happen before `variantSources.whenAvailable(...)` | |
| 238 | becomes observable |
|
268 | becomes observable | |
| 239 | - compile-unit names are projected and validated before queued |
|
269 | - compile-unit names are projected and validated before queued | |
| 240 |
`when |
|
270 | `whenAvailable(...)` callbacks are replayed | |
| 241 |
- changing naming policy from inside a `when |
|
271 | - changing naming policy from inside a `whenAvailable(...)` callback is too late | |
| 242 |
|
272 | |||
| 243 | --- |
|
273 | --- | |
| 244 |
|
274 | |||
| @@ -246,22 +276,34 Operationally this means: | |||||
| 246 |
|
276 | |||
| 247 | ```groovy |
|
277 | ```groovy | |
| 248 | variantSources { |
|
278 | variantSources { | |
|
|
279 | configureEach { | |||
|
|
280 | sourceSet { | |||
|
|
281 | declareOutputs("js", "dts") | |||
|
|
282 | } | |||
|
|
283 | } | |||
|
|
284 | ||||
| 249 | variant("browser") { |
|
285 | variant("browser") { | |
| 250 | declareOutputs("js", "dts") |
|
286 | sourceSet { | |
|
|
287 | registerOutput("js", layout.projectDirectory.file("inputs/browser.js")) | |||
|
|
288 | } | |||
| 251 | } |
|
289 | } | |
| 252 |
|
290 | |||
| 253 | layer("main") { |
|
291 | layer("main") { | |
| 254 |
s |
|
292 | sourceSet { | |
|
|
293 | sets.create("ts") { | |||
| 255 | srcDir("src/main/ts") |
|
294 | srcDir("src/main/ts") | |
| 256 | } |
|
295 | } | |
| 257 | } |
|
296 | } | |
|
|
297 | } | |||
| 258 |
|
298 | |||
| 259 | unit("browser", "main") { |
|
299 | unit("browser", "main") { | |
| 260 |
|
|
300 | sourceSet { | |
|
|
301 | sets.create("resources") { | |||
| 261 | srcDir("src/browserMain/resources") |
|
302 | srcDir("src/browserMain/resources") | |
| 262 | } |
|
303 | } | |
| 263 | } |
|
304 | } | |
| 264 | } |
|
305 | } | |
|
|
306 | } | |||
| 265 | ``` |
|
307 | ``` | |
| 266 |
|
308 | |||
| 267 | For compile unit `(browser, main)` the effective configuration is built in this order: |
|
309 | For compile unit `(browser, main)` the effective configuration is built in this order: | |
| @@ -270,6 +312,9 1. `variant("browser")` | |||||
| 270 | 2. `layer("main")` |
|
312 | 2. `layer("main")` | |
| 271 | 3. `unit("browser", "main")` |
|
313 | 3. `unit("browser", "main")` | |
| 272 |
|
314 | |||
|
|
315 | The global `configureEach(...)` selector is applied before the listed | |||
|
|
316 | variant/layer/unit selectors for every compile unit. | |||
|
|
317 | ||||
| 273 | For compile unit `(browser, rjs)` the effective configuration is built in this order: |
|
318 | For compile unit `(browser, rjs)` the effective configuration is built in this order: | |
| 274 |
|
319 | |||
| 275 | 1. `variant("browser")` |
|
320 | 1. `variant("browser")` | |
| @@ -324,7 +369,7 This guarantees that: | |||||
| 324 | - precedence is: |
|
369 | - precedence is: | |
| 325 |
|
370 | |||
| 326 | ```text |
|
371 | ```text | |
| 327 | variant < layer < unit |
|
372 | configureEach < variant < layer < unit | |
| 328 | ``` |
|
373 | ``` | |
| 329 |
|
374 | |||
| 330 | - registration order is preserved within the same selector level |
|
375 | - registration order is preserved within the same selector level | |
| @@ -3,6 +3,8 plugins { | |||||
| 3 | id "ivy-publish" |
|
3 | id "ivy-publish" | |
| 4 | } |
|
4 | } | |
| 5 |
|
5 | |||
|
|
6 | description = "Variant, source-set, and outgoing artifact model plugins for Gradle builds" | |||
|
|
7 | ||||
| 6 | java { |
|
8 | java { | |
| 7 | withJavadocJar() |
|
9 | withJavadocJar() | |
| 8 | withSourcesJar() |
|
10 | withSourcesJar() | |
| @@ -15,9 +17,7 dependencies { | |||||
| 15 | compileOnly libs.jdt.annotations |
|
17 | compileOnly libs.jdt.annotations | |
| 16 |
|
18 | |||
| 17 | api gradleApi(), |
|
19 | api gradleApi(), | |
| 18 | libs.bundles.jackson |
|
20 | project(":common") | |
| 19 |
|
||||
| 20 | implementation project(":common") |
|
|||
| 21 |
|
21 | |||
| 22 | testImplementation gradleTestKit() |
|
22 | testImplementation gradleTestKit() | |
| 23 | testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4" |
|
23 | testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4" | |
| @@ -52,6 +52,10 publishing { | |||||
| 52 | descriptor.description { |
|
52 | descriptor.description { | |
| 53 | text = providers.provider({ description }) |
|
53 | text = providers.provider({ description }) | |
| 54 | } |
|
54 | } | |
|
|
55 | descriptor.license { | |||
|
|
56 | name = "BSD-2-Clause" | |||
|
|
57 | url = "https://spdx.org/licenses/BSD-2-Clause.html" | |||
| 55 | } |
|
58 | } | |
| 56 | } |
|
59 | } | |
| 57 | } |
|
60 | } | |
|
|
61 | } | |||
General Comments 0
You need to be logged in to leave comments.
Login now
