| @@ -1,112 +1,112 | |||||
| 1 | package org.implab.gradle.variants; |
|
1 | package org.implab.gradle.variants; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Action; |
|
3 | import org.gradle.api.Action; | |
| 4 | import org.gradle.api.Plugin; |
|
4 | import org.gradle.api.Plugin; | |
| 5 | import org.gradle.api.Project; |
|
5 | import org.gradle.api.Project; | |
| 6 | import org.implab.gradle.common.core.lang.Deferred; |
|
6 | import org.implab.gradle.common.core.lang.Deferred; | |
| 7 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec; |
|
7 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec; | |
| 8 | import org.implab.gradle.variants.artifacts.OutgoingVariantsContext; |
|
8 | import org.implab.gradle.variants.artifacts.OutgoingVariantsContext; | |
| 9 | import org.implab.gradle.variants.artifacts.VariantArtifactsExtension; |
|
9 | import org.implab.gradle.variants.artifacts.VariantArtifactsExtension; | |
| 10 | import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; |
|
10 | import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; | |
| 11 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyBinder; |
|
11 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyBinder; | |
| 12 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyHandler; |
|
12 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyHandler; | |
| 13 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyRegistry; |
|
13 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyRegistry; | |
| 14 | import org.implab.gradle.variants.artifacts.internal.DefaultOutgoingVariantsContext; |
|
14 | import org.implab.gradle.variants.artifacts.internal.DefaultOutgoingVariantsContext; | |
| 15 | import org.implab.gradle.variants.artifacts.internal.MaterializationPolicyHandler; |
|
15 | import org.implab.gradle.variants.artifacts.internal.MaterializationPolicyHandler; | |
| 16 | import org.implab.gradle.variants.artifacts.internal.OutgoingRegistry; |
|
16 | import org.implab.gradle.variants.artifacts.internal.OutgoingRegistry; | |
| 17 | import org.implab.gradle.variants.artifacts.internal.SingleSlotConvention; |
|
17 | import org.implab.gradle.variants.artifacts.internal.SingleSlotConvention; | |
| 18 | import org.implab.gradle.variants.core.Variant; |
|
18 | import org.implab.gradle.variants.core.Variant; | |
| 19 | import org.implab.gradle.variants.core.VariantsExtension; |
|
19 | import org.implab.gradle.variants.core.VariantsExtension; | |
| 20 | import org.implab.gradle.variants.sources.VariantSourcesExtension; |
|
20 | import org.implab.gradle.variants.sources.VariantSourcesExtension; | |
| 21 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSlotSpec; |
|
21 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSlotSpec; | |
| 22 |
|
22 | |||
| 23 | public abstract class VariantArtifactsPlugin implements Plugin<Project> { |
|
23 | public abstract class VariantArtifactsPlugin implements Plugin<Project> { | |
| 24 |
|
24 | |||
| 25 | @Override |
|
25 | @Override | |
| 26 | public void apply(Project target) { |
|
26 | public void apply(Project target) { | |
| 27 | var extensions = target.getExtensions(); |
|
27 | var extensions = target.getExtensions(); | |
| 28 | var objects = target.getObjects(); |
|
28 | var objects = target.getObjects(); | |
| 29 | var providers = target.getProviders(); |
|
29 | var providers = target.getProviders(); | |
| 30 | var plugins = target.getPlugins(); |
|
30 | var plugins = target.getPlugins(); | |
| 31 | var configurations = target.getConfigurations(); |
|
31 | var configurations = target.getConfigurations(); | |
| 32 | var tasks = target.getTasks(); |
|
32 | var tasks = target.getTasks(); | |
| 33 | var layout = target.getLayout(); |
|
33 | var layout = target.getLayout(); | |
| 34 |
|
34 | |||
| 35 | // Apply the main VariantsPlugin to ensure the core variant model is available. |
|
35 | // Apply the main VariantsPlugin to ensure the core variant model is available. | |
| 36 | plugins.apply(VariantsPlugin.class); |
|
36 | plugins.apply(VariantsPlugin.class); | |
| 37 | plugins.apply(VariantSourcesPlugin.class); |
|
37 | plugins.apply(VariantSourcesPlugin.class); | |
| 38 | // Access the VariantsExtension to configure variant sources. |
|
38 | // Access the VariantsExtension to configure variant sources. | |
| 39 | var variantsExtension = extensions.getByType(VariantsExtension.class); |
|
39 | var variantsExtension = extensions.getByType(VariantsExtension.class); | |
| 40 | var sourcesExtension = extensions.getByType(VariantSourcesExtension.class); |
|
40 | var sourcesExtension = extensions.getByType(VariantSourcesExtension.class); | |
| 41 |
|
41 | |||
| 42 | var deferred = new Deferred<OutgoingVariantsContext>(); |
|
42 | var deferred = new Deferred<OutgoingVariantsContext>(); | |
| 43 |
|
43 | |||
| 44 | variantsExtension.whenFinalized(variants -> { |
|
44 | variantsExtension.whenFinalized(variants -> { | |
| 45 |
|
45 | |||
| 46 | var outgoing = new OutgoingRegistry(configurations, objects, variants.getVariants()); |
|
46 | var outgoing = new OutgoingRegistry(configurations, objects, variants.getVariants()); | |
| 47 | var assemblies = new ArtifactAssemblyRegistry(); |
|
47 | var assemblies = new ArtifactAssemblyRegistry(); | |
| 48 |
|
48 | |||
| 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); | |
| 56 | // apply primary slot convention when outgoing variant has a single slot |
|
56 | // apply primary slot convention when outgoing variant has a single slot | |
| 57 | outgoing.configureEach(primarySlotConvention::execute); |
|
57 | outgoing.configureEach(primarySlotConvention::execute); | |
| 58 | // apply materialization policy hooks to outgoing variants |
|
58 | // apply materialization policy hooks to outgoing variants | |
| 59 | outgoing.configureEach(materializationHandler::execute); |
|
59 | outgoing.configureEach(materializationHandler::execute); | |
| 60 |
|
60 | |||
| 61 | sourcesExtension.whenFinalized(sources -> { |
|
61 | sourcesExtension.whenFinalized(sources -> { | |
| 62 | var assemblyHandler = new ArtifactAssemblyHandler( |
|
62 | var assemblyHandler = new ArtifactAssemblyHandler( | |
| 63 | objects, |
|
63 | objects, | |
| 64 | tasks, |
|
64 | tasks, | |
| 65 | assemblies, |
|
65 | assemblies, | |
| 66 | sources.getCompileUnits(), |
|
66 | sources.getCompileUnits(), | |
| 67 | sources.getRoleProjections(), |
|
67 | sources.getRoleProjections(), | |
| 68 | sources.getSourceSets()); |
|
68 | sources.getSourceSets()); | |
| 69 | assemblyHandler.getAssembliesDirectory().set(layout.getBuildDirectory().dir("variant-assemblies")); |
|
69 | assemblyHandler.getAssembliesDirectory().set(layout.getBuildDirectory().dir("variant-assemblies")); | |
| 70 |
|
70 | |||
| 71 | deferred.resolve(new DefaultOutgoingVariantsContext( |
|
71 | deferred.resolve(new DefaultOutgoingVariantsContext( | |
| 72 | assemblies, |
|
72 | assemblies, | |
| 73 | outgoing, |
|
73 | outgoing, | |
| 74 | assemblyHandler, |
|
74 | assemblyHandler, | |
| 75 | materializationHandler)); |
|
75 | materializationHandler)); | |
| 76 | }); |
|
76 | }); | |
| 77 |
|
77 | |||
| 78 | }); |
|
78 | }); | |
| 79 |
|
79 | |||
| 80 | var variantArtifacts = new VariantArtifactsExtension() { |
|
80 | var variantArtifacts = new VariantArtifactsExtension() { | |
| 81 |
|
81 | |||
| 82 | @Override |
|
82 | @Override | |
| 83 | public void variant(String variantName, Action<? super VariantArtifactsSpec> action) { |
|
83 | public void variant(String variantName, Action<? super VariantArtifactsSpec> action) { | |
| 84 | deferred.whenResolved(context -> { |
|
84 | deferred.whenResolved(context -> { | |
| 85 | var variant = objects.named(Variant.class, variantName); |
|
85 | var variant = objects.named(Variant.class, variantName); | |
| 86 | context.configureVariant(variant, action); |
|
86 | context.configureVariant(variant, action); | |
| 87 | }); |
|
87 | }); | |
| 88 | } |
|
88 | } | |
| 89 |
|
89 | |||
| 90 | @Override |
|
90 | @Override | |
| 91 | public void whenAvailable(Action<? super OutgoingVariantsContext> action) { |
|
91 | public void whenAvailable(Action<? super OutgoingVariantsContext> action) { | |
| 92 | deferred.whenResolved(handler -> action.execute(handler)); |
|
92 | deferred.whenResolved(handler -> action.execute(handler)); | |
| 93 | } |
|
93 | } | |
| 94 |
|
94 | |||
| 95 | @Override |
|
95 | @Override | |
| 96 | public void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action) { |
|
96 | public void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action) { | |
| 97 | deferred.whenResolved(registry -> registry.whenOutgoingConfiguration(action)); |
|
97 | deferred.whenResolved(registry -> registry.whenOutgoingConfiguration(action)); | |
| 98 |
|
98 | |||
| 99 | } |
|
99 | } | |
| 100 |
|
100 | |||
| 101 | @Override |
|
101 | @Override | |
| 102 | public void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action) { |
|
102 | public void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action) { | |
| 103 | deferred.whenResolved(registry -> registry.whenOutgoingSlot(action)); |
|
103 | deferred.whenResolved(registry -> registry.whenOutgoingSlot(action)); | |
| 104 | } |
|
104 | } | |
| 105 |
|
105 | |||
| 106 | }; |
|
106 | }; | |
| 107 |
|
107 | |||
| 108 | extensions.add(VariantArtifactsExtension.class, "variantArtifacts", variantArtifacts); |
|
108 | extensions.add(VariantArtifactsExtension.class, "variantArtifacts", variantArtifacts); | |
| 109 |
|
109 | |||
| 110 | } |
|
110 | } | |
| 111 |
|
111 | |||
| 112 | } |
|
112 | } | |
| @@ -1,56 +1,61 | |||||
| 1 | package org.implab.gradle.variants.artifacts; |
|
1 | package org.implab.gradle.variants.artifacts; | |
| 2 |
|
2 | |||
| 3 | import java.util.Optional; |
|
3 | import java.util.Optional; | |
| 4 |
|
4 | |||
| 5 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 6 | import org.gradle.api.Action; |
|
6 | import org.gradle.api.Action; | |
| 7 | import org.gradle.api.InvalidUserDataException; |
|
7 | import org.gradle.api.InvalidUserDataException; | |
| 8 |
|
8 | |||
| 9 | /** |
|
9 | /** | |
| 10 | * Resolves stateful slot assemblies from cheap slot identities. |
|
10 | * Resolves stateful slot assemblies from cheap slot identities. | |
| 11 | * |
|
11 | * | |
| 12 | * <p> |
|
12 | * <p> | |
| 13 | * The returned assembly is a materialized build-model handle. It may expose |
|
13 | * The returned assembly is a materialized build-model handle. It may expose | |
| 14 | * lazy Gradle providers, but |
|
14 | * lazy Gradle providers, but | |
| 15 | * it is no longer an identity object suitable for replayable discovery. |
|
15 | * it is no longer an identity object suitable for replayable discovery. | |
| 16 | */ |
|
16 | */ | |
| 17 | @NonNullByDefault |
|
17 | @NonNullByDefault | |
| 18 | public interface ArtifactAssemblies { |
|
18 | public interface ArtifactAssemblies { | |
| 19 | /** |
|
19 | /** | |
| 20 | * Resolves the assembly for the given slot. |
|
20 | * Resolves the assembly for the given slot. | |
| 21 | * |
|
21 | * | |
| 22 | * <p> |
|
22 | * <p> | |
| 23 | * This call materializes the build-facing body of the slot from its identity. |
|
23 | * This call materializes the build-facing body of the slot from its identity. | |
| 24 | * |
|
24 | * | |
| 25 | * @param slot slot identity inside a variant outgoing contract |
|
25 | * @param slot slot identity inside a variant outgoing contract | |
| 26 | * @return assembly handle for the slot |
|
26 | * @return assembly handle for the slot | |
| 27 | */ |
|
27 | */ | |
| 28 | default ArtifactAssembly require(ArtifactSlot slot) { |
|
28 | default ArtifactAssembly require(ArtifactSlot slot) { | |
| 29 | return find(slot) |
|
29 | return find(slot) | |
| 30 | .orElseThrow(() -> new InvalidUserDataException("Artifact assembly '" + slot + "' isn't registered")); |
|
30 | .orElseThrow(() -> new InvalidUserDataException("Artifact assembly '" + slot + "' isn't registered")); | |
| 31 | } |
|
31 | } | |
| 32 |
|
32 | |||
| 33 | /** |
|
33 | /** | |
| 34 | * Registers a configuration action for the assembly of the given slot. |
|
34 | * Registers a configuration action for the assembly of the given slot. | |
| 35 | * |
|
35 | * | |
| 36 | * <p>If the assembly is already registered, the action is invoked immediately. |
|
36 | * <p>If the assembly is already registered, the action is invoked immediately. | |
| 37 | * Otherwise, it is queued and invoked when slot materialization registers the |
|
37 | * Otherwise, it is queued and invoked when slot materialization registers the | |
| 38 | * assembly handle. |
|
38 | * assembly handle. | |
| 39 | * |
|
39 | * | |
| 40 | * @param slot slot identity inside a variant outgoing contract |
|
40 | * @param slot slot identity inside a variant outgoing contract | |
| 41 | * @param action assembly configuration action |
|
41 | * @param action assembly configuration action | |
| 42 | */ |
|
42 | */ | |
| 43 | void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action); |
|
43 | void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action); | |
| 44 |
|
44 | |||
| 45 | /** |
|
45 | /** | |
| 46 | * Adds global configuration action for all materialized assemblies. If some assemblies are |
|
46 | * Adds global configuration action for all materialized assemblies. If some assemblies are | |
| 47 | * already registered, the action will be invoked for them immediately. For assemblies that |
|
47 | * already registered, the action will be invoked for them immediately. For assemblies that | |
| 48 | * are materialized later, the action will be invoked when they are registered. |
|
48 | * are materialized later, the action will be invoked when they are registered. | |
| 49 | * |
|
49 | * | |
| 50 | * @param action assembly configuration action. |
|
50 | * @param action assembly configuration action. | |
| 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 | } | |
| @@ -1,43 +1,43 | |||||
| 1 | package org.implab.gradle.variants.artifacts; |
|
1 | package org.implab.gradle.variants.artifacts; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Action; |
|
3 | import org.gradle.api.Action; | |
| 4 | import org.gradle.api.artifacts.Configuration; |
|
4 | import org.gradle.api.artifacts.Configuration; | |
| 5 | import org.implab.gradle.common.core.lang.Closures; |
|
5 | import org.implab.gradle.common.core.lang.Closures; | |
| 6 | import org.implab.gradle.variants.core.Variant; |
|
6 | import org.implab.gradle.variants.core.Variant; | |
| 7 |
|
7 | |||
| 8 | import groovy.lang.Closure; |
|
8 | import groovy.lang.Closure; | |
| 9 |
|
9 | |||
| 10 | /** |
|
10 | /** | |
| 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 Outgoing |
|
14 | * {@link OutgoingConfigurationSlotSpec}. | |
| 15 | */ |
|
15 | */ | |
| 16 | public interface OutgoingConfigurationSpec { |
|
16 | public interface OutgoingConfigurationSpec { | |
| 17 | /** |
|
17 | /** | |
| 18 | * Returns the variant whose outgoing configuration is represented here. |
|
18 | * Returns the variant whose outgoing configuration is represented here. | |
| 19 | * |
|
19 | * | |
| 20 | * @return variant identity |
|
20 | * @return variant identity | |
| 21 | */ |
|
21 | */ | |
| 22 | Variant getVariant(); |
|
22 | Variant getVariant(); | |
| 23 |
|
23 | |||
| 24 | /** |
|
24 | /** | |
| 25 | * Returns the root consumable outgoing configuration of the variant. |
|
25 | * Returns the root consumable outgoing configuration of the variant. | |
| 26 | * |
|
26 | * | |
| 27 | * @return outgoing configuration |
|
27 | * @return outgoing configuration | |
| 28 | */ |
|
28 | */ | |
| 29 | Configuration getConfiguration(); |
|
29 | Configuration getConfiguration(); | |
| 30 |
|
30 | |||
| 31 | /** |
|
31 | /** | |
| 32 | * Applies a configuration action to the root outgoing configuration. |
|
32 | * Applies a configuration action to the root outgoing configuration. | |
| 33 | * |
|
33 | * | |
| 34 | * @param action configuration action |
|
34 | * @param action configuration action | |
| 35 | */ |
|
35 | */ | |
| 36 | default void configuration(Action<? super Configuration> action) { |
|
36 | default void configuration(Action<? super Configuration> action) { | |
| 37 | action.execute(getConfiguration()); |
|
37 | action.execute(getConfiguration()); | |
| 38 | } |
|
38 | } | |
| 39 |
|
39 | |||
| 40 | default void configuration(Closure<?> closure) { |
|
40 | default void configuration(Closure<?> closure) { | |
| 41 | configuration(Closures.action(closure)); |
|
41 | configuration(Closures.action(closure)); | |
| 42 | } |
|
42 | } | |
| 43 | } |
|
43 | } | |
| @@ -1,50 +1,63 | |||||
| 1 | package org.implab.gradle.variants.artifacts; |
|
1 | package org.implab.gradle.variants.artifacts; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Action; |
|
3 | import org.gradle.api.Action; | |
| 4 | import org.gradle.api.NamedDomainObjectContainer; |
|
4 | import org.gradle.api.NamedDomainObjectContainer; | |
| 5 | import org.gradle.api.NamedDomainObjectProvider; |
|
5 | import org.gradle.api.NamedDomainObjectProvider; | |
| 6 | import org.gradle.api.artifacts.Configuration; |
|
6 | import org.gradle.api.artifacts.Configuration; | |
| 7 | import org.gradle.api.provider.Property; |
|
7 | 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 | } | |
| @@ -1,36 +1,87 | |||||
| 1 | package org.implab.gradle.variants.artifacts; |
|
1 | package org.implab.gradle.variants.artifacts; | |
| 2 |
|
2 | |||
| 3 | import java.util.Optional; |
|
3 | import java.util.Optional; | |
| 4 |
|
4 | |||
| 5 | import org.gradle.api.Action; |
|
5 | import org.gradle.api.Action; | |
| 6 | import org.gradle.api.InvalidUserDataException; |
|
6 | import org.gradle.api.InvalidUserDataException; | |
| 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 | |||
| 36 | } |
|
87 | } | |
| @@ -1,40 +1,38 | |||||
| 1 | package org.implab.gradle.variants.artifacts; |
|
1 | package org.implab.gradle.variants.artifacts; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Action; |
|
3 | import org.gradle.api.Action; | |
| 4 | import groovy.lang.Closure; |
|
4 | import groovy.lang.Closure; | |
| 5 | import org.implab.gradle.common.core.lang.Closures; |
|
5 | import org.implab.gradle.common.core.lang.Closures; | |
| 6 |
|
6 | |||
| 7 | /** |
|
7 | /** | |
| 8 | * DSL model for declaring slots of a single variant. |
|
8 | * DSL model for declaring slots of a single variant. | |
| 9 | * |
|
9 | * | |
| 10 | * <p>The surrounding variant defines the external outgoing contract. Slots declared here define artifact |
|
10 | * <p>The surrounding variant defines the external outgoing contract. Slots declared here define artifact | |
| 11 | * sets within that contract. If a variant exposes more than one slot, one of them is expected to be the |
|
11 | * sets within that contract. If a variant exposes more than one slot, one of them is expected to be the | |
| 12 | * primary slot. |
|
12 | * primary slot. | |
| 13 | */ |
|
13 | */ | |
| 14 | public interface VariantArtifactsSpec { |
|
14 | public interface VariantArtifactsSpec { | |
| 15 | /** |
|
15 | /** | |
| 16 | * Declares a non-primary slot of the current variant. |
|
16 | * Declares a non-primary slot of the current variant. | |
| 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 | |||
| 24 | default void slot(String name, Closure<?> closure) { |
|
23 | default void slot(String name, Closure<?> closure) { | |
| 25 | slot(name, Closures.action(closure)); |
|
24 | slot(name, Closures.action(closure)); | |
| 26 | } |
|
25 | } | |
| 27 |
|
26 | |||
| 28 | /** |
|
27 | /** | |
| 29 | * Declares the primary slot of the current variant. |
|
28 | * Declares the primary slot of the current variant. | |
| 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 | |||
| 37 | default void primarySlot(String name, Closure<?> closure) { |
|
35 | default void primarySlot(String name, Closure<?> closure) { | |
| 38 | primarySlot(name, Closures.action(closure)); |
|
36 | primarySlot(name, Closures.action(closure)); | |
| 39 | } |
|
37 | } | |
| 40 | } |
|
38 | } | |
| @@ -1,56 +1,56 | |||||
| 1 | package org.implab.gradle.variants.artifacts.internal; |
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
| 2 |
|
2 | |||
| 3 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
3 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 4 | import org.gradle.api.Action; |
|
4 | import org.gradle.api.Action; | |
| 5 | import org.implab.gradle.variants.artifacts.ArtifactAssemblies; |
|
5 | import org.implab.gradle.variants.artifacts.ArtifactAssemblies; | |
| 6 | import org.implab.gradle.variants.artifacts.ArtifactSlot; |
|
6 | import org.implab.gradle.variants.artifacts.ArtifactSlot; | |
| 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> { | |
| 15 |
|
14 | |||
| 16 | private final ArtifactAssemblies resolver; |
|
15 | private final ArtifactAssemblies resolver; | |
| 17 |
|
16 | |||
| 18 | public ArtifactAssemblyBinder(ArtifactAssemblies resolver) { |
|
17 | public ArtifactAssemblyBinder(ArtifactAssemblies resolver) { | |
| 19 | this.resolver = resolver; |
|
18 | this.resolver = resolver; | |
| 20 | } |
|
19 | } | |
| 21 |
|
20 | |||
| 22 | @Override |
|
21 | @Override | |
| 23 | public void execute(OutgoingVariant outgoingVariant) { |
|
22 | public void execute(OutgoingVariant outgoingVariant) { | |
| 24 | var slots = outgoingVariant.getSlots(); |
|
23 | var slots = outgoingVariant.getSlots(); | |
| 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 |
. |
|
48 | .create(slot.getName()) | |
| 49 |
|
|
49 | .artifact(assembly.getArtifact())); | |
| 50 | }); |
|
50 | }); | |
| 51 | }); |
|
51 | }); | |
| 52 | } |
|
52 | } | |
| 53 |
|
53 | |||
| 54 |
|
54 | |||
| 55 |
|
55 | |||
| 56 | } |
|
56 | } | |
| @@ -1,218 +1,202 | |||||
| 1 | package org.implab.gradle.variants.artifacts.internal; |
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
| 2 |
|
2 | |||
| 3 | import java.util.HashMap; |
|
3 | import java.util.HashMap; | |
| 4 | import java.util.HashSet; |
|
4 | import java.util.HashSet; | |
| 5 | import java.util.Map; |
|
5 | import java.util.Map; | |
| 6 | import java.util.Set; |
|
6 | import java.util.Set; | |
| 7 |
|
7 | |||
| 8 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
8 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 9 | import org.gradle.api.Action; |
|
9 | import org.gradle.api.Action; | |
| 10 | import org.gradle.api.file.ConfigurableFileCollection; |
|
10 | import org.gradle.api.file.ConfigurableFileCollection; | |
| 11 | import org.gradle.api.file.Directory; |
|
11 | import org.gradle.api.file.Directory; | |
| 12 | import org.gradle.api.file.DirectoryProperty; |
|
12 | import org.gradle.api.file.DirectoryProperty; | |
| 13 | import org.gradle.api.file.FileCollection; |
|
13 | import org.gradle.api.file.FileCollection; | |
| 14 | import org.gradle.api.model.ObjectFactory; |
|
14 | import org.gradle.api.model.ObjectFactory; | |
| 15 | import org.gradle.api.provider.Provider; |
|
15 | import org.gradle.api.provider.Provider; | |
| 16 | import org.gradle.api.tasks.Sync; |
|
16 | 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; | |
| 23 | import org.implab.gradle.variants.sources.CompileUnitsView; |
|
24 | import org.implab.gradle.variants.sources.CompileUnitsView; | |
| 24 | import org.implab.gradle.variants.sources.RoleProjectionsView; |
|
25 | import org.implab.gradle.variants.sources.RoleProjectionsView; | |
| 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 { | |
| 51 | private final ObjectFactory objects; |
|
43 | private final ObjectFactory objects; | |
| 52 |
|
44 | |||
| 53 | private final ArtifactAssemblyRegistry assemblyRegistry; |
|
45 | private final ArtifactAssemblyRegistry assemblyRegistry; | |
| 54 |
|
46 | |||
| 55 | private final DirectoryProperty assembliesDirectory; |
|
47 | private final DirectoryProperty assembliesDirectory; | |
| 56 |
|
48 | |||
| 57 | private final TaskContainer tasks; |
|
49 | private final TaskContainer tasks; | |
| 58 |
|
50 | |||
| 59 | private final CompileUnitsView compileUnitsView; |
|
51 | private final CompileUnitsView compileUnitsView; | |
| 60 |
|
52 | |||
| 61 | private final RoleProjectionsView roleProjectionsView; |
|
53 | private final RoleProjectionsView roleProjectionsView; | |
| 62 |
|
54 | |||
| 63 | private final SourceSetMaterializer sourceSetMaterializer; |
|
55 | private final SourceSetMaterializer sourceSetMaterializer; | |
| 64 |
|
56 | |||
| 65 | private final Map<ArtifactSlot, SlotAssembly> slotInputs = new HashMap<>(); |
|
57 | private final Map<ArtifactSlot, SlotAssembly> slotInputs = new HashMap<>(); | |
| 66 |
|
58 | |||
| 67 | public ArtifactAssemblyHandler( |
|
59 | public ArtifactAssemblyHandler( | |
| 68 | ObjectFactory objects, |
|
60 | ObjectFactory objects, | |
| 69 | TaskContainer tasks, |
|
61 | TaskContainer tasks, | |
| 70 | ArtifactAssemblyRegistry assemblyRegistry, |
|
62 | ArtifactAssemblyRegistry assemblyRegistry, | |
| 71 | CompileUnitsView compileUnitsView, |
|
63 | CompileUnitsView compileUnitsView, | |
| 72 | RoleProjectionsView roleProjectionsView, |
|
64 | RoleProjectionsView roleProjectionsView, | |
| 73 | SourceSetMaterializer sourceSetMaterializer) { |
|
65 | SourceSetMaterializer sourceSetMaterializer) { | |
| 74 | this.objects = objects; |
|
66 | this.objects = objects; | |
| 75 | this.tasks = tasks; |
|
67 | this.tasks = tasks; | |
| 76 | this.assemblyRegistry = assemblyRegistry; |
|
68 | this.assemblyRegistry = assemblyRegistry; | |
| 77 | this.compileUnitsView = compileUnitsView; |
|
69 | this.compileUnitsView = compileUnitsView; | |
| 78 | this.roleProjectionsView = roleProjectionsView; |
|
70 | this.roleProjectionsView = roleProjectionsView; | |
| 79 | this.sourceSetMaterializer = sourceSetMaterializer; |
|
71 | this.sourceSetMaterializer = sourceSetMaterializer; | |
| 80 |
|
72 | |||
| 81 | assembliesDirectory = objects.directoryProperty(); |
|
73 | assembliesDirectory = objects.directoryProperty(); | |
| 82 | } |
|
74 | } | |
| 83 |
|
75 | |||
| 84 | public DirectoryProperty getAssembliesDirectory() { |
|
76 | public DirectoryProperty getAssembliesDirectory() { | |
| 85 | return assembliesDirectory; |
|
77 | return assembliesDirectory; | |
| 86 | } |
|
78 | } | |
| 87 |
|
79 | |||
| 88 | public void configureAssembly(ArtifactSlot artifactSlot, Action<? super ArtifactAssemblySpec> action) { |
|
80 | public void configureAssembly(ArtifactSlot artifactSlot, Action<? super ArtifactAssemblySpec> action) { | |
| 89 | var visitor = contributionVisitor(artifactSlot); |
|
81 | var visitor = contributionVisitor(artifactSlot); | |
| 90 | var spec = new DefaultArtifactAssemblySpec(objects, c -> c.accept(visitor)); |
|
82 | var spec = new DefaultArtifactAssemblySpec(objects, c -> c.accept(visitor)); | |
| 91 | action.execute(spec); |
|
83 | action.execute(spec); | |
| 92 | } |
|
84 | } | |
| 93 |
|
85 | |||
| 94 | public SlotContributionVisitor contributionVisitor(ArtifactSlot artifactSlot) { |
|
86 | public SlotContributionVisitor contributionVisitor(ArtifactSlot artifactSlot) { | |
| 95 | var assembly = slotInputs.computeIfAbsent(artifactSlot, this::createSlotAssembly); |
|
87 | var assembly = slotInputs.computeIfAbsent(artifactSlot, this::createSlotAssembly); | |
| 96 | return new ContributionVisitor(artifactSlot, assembly); |
|
88 | return new ContributionVisitor(artifactSlot, assembly); | |
| 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(); | |
| 106 | var fileCollection = assembly.inputs(); |
|
96 | var fileCollection = assembly.inputs(); | |
| 107 |
|
97 | |||
| 108 | var outputDirectory = outputDirectory(artifactSlot); |
|
98 | var outputDirectory = outputDirectory(artifactSlot); | |
| 109 |
|
99 | |||
| 110 | var task = tasks.register(assembleTaskName(artifactSlot), Sync.class, copy -> { |
|
100 | var task = tasks.register(assembleTaskName(artifactSlot), Sync.class, copy -> { | |
| 111 | copy.setGroup(LifecycleBasePlugin.BUILD_GROUP); |
|
101 | copy.setGroup(LifecycleBasePlugin.BUILD_GROUP); | |
| 112 | copy.into(outputDirectory); |
|
102 | copy.into(outputDirectory); | |
| 113 | copy.from(fileCollection); |
|
103 | copy.from(fileCollection); | |
| 114 | }); |
|
104 | }); | |
| 115 |
|
105 | |||
| 116 | assemblyRegistry.register(artifactSlot, task, t -> outputDirectory); |
|
106 | assemblyRegistry.register(artifactSlot, task, t -> outputDirectory); | |
| 117 |
|
107 | |||
| 118 | return assembly; |
|
108 | return assembly; | |
| 119 | } |
|
109 | } | |
| 120 |
|
110 | |||
| 121 | private String assembleTaskName(ArtifactSlot artifactSlot) { |
|
111 | private String assembleTaskName(ArtifactSlot artifactSlot) { | |
| 122 | var variantName = artifactSlot.variant().getName(); |
|
112 | var variantName = artifactSlot.variant().getName(); | |
| 123 | var slotName = artifactSlot.slot().getName(); |
|
113 | var slotName = artifactSlot.slot().getName(); | |
| 124 |
|
114 | |||
| 125 | return "assembleVariantArtifactSlot" |
|
115 | return "assembleVariantArtifactSlot" | |
| 126 | + "_v" + variantName.length() + "_" + variantName |
|
116 | + "_v" + variantName.length() + "_" + variantName | |
| 127 | + "_s" + slotName.length() + "_" + slotName; |
|
117 | + "_s" + slotName.length() + "_" + slotName; | |
| 128 | } |
|
118 | } | |
| 129 |
|
119 | |||
| 130 | private Provider<Directory> outputDirectory(ArtifactSlot artifactSlot) { |
|
120 | private Provider<Directory> outputDirectory(ArtifactSlot artifactSlot) { | |
| 131 | return assembliesDirectory.dir( |
|
121 | return assembliesDirectory.dir( | |
| 132 | FilePaths.cat( |
|
122 | FilePaths.cat( | |
| 133 | artifactSlot.variant().getName(), |
|
123 | artifactSlot.variant().getName(), | |
| 134 | artifactSlot.slot().getName())); |
|
124 | artifactSlot.slot().getName())); | |
| 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 | |
| 148 | private final ArtifactSlot artifactSlot; |
|
132 | private final ArtifactSlot artifactSlot; | |
| 149 |
|
133 | |||
| 150 | // seen inputs, used for deduplication |
|
134 | // seen inputs, used for deduplication | |
| 151 | private final SlotAssembly assembly; |
|
135 | private final SlotAssembly assembly; | |
| 152 |
|
136 | |||
| 153 | ContributionVisitor(ArtifactSlot artifactSlot, SlotAssembly assembly) { |
|
137 | ContributionVisitor(ArtifactSlot artifactSlot, SlotAssembly assembly) { | |
| 154 | this.artifactSlot = artifactSlot; |
|
138 | this.artifactSlot = artifactSlot; | |
| 155 | this.assembly = assembly; |
|
139 | this.assembly = assembly; | |
| 156 | } |
|
140 | } | |
| 157 |
|
141 | |||
| 158 | @Override |
|
142 | @Override | |
| 159 | public void visit(DirectContribution contribution) { |
|
143 | public void visit(DirectContribution contribution) { | |
| 160 | contribute( |
|
144 | contribute( | |
| 161 | SlotInputKey.newUniqueKey("Direct input for " + artifactSlot), |
|
145 | SlotInputKey.newUniqueKey("Direct input for " + artifactSlot), | |
| 162 | contribution.input()); |
|
146 | contribution.input()); | |
| 163 | } |
|
147 | } | |
| 164 |
|
148 | |||
| 165 | @Override |
|
149 | @Override | |
| 166 | public void visit(VariantOutputsContribution contribution) { |
|
150 | public void visit(VariantOutputsContribution contribution) { | |
| 167 | var units = compileUnitsView.getUnitsForVariant(artifactSlot.variant()); |
|
151 | var units = compileUnitsView.getUnitsForVariant(artifactSlot.variant()); | |
| 168 | contributeCompileUnits(units, contribution.outputs()); |
|
152 | contributeCompileUnits(units, contribution.outputs()); | |
| 169 | } |
|
153 | } | |
| 170 |
|
154 | |||
| 171 | @Override |
|
155 | @Override | |
| 172 | public void visit(RoleOutputsContribution contribution) { |
|
156 | public void visit(RoleOutputsContribution contribution) { | |
| 173 | var roleProjection = roleProjectionsView.requireProjection(artifactSlot.variant(), |
|
157 | var roleProjection = roleProjectionsView.requireProjection(artifactSlot.variant(), | |
| 174 | contribution.role()); |
|
158 | contribution.role()); | |
| 175 | var units = roleProjectionsView.getUnits(roleProjection); |
|
159 | var units = roleProjectionsView.getUnits(roleProjection); | |
| 176 |
|
160 | |||
| 177 | contributeCompileUnits(units, contribution.outputs()); |
|
161 | contributeCompileUnits(units, contribution.outputs()); | |
| 178 |
|
162 | |||
| 179 | } |
|
163 | } | |
| 180 |
|
164 | |||
| 181 | @Override |
|
165 | @Override | |
| 182 | public void visit(LayerOutputsContribution contribution) { |
|
166 | public void visit(LayerOutputsContribution contribution) { | |
| 183 | var unit = compileUnitsView.requireUnit(artifactSlot.variant(), contribution.layer()); |
|
167 | var unit = compileUnitsView.requireUnit(artifactSlot.variant(), contribution.layer()); | |
| 184 | contributeCompileUnits(Set.of(unit), contribution.outputs()); |
|
168 | contributeCompileUnits(Set.of(unit), contribution.outputs()); | |
| 185 | } |
|
169 | } | |
| 186 |
|
170 | |||
| 187 | private void contributeCompileUnits(Set<CompileUnit> units, Set<String> outputs) { |
|
171 | private void contributeCompileUnits(Set<CompileUnit> units, Set<String> outputs) { | |
| 188 | units.stream() |
|
172 | units.stream() | |
| 189 | // expand variant compile units, make (compileUnit, outputName) pairs |
|
173 | // expand variant compile units, make (compileUnit, outputName) pairs | |
| 190 | .flatMap(unit -> outputs.stream() |
|
174 | .flatMap(unit -> outputs.stream() | |
| 191 | .map(output -> new CompileUnitOutputKey(unit, output))) |
|
175 | .map(output -> new CompileUnitOutputKey(unit, output))) | |
| 192 | .forEach(key -> contribute( |
|
176 | .forEach(key -> contribute( | |
| 193 | key, |
|
177 | key, | |
| 194 | sourceSetMaterializer.getSourceSet(key.unit()) |
|
178 | sourceSetMaterializer.getSourceSet(key.unit()) | |
| 195 | .map(s -> s.output(key.outputName())))); |
|
179 | .map(s -> s.output(key.outputName())))); | |
| 196 | } |
|
180 | } | |
| 197 |
|
181 | |||
| 198 | private void contribute(SlotInputKey key, Object resolvedInput) { |
|
182 | private void contribute(SlotInputKey key, Object resolvedInput) { | |
| 199 | assembly.addSlotInput(key, resolvedInput); |
|
183 | assembly.addSlotInput(key, resolvedInput); | |
| 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<>(); | |
| 207 |
|
191 | |||
| 208 | public void addSlotInput(SlotInputKey key, Object input) { |
|
192 | public void addSlotInput(SlotInputKey key, Object input) { | |
| 209 | if (!seen.add(key)) |
|
193 | if (!seen.add(key)) | |
| 210 | return; |
|
194 | return; | |
| 211 | inputs.from(input); |
|
195 | inputs.from(input); | |
| 212 | } |
|
196 | } | |
| 213 |
|
197 | |||
| 214 | public FileCollection inputs() { |
|
198 | public FileCollection inputs() { | |
| 215 | return inputs; |
|
199 | return inputs; | |
| 216 | } |
|
200 | } | |
| 217 | } |
|
201 | } | |
| 218 | } |
|
202 | } | |
| @@ -1,79 +1,81 | |||||
| 1 | package org.implab.gradle.variants.artifacts.internal; |
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
| 2 |
|
2 | |||
| 3 | import java.util.HashSet; |
|
3 | import java.util.HashSet; | |
| 4 | import java.util.Set; |
|
4 | import java.util.Set; | |
| 5 | import java.util.function.Consumer; |
|
5 | import java.util.function.Consumer; | |
| 6 | import java.util.stream.Stream; |
|
6 | import java.util.stream.Stream; | |
| 7 |
|
7 | |||
| 8 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
8 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 9 | import org.gradle.api.Action; |
|
9 | import org.gradle.api.Action; | |
| 10 | import org.gradle.api.model.ObjectFactory; |
|
10 | import org.gradle.api.model.ObjectFactory; | |
| 11 | import org.implab.gradle.common.core.lang.Strings; |
|
11 | import org.implab.gradle.common.core.lang.Strings; | |
| 12 | import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec; |
|
12 | import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec; | |
| 13 | import org.implab.gradle.variants.core.Layer; |
|
13 | import org.implab.gradle.variants.core.Layer; | |
| 14 | import org.implab.gradle.variants.core.Role; |
|
14 | import org.implab.gradle.variants.core.Role; | |
| 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 { | |
| 25 | private final Consumer<? super SlotContribution> consumer; |
|
27 | private final Consumer<? super SlotContribution> consumer; | |
| 26 | private final ObjectFactory objectFactory; |
|
28 | private final ObjectFactory objectFactory; | |
| 27 |
|
29 | |||
| 28 | DefaultArtifactAssemblySpec(ObjectFactory objectFactory, Consumer<? super SlotContribution> consumer) { |
|
30 | DefaultArtifactAssemblySpec(ObjectFactory objectFactory, Consumer<? super SlotContribution> consumer) { | |
| 29 | this.consumer = consumer; |
|
31 | this.consumer = consumer; | |
| 30 | this.objectFactory = objectFactory; |
|
32 | this.objectFactory = objectFactory; | |
| 31 | } |
|
33 | } | |
| 32 |
|
34 | |||
| 33 | @Override |
|
35 | @Override | |
| 34 | public void from(Object artifact) { |
|
36 | public void from(Object artifact) { | |
| 35 | consumer.accept(new DirectContribution(artifact)); |
|
37 | consumer.accept(new DirectContribution(artifact)); | |
| 36 | } |
|
38 | } | |
| 37 |
|
39 | |||
| 38 | @Override |
|
40 | @Override | |
| 39 | public void fromVariant(Action<? super OutputSelectionSpec> action) { |
|
41 | public void fromVariant(Action<? super OutputSelectionSpec> action) { | |
| 40 | consumer.accept(new VariantOutputsContribution(outputs(action))); |
|
42 | consumer.accept(new VariantOutputsContribution(outputs(action))); | |
| 41 | } |
|
43 | } | |
| 42 |
|
44 | |||
| 43 | @Override |
|
45 | @Override | |
| 44 | public void fromRole(String roleName, Action<? super OutputSelectionSpec> action) { |
|
46 | public void fromRole(String roleName, Action<? super OutputSelectionSpec> action) { | |
| 45 |
|
47 | |||
| 46 | consumer.accept(new RoleOutputsContribution( |
|
48 | consumer.accept(new RoleOutputsContribution( | |
| 47 | objectFactory.named(Role.class, roleName), |
|
49 | objectFactory.named(Role.class, roleName), | |
| 48 | outputs(action))); |
|
50 | outputs(action))); | |
| 49 | } |
|
51 | } | |
| 50 |
|
52 | |||
| 51 | @Override |
|
53 | @Override | |
| 52 | public void fromLayer(String layerName, Action<? super OutputSelectionSpec> action) { |
|
54 | public void fromLayer(String layerName, Action<? super OutputSelectionSpec> action) { | |
| 53 | consumer.accept(new LayerOutputsContribution( |
|
55 | consumer.accept(new LayerOutputsContribution( | |
| 54 | objectFactory.named(Layer.class, layerName), |
|
56 | objectFactory.named(Layer.class, layerName), | |
| 55 | outputs(action))); |
|
57 | outputs(action))); | |
| 56 | } |
|
58 | } | |
| 57 |
|
59 | |||
| 58 | private static Set<String> outputs(Action<? super OutputSelectionSpec> action) { |
|
60 | private static Set<String> outputs(Action<? super OutputSelectionSpec> action) { | |
| 59 | var spec = new OutputsSetSpec(); |
|
61 | var spec = new OutputsSetSpec(); | |
| 60 | action.execute(spec); |
|
62 | action.execute(spec); | |
| 61 | return spec.outputs(); |
|
63 | return spec.outputs(); | |
| 62 | } |
|
64 | } | |
| 63 |
|
65 | |||
| 64 | private static class OutputsSetSpec implements OutputSelectionSpec { |
|
66 | private static class OutputsSetSpec implements OutputSelectionSpec { | |
| 65 | private final Set<String> outputs = new HashSet<>(); |
|
67 | private final Set<String> outputs = new HashSet<>(); | |
| 66 |
|
68 | |||
| 67 | @Override |
|
69 | @Override | |
| 68 | public void output(String name, String... extra) { |
|
70 | public void output(String name, String... extra) { | |
| 69 | Stream.concat(Stream.of(name), Stream.of(extra)) |
|
71 | Stream.concat(Stream.of(name), Stream.of(extra)) | |
| 70 | .map(Strings::requireNonBlank) |
|
72 | .map(Strings::requireNonBlank) | |
| 71 | .forEach(outputs::add); |
|
73 | .forEach(outputs::add); | |
| 72 | } |
|
74 | } | |
| 73 |
|
75 | |||
| 74 | Set<String> outputs() { |
|
76 | Set<String> outputs() { | |
| 75 | return Set.copyOf(outputs); |
|
77 | return Set.copyOf(outputs); | |
| 76 | } |
|
78 | } | |
| 77 |
|
79 | |||
| 78 | } |
|
80 | } | |
| 79 | } |
|
81 | } | |
| @@ -1,107 +1,112 | |||||
| 1 | package org.implab.gradle.variants.artifacts.internal; |
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
| 2 |
|
2 | |||
| 3 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
3 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 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 | /** | |
| 15 | * Handles outgoing artifact materialization policy. |
|
17 | * Handles outgoing artifact materialization policy. | |
| 16 | * |
|
18 | * | |
| 17 | * <p>Materialization is the phase where the plugin interprets variant artifact |
|
19 | * <p>Materialization is the phase where the plugin interprets variant artifact | |
| 18 | * declarations as Gradle outgoing publication state: a consumable configuration, |
|
20 | * declarations as Gradle outgoing publication state: a consumable configuration, | |
| 19 | * its primary artifact set, secondary artifact variants, and attributes. |
|
21 | * its primary artifact set, secondary artifact variants, and attributes. | |
| 20 | * |
|
22 | * | |
| 21 | * <p>The handler provides extension points for customizing the materialized |
|
23 | * <p>The handler provides extension points for customizing the materialized | |
| 22 | * Gradle-facing objects. These hooks intentionally expose Gradle API objects. |
|
24 | * Gradle-facing objects. These hooks intentionally expose Gradle API objects. | |
| 23 | * This allows advanced customization, but also means that callers can bypass |
|
25 | * This allows advanced customization, but also means that callers can bypass | |
| 24 | * the plugin model. Such customizations are considered caller responsibility. |
|
26 | * the plugin model. Such customizations are considered caller responsibility. | |
| 25 | * |
|
27 | * | |
| 26 | * <p>The internal binding mechanics are not part of the public contract. The |
|
28 | * <p>The internal binding mechanics are not part of the public contract. The | |
| 27 | * contract is the materialized outgoing state exposed through the specification |
|
29 | * contract is the materialized outgoing state exposed through the specification | |
| 28 | * objects. |
|
30 | * objects. | |
| 29 | */ |
|
31 | */ | |
| 30 | @NonNullByDefault |
|
32 | @NonNullByDefault | |
| 31 | public class MaterializationPolicyHandler implements Action<OutgoingVariant> { |
|
33 | public class MaterializationPolicyHandler implements Action<OutgoingVariant> { | |
| 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(); | |
| 49 |
|
52 | |||
| 50 | variantMaterialized(variant, configuration); |
|
53 | variantMaterialized(variant, configuration); | |
| 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 | }); | |
| 62 | }; |
|
67 | }; | |
| 63 |
|
68 | |||
| 64 | public void whenVariantMaterialized(Action<? super OutgoingConfigurationSpec> action) { |
|
69 | public void whenVariantMaterialized(Action<? super OutgoingConfigurationSpec> action) { | |
| 65 | variantMaterialization.forEach(action::execute); |
|
70 | variantMaterialization.forEach(action::execute); | |
| 66 | } |
|
71 | } | |
| 67 |
|
72 | |||
| 68 | public void whenSlotMaterialized(Action<? super OutgoingConfigurationSlotSpec> action) { |
|
73 | public void whenSlotMaterialized(Action<? super OutgoingConfigurationSlotSpec> action) { | |
| 69 | slotMaterialization.forEach(action::execute); |
|
74 | slotMaterialization.forEach(action::execute); | |
| 70 | } |
|
75 | } | |
| 71 |
|
76 | |||
| 72 | private void variantMaterialized(Variant variant, Configuration configuration) { |
|
77 | private void variantMaterialized(Variant variant, Configuration configuration) { | |
| 73 | variantMaterialization.add(new OutgoingConfigurationSpec() { |
|
78 | variantMaterialization.add(new OutgoingConfigurationSpec() { | |
| 74 |
|
79 | |||
| 75 | @Override |
|
80 | @Override | |
| 76 | public Variant getVariant() { |
|
81 | public Variant getVariant() { | |
| 77 | return variant; |
|
82 | return variant; | |
| 78 | } |
|
83 | } | |
| 79 |
|
84 | |||
| 80 | @Override |
|
85 | @Override | |
| 81 | public Configuration getConfiguration() { |
|
86 | public Configuration getConfiguration() { | |
| 82 | return configuration; |
|
87 | return configuration; | |
| 83 | } |
|
88 | } | |
| 84 |
|
89 | |||
| 85 | }); |
|
90 | }); | |
| 86 | } |
|
91 | } | |
| 87 |
|
92 | |||
| 88 | private void slotMaterialized(ArtifactSlot slot, boolean primary, AttributeContainer attributes) { |
|
93 | private void slotMaterialized(ArtifactSlot slot, boolean primary, AttributeContainer attributes) { | |
| 89 | slotMaterialization.add(new OutgoingConfigurationSlotSpec() { |
|
94 | slotMaterialization.add(new OutgoingConfigurationSlotSpec() { | |
| 90 | @Override |
|
95 | @Override | |
| 91 | public boolean isPrimary() { |
|
96 | public boolean isPrimary() { | |
| 92 | return primary; |
|
97 | return primary; | |
| 93 | } |
|
98 | } | |
| 94 |
|
99 | |||
| 95 | @Override |
|
100 | @Override | |
| 96 | public ArtifactSlot getArtifactSlot() { |
|
101 | public ArtifactSlot getArtifactSlot() { | |
| 97 | return slot; |
|
102 | return slot; | |
| 98 | } |
|
103 | } | |
| 99 |
|
104 | |||
| 100 | @Override |
|
105 | @Override | |
| 101 | public void artifactAttributes(Action<? super AttributeContainer> action) { |
|
106 | public void artifactAttributes(Action<? super AttributeContainer> action) { | |
| 102 | action.execute(attributes); |
|
107 | action.execute(attributes); | |
| 103 | } |
|
108 | } | |
| 104 | }); |
|
109 | }); | |
| 105 | } |
|
110 | } | |
| 106 |
|
111 | |||
| 107 | } |
|
112 | } | |
| @@ -1,33 +1,33 | |||||
| 1 | package org.implab.gradle.variants.artifacts.internal; |
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Action; |
|
3 | import org.gradle.api.Action; | |
| 4 | import org.gradle.api.InvalidUserDataException; |
|
4 | import org.gradle.api.InvalidUserDataException; | |
| 5 | import org.gradle.api.provider.ProviderFactory; |
|
5 | import org.gradle.api.provider.ProviderFactory; | |
| 6 | import org.implab.gradle.variants.artifacts.OutgoingVariant; |
|
6 | import org.implab.gradle.variants.artifacts.OutgoingVariant; | |
| 7 |
|
7 | |||
| 8 | public class SingleSlotConvention implements Action<OutgoingVariant> { |
|
8 | public class SingleSlotConvention implements Action<OutgoingVariant> { | |
| 9 |
|
9 | |||
| 10 | private final ProviderFactory providers; |
|
10 | private final ProviderFactory providers; | |
| 11 |
|
11 | |||
| 12 | public SingleSlotConvention(ProviderFactory providers) { |
|
12 | public SingleSlotConvention(ProviderFactory providers) { | |
| 13 | this.providers = providers; |
|
13 | this.providers = providers; | |
| 14 | } |
|
14 | } | |
| 15 |
|
15 | |||
| 16 | @Override |
|
16 | @Override | |
| 17 | public void execute(OutgoingVariant outgoingVariant) { |
|
17 | public void execute(OutgoingVariant outgoingVariant) { | |
| 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()); | |
| 25 | if (slots.size() > 1) |
|
25 | if (slots.size() > 1) | |
| 26 | throw new InvalidUserDataException("Multiple slots declared for " + outgoingVariant.getVariant() + |
|
26 | throw new InvalidUserDataException("Multiple slots declared for " + outgoingVariant.getVariant() + | |
| 27 | ", please specify primary slot explicitly"); |
|
27 | ", please specify primary slot explicitly"); | |
| 28 |
|
28 | |||
| 29 | return slots.stream().findAny().get(); |
|
29 | return slots.stream().findAny().get(); | |
| 30 | })); |
|
30 | })); | |
| 31 | } |
|
31 | } | |
| 32 |
|
32 | |||
| 33 | } |
|
33 | } | |
| @@ -1,41 +1,40 | |||||
| 1 | /** |
|
1 | /** | |
| 2 | * Variant-scoped outgoing artifacts. |
|
2 | * Variant-scoped outgoing artifacts. | |
| 3 | * |
|
3 | * | |
| 4 | * <p>This package models the external artifact contract of a project in terms of variant-local slots. |
|
4 | * <p>This package models the external artifact contract of a project in terms of variant-local slots. | |
| 5 | * A variant represents one outgoing contract, while a slot represents one artifact set inside that |
|
5 | * A variant represents one outgoing contract, while a slot represents one artifact set inside that | |
| 6 | * contract. |
|
6 | * contract. | |
| 7 | * |
|
7 | * | |
| 8 | * <p>The model intentionally separates cheap identity objects from stateful build objects: |
|
8 | * <p>The model intentionally separates cheap identity objects from stateful build objects: | |
| 9 | * |
|
9 | * | |
| 10 | * <ul> |
|
10 | * <ul> | |
| 11 | * <li>{@link org.implab.gradle.variants.artifacts.ArtifactSlot} identifies a published slot inside a |
|
11 | * <li>{@link org.implab.gradle.variants.artifacts.ArtifactSlot} identifies a published slot inside a | |
| 12 | * variant;</li> |
|
12 | * variant;</li> | |
| 13 | * <li>{@link org.implab.gradle.variants.artifacts.ArtifactAssembly} is the lazily materialized body of |
|
13 | * <li>{@link org.implab.gradle.variants.artifacts.ArtifactAssembly} is the lazily materialized body of | |
| 14 | * that slot.</li> |
|
14 | * that slot.</li> | |
| 15 | * </ul> |
|
15 | * </ul> | |
| 16 | * |
|
16 | * | |
| 17 | * <p>Each slot is expected to materialize to exactly one published artifact: either one file or one |
|
17 | * <p>Each slot is expected to materialize to exactly one published artifact: either one file or one | |
| 18 | * directory. Internal build topology such as roles may participate in slot assembly rules, but does not |
|
18 | * directory. Internal build topology such as roles may participate in slot assembly rules, but does not | |
| 19 | * belong to external artifact identity. |
|
19 | * belong to external artifact identity. | |
| 20 | * |
|
20 | * | |
| 21 | * <p>Typical usage: |
|
21 | * <p>Typical usage: | |
| 22 | * |
|
22 | * | |
| 23 | * <pre>{@code |
|
23 | * <pre>{@code | |
| 24 | * variantArtifacts { |
|
24 | * variantArtifacts { | |
| 25 | * variant("browser") { |
|
25 | * variant("browser") { | |
| 26 | * primarySlot("runtime") { |
|
26 | * primarySlot("runtime") { | |
| 27 | * fromRole("main") { output("js") } |
|
27 | * fromRole("main") { output("js") } | |
| 28 | * } |
|
28 | * } | |
| 29 | * slot("sources") { |
|
29 | * slot("sources") { | |
| 30 | * fromLayer("main") { output("sources") } |
|
30 | * fromLayer("main") { output("sources") } | |
| 31 | * } |
|
31 | * } | |
| 32 | * } |
|
32 | * } | |
| 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; | |
| @@ -1,563 +1,691 | |||||
| 1 | package org.implab.gradle.variants; |
|
1 | package org.implab.gradle.variants; | |
| 2 |
|
2 | |||
| 3 | import static org.junit.jupiter.api.Assertions.assertTrue; |
|
3 | import static org.junit.jupiter.api.Assertions.assertTrue; | |
| 4 |
|
4 | |||
| 5 | import org.gradle.testkit.runner.BuildResult; |
|
5 | import org.gradle.testkit.runner.BuildResult; | |
| 6 | import org.gradle.testkit.runner.TaskOutcome; |
|
6 | import org.gradle.testkit.runner.TaskOutcome; | |
| 7 | import org.junit.jupiter.api.Test; |
|
7 | import org.junit.jupiter.api.Test; | |
| 8 |
|
8 | |||
| 9 | class VariantArtifactsPluginFunctionalTest extends AbstractFunctionalTest { |
|
9 | class VariantArtifactsPluginFunctionalTest extends AbstractFunctionalTest { | |
| 10 |
|
10 | |||
| 11 | @Test |
|
11 | @Test | |
| 12 | void gradleReferenceLazyOutgoingConfigurationAllowsSecondaryArtifactSelection() throws Exception { |
|
12 | void gradleReferenceLazyOutgoingConfigurationAllowsSecondaryArtifactSelection() throws Exception { | |
| 13 | writeFile("settings.gradle", """ |
|
13 | writeFile("settings.gradle", """ | |
| 14 | rootProject.name = 'gradle-reference-outgoing-resolution' |
|
14 | rootProject.name = 'gradle-reference-outgoing-resolution' | |
| 15 | include 'producer', 'consumer' |
|
15 | include 'producer', 'consumer' | |
| 16 | """); |
|
16 | """); | |
| 17 | writeFile("producer/inputs/typesPackage", "types\n"); |
|
17 | writeFile("producer/inputs/typesPackage", "types\n"); | |
| 18 | writeFile("producer/inputs/js", "js\n"); |
|
18 | writeFile("producer/inputs/js", "js\n"); | |
| 19 | writeBuildFile(""" |
|
19 | writeBuildFile(""" | |
| 20 | import org.gradle.api.attributes.Attribute |
|
20 | import org.gradle.api.attributes.Attribute | |
| 21 |
|
21 | |||
| 22 | def variantAttr = Attribute.of('test.variant', String) |
|
22 | def variantAttr = Attribute.of('test.variant', String) | |
| 23 | def slotAttr = Attribute.of('test.slot', String) |
|
23 | def slotAttr = Attribute.of('test.slot', String) | |
| 24 |
|
24 | |||
| 25 | project(':producer') { |
|
25 | project(':producer') { | |
| 26 | def browserElements = configurations.consumable('browserElements') |
|
26 | def browserElements = configurations.consumable('browserElements') | |
| 27 |
|
27 | |||
| 28 | println('reference: registered browserElements provider') |
|
28 | println('reference: registered browserElements provider') | |
| 29 |
|
29 | |||
| 30 | browserElements.configure { configuration -> |
|
30 | browserElements.configure { configuration -> | |
| 31 | println('reference: configuring browserElements') |
|
31 | println('reference: configuring browserElements') | |
| 32 |
|
32 | |||
| 33 | configuration.attributes.attribute(variantAttr, 'browser') |
|
33 | configuration.attributes.attribute(variantAttr, 'browser') | |
| 34 | configuration.outgoing.attributes.attribute(slotAttr, 'typesPackage') |
|
34 | configuration.outgoing.attributes.attribute(slotAttr, 'typesPackage') | |
| 35 | configuration.outgoing.artifact(layout.projectDirectory.file('inputs/typesPackage')) |
|
35 | configuration.outgoing.artifact(layout.projectDirectory.file('inputs/typesPackage')) | |
| 36 |
|
36 | |||
| 37 | configuration.outgoing.variants.create('js') { secondary -> |
|
37 | configuration.outgoing.variants.create('js') { secondary -> | |
| 38 | println('reference: creating js outgoing variant') |
|
38 | println('reference: creating js outgoing variant') | |
| 39 |
|
39 | |||
| 40 | secondary.attributes.attribute(slotAttr, 'js') |
|
40 | secondary.attributes.attribute(slotAttr, 'js') | |
| 41 | secondary.artifact(layout.projectDirectory.file('inputs/js')) |
|
41 | secondary.artifact(layout.projectDirectory.file('inputs/js')) | |
| 42 | } |
|
42 | } | |
| 43 | } |
|
43 | } | |
| 44 | } |
|
44 | } | |
| 45 |
|
45 | |||
| 46 | project(':consumer') { |
|
46 | project(':consumer') { | |
| 47 | configurations { |
|
47 | configurations { | |
| 48 | compileView { |
|
48 | compileView { | |
| 49 | canBeResolved = true |
|
49 | canBeResolved = true | |
| 50 | canBeConsumed = false |
|
50 | canBeConsumed = false | |
| 51 | canBeDeclared = true |
|
51 | canBeDeclared = true | |
| 52 | attributes { |
|
52 | attributes { | |
| 53 | attribute(variantAttr, 'browser') |
|
53 | attribute(variantAttr, 'browser') | |
| 54 | attribute(slotAttr, 'typesPackage') |
|
54 | attribute(slotAttr, 'typesPackage') | |
| 55 | } |
|
55 | } | |
| 56 | } |
|
56 | } | |
| 57 | } |
|
57 | } | |
| 58 |
|
58 | |||
| 59 | dependencies { |
|
59 | dependencies { | |
| 60 | compileView project(':producer') |
|
60 | compileView project(':producer') | |
| 61 | } |
|
61 | } | |
| 62 |
|
62 | |||
| 63 | tasks.register('probe') { |
|
63 | tasks.register('probe') { | |
| 64 | doLast { |
|
64 | doLast { | |
| 65 | println('reference: resolving primary files') |
|
65 | println('reference: resolving primary files') | |
| 66 |
|
66 | |||
| 67 | def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',') |
|
67 | def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',') | |
| 68 |
|
68 | |||
| 69 | println('reference: resolving secondary files') |
|
69 | println('reference: resolving secondary files') | |
| 70 |
|
70 | |||
| 71 | def jsFiles = configurations.compileView.incoming.artifactView { |
|
71 | def jsFiles = configurations.compileView.incoming.artifactView { | |
| 72 | attributes { |
|
72 | attributes { | |
| 73 | attribute(slotAttr, 'js') |
|
73 | attribute(slotAttr, 'js') | |
| 74 | } |
|
74 | } | |
| 75 | }.files.files.collect { it.name }.sort().join(',') |
|
75 | }.files.files.collect { it.name }.sort().join(',') | |
| 76 |
|
76 | |||
| 77 | println('compileFiles=' + compileFiles) |
|
77 | println('compileFiles=' + compileFiles) | |
| 78 | println('jsFiles=' + jsFiles) |
|
78 | println('jsFiles=' + jsFiles) | |
| 79 | } |
|
79 | } | |
| 80 | } |
|
80 | } | |
| 81 | } |
|
81 | } | |
| 82 | """); |
|
82 | """); | |
| 83 |
|
83 | |||
| 84 | BuildResult result = runner(":consumer:probe").build(); |
|
84 | BuildResult result = runner(":consumer:probe").build(); | |
| 85 | var output = result.getOutput(); |
|
85 | var output = result.getOutput(); | |
| 86 | var registered = output.indexOf("reference: registered browserElements provider"); |
|
86 | var registered = output.indexOf("reference: registered browserElements provider"); | |
| 87 | var resolvingPrimary = output.indexOf("reference: resolving primary files"); |
|
87 | var resolvingPrimary = output.indexOf("reference: resolving primary files"); | |
| 88 | var configuring = output.indexOf("reference: configuring browserElements"); |
|
88 | var configuring = output.indexOf("reference: configuring browserElements"); | |
| 89 | var creatingSecondary = output.indexOf("reference: creating js outgoing variant"); |
|
89 | var creatingSecondary = output.indexOf("reference: creating js outgoing variant"); | |
| 90 | var resolvingSecondary = output.indexOf("reference: resolving secondary files"); |
|
90 | var resolvingSecondary = output.indexOf("reference: resolving secondary files"); | |
| 91 |
|
91 | |||
| 92 | assertTrue(registered >= 0); |
|
92 | assertTrue(registered >= 0); | |
| 93 | assertTrue(resolvingPrimary >= 0); |
|
93 | assertTrue(resolvingPrimary >= 0); | |
| 94 | assertTrue(configuring >= 0); |
|
94 | assertTrue(configuring >= 0); | |
| 95 | assertTrue(creatingSecondary >= 0); |
|
95 | assertTrue(creatingSecondary >= 0); | |
| 96 | assertTrue(resolvingSecondary >= 0); |
|
96 | assertTrue(resolvingSecondary >= 0); | |
| 97 | assertTrue(registered < resolvingPrimary); |
|
97 | assertTrue(registered < resolvingPrimary); | |
| 98 | assertTrue(resolvingPrimary < configuring); |
|
98 | assertTrue(resolvingPrimary < configuring); | |
| 99 | assertTrue(configuring < creatingSecondary); |
|
99 | assertTrue(configuring < creatingSecondary); | |
| 100 | assertTrue(creatingSecondary < resolvingSecondary); |
|
100 | assertTrue(creatingSecondary < resolvingSecondary); | |
| 101 | assertTrue(output.contains("compileFiles=typesPackage")); |
|
101 | assertTrue(output.contains("compileFiles=typesPackage")); | |
| 102 | assertTrue(output.contains("jsFiles=js")); |
|
102 | assertTrue(output.contains("jsFiles=js")); | |
| 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"); | |
| 109 | writeFile("inputs/amd.js", "console.log('amd')\n"); |
|
177 | writeFile("inputs/amd.js", "console.log('amd')\n"); | |
| 110 | writeFile("inputs/mainJs.txt", "mainJs marker\n"); |
|
178 | writeFile("inputs/mainJs.txt", "mainJs marker\n"); | |
| 111 | writeFile("inputs/amdJs.txt", "amdJs marker\n"); |
|
179 | writeFile("inputs/amdJs.txt", "amdJs marker\n"); | |
| 112 | writeBuildFile(""" |
|
180 | writeBuildFile(""" | |
| 113 | import org.gradle.api.attributes.Attribute |
|
181 | import org.gradle.api.attributes.Attribute | |
| 114 |
|
182 | |||
| 115 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
183 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 116 |
|
184 | |||
| 117 | def variantAttr = Attribute.of('test.variant', String) |
|
185 | def variantAttr = Attribute.of('test.variant', String) | |
| 118 | def slotAttr = Attribute.of('test.slot', String) |
|
186 | def slotAttr = Attribute.of('test.slot', String) | |
| 119 |
|
187 | |||
| 120 | variants.layers.create('mainBase') |
|
188 | variants.layers.create('mainBase') | |
| 121 | variants.layers.create('mainAmd') |
|
189 | variants.layers.create('mainAmd') | |
| 122 | variants.roles.create('main') |
|
190 | variants.roles.create('main') | |
| 123 | variants.roles.create('test') |
|
191 | variants.roles.create('test') | |
| 124 | variants.variant('browser') { |
|
192 | variants.variant('browser') { | |
| 125 | role('main') { |
|
193 | role('main') { | |
| 126 | layers('mainBase', 'mainAmd') |
|
194 | layers('mainBase', 'mainAmd') | |
| 127 | } |
|
195 | } | |
| 128 | } |
|
196 | } | |
| 129 |
|
197 | |||
| 130 | variantSources { |
|
198 | variantSources { | |
| 131 | layer('mainBase') { |
|
199 | layer('mainBase') { | |
| 132 | declareOutputs('js') |
|
200 | declareOutputs('js') | |
| 133 | registerOutput('js', layout.projectDirectory.file('inputs/base.js')) |
|
201 | registerOutput('js', layout.projectDirectory.file('inputs/base.js')) | |
| 134 | } |
|
202 | } | |
| 135 | layer('mainAmd') { |
|
203 | layer('mainAmd') { | |
| 136 | declareOutputs('js') |
|
204 | declareOutputs('js') | |
| 137 | registerOutput('js', layout.projectDirectory.file('inputs/amd.js')) |
|
205 | registerOutput('js', layout.projectDirectory.file('inputs/amd.js')) | |
| 138 | } |
|
206 | } | |
| 139 | } |
|
207 | } | |
| 140 |
|
208 | |||
| 141 | variantArtifacts { |
|
209 | variantArtifacts { | |
| 142 | variant('browser') { |
|
210 | variant('browser') { | |
| 143 | primarySlot('mainJs') { |
|
211 | primarySlot('mainJs') { | |
| 144 | fromRole('main') { |
|
212 | fromRole('main') { | |
| 145 | output('js') |
|
213 | output('js') | |
| 146 | } |
|
214 | } | |
| 147 | from(layout.projectDirectory.file('inputs/mainJs.txt')) |
|
215 | from(layout.projectDirectory.file('inputs/mainJs.txt')) | |
| 148 | } |
|
216 | } | |
| 149 | slot('amdJs') { |
|
217 | slot('amdJs') { | |
| 150 | fromLayer('mainAmd') { |
|
218 | fromLayer('mainAmd') { | |
| 151 | output('js') |
|
219 | output('js') | |
| 152 | } |
|
220 | } | |
| 153 | from(layout.projectDirectory.file('inputs/amdJs.txt')) |
|
221 | from(layout.projectDirectory.file('inputs/amdJs.txt')) | |
| 154 | } |
|
222 | } | |
| 155 | } |
|
223 | } | |
| 156 |
|
224 | |||
| 157 | whenOutgoingConfiguration { publication -> |
|
225 | whenOutgoingConfiguration { publication -> | |
| 158 | publication.configuration { |
|
226 | publication.configuration { | |
| 159 | attributes.attribute(variantAttr, publication.variant.name) |
|
227 | attributes.attribute(variantAttr, publication.variant.name) | |
| 160 | } |
|
228 | } | |
| 161 | } |
|
229 | } | |
| 162 |
|
230 | |||
| 163 | whenOutgoingSlot { publication -> |
|
231 | whenOutgoingSlot { publication -> | |
| 164 | def slotName = publication.artifactSlot.slot.name |
|
232 | def slotName = publication.artifactSlot.slot.name | |
| 165 | publication.artifactAttributes { |
|
233 | publication.artifactAttributes { | |
| 166 | attribute(slotAttr, slotName) |
|
234 | attribute(slotAttr, slotName) | |
| 167 | } |
|
235 | } | |
| 168 | } |
|
236 | } | |
| 169 | } |
|
237 | } | |
| 170 |
|
238 | |||
| 171 | tasks.register('probe') { |
|
239 | tasks.register('probe') { | |
| 172 | dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_mainJs' |
|
240 | dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_mainJs' | |
| 173 | dependsOn 'assembleVariantArtifactSlot_v7_browser_s5_amdJs' |
|
241 | dependsOn 'assembleVariantArtifactSlot_v7_browser_s5_amdJs' | |
| 174 |
|
242 | |||
| 175 | doLast { |
|
243 | doLast { | |
| 176 | def mainDir = layout.buildDirectory.dir('variant-assemblies/browser/mainJs').get().asFile |
|
244 | def mainDir = layout.buildDirectory.dir('variant-assemblies/browser/mainJs').get().asFile | |
| 177 | def amdDir = layout.buildDirectory.dir('variant-assemblies/browser/amdJs').get().asFile |
|
245 | def amdDir = layout.buildDirectory.dir('variant-assemblies/browser/amdJs').get().asFile | |
| 178 |
|
246 | |||
| 179 | assert new File(mainDir, 'base.js').exists() |
|
247 | assert new File(mainDir, 'base.js').exists() | |
| 180 | assert new File(mainDir, 'amd.js').exists() |
|
248 | assert new File(mainDir, 'amd.js').exists() | |
| 181 | assert new File(mainDir, 'mainJs.txt').exists() |
|
249 | assert new File(mainDir, 'mainJs.txt').exists() | |
| 182 |
|
250 | |||
| 183 | assert !new File(amdDir, 'base.js').exists() |
|
251 | assert !new File(amdDir, 'base.js').exists() | |
| 184 | assert new File(amdDir, 'amd.js').exists() |
|
252 | assert new File(amdDir, 'amd.js').exists() | |
| 185 | assert new File(amdDir, 'amdJs.txt').exists() |
|
253 | assert new File(amdDir, 'amdJs.txt').exists() | |
| 186 |
|
254 | |||
| 187 | def elements = configurations.getByName('browserElements') |
|
255 | def elements = configurations.getByName('browserElements') | |
| 188 | def amdVariant = elements.outgoing.variants.getByName('amdJs') |
|
256 | def amdVariant = elements.outgoing.variants.getByName('amdJs') | |
| 189 |
|
257 | |||
| 190 | println('variantAttr=' + elements.attributes.getAttribute(variantAttr)) |
|
258 | println('variantAttr=' + elements.attributes.getAttribute(variantAttr)) | |
| 191 | println('primarySlotAttr=' + elements.outgoing.attributes.getAttribute(slotAttr)) |
|
259 | println('primarySlotAttr=' + elements.outgoing.attributes.getAttribute(slotAttr)) | |
| 192 | println('amdSlotAttr=' + amdVariant.attributes.getAttribute(slotAttr)) |
|
260 | println('amdSlotAttr=' + amdVariant.attributes.getAttribute(slotAttr)) | |
| 193 | println('configurations=' + configurations.matching { it.name == 'browserElements' }.collect { it.name }.join(',')) |
|
261 | println('configurations=' + configurations.matching { it.name == 'browserElements' }.collect { it.name }.join(',')) | |
| 194 | println('secondaryVariants=' + elements.outgoing.variants.collect { it.name }.sort().join(',')) |
|
262 | println('secondaryVariants=' + elements.outgoing.variants.collect { it.name }.sort().join(',')) | |
| 195 | } |
|
263 | } | |
| 196 | } |
|
264 | } | |
| 197 | """); |
|
265 | """); | |
| 198 |
|
266 | |||
| 199 | BuildResult result = runner("probe").build(); |
|
267 | BuildResult result = runner("probe").build(); | |
| 200 |
|
268 | |||
| 201 | assertTrue(result.getOutput().contains("variantAttr=browser")); |
|
269 | assertTrue(result.getOutput().contains("variantAttr=browser")); | |
| 202 | assertTrue(result.getOutput().contains("primarySlotAttr=mainJs")); |
|
270 | assertTrue(result.getOutput().contains("primarySlotAttr=mainJs")); | |
| 203 | assertTrue(result.getOutput().contains("amdSlotAttr=amdJs")); |
|
271 | assertTrue(result.getOutput().contains("amdSlotAttr=amdJs")); | |
| 204 | assertTrue(result.getOutput().contains("configurations=browserElements")); |
|
272 | assertTrue(result.getOutput().contains("configurations=browserElements")); | |
| 205 | assertTrue(result.getOutput().contains("secondaryVariants=amdJs")); |
|
273 | assertTrue(result.getOutput().contains("secondaryVariants=amdJs")); | |
| 206 | assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS); |
|
274 | assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS); | |
| 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(""" | |
| 213 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
341 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 214 |
|
342 | |||
| 215 | variants.layers.create('main') |
|
343 | variants.layers.create('main') | |
| 216 | variants.roles.create('main') |
|
344 | variants.roles.create('main') | |
| 217 | variants.variant('browser') { |
|
345 | variants.variant('browser') { | |
| 218 | role('main') { |
|
346 | role('main') { | |
| 219 | layers('main') |
|
347 | layers('main') | |
| 220 | } |
|
348 | } | |
| 221 | } |
|
349 | } | |
| 222 |
|
350 | |||
| 223 | variantSources.layer('main') { |
|
351 | variantSources.layer('main') { | |
| 224 | declareOutputs('types') |
|
352 | declareOutputs('types') | |
| 225 | } |
|
353 | } | |
| 226 |
|
354 | |||
| 227 | variantArtifacts { |
|
355 | variantArtifacts { | |
| 228 | variant('browser') { |
|
356 | variant('browser') { | |
| 229 | slot('typesPackage') { |
|
357 | slot('typesPackage') { | |
| 230 | fromVariant { |
|
358 | fromVariant { | |
| 231 | output('types') |
|
359 | output('types') | |
| 232 | } |
|
360 | } | |
| 233 | } |
|
361 | } | |
| 234 | } |
|
362 | } | |
| 235 | } |
|
363 | } | |
| 236 |
|
364 | |||
| 237 | tasks.register('probe') { |
|
365 | tasks.register('probe') { | |
| 238 | doLast { |
|
366 | doLast { | |
| 239 | variantArtifacts.whenAvailable { ctx -> |
|
367 | variantArtifacts.whenAvailable { ctx -> | |
| 240 | def browser = objects.named(org.implab.gradle.variants.core.Variant, 'browser') |
|
368 | def browser = objects.named(org.implab.gradle.variants.core.Variant, 'browser') | |
| 241 | println('primary=' + ctx.findOutgoing(browser).get().primarySlot.get().name) |
|
369 | println('primary=' + ctx.findOutgoing(browser).get().primarySlot.get().name) | |
| 242 | } |
|
370 | } | |
| 243 | } |
|
371 | } | |
| 244 | } |
|
372 | } | |
| 245 | """); |
|
373 | """); | |
| 246 |
|
374 | |||
| 247 | BuildResult result = runner("probe").build(); |
|
375 | BuildResult result = runner("probe").build(); | |
| 248 |
|
376 | |||
| 249 | assertTrue(result.getOutput().contains("primary=typesPackage")); |
|
377 | assertTrue(result.getOutput().contains("primary=typesPackage")); | |
| 250 | } |
|
378 | } | |
| 251 |
|
379 | |||
| 252 | @Test |
|
380 | @Test | |
| 253 | void materializesDirectSlotInputsWithoutVariantSourceBindings() throws Exception { |
|
381 | void materializesDirectSlotInputsWithoutVariantSourceBindings() throws Exception { | |
| 254 | writeSettings("variant-artifacts-direct-input"); |
|
382 | writeSettings("variant-artifacts-direct-input"); | |
| 255 | writeFile("inputs/bundle.js", "console.log('bundle')\n"); |
|
383 | writeFile("inputs/bundle.js", "console.log('bundle')\n"); | |
| 256 | writeBuildFile(""" |
|
384 | writeBuildFile(""" | |
| 257 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
385 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 258 |
|
386 | |||
| 259 | variants.layers.create('main') |
|
387 | variants.layers.create('main') | |
| 260 | variants.roles.create('main') |
|
388 | variants.roles.create('main') | |
| 261 | variants.variant('browser') { |
|
389 | variants.variant('browser') { | |
| 262 | role('main') { |
|
390 | role('main') { | |
| 263 | layers('main') |
|
391 | layers('main') | |
| 264 | } |
|
392 | } | |
| 265 | } |
|
393 | } | |
| 266 |
|
394 | |||
| 267 | variantArtifacts { |
|
395 | variantArtifacts { | |
| 268 | variant('browser') { |
|
396 | variant('browser') { | |
| 269 | primarySlot('bundle') { |
|
397 | primarySlot('bundle') { | |
| 270 | from(layout.projectDirectory.file('inputs/bundle.js')) |
|
398 | from(layout.projectDirectory.file('inputs/bundle.js')) | |
| 271 | } |
|
399 | } | |
| 272 | } |
|
400 | } | |
| 273 | } |
|
401 | } | |
| 274 |
|
402 | |||
| 275 | tasks.register('probe') { |
|
403 | tasks.register('probe') { | |
| 276 | dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_bundle' |
|
404 | dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_bundle' | |
| 277 |
|
405 | |||
| 278 | doLast { |
|
406 | doLast { | |
| 279 | def bundleDir = layout.buildDirectory.dir('variant-assemblies/browser/bundle').get().asFile |
|
407 | def bundleDir = layout.buildDirectory.dir('variant-assemblies/browser/bundle').get().asFile | |
| 280 | assert new File(bundleDir, 'bundle.js').exists() |
|
408 | assert new File(bundleDir, 'bundle.js').exists() | |
| 281 | } |
|
409 | } | |
| 282 | } |
|
410 | } | |
| 283 | """); |
|
411 | """); | |
| 284 |
|
412 | |||
| 285 | BuildResult result = runner("probe").build(); |
|
413 | BuildResult result = runner("probe").build(); | |
| 286 |
|
414 | |||
| 287 | assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS); |
|
415 | assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS); | |
| 288 | } |
|
416 | } | |
| 289 |
|
417 | |||
| 290 | @Test |
|
418 | @Test | |
| 291 | void combinesDirectAndTopologyAwareSlotInputs() throws Exception { |
|
419 | void combinesDirectAndTopologyAwareSlotInputs() throws Exception { | |
| 292 | writeSettings("variant-artifacts-combined-inputs"); |
|
420 | writeSettings("variant-artifacts-combined-inputs"); | |
| 293 | writeFile("inputs/base.js", "console.log('base')\n"); |
|
421 | writeFile("inputs/base.js", "console.log('base')\n"); | |
| 294 | writeFile("inputs/marker.txt", "marker\n"); |
|
422 | writeFile("inputs/marker.txt", "marker\n"); | |
| 295 | writeBuildFile(""" |
|
423 | writeBuildFile(""" | |
| 296 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
424 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 297 |
|
425 | |||
| 298 | variants.layers.create('main') |
|
426 | variants.layers.create('main') | |
| 299 | variants.roles.create('main') |
|
427 | variants.roles.create('main') | |
| 300 | variants.variant('browser') { |
|
428 | variants.variant('browser') { | |
| 301 | role('main') { |
|
429 | role('main') { | |
| 302 | layers('main') |
|
430 | layers('main') | |
| 303 | } |
|
431 | } | |
| 304 | } |
|
432 | } | |
| 305 |
|
433 | |||
| 306 | variantSources.layer('main') { |
|
434 | variantSources.layer('main') { | |
| 307 | declareOutputs('js') |
|
435 | declareOutputs('js') | |
| 308 | registerOutput('js', layout.projectDirectory.file('inputs/base.js')) |
|
436 | registerOutput('js', layout.projectDirectory.file('inputs/base.js')) | |
| 309 | } |
|
437 | } | |
| 310 |
|
438 | |||
| 311 | variantArtifacts { |
|
439 | variantArtifacts { | |
| 312 | variant('browser') { |
|
440 | variant('browser') { | |
| 313 | primarySlot('bundle') { |
|
441 | primarySlot('bundle') { | |
| 314 | fromVariant { |
|
442 | fromVariant { | |
| 315 | output('js') |
|
443 | output('js') | |
| 316 | } |
|
444 | } | |
| 317 | from(layout.projectDirectory.file('inputs/marker.txt')) |
|
445 | from(layout.projectDirectory.file('inputs/marker.txt')) | |
| 318 | } |
|
446 | } | |
| 319 | } |
|
447 | } | |
| 320 | } |
|
448 | } | |
| 321 |
|
449 | |||
| 322 | tasks.register('probe') { |
|
450 | tasks.register('probe') { | |
| 323 | dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_bundle' |
|
451 | dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_bundle' | |
| 324 |
|
452 | |||
| 325 | doLast { |
|
453 | doLast { | |
| 326 | def bundleDir = layout.buildDirectory.dir('variant-assemblies/browser/bundle').get().asFile |
|
454 | def bundleDir = layout.buildDirectory.dir('variant-assemblies/browser/bundle').get().asFile | |
| 327 | assert new File(bundleDir, 'base.js').exists() |
|
455 | assert new File(bundleDir, 'base.js').exists() | |
| 328 | assert new File(bundleDir, 'marker.txt').exists() |
|
456 | assert new File(bundleDir, 'marker.txt').exists() | |
| 329 | } |
|
457 | } | |
| 330 | } |
|
458 | } | |
| 331 | """); |
|
459 | """); | |
| 332 |
|
460 | |||
| 333 | BuildResult result = runner("probe").build(); |
|
461 | BuildResult result = runner("probe").build(); | |
| 334 |
|
462 | |||
| 335 | assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS); |
|
463 | assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS); | |
| 336 | } |
|
464 | } | |
| 337 |
|
465 | |||
| 338 | @Test |
|
466 | @Test | |
| 339 | void failsOnUnknownVariantReference() throws Exception { |
|
467 | void failsOnUnknownVariantReference() throws Exception { | |
| 340 | writeSettings("variant-artifacts-missing-variant"); |
|
468 | writeSettings("variant-artifacts-missing-variant"); | |
| 341 | writeBuildFile(""" |
|
469 | writeBuildFile(""" | |
| 342 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
470 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 343 |
|
471 | |||
| 344 | variants.layers.create('main') |
|
472 | variants.layers.create('main') | |
| 345 |
|
473 | |||
| 346 | variantArtifacts { |
|
474 | variantArtifacts { | |
| 347 | variant('browser') { |
|
475 | variant('browser') { | |
| 348 | slot('mainJs') { |
|
476 | slot('mainJs') { | |
| 349 | fromVariant { |
|
477 | fromVariant { | |
| 350 | output('js') |
|
478 | output('js') | |
| 351 | } |
|
479 | } | |
| 352 | } |
|
480 | } | |
| 353 | } |
|
481 | } | |
| 354 | } |
|
482 | } | |
| 355 | """); |
|
483 | """); | |
| 356 |
|
484 | |||
| 357 | assertBuildFails("isn't declared", "help"); |
|
485 | assertBuildFails("isn't declared", "help"); | |
| 358 | } |
|
486 | } | |
| 359 |
|
487 | |||
| 360 | @Test |
|
488 | @Test | |
| 361 | void failsOnUnknownRoleReference() throws Exception { |
|
489 | void failsOnUnknownRoleReference() throws Exception { | |
| 362 | writeSettings("variant-artifacts-missing-role"); |
|
490 | writeSettings("variant-artifacts-missing-role"); | |
| 363 | writeBuildFile(""" |
|
491 | writeBuildFile(""" | |
| 364 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
492 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 365 |
|
493 | |||
| 366 | variants.layers.create('main') |
|
494 | variants.layers.create('main') | |
| 367 | variants.roles.create('main') |
|
495 | variants.roles.create('main') | |
| 368 | variants.variant('browser') { |
|
496 | variants.variant('browser') { | |
| 369 | role('main') { |
|
497 | role('main') { | |
| 370 | layers('main') |
|
498 | layers('main') | |
| 371 | } |
|
499 | } | |
| 372 | } |
|
500 | } | |
| 373 |
|
501 | |||
| 374 | variantArtifacts { |
|
502 | variantArtifacts { | |
| 375 | variant('browser') { |
|
503 | variant('browser') { | |
| 376 | slot('mainJs') { |
|
504 | slot('mainJs') { | |
| 377 | fromRole('test') { |
|
505 | fromRole('test') { | |
| 378 | output('js') |
|
506 | output('js') | |
| 379 | } |
|
507 | } | |
| 380 | } |
|
508 | } | |
| 381 | } |
|
509 | } | |
| 382 | } |
|
510 | } | |
| 383 | """); |
|
511 | """); | |
| 384 |
|
512 | |||
| 385 | assertBuildFails("Role projection for variant 'browser' and role 'test' not found", "help"); |
|
513 | assertBuildFails("Role projection for variant 'browser' and role 'test' not found", "help"); | |
| 386 | } |
|
514 | } | |
| 387 |
|
515 | |||
| 388 | @Test |
|
516 | @Test | |
| 389 | void failsWhenPrimarySlotIsMissingForMultipleSlots() throws Exception { |
|
517 | void failsWhenPrimarySlotIsMissingForMultipleSlots() throws Exception { | |
| 390 | writeSettings("variant-artifacts-missing-primary"); |
|
518 | writeSettings("variant-artifacts-missing-primary"); | |
| 391 | writeBuildFile(""" |
|
519 | writeBuildFile(""" | |
| 392 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
520 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 393 |
|
521 | |||
| 394 | variants.layers.create('main') |
|
522 | variants.layers.create('main') | |
| 395 | variants.roles.create('main') |
|
523 | variants.roles.create('main') | |
| 396 | variants.variant('browser') { |
|
524 | variants.variant('browser') { | |
| 397 | role('main') { |
|
525 | role('main') { | |
| 398 | layers('main') |
|
526 | layers('main') | |
| 399 | } |
|
527 | } | |
| 400 | } |
|
528 | } | |
| 401 |
|
529 | |||
| 402 | variantSources.layer('main') { |
|
530 | variantSources.layer('main') { | |
| 403 | declareOutputs('types', 'js') |
|
531 | declareOutputs('types', 'js') | |
| 404 | } |
|
532 | } | |
| 405 |
|
533 | |||
| 406 | variantArtifacts { |
|
534 | variantArtifacts { | |
| 407 | variant('browser') { |
|
535 | variant('browser') { | |
| 408 | slot('typesPackage') { |
|
536 | slot('typesPackage') { | |
| 409 | fromVariant { |
|
537 | fromVariant { | |
| 410 | output('types') |
|
538 | output('types') | |
| 411 | } |
|
539 | } | |
| 412 | } |
|
540 | } | |
| 413 | slot('js') { |
|
541 | slot('js') { | |
| 414 | fromVariant { |
|
542 | fromVariant { | |
| 415 | output('js') |
|
543 | output('js') | |
| 416 | } |
|
544 | } | |
| 417 | } |
|
545 | } | |
| 418 | } |
|
546 | } | |
| 419 | } |
|
547 | } | |
| 420 |
|
548 | |||
| 421 | tasks.register('probe') { |
|
549 | tasks.register('probe') { | |
| 422 | doLast { |
|
550 | doLast { | |
| 423 | variantArtifacts.whenAvailable { ctx -> |
|
551 | variantArtifacts.whenAvailable { ctx -> | |
| 424 | def browser = objects.named(org.implab.gradle.variants.core.Variant, 'browser') |
|
552 | def browser = objects.named(org.implab.gradle.variants.core.Variant, 'browser') | |
| 425 | ctx.findOutgoing(browser).get().primarySlot.get() |
|
553 | ctx.findOutgoing(browser).get().primarySlot.get() | |
| 426 | } |
|
554 | } | |
| 427 | } |
|
555 | } | |
| 428 | } |
|
556 | } | |
| 429 | """); |
|
557 | """); | |
| 430 |
|
558 | |||
| 431 | assertBuildFails("Multiple slots declared for browser, please specify primary slot explicitly", "probe"); |
|
559 | assertBuildFails("Multiple slots declared for browser, please specify primary slot explicitly", "probe"); | |
| 432 | } |
|
560 | } | |
| 433 |
|
561 | |||
| 434 | @Test |
|
562 | @Test | |
| 435 | void failsOnLayerReferenceOutsideVariantTopology() throws Exception { |
|
563 | void failsOnLayerReferenceOutsideVariantTopology() throws Exception { | |
| 436 | writeSettings("variant-artifacts-layer-outside-topology"); |
|
564 | writeSettings("variant-artifacts-layer-outside-topology"); | |
| 437 | writeBuildFile(""" |
|
565 | writeBuildFile(""" | |
| 438 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
566 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 439 |
|
567 | |||
| 440 | variants.layers.create('mainBase') |
|
568 | variants.layers.create('mainBase') | |
| 441 | variants.layers.create('extra') |
|
569 | variants.layers.create('extra') | |
| 442 | variants.roles.create('main') |
|
570 | variants.roles.create('main') | |
| 443 | variants.variant('browser') { |
|
571 | variants.variant('browser') { | |
| 444 | role('main') { |
|
572 | role('main') { | |
| 445 | layers('mainBase') |
|
573 | layers('mainBase') | |
| 446 | } |
|
574 | } | |
| 447 | } |
|
575 | } | |
| 448 |
|
576 | |||
| 449 | variantArtifacts { |
|
577 | variantArtifacts { | |
| 450 | variant('browser') { |
|
578 | variant('browser') { | |
| 451 | slot('extraJs') { |
|
579 | slot('extraJs') { | |
| 452 | fromLayer('extra') { |
|
580 | fromLayer('extra') { | |
| 453 | output('js') |
|
581 | output('js') | |
| 454 | } |
|
582 | } | |
| 455 | } |
|
583 | } | |
| 456 | } |
|
584 | } | |
| 457 | } |
|
585 | } | |
| 458 | """); |
|
586 | """); | |
| 459 |
|
587 | |||
| 460 | assertBuildFails("Compile unit for variant 'browser' and layer 'extra' not found", "help"); |
|
588 | assertBuildFails("Compile unit for variant 'browser' and layer 'extra' not found", "help"); | |
| 461 | } |
|
589 | } | |
| 462 |
|
590 | |||
| 463 | @Test |
|
591 | @Test | |
| 464 | void preservesPrimaryResolutionAndAllowsSecondaryArtifactSelection() throws Exception { |
|
592 | void preservesPrimaryResolutionAndAllowsSecondaryArtifactSelection() throws Exception { | |
| 465 | writeFile("settings.gradle", """ |
|
593 | writeFile("settings.gradle", """ | |
| 466 | rootProject.name = 'variant-artifacts-resolution' |
|
594 | rootProject.name = 'variant-artifacts-resolution' | |
| 467 | include 'producer', 'consumer' |
|
595 | include 'producer', 'consumer' | |
| 468 | """); |
|
596 | """); | |
| 469 | writeFile("producer/inputs/types.d.ts", "export type Foo = string\n"); |
|
597 | writeFile("producer/inputs/types.d.ts", "export type Foo = string\n"); | |
| 470 | writeFile("producer/inputs/index.js", "export const foo = 'bar'\n"); |
|
598 | writeFile("producer/inputs/index.js", "export const foo = 'bar'\n"); | |
| 471 | writeBuildFile(""" |
|
599 | writeBuildFile(""" | |
| 472 | import org.gradle.api.attributes.Attribute |
|
600 | import org.gradle.api.attributes.Attribute | |
| 473 |
|
601 | |||
| 474 | def variantAttr = Attribute.of('test.variant', String) |
|
602 | def variantAttr = Attribute.of('test.variant', String) | |
| 475 | def slotAttr = Attribute.of('test.slot', String) |
|
603 | def slotAttr = Attribute.of('test.slot', String) | |
| 476 |
|
604 | |||
| 477 | subprojects { |
|
605 | subprojects { | |
| 478 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin |
|
606 | apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin | |
| 479 | } |
|
607 | } | |
| 480 |
|
608 | |||
| 481 | project(':producer') { |
|
609 | project(':producer') { | |
| 482 | variants.layers.create('main') |
|
610 | variants.layers.create('main') | |
| 483 | variants.roles.create('main') |
|
611 | variants.roles.create('main') | |
| 484 | variants.variant('browser') { |
|
612 | variants.variant('browser') { | |
| 485 | role('main') { |
|
613 | role('main') { | |
| 486 | layers('main') |
|
614 | layers('main') | |
| 487 | } |
|
615 | } | |
| 488 | } |
|
616 | } | |
| 489 |
|
617 | |||
| 490 | variantSources.layer('main') { |
|
618 | variantSources.layer('main') { | |
| 491 | declareOutputs('types', 'js') |
|
619 | declareOutputs('types', 'js') | |
| 492 | registerOutput('types', layout.projectDirectory.file('inputs/types.d.ts')) |
|
620 | registerOutput('types', layout.projectDirectory.file('inputs/types.d.ts')) | |
| 493 | registerOutput('js', layout.projectDirectory.file('inputs/index.js')) |
|
621 | registerOutput('js', layout.projectDirectory.file('inputs/index.js')) | |
| 494 | } |
|
622 | } | |
| 495 |
|
623 | |||
| 496 | variantArtifacts { |
|
624 | variantArtifacts { | |
| 497 | variant('browser') { |
|
625 | variant('browser') { | |
| 498 | primarySlot('typesPackage') { |
|
626 | primarySlot('typesPackage') { | |
| 499 | fromVariant { |
|
627 | fromVariant { | |
| 500 | output('types') |
|
628 | output('types') | |
| 501 | } |
|
629 | } | |
| 502 | } |
|
630 | } | |
| 503 | slot('js') { |
|
631 | slot('js') { | |
| 504 | fromVariant { |
|
632 | fromVariant { | |
| 505 | output('js') |
|
633 | output('js') | |
| 506 | } |
|
634 | } | |
| 507 | } |
|
635 | } | |
| 508 | } |
|
636 | } | |
| 509 |
|
637 | |||
| 510 | whenOutgoingConfiguration { publication -> |
|
638 | whenOutgoingConfiguration { publication -> | |
| 511 | publication.configuration { |
|
639 | publication.configuration { | |
| 512 | attributes.attribute(variantAttr, publication.variant.name) |
|
640 | attributes.attribute(variantAttr, publication.variant.name) | |
| 513 | } |
|
641 | } | |
| 514 | } |
|
642 | } | |
| 515 |
|
643 | |||
| 516 | whenOutgoingSlot { publication -> |
|
644 | whenOutgoingSlot { publication -> | |
| 517 | publication.artifactAttributes { |
|
645 | publication.artifactAttributes { | |
| 518 | attribute(slotAttr, publication.artifactSlot.slot.name) |
|
646 | attribute(slotAttr, publication.artifactSlot.slot.name) | |
| 519 | } |
|
647 | } | |
| 520 | } |
|
648 | } | |
| 521 | } |
|
649 | } | |
| 522 |
|
650 | |||
| 523 | } |
|
651 | } | |
| 524 |
|
652 | |||
| 525 | project(':consumer') { |
|
653 | project(':consumer') { | |
| 526 | configurations { |
|
654 | configurations { | |
| 527 | compileView { |
|
655 | compileView { | |
| 528 | canBeResolved = true |
|
656 | canBeResolved = true | |
| 529 | canBeConsumed = false |
|
657 | canBeConsumed = false | |
| 530 | canBeDeclared = true |
|
658 | canBeDeclared = true | |
| 531 | attributes { |
|
659 | attributes { | |
| 532 | attribute(variantAttr, 'browser') |
|
660 | attribute(variantAttr, 'browser') | |
| 533 | attribute(slotAttr, 'typesPackage') |
|
661 | attribute(slotAttr, 'typesPackage') | |
| 534 | } |
|
662 | } | |
| 535 | } |
|
663 | } | |
| 536 | } |
|
664 | } | |
| 537 |
|
665 | |||
| 538 | dependencies { |
|
666 | dependencies { | |
| 539 | compileView project(':producer') |
|
667 | compileView project(':producer') | |
| 540 | } |
|
668 | } | |
| 541 |
|
669 | |||
| 542 | tasks.register('probe') { |
|
670 | tasks.register('probe') { | |
| 543 | doLast { |
|
671 | doLast { | |
| 544 | def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',') |
|
672 | def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',') | |
| 545 | def jsFiles = configurations.compileView.incoming.artifactView { |
|
673 | def jsFiles = configurations.compileView.incoming.artifactView { | |
| 546 | attributes { |
|
674 | attributes { | |
| 547 | attribute(slotAttr, 'js') |
|
675 | attribute(slotAttr, 'js') | |
| 548 | } |
|
676 | } | |
| 549 | }.files.files.collect { it.name }.sort().join(',') |
|
677 | }.files.files.collect { it.name }.sort().join(',') | |
| 550 |
|
678 | |||
| 551 | println('compileFiles=' + compileFiles) |
|
679 | println('compileFiles=' + compileFiles) | |
| 552 | println('jsFiles=' + jsFiles) |
|
680 | println('jsFiles=' + jsFiles) | |
| 553 | } |
|
681 | } | |
| 554 | } |
|
682 | } | |
| 555 | } |
|
683 | } | |
| 556 | """); |
|
684 | """); | |
| 557 |
|
685 | |||
| 558 | BuildResult result = runner(":consumer:probe").build(); |
|
686 | BuildResult result = runner(":consumer:probe").build(); | |
| 559 |
|
687 | |||
| 560 | assertTrue(result.getOutput().contains("compileFiles=typesPackage")); |
|
688 | assertTrue(result.getOutput().contains("compileFiles=typesPackage")); | |
| 561 | assertTrue(result.getOutput().contains("jsFiles=js")); |
|
689 | assertTrue(result.getOutput().contains("jsFiles=js")); | |
| 562 | } |
|
690 | } | |
| 563 | } |
|
691 | } | |
General Comments 0
You need to be logged in to leave comments.
Login now
