##// END OF EJS Templates
variants: stabilize artifact slot materialization
cin -
r55:a06b08ec0a7f default
parent child
Show More
@@ -49,7 +49,7 public abstract class VariantArtifactsPl
49 // wire artifact assemblies to configuration variants
49 // wire artifact assemblies to configuration variants
50 var assembliesBridge = new ArtifactAssemblyBinder(assemblies);
50 var assembliesBridge = new ArtifactAssemblyBinder(assemblies);
51 var primarySlotConvention = new SingleSlotConvention(providers);
51 var primarySlotConvention = new SingleSlotConvention(providers);
52 var materializationHandler = new MaterializationPolicyHandler();
52 var materializationHandler = new MaterializationPolicyHandler(objects);
53
53
54 // bind slot assemblies to outgoing variants
54 // bind slot assemblies to outgoing variants
55 outgoing.configureEach(assembliesBridge::execute);
55 outgoing.configureEach(assembliesBridge::execute);
@@ -51,6 +51,11 public interface ArtifactAssemblies {
51 */
51 */
52 void configureEach(Action<? super ArtifactAssembly> action);
52 void configureEach(Action<? super ArtifactAssembly> action);
53
53
54 /** Π˜Ρ‰Π΅Ρ‚ зарСгистрированный слот */
54 /**
55 * Finds a registered assembly for the given slot identity.
56 *
57 * @param slot slot identity inside a variant outgoing contract
58 * @return registered assembly, if the slot body has already been materialized
59 */
55 Optional<ArtifactAssembly> find(ArtifactSlot slot);
60 Optional<ArtifactAssembly> find(ArtifactSlot slot);
56 }
61 }
@@ -11,7 +11,7 import groovy.lang.Closure;
11 * Materialized root outgoing configuration of a variant.
11 * Materialized root outgoing configuration of a variant.
12 *
12 *
13 * <p>This is a variant-level publication hook. Slot-specific publication state is exposed separately via
13 * <p>This is a variant-level publication hook. Slot-specific publication state is exposed separately via
14 * {@link OutgoingArtifactSlotSpec}.
14 * {@link OutgoingConfigurationSlotSpec}.
15 */
15 */
16 public interface OutgoingConfigurationSpec {
16 public interface OutgoingConfigurationSpec {
17 /**
17 /**
@@ -8,43 +8,56 import org.gradle.api.provider.Property;
8 import org.implab.gradle.variants.core.Variant;
8 import org.implab.gradle.variants.core.Variant;
9
9
10 /**
10 /**
11 * ΠžΠΏΠΈΡΡ‹Π²Π°Π΅Ρ‚ ΠΈΡΡ…ΠΎΠ΄ΡΡ‰ΡƒΡŽ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π°
11 * Plugin model object for one variant-level outgoing contract.
12 *
12 *
13 * Π—Π°Π΄Π°Π΅Ρ‚ связь ΠΌΠ΅ΠΆΠ΄Ρƒ модСлью Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠ² ΠΈ модСлью ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ gradle Ρ‡Π΅Ρ€Π΅Π·
13 * <p>An outgoing variant connects a core {@link Variant} identity with the lazy
14 * свойство {@link #getConfiguration()}. Π’Π°ΠΊΠΆΠ΅ Π·Π°Π΄Π°Π΅Ρ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ ось слотов
14 * Gradle consumable configuration registered for that variant. It also exposes a
15 * ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ, Π½ΠΎ Π½Π΅ Π·Π°Π΄Π°Π΅Ρ‚ ΠΏΡ€Π°Π²ΠΈΠ» связывания этих слотов с самой ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠ΅ΠΉ
15 * live container of slot identities. Slot identities are only declarations and do
16 * ΠΈ ΠΈΡ… содСрТимым. Π‘Π°ΠΌΡ‹ΠΉ простой Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ это {@link ArtifactAssemblies}.
16 * not imply that a Gradle outgoing artifact variant or an {@link ArtifactAssembly}
17 * has been materialized.
17 */
18 */
18 public interface OutgoingVariant {
19 public interface OutgoingVariant {
19 /**
20 /**
20 * Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ строится Outgoing конфигурация
21 * Returns the variant that owns this outgoing contract.
22 *
23 * @return variant identity
21 */
24 */
22 Variant getVariant();
25 Variant getVariant();
23
26
24 /**
27 /**
25 * ΠŸΡ€ΠΎΠ²Π°ΠΉΠ΄Π΅Ρ€ зарСгистрированной ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
28 * Returns the provider of the registered consumable outgoing configuration.
29 *
30 * @return outgoing configuration provider
26 */
31 */
27 NamedDomainObjectProvider<? extends Configuration> getConfiguration();
32 NamedDomainObjectProvider<? extends Configuration> getConfiguration();
28
33
34 /**
35 * Configures the registered outgoing configuration.
36 *
37 * @param action configuration action
38 */
29 default void configureOutgoing(Action<? super Configuration> action) {
39 default void configureOutgoing(Action<? super Configuration> action) {
30 getConfiguration().configure(action);
40 getConfiguration().configure(action);
31 }
41 }
32
42
33 /**
43 /**
34 * Π‘Π»ΠΎΡ‚Ρ‹ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ, данная коллСкция Тивая, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для
44 * Returns the live slot identity container.
35 * получСния ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎΠ± ΠΎΠ±ΡŠΡΠ²Π»Π΅Π½Π½Ρ‹Ρ… слотах, Π½ΠΎ эти слоты Π½Π΅
45 *
36 * обязаны Π±Ρ‹Ρ‚ΡŒ сконфигурированы, Ρ‚.Π΅. это Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Identity.
46 * <p>This collection is intended for discovery and selection. Slot presence does
47 * not guarantee that the slot has a configured assembly body or a materialized
48 * Gradle outgoing artifact variant.
37 *
49 *
38 * @see {@link ArtifactSlot}
50 * @see {@link ArtifactSlot}
39 */
51 */
40 NamedDomainObjectContainer<Slot> getSlots();
52 NamedDomainObjectContainer<Slot> getSlots();
41
53
42 /**
54 /**
43 * Основной Π½Π°Π±ΠΎΡ€ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ΠΎΠ² (primary variant) для исходящСй ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
55 * Returns the primary slot property.
44 *
56 *
45 * <p>
57 * <p>If exactly one slot is declared, the single-slot convention uses that slot as
46 * Если Π² свойствС {@link #getSlots()} Π΅ΡΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ слой, Ρ‚ΠΎ ΠΏΠΎ ΠΊΠΎΠ½Π²Π΅Π½Ρ†ΠΈΠΈ ΠΎΠ½
58 * the primary one. Reading this property finalizes the selected primary slot.
47 * считаСтся Ρ‚Π°ΠΊΠΆΠ΅ основным.
59 *
60 * @return primary slot property
48 */
61 */
49 Property<Slot> getPrimarySlot();
62 Property<Slot> getPrimarySlot();
50 }
63 }
@@ -7,29 +7,80 import org.gradle.api.InvalidUserDataExc
7 import org.implab.gradle.variants.core.Variant;
7 import org.implab.gradle.variants.core.Variant;
8
8
9 /**
9 /**
10 * ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π°ΠΌΠΈ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ, становится доступным послС
10 * Live context for declaring and observing variant outgoing publications.
11 * Ρ„ΠΈΠ½Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠ². ЀактичСски являСтся ΠΆΠΈΠ²ΠΎΠΉ модСлью
11 *
12 * <p>The context becomes available after the core variant model has been finalized.
13 * It owns variant-level outgoing declarations, assembly lookup, and hooks for
14 * materialized Gradle-facing publication state.
12 */
15 */
13 public interface OutgoingVariantsContext {
16 public interface OutgoingVariantsContext {
14
17
18 /**
19 * Returns the assembly lookup service.
20 *
21 * <p>Assemblies are stateful slot bodies resolved from cheap {@link ArtifactSlot}
22 * identities.
23 *
24 * @return assembly lookup service
25 */
15 ArtifactAssemblies getAssemblies();
26 ArtifactAssemblies getAssemblies();
16
27
28 /**
29 * Configures artifact slots of the given variant.
30 *
31 * @param variant variant identity
32 * @param action variant artifact declaration
33 */
17 void configureVariant(Variant variant, Action<? super VariantArtifactsSpec> action);
34 void configureVariant(Variant variant, Action<? super VariantArtifactsSpec> action);
18
35
19 /**
36 /**
20 * Replayable hook для всСх ΠΎΠ±ΡŠΡΠ²Π»Π΅Π½Π½Ρ‹Ρ… ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ
37 * Registers a replayable action for declared outgoing variants.
38 *
39 * <p>The action receives the plugin model object, not necessarily a materialized
40 * Gradle publication. Use {@link #whenOutgoingConfiguration(Action)} and
41 * {@link #whenOutgoingSlot(Action)} for materialized Gradle-facing state.
42 *
43 * @param action outgoing variant action
21 */
44 */
22 void configureEach(Action<? super OutgoingVariant> action);
45 void configureEach(Action<? super OutgoingVariant> action);
23
46
47 /**
48 * Finds the outgoing model for the given variant.
49 *
50 * @param variant variant identity
51 * @return outgoing model, if declared
52 */
24 Optional<OutgoingVariant> findOutgoing(Variant variant);
53 Optional<OutgoingVariant> findOutgoing(Variant variant);
25
54
55 /**
56 * Requires the outgoing model for the given variant.
57 *
58 * @param variant variant identity
59 * @return outgoing model
60 * @throws InvalidUserDataException if the outgoing variant is not declared
61 */
26 default OutgoingVariant requireOutgoing(Variant variant) {
62 default OutgoingVariant requireOutgoing(Variant variant) {
27 return findOutgoing(variant)
63 return findOutgoing(variant)
28 .orElseThrow(() -> new InvalidUserDataException("Outgoing variant '" + variant + "' isn't registered"));
64 .orElseThrow(() -> new InvalidUserDataException("Outgoing variant '" + variant + "' isn't registered"));
29 }
65 }
30
66
67 /**
68 * Registers a replayable action for materialized variant-level outgoing
69 * configurations.
70 *
71 * @param action materialized outgoing configuration action
72 */
31 void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action);
73 void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action);
32
74
75 /**
76 * Registers a replayable action for materialized slot publications.
77 *
78 * <p>Slot publication hooks follow the Gradle outgoing publication model. A
79 * declared slot identity by itself does not guarantee that a slot publication has
80 * been materialized.
81 *
82 * @param action materialized slot publication action
83 */
33 void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action);
84 void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action);
34
85
35
86
@@ -17,7 +17,6 public interface VariantArtifactsSpec {
17 *
17 *
18 * @param name slot name
18 * @param name slot name
19 * @param action slot declaration
19 * @param action slot declaration
20 * @return slot identity
21 */
20 */
22 void slot(String name, Action<? super ArtifactAssemblySpec> action);
21 void slot(String name, Action<? super ArtifactAssemblySpec> action);
23
22
@@ -30,7 +29,6 public interface VariantArtifactsSpec {
30 *
29 *
31 * @param name slot name
30 * @param name slot name
32 * @param action slot declaration
31 * @param action slot declaration
33 * @return slot identity
34 */
32 */
35 void primarySlot(String name, Action<? super ArtifactAssemblySpec> action);
33 void primarySlot(String name, Action<? super ArtifactAssemblySpec> action);
36
34
@@ -7,8 +7,7 import org.implab.gradle.variants.artifa
7 import org.implab.gradle.variants.artifacts.OutgoingVariant;
7 import org.implab.gradle.variants.artifacts.OutgoingVariant;
8
8
9 /**
9 /**
10 * БвязываСт описаниС исходящих ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ gradle ΠΈ сборку содСрТимого слотов
10 * Binds materialized slot assemblies to Gradle outgoing publications.
11 * ΠΈΠ· {@link ArtifactAssemblies}
12 */
11 */
13 @NonNullByDefault
12 @NonNullByDefault
14 public class ArtifactAssemblyBinder implements Action<OutgoingVariant> {
13 public class ArtifactAssemblyBinder implements Action<OutgoingVariant> {
@@ -25,28 +24,29 public class ArtifactAssemblyBinder impl
25 var primarySlotProvider = outgoingVariant.getPrimarySlot();
24 var primarySlotProvider = outgoingVariant.getPrimarySlot();
26 var variant = outgoingVariant.getVariant();
25 var variant = outgoingVariant.getVariant();
27
26
28 // связываСм ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ
27 // Bind publication state when the owning configuration is materialized.
29 outgoingVariant.configureOutgoing(configuration -> {
28 outgoingVariant.configureOutgoing(configuration -> {
30 var primarySlot = primarySlotProvider.get();
29 var primarySlot = primarySlotProvider.get();
31 var outgoing = configuration.getOutgoing();
30 var outgoing = configuration.getOutgoing();
32
31
33 // связываСм основной Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
32 // Bind the primary artifact set to the root outgoing configuration.
34 resolver.when(
33 resolver.when(
35 new ArtifactSlot(variant, primarySlot),
34 new ArtifactSlot(variant, primarySlot),
36 assembly -> outgoing.artifact(assembly.getArtifact()));
35 assembly -> outgoing.artifact(assembly.getArtifact()));
37
36
38 // для всСх ΠΎΠ±ΡŠΡΠ²Π»Π΅Π½Π½Ρ‹Ρ… слотов
37 // Bind non-primary slots to Gradle secondary artifact variants.
39 slots.all(slot -> {
38 slots.all(slot -> {
40 // ΠΊΡ€ΠΎΠΌΠ΅ основного
41 if (slot.equals(primarySlot))
39 if (slot.equals(primarySlot))
42 return;
40 return;
43
41
44 // связываСм Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Ρ‹
45 resolver.when(
42 resolver.when(
46 new ArtifactSlot(variant, slot),
43 new ArtifactSlot(variant, slot),
44 // Gradle artifact variants must be created while the owning
45 // configuration is being materialized. Lazy registration may
46 // otherwise be realized only after dependency resolution starts.
47 assembly -> outgoing.getVariants()
47 assembly -> outgoing.getVariants()
48 .register(slot.getName())
48 .create(slot.getName())
49 .configure(cv -> cv.artifact(assembly.getArtifact())));
49 .artifact(assembly.getArtifact()));
50 });
50 });
51 });
51 });
52 }
52 }
@@ -17,6 +17,7 import org.gradle.api.tasks.Sync;
17 import org.gradle.api.tasks.TaskContainer;
17 import org.gradle.api.tasks.TaskContainer;
18 import org.gradle.language.base.plugins.LifecycleBasePlugin;
18 import org.gradle.language.base.plugins.LifecycleBasePlugin;
19 import org.implab.gradle.common.core.lang.FilePaths;
19 import org.implab.gradle.common.core.lang.FilePaths;
20 import org.implab.gradle.variants.artifacts.ArtifactAssembly;
20 import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec;
21 import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec;
21 import org.implab.gradle.variants.artifacts.ArtifactSlot;
22 import org.implab.gradle.variants.artifacts.ArtifactSlot;
22 import org.implab.gradle.variants.sources.CompileUnit;
23 import org.implab.gradle.variants.sources.CompileUnit;
@@ -25,26 +26,17 import org.implab.gradle.variants.source
25 import org.implab.gradle.variants.sources.SourceSetMaterializer;
26 import org.implab.gradle.variants.sources.SourceSetMaterializer;
26
27
27 /**
28 /**
28 * АдаптСр ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ΠΎΠ², прСдставлСнными Π² Π²ΠΈΠ΄Π΅
29 * Adapts slot contribution declarations to materialized {@link ArtifactAssembly}
29 * {@link SlotContribution},
30 * handles.
30 * ΠΈ ArtifactAssemblyRegistry, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΠΏΠ΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ ΡƒΠΆΠ΅ собранными
31 * {@link ArtifactAssembly}.
32 *
31 *
33 * Π”Π°Π½Π½Ρ‹ΠΉ класс ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° сборку ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ΠΎΠ² Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ΠΎΠ² Π² Π΅Π΄ΠΈΠ½Ρ‹ΠΉ
32 * <p>The handler creates one {@link Sync} task per {@link ArtifactSlot}. The task
34 * ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π·Π°Ρ‚Π΅ΠΌ рСгистрируСтся Π² ArtifactAssemblyRegistry Π² Π²ΠΈΠ΄Π΅
33 * copies all collected slot inputs into a single output directory. That output
35 * {@link ArtifactAssembly}. Π‘Π±ΠΎΡ€ΠΊΠ° ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎΠ³ΠΎ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Π° происходит ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ
34 * directory is then registered in {@link ArtifactAssemblyRegistry} as the
36 * Π·Π°Π΄Π°Ρ‡ΠΈ, которая ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅Ρ‚ всС Π²Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ Π² Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΉ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³. Π—Π°Π΄Π°Ρ‡Π°
35 * published artifact for the slot.
37 * создаСтся для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ {@link ArtifactSlot} ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚
38 * {@link SlotAssembly#inputs()} ΠΊΠ°ΠΊ источник Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ….
39 *
36 *
40 * Для сборки ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ Visitor: ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Π°
37 * <p>Input collection uses {@link SlotContributionVisitor}. Each contribution is
41 * прСдставлСн Π² Π²ΠΈΠ΄Π΅ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ интСрфСйса {@link SlotContribution}, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ
38 * converted to a {@link SlotInputKey}; duplicate keys are ignored so that repeated
42 * ΠΈΠΌΠ΅Π΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ accept, ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‰ΠΈΠΉ Visitor.
39 * topology-based selections do not add the same input twice.
43 * Visitor Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ Π²ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΌ классС {@link ContributionVisitor}, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ
44 * Π·Π½Π°Π΅Ρ‚, ΠΊΠ°ΠΊ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ‚ΠΈΠΏ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π° ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Π΅Π³ΠΎ Π² сборку.
45 * Для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ {@link SlotContribution} создаСтся ΠΊΠ»ΡŽΡ‡ {@link SlotInputKey},
46 * ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для Π΄Π΅Π΄ΡƒΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ: Ссли Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ с Ρ‚Π°ΠΊΠΈΠΌ ΠΆΠ΅ ΠΊΠ»ΡŽΡ‡ΠΎΠΌ ΡƒΠΆΠ΅
47 * Π±Ρ‹Π» Π΄ΠΎΠ±Π°Π²Π»Π΅Π½, Ρ‚ΠΎ ΠΎΠ½ игнорируСтся.
48 */
40 */
49 @NonNullByDefault
41 @NonNullByDefault
50 public class ArtifactAssemblyHandler {
42 public class ArtifactAssemblyHandler {
@@ -97,9 +89,7 public class ArtifactAssemblyHandler {
97 }
89 }
98
90
99 /**
91 /**
100 * Π‘ΠΎΠ·Π΄Π°Π΅Ρ‚ сборку для ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ слота Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Π°, сборка рСгистрируСтся Π²
92 * Creates the assembly task for the given slot and registers its output artifact.
101 * ArtifactAssemblyRegistry, Ссли для слота сборка ΡƒΠΆΠ΅ Π±Ρ‹Π»Π° зарСгистрирована
102 * ΠΊΠ΅ΠΌ-Ρ‚ΠΎ Π΅Ρ‰Π΅, Ρ‚ΠΎ Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ошибка.
103 */
93 */
104 private SlotAssembly createSlotAssembly(ArtifactSlot artifactSlot) {
94 private SlotAssembly createSlotAssembly(ArtifactSlot artifactSlot) {
105 var assembly = new SlotAssembly();
95 var assembly = new SlotAssembly();
@@ -135,13 +125,7 public class ArtifactAssemblyHandler {
135 }
125 }
136
126
137 /**
127 /**
138 * Π‘ΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Ρ‹ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ΠΎΠ² Π² Π΅Π΄ΠΈΠ½Ρ‹ΠΉ источник
128 * Collects slot contributions into one {@link ConfigurableFileCollection}.
139 * {@link ConfigurableFileCollection}.
140 * Для Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ΠΎΠ² {@link SlotContribution} ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ Π΄Π΅Π΄ΡƒΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ:
141 * для каТдого
142 * водящСго Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π° создаСтся ΠΊΠ»ΡŽΡ‡ {@link SlotInputKey} ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ
143 * Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ
144 * с ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΌ ΠΊΠ»ΡŽΡ‡ΠΎΠΌ, ΠΏΠΎΠ²Ρ‚ΠΎΡ€Ρ‹ ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΡŽΡ‚ΡΡ.
145 */
129 */
146 private class ContributionVisitor implements SlotContributionVisitor {
130 private class ContributionVisitor implements SlotContributionVisitor {
147 // artifact slot for this assembly
131 // artifact slot for this assembly
@@ -200,7 +184,7 public class ArtifactAssemblyHandler {
200 }
184 }
201 }
185 }
202
186
203 /** БостояниС для ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ слота */
187 /** Mutable input state for one slot assembly. */
204 class SlotAssembly {
188 class SlotAssembly {
205 private final ConfigurableFileCollection inputs = objects.fileCollection();
189 private final ConfigurableFileCollection inputs = objects.fileCollection();
206 private final Set<SlotInputKey> seen = new HashSet<>();
190 private final Set<SlotInputKey> seen = new HashSet<>();
@@ -15,10 +15,12 import org.implab.gradle.variants.core.R
15 import org.implab.gradle.variants.artifacts.OutputSelectionSpec;
15 import org.implab.gradle.variants.artifacts.OutputSelectionSpec;
16
16
17 /**
17 /**
18 * РСализация DSL ΠΌΠΎΠ΄Π΅Π»ΠΈ, строит Π½Π°Π±ΠΎΡ€ {@link SlotContribution}. ΠŸΡ€ΠΈ построСнии Π½Π°Π±ΠΎΡ€Π°
18 * Default DSL facade for collecting {@link SlotContribution} declarations.
19 * ΠΏΡ€Π°Π²ΠΈΠ»Π° ΠΈ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΡΡ‚ΡŒ Π½Π΅ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡŽΡ‚ΡΡ. По ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΠΈ использования ΠΊΠ»ΠΈΠ΅Π½Ρ‚
20 * Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ {@link #process(Consumer)} для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ².
21 *
19 *
20 * <p>The spec does not validate topology references immediately. It translates DSL
21 * calls to contribution objects and passes them to the supplied consumer; semantic
22 * validation happens later when the assembly handler resolves contributions
23 * against the finalized source model.
22 */
24 */
23 @NonNullByDefault
25 @NonNullByDefault
24 final class DefaultArtifactAssemblySpec implements ArtifactAssemblySpec {
26 final class DefaultArtifactAssemblySpec implements ArtifactAssemblySpec {
@@ -4,11 +4,13 import org.eclipse.jdt.annotation.NonNul
4 import org.gradle.api.Action;
4 import org.gradle.api.Action;
5 import org.gradle.api.artifacts.Configuration;
5 import org.gradle.api.artifacts.Configuration;
6 import org.gradle.api.attributes.AttributeContainer;
6 import org.gradle.api.attributes.AttributeContainer;
7 import org.implab.gradle.internal.ReplayableQueue;
7 import org.gradle.api.model.ObjectFactory;
8 import org.implab.gradle.common.core.lang.ReplayableQueue;
8 import org.implab.gradle.variants.artifacts.ArtifactSlot;
9 import org.implab.gradle.variants.artifacts.ArtifactSlot;
9 import org.implab.gradle.variants.artifacts.OutgoingConfigurationSlotSpec;
10 import org.implab.gradle.variants.artifacts.OutgoingConfigurationSlotSpec;
10 import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec;
11 import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec;
11 import org.implab.gradle.variants.artifacts.OutgoingVariant;
12 import org.implab.gradle.variants.artifacts.OutgoingVariant;
13 import org.implab.gradle.variants.artifacts.Slot;
12 import org.implab.gradle.variants.core.Variant;
14 import org.implab.gradle.variants.core.Variant;
13
15
14 /**
16 /**
@@ -32,17 +34,18 public class MaterializationPolicyHandle
32
34
33 private final ReplayableQueue<OutgoingConfigurationSpec> variantMaterialization = new ReplayableQueue<>();
35 private final ReplayableQueue<OutgoingConfigurationSpec> variantMaterialization = new ReplayableQueue<>();
34 private final ReplayableQueue<OutgoingConfigurationSlotSpec> slotMaterialization = new ReplayableQueue<>();
36 private final ReplayableQueue<OutgoingConfigurationSlotSpec> slotMaterialization = new ReplayableQueue<>();
37 private final ObjectFactory objects;
35
38
36 public MaterializationPolicyHandler() {
39 public MaterializationPolicyHandler(ObjectFactory objects) {
40 this.objects = objects;
37 }
41 }
38
42
39 @Override
43 @Override
40 public void execute(OutgoingVariant outgoingVariant) {
44 public void execute(OutgoingVariant outgoingVariant) {
41 var slots = outgoingVariant.getSlots();
42 var primarySlotProvider = outgoingVariant.getPrimarySlot();
45 var primarySlotProvider = outgoingVariant.getPrimarySlot();
43 var variant = outgoingVariant.getVariant();
46 var variant = outgoingVariant.getVariant();
44
47
45 // связываСм ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ
48 // Materialization hooks are attached to the owning outgoing configuration.
46 outgoingVariant.configureOutgoing(configuration -> {
49 outgoingVariant.configureOutgoing(configuration -> {
47 var primarySlot = primarySlotProvider.get();
50 var primarySlot = primarySlotProvider.get();
48 var outgoing = configuration.getOutgoing();
51 var outgoing = configuration.getOutgoing();
@@ -51,11 +54,13 public class MaterializationPolicyHandle
51
54
52 slotMaterialized(new ArtifactSlot(variant, primarySlot), true, outgoing.getAttributes());
55 slotMaterialized(new ArtifactSlot(variant, primarySlot), true, outgoing.getAttributes());
53
56
54 slots.forEach(slot -> {
57 // Slot publication hooks follow materialized Gradle artifact variants,
58 // not the live slot identity view.
59 outgoing.getVariants().configureEach(variantConfiguration -> {
60 var slot = objects.named(Slot.class, variantConfiguration.getName());
55 if (slot.equals(primarySlot))
61 if (slot.equals(primarySlot))
56 return;
62 return;
57
63
58 var variantConfiguration = outgoing.getVariants().getByName(slot.getName());
59 slotMaterialized(new ArtifactSlot(variant, slot), false, variantConfiguration.getAttributes());
64 slotMaterialized(new ArtifactSlot(variant, slot), false, variantConfiguration.getAttributes());
60 });
65 });
61 });
66 });
@@ -18,7 +18,7 public class SingleSlotConvention implem
18 var slots = outgoingVariant.getSlots();
18 var slots = outgoingVariant.getSlots();
19
19
20 outgoingVariant.getPrimarySlot().convention(
20 outgoingVariant.getPrimarySlot().convention(
21 // Ссли Π΅ΡΡ‚ΡŒ Ρ€ΠΎΠ²Π½ΠΎ ΠΎΠ΄ΠΈΠ½ слот, Ρ‚ΠΎ ΠΎΠ½ считаСтся primary
21 // If exactly one slot is declared, it becomes the primary slot.
22 providers.provider(() -> {
22 providers.provider(() -> {
23 if (slots.size() == 0)
23 if (slots.size() == 0)
24 throw new InvalidUserDataException("No slots declared for " + outgoingVariant.getVariant());
24 throw new InvalidUserDataException("No slots declared for " + outgoingVariant.getVariant());
@@ -33,9 +33,8
33 * }
33 * }
34 * }</pre>
34 * }</pre>
35 *
35 *
36 * <p>After finalization, slot identities can be observed through
36 * <p>After finalization, {@link org.implab.gradle.variants.artifacts.OutgoingVariant} exposes declared slot
37 * {@link org.implab.gradle.variants.artifacts.OutgoingVariantsContext#getSlots()}, while slot bodies are
37 * identities through {@code getSlots()}, while slot bodies are obtained on demand through
38 * obtained on demand through
39 * {@link org.implab.gradle.variants.artifacts.OutgoingVariantsContext#getAssemblies()}.
38 * {@link org.implab.gradle.variants.artifacts.OutgoingVariantsContext#getAssemblies()}.
40 */
39 */
41 package org.implab.gradle.variants.artifacts;
40 package org.implab.gradle.variants.artifacts;
@@ -103,6 +103,74 class VariantArtifactsPluginFunctionalTe
103 }
103 }
104
104
105 @Test
105 @Test
106 void gradleReferenceRegisteredSecondaryArtifactVariantIsNotRealizedBeforeResolution() throws Exception {
107 // Gradle issue: https://github.com/gradle/gradle/issues/27441
108 // Registered outgoing artifact variants are not realized before dependency resolution.
109 writeFile("settings.gradle", """
110 rootProject.name = 'gradle-reference-registered-secondary-variant'
111 include 'producer', 'consumer'
112 """);
113 writeFile("producer/inputs/typesPackage", "types\n");
114 writeFile("producer/inputs/js", "js\n");
115 writeFile("build.gradle", """
116 import org.gradle.api.attributes.Attribute
117
118 def variantAttr = Attribute.of('test.variant', String)
119 def slotAttr = Attribute.of('test.slot', String)
120
121 project(':producer') {
122 def browserElements = configurations.consumable('browserElements')
123
124 browserElements.configure { configuration ->
125 configuration.attributes.attribute(variantAttr, 'browser')
126 configuration.outgoing.attributes.attribute(slotAttr, 'typesPackage')
127 configuration.outgoing.artifact(layout.projectDirectory.file('inputs/typesPackage'))
128
129 configuration.outgoing.variants.register('js') { secondary ->
130 secondary.attributes.attribute(slotAttr, 'js')
131 secondary.artifact(layout.projectDirectory.file('inputs/js'))
132 }
133 }
134 }
135
136 project(':consumer') {
137 configurations {
138 compileView {
139 canBeResolved = true
140 canBeConsumed = false
141 canBeDeclared = true
142 attributes {
143 attribute(variantAttr, 'browser')
144 attribute(slotAttr, 'typesPackage')
145 }
146 }
147 }
148
149 dependencies {
150 compileView project(':producer')
151 }
152
153 tasks.register('probe') {
154 doLast {
155 def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',')
156 def jsFiles = configurations.compileView.incoming.artifactView {
157 attributes {
158 attribute(slotAttr, 'js')
159 }
160 }.files.files.collect { it.name }.sort().join(',')
161
162 println('compileFiles=' + compileFiles)
163 println('jsFiles=' + jsFiles)
164 }
165 }
166 }
167 """);
168
169 assertBuildFails("Cannot create variant 'js' after dependency configuration ':producer:browserElements' has been resolved",
170 ":consumer:probe");
171 }
172
173 @Test
106 void materializesPrimaryAndSecondarySlotsAndInvokesOutgoingHooks() throws Exception {
174 void materializesPrimaryAndSecondarySlotsAndInvokesOutgoingHooks() throws Exception {
107 writeSettings("variant-artifacts-slots");
175 writeSettings("variant-artifacts-slots");
108 writeFile("inputs/base.js", "console.log('base')\n");
176 writeFile("inputs/base.js", "console.log('base')\n");
@@ -207,6 +275,66 class VariantArtifactsPluginFunctionalTe
207 }
275 }
208
276
209 @Test
277 @Test
278 void outgoingSlotHookFollowsMaterializedGradleArtifactVariants() throws Exception {
279 writeSettings("variant-artifacts-materialized-gradle-variant");
280 writeFile("inputs/typesPackage", "types\n");
281 writeFile("inputs/js", "js\n");
282 writeBuildFile("""
283 import org.gradle.api.attributes.Attribute
284
285 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
286
287 def slotAttr = Attribute.of('test.slot', String)
288
289 variants.layers.create('main')
290 variants.roles.create('main')
291 variants.variant('browser') {
292 role('main') {
293 layers('main')
294 }
295 }
296
297 variantArtifacts {
298 variant('browser') {
299 primarySlot('typesPackage') {
300 from(layout.projectDirectory.file('inputs/typesPackage'))
301 }
302 }
303
304 whenOutgoingConfiguration { publication ->
305 publication.configuration {
306 outgoing.variants.create('js') { secondary ->
307 secondary.artifact(layout.projectDirectory.file('inputs/js'))
308 }
309 }
310 }
311
312 whenOutgoingSlot { publication ->
313 publication.artifactAttributes {
314 attribute(slotAttr, publication.artifactSlot.slot.name)
315 }
316 }
317 }
318
319 tasks.register('probe') {
320 doLast {
321 def elements = configurations.getByName('browserElements')
322 def jsVariant = elements.outgoing.variants.getByName('js')
323
324 println('primarySlotAttr=' + elements.outgoing.attributes.getAttribute(slotAttr))
325 println('jsSlotAttr=' + jsVariant.attributes.getAttribute(slotAttr))
326 }
327 }
328 """);
329
330 BuildResult result = runner("probe").build();
331
332 assertTrue(result.getOutput().contains("primarySlotAttr=typesPackage"));
333 assertTrue(result.getOutput().contains("jsSlotAttr=js"));
334 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
335 }
336
337 @Test
210 void allowsSingleSlotVariantWithoutExplicitPrimarySlot() throws Exception {
338 void allowsSingleSlotVariantWithoutExplicitPrimarySlot() throws Exception {
211 writeSettings("variant-artifacts-single-slot");
339 writeSettings("variant-artifacts-single-slot");
212 writeBuildFile("""
340 writeBuildFile("""
General Comments 0
You need to be logged in to leave comments. Login now