##// END OF EJS Templates
Rework variant artifacts materialization model...
Rework variant artifacts materialization model Refactor VariantArtifactsPlugin around a live outgoing artifacts context and split artifact publication into explicit internal services: outgoing variant registry, assembly binding, materialization policy hooks, primary-slot convention, and slot assembly handling. Introduce variant artifact slots as identity-first public API and expose materialized assembly handles through ArtifactAssemblies. Add replayable configuration hooks for outgoing configurations, outgoing slots, outgoing variants, and registered assemblies. Create consumable outgoing configurations per variant, bind the primary slot to the root outgoing artifact set, and publish non-primary slots as Gradle outgoing configuration variants. Add deterministic injective task names for slot assembly tasks, use Sync for directory assembly, and configure the default assembly output location under build/variant-assemblies. Make primary-slot selection finalize-on-read and provide a single-slot convention that fails when no unique default can be inferred. Mark artifact internal implementation package as non-public API.

File last commit:

r35:389e9d6c7860 default
r51:9db7822cd26c default
Show More
variant-artifacts-plugin.md
354 lines | 10.5 KiB | text/x-minidsrc | MarkdownLexer
/ common / variant-artifacts-plugin.md
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34 # Variant Artifacts Plugin
## NAME
`VariantsArtifactsPlugin` и extension `variantArtifacts`.
## SYNOPSIS
```groovy
import org.gradle.api.attributes.Attribute
plugins {
id 'org.implab.gradle-variants-artifacts'
}
def variantAttr = Attribute.of('test.variant', String)
def slotAttr = Attribute.of('test.slot', String)
variants {
layer('main')
variant('browser') {
role('main') { layers('main') }
}
}
variantSources {
bind('main') {
configureSourceSet {
declareOutputs('types', 'js', 'resources')
}
}
}
variantArtifacts {
variant('browser') {
primarySlot('typesPackage') {
fromVariant {
output('types')
}
}
slot('js') {
fromVariant {
output('js')
}
}
slot('resources') {
fromVariant {
output('resources')
}
}
}
whenOutgoingVariant { publication ->
publication.configureConfiguration {
attributes.attribute(variantAttr, publication.variantName())
}
publication.primarySlot().configureArtifactAttributes {
attribute(slotAttr, publication.primarySlot().slotName())
}
publication.requireSlot('js').configureArtifactAttributes {
attribute(slotAttr, 'js')
}
publication.requireSlot('resources').configureArtifactAttributes {
attribute(slotAttr, 'resources')
}
}
}
```
## DESCRIPTION
`VariantsArtifactsPlugin` применяет `VariantsSourcesPlugin`, затем строит
outgoing publication model поверх `variantSources`.
### publication model
Для каждого `variantArtifacts.variant('<name>')` публикуется один outgoing
build variant:
- primary configuration `<variant>Elements`;
- primary artifact slot на самой configuration;
- secondary variants внутри `configuration.outgoing.variants` для остальных slots.
Пример:
- `browserElements`
- primary slot: `typesPackage`
- secondary variants: `js`, `resources`
Это разделяет:
- graph selection build variant-а;
- artifact selection внутри уже выбранного variant-а.
cin
Refactor variant artifact slots into contribution-based inputs
r35 ### slot contributions и DSL
`slot('<name>')` описывает artifact representation не как один файл или одну
задачу, а как набор contributions, которые потом materialize-ятся в отдельный
`ArtifactAssembly`.
Текущий DSL поддерживает два вида contributions:
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34
cin
Refactor variant artifact slots into contribution-based inputs
r35 - topology-aware:
- `fromVariant { output(...) }`
- `fromRole('<role>') { output(...) }`
- `fromLayer('<layer>') { output(...) }`
- direct:
- `from(someFileOrProviderOrTaskOutput)`
Смысл DSL по слоям:
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34
cin
Refactor variant artifact slots into contribution-based inputs
r35 - `fromVariant/fromRole/fromLayer` выбирают область topology model, в которой
contribution активен;
- `output(...)` выбирает named output соответствующего `GenericSourceSet`;
- `from(Object)` добавляет direct contribution, не зависящий от
`variantSources` bindings;
- итоговый contribution при materialization:
- проверяет, подходит ли текущий `SourceSetUsageBinding`;
- выдает object для `files.from(...)`;
- при необходимости выдает `BindingKey`, если такой contribution должен
схлопываться по logical identity.
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34
cin
Refactor variant artifact slots into contribution-based inputs
r35 Связь slot-а с остальной моделью:
- `variants` задает topology variant/role/layer;
- `variantSources` превращает topology в concrete `SourceSetUsageBinding`;
- `variantArtifacts.slot(...)` описывает, какие bindings надо включить в slot;
- `VariantArtifactsResolver` превращает contributions slot-а в `FileCollection`;
- `VariantArtifactsPlugin` регистрирует для slot-а отдельный `ArtifactAssembly`;
- `OutgoingVariantPublication` и `OutgoingArtifactSlotPublication` публикуют
уже собранные slot artifacts наружу.
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34
Каждый slot materialize-ится в отдельный `ArtifactAssembly`:
- task: `process<Variant><Slot>`;
- output dir: `build/variant-artifacts/<variant>/<slot>`.
### primary slot
Primary slot задает artifact, который публикуется как основной artifact
configuration `<variant>Elements`.
Формы DSL:
```groovy
variant('browser') {
primarySlot('typesPackage')
slot('typesPackage') {
fromVariant { output('types') }
}
}
```
или sugar:
```groovy
variant('browser') {
primarySlot('typesPackage') {
fromVariant { output('types') }
}
}
```
Правила:
- если slot один, он считается primary неявно;
- если slots несколько, `primarySlot(...)` обязателен;
- `primarySlot` должен ссылаться на существующий slot.
## LIFECYCLE
- `VariantsArtifactsPlugin` ждет `variants.whenFinalized(...)`;
- после этого валидирует `variantArtifacts`;
- регистрирует `ArtifactAssembly` по каждому slot;
- materialize-ит outgoing publications;
- вызывает `whenOutgoingVariant(...)`;
- callbacks replayable.
После finalize мутации `variantArtifacts` запрещены.
## EVENTS
### whenOutgoingVariant
Replayable callback на готовую outgoing publication variant-а.
Подходит для:
- настройки общих attributes build variant-а один раз;
- настройки per-slot artifact attributes;
- доконфигурации `ArtifactAssembly`.
## PAYLOAD TYPES
### OutgoingVariantPublication
Содержит:
- `variantName()`;
- `topologyVariant()`;
- `variantArtifact()`;
- `configuration()` — primary `<variant>Elements`;
- `primarySlot()`;
- `slots()` — все slot publications;
- `secondarySlots()`;
- `findSlot(name)`, `requireSlot(name)`.
Sugar:
- `configureConfiguration(Action|Closure)`.
### OutgoingArtifactSlotPublication
Содержит:
- `slotName()`;
- `primary()`;
- `slot()` — модель `VariantArtifactSlot`;
- `assembly()`.
Sugar:
- `configureAssembly(Action|Closure)`;
- `configureArtifactAttributes(Action|Closure)`.
`configureArtifactAttributes(...)` пишет attributes:
- в `Configuration.attributes` для primary slot;
- в `ConfigurationVariant.attributes` для secondary slot.
## CONSUMER SIDE
### primary resolution
Обычное inter-project resolution выбирает primary artifact `<variant>Elements`.
Пример:
```groovy
configurations {
compileView {
canBeResolved = true
canBeConsumed = false
canBeDeclared = true
attributes {
attribute(variantAttr, 'browser')
attribute(slotAttr, 'typesPackage')
}
}
}
dependencies {
compileView project(':producer')
}
```
### artifact selection for secondary slots
Secondary artifacts выбираются через `artifactView`.
```groovy
def jsFiles = configurations.compileView.incoming.artifactView {
attributes {
attribute(slotAttr, 'js')
}
}.files
```
Здесь graph variant уже выбран, а `artifactView` выбирает нужный secondary
artifact representation.
## VALIDATION
Проверяется:
- variant существует в topology model;
cin
Refactor variant artifact slots into contribution-based inputs
r35 - slot contributions не ссылаются на неизвестные role/layer;
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34 - при нескольких slots указан `primarySlot`;
- `primarySlot` ссылается на существующий slot.
## API
### VariantArtifactsExtension
- `variant(String)` — получить/создать variant artifact model;
- `variant(String, Action|Closure)` — сконфигурировать variant artifact;
- `getVariants()` — контейнер variant artifacts;
- `findVariant(name)`, `requireVariant(name)`;
- `whenOutgoingVariant(...)`.
### VariantArtifact
- `slot(String)` — получить/создать slot;
- `slot(String, Action|Closure)` — сконфигурировать slot;
- `primarySlot(String)` — назначить primary slot;
- `primarySlot(String, Action|Closure)` — sugar: configure slot + mark as primary;
- `getSlots()`;
- `findSlot(name)`, `requireSlot(name)`;
- `findPrimarySlotName()`, `requirePrimarySlotName()`;
- `findPrimarySlot()`, `requirePrimarySlot()`.
### VariantArtifactSlot
cin
Refactor variant artifact slots into contribution-based inputs
r35 - `from(Object)`;
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34 - `fromVariant(...)`;
- `fromRole(String, ...)`;
- `fromLayer(String, ...)`.
cin
Refactor variant artifact slots into contribution-based inputs
r35 Внутренняя модель:
- slot хранит contributions, а не строковые rules;
- `fromVariant/fromRole/fromLayer` создают topology-aware contributions;
- `from(Object)` создает direct contribution, который materialize-ится даже
если у variant-а нет ни одного `SourceSetUsageBinding`;
- slot отдельно хранит topology references для validation:
`referencedRoleNames()` и `referencedLayerNames()`.
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34 ### OutputSelectionSpec
- `output(name)`;
- `output(name, extra...)`.
cin
Refactor variant artifact slots into contribution-based inputs
r35 `OutputSelectionSpec` это внутренний DSL-buffer для одного блока
`fromVariant/fromRole/fromLayer`. Он локально накапливает contributions и
передает их в slot только после успешного завершения configure-блока.
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34 ## KEY CLASSES
- `VariantsArtifactsPlugin` — plugin adapter и materialization outgoing variants.
- `VariantArtifactsExtension` — root DSL и lifecycle.
- `VariantArtifact` — outgoing build variant model.
- `VariantArtifactSlot` — artifact representation slot.
cin
Refactor variant artifact slots into contribution-based inputs
r35 - `VariantArtifactsResolver` — adapter между `variantSources` bindings и
contribution model slot-а.
cin
Refactor variantArtifacts to variant-level publications with primary and secondary slots
r34 - `OutgoingVariantPublication` — payload variant-level publication callback.
- `OutgoingArtifactSlotPublication` — payload per-slot publication callback.
- `ArtifactAssembly` — assembled files for a slot.
## NOTES
- `common` не навязывает доменную логику выбора primary slot.
- `common` не фиксирует значения `usage`, `libraryelements` и прочих
slot-specific attributes.
- `common` не смешивает эту модель с отдельными publish осями вроде package
metadata.
- Closure callbacks используют delegate-first; для вложенных closure удобнее
явный параметр (`publication -> ...`, `slotPublication -> ...`).