| @@ -0,0 +1,29 | |||||
|
|
1 | package org.implab.gradle.variants; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Plugin; | |||
|
|
4 | import org.gradle.api.Project; | |||
|
|
5 | import org.implab.gradle.common.core.lang.Deferred; | |||
|
|
6 | import org.implab.gradle.variants.artifacts.VariantArtifactsContext; | |||
|
|
7 | import org.implab.gradle.variants.core.VariantsExtension; | |||
|
|
8 | ||||
|
|
9 | public abstract class VariantArtifactsPlugin implements Plugin<Project> { | |||
|
|
10 | ||||
|
|
11 | @Override | |||
|
|
12 | public void apply(Project target) { | |||
|
|
13 | var extensions = target.getExtensions(); | |||
|
|
14 | ||||
|
|
15 | // Apply the main VariantsPlugin to ensure the core variant model is available. | |||
|
|
16 | target.getPlugins().apply(VariantsPlugin.class); | |||
|
|
17 | // Access the VariantsExtension to configure variant sources. | |||
|
|
18 | var variantsExtension = extensions.getByType(VariantsExtension.class); | |||
|
|
19 | ||||
|
|
20 | var deferred = new Deferred<VariantArtifactsContext>(); | |||
|
|
21 | ||||
|
|
22 | variantsExtension.whenFinalized(variants -> { | |||
|
|
23 | ||||
|
|
24 | }); | |||
|
|
25 | ||||
|
|
26 | ||||
|
|
27 | } | |||
|
|
28 | ||||
|
|
29 | } | |||
| @@ -0,0 +1,22 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
4 | ||||
|
|
5 | /** | |||
|
|
6 | * Resolves stateful slot assemblies from cheap slot identities. | |||
|
|
7 | * | |||
|
|
8 | * <p>The returned assembly is a materialized build-model handle. It may expose lazy Gradle providers, but | |||
|
|
9 | * it is no longer an identity object suitable for replayable discovery. | |||
|
|
10 | */ | |||
|
|
11 | @NonNullByDefault | |||
|
|
12 | public interface ArtifactAssemblies { | |||
|
|
13 | /** | |||
|
|
14 | * Resolves the assembly for the given slot. | |||
|
|
15 | * | |||
|
|
16 | * <p>This call materializes the build-facing body of the slot from its identity. | |||
|
|
17 | * | |||
|
|
18 | * @param slot slot identity inside a variant outgoing contract | |||
|
|
19 | * @return assembly handle for the slot | |||
|
|
20 | */ | |||
|
|
21 | ArtifactAssembly resolveSlot(ArtifactSlot slot); | |||
|
|
22 | } | |||
| @@ -0,0 +1,32 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Task; | |||
|
|
4 | import org.gradle.api.file.FileSystemLocation; | |||
|
|
5 | import org.gradle.api.provider.Provider; | |||
|
|
6 | import org.gradle.api.tasks.TaskProvider; | |||
|
|
7 | ||||
|
|
8 | /** | |||
|
|
9 | * Materialized body of an {@link ArtifactSlot}. | |||
|
|
10 | * | |||
|
|
11 | * <p>An assembly is a stateful build object obtained on demand from | |||
|
|
12 | * {@link ArtifactAssemblies#resolveSlot(ArtifactSlot)}. It describes how the slot artifact is produced and | |||
|
|
13 | * where that single published artifact will appear. | |||
|
|
14 | */ | |||
|
|
15 | public interface ArtifactAssembly { | |||
|
|
16 | ||||
|
|
17 | /** | |||
|
|
18 | * Returns the published artifact produced for the slot. | |||
|
|
19 | * | |||
|
|
20 | * <p>A slot is expected to produce exactly one artifact represented by one file or one directory. | |||
|
|
21 | * | |||
|
|
22 | * @return provider of the produced artifact location | |||
|
|
23 | */ | |||
|
|
24 | Provider<? extends FileSystemLocation> getArtifact(); | |||
|
|
25 | ||||
|
|
26 | /** | |||
|
|
27 | * Returns the task that assembles the slot artifact. | |||
|
|
28 | * | |||
|
|
29 | * @return provider of the assembly task | |||
|
|
30 | */ | |||
|
|
31 | TaskProvider<? extends Task> getAssemblyTask(); | |||
|
|
32 | } | |||
| @@ -0,0 +1,60 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Action; | |||
|
|
4 | import groovy.lang.Closure; | |||
|
|
5 | import org.implab.gradle.common.core.lang.Closures; | |||
|
|
6 | ||||
|
|
7 | /** | |||
|
|
8 | * DSL model describing how a slot artifact is assembled. | |||
|
|
9 | * | |||
|
|
10 | * <p>Selection rules declared here may refer to internal build topology such as roles, layers or units. | |||
|
|
11 | * Those selectors influence slot assembly only and do not become part of published artifact identity. | |||
|
|
12 | * | |||
|
|
13 | * <p>Regardless of the number of declared inputs, a slot is expected to materialize to a single published | |||
|
|
14 | * artifact. | |||
|
|
15 | */ | |||
|
|
16 | public interface ArtifactAssemblySpec { | |||
|
|
17 | /** | |||
|
|
18 | * Contributes direct input material to the slot assembly. | |||
|
|
19 | * | |||
|
|
20 | * <p>The resulting slot still represents one published artifact. | |||
|
|
21 | * | |||
|
|
22 | * @param artifact direct input notation understood by the implementation | |||
|
|
23 | */ | |||
|
|
24 | void from(Object artifact); | |||
|
|
25 | ||||
|
|
26 | /** | |||
|
|
27 | * Selects outputs from the whole variant scope. | |||
|
|
28 | * | |||
|
|
29 | * @param action output selection rule | |||
|
|
30 | */ | |||
|
|
31 | void fromVariant(Action<? super OutputSelectionSpec> action); | |||
|
|
32 | ||||
|
|
33 | default void fromVariant(Closure<?> closure) { | |||
|
|
34 | fromVariant(Closures.action(closure)); | |||
|
|
35 | } | |||
|
|
36 | ||||
|
|
37 | /** | |||
|
|
38 | * Selects outputs from a role inside the current variant. | |||
|
|
39 | * | |||
|
|
40 | * @param roleName role name used only for assembly-time selection | |||
|
|
41 | * @param action output selection rule | |||
|
|
42 | */ | |||
|
|
43 | void fromRole(String roleName, Action<? super OutputSelectionSpec> action); | |||
|
|
44 | ||||
|
|
45 | default void fromRole(String roleName, Closure<?> closure) { | |||
|
|
46 | fromRole(roleName, Closures.action(closure)); | |||
|
|
47 | } | |||
|
|
48 | ||||
|
|
49 | /** | |||
|
|
50 | * Selects outputs from a layer inside the current variant. | |||
|
|
51 | * | |||
|
|
52 | * @param layerName layer name used only for assembly-time selection | |||
|
|
53 | * @param action output selection rule | |||
|
|
54 | */ | |||
|
|
55 | void fromLayer(String layerName, Action<? super OutputSelectionSpec> action); | |||
|
|
56 | ||||
|
|
57 | default void fromLayer(String layerName, Closure<?> closure) { | |||
|
|
58 | fromLayer(layerName, Closures.action(closure)); | |||
|
|
59 | } | |||
|
|
60 | } | |||
| @@ -0,0 +1,14 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.implab.gradle.variants.core.Variant; | |||
|
|
4 | ||||
|
|
5 | /** | |||
|
|
6 | * Identity of a published artifact slot inside a variant outgoing contract. | |||
|
|
7 | * | |||
|
|
8 | * <p>This is a cheap immutable identity object suitable for discovery and selection. Heavy build state is | |||
|
|
9 | * obtained separately through {@link ArtifactAssemblies}. | |||
|
|
10 | * | |||
|
|
11 | * @param variant variant owning the outgoing contract | |||
|
|
12 | * @param slot slot identity inside the variant | |||
|
|
13 | */ | |||
|
|
14 | public record ArtifactSlot(Variant variant, Slot slot) {} | |||
| @@ -0,0 +1,48 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import java.util.Optional; | |||
|
|
4 | import java.util.Set; | |||
|
|
5 | ||||
|
|
6 | import org.implab.gradle.variants.core.Variant; | |||
|
|
7 | ||||
|
|
8 | /** | |||
|
|
9 | * Finalized view of artifact slot identities. | |||
|
|
10 | * | |||
|
|
11 | * <p>This view exposes only cheap slot identities. Assemblies and publication state are resolved | |||
|
|
12 | * separately. | |||
|
|
13 | */ | |||
|
|
14 | public interface ArtifactSlotsView { | |||
|
|
15 | /** | |||
|
|
16 | * Returns all declared slot identities. | |||
|
|
17 | * | |||
|
|
18 | * @return all slots known to the finalized model | |||
|
|
19 | */ | |||
|
|
20 | Set<ArtifactSlot> getSlots(); | |||
|
|
21 | ||||
|
|
22 | /** | |||
|
|
23 | * Returns all slots declared for the given variant. | |||
|
|
24 | * | |||
|
|
25 | * @param variant variant identity | |||
|
|
26 | * @return slots declared for the variant | |||
|
|
27 | */ | |||
|
|
28 | Set<ArtifactSlot> getSlotsForVariant(Variant variant); | |||
|
|
29 | ||||
|
|
30 | /** | |||
|
|
31 | * Finds a slot by typed identities. | |||
|
|
32 | * | |||
|
|
33 | * @param variant variant identity | |||
|
|
34 | * @param slot slot identity inside the variant | |||
|
|
35 | * @return matching slot when present | |||
|
|
36 | */ | |||
|
|
37 | Optional<ArtifactSlot> findSlot(Variant variant, Slot slot); | |||
|
|
38 | ||||
|
|
39 | /** | |||
|
|
40 | * Requires a slot by typed identities. | |||
|
|
41 | * | |||
|
|
42 | * @param variant variant identity | |||
|
|
43 | * @param slot slot identity inside the variant | |||
|
|
44 | * @return matching slot | |||
|
|
45 | */ | |||
|
|
46 | ArtifactSlot requireSlot(Variant variant, Slot slot); | |||
|
|
47 | ||||
|
|
48 | } | |||
| @@ -0,0 +1,59 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Action; | |||
|
|
4 | import org.gradle.api.Task; | |||
|
|
5 | import org.gradle.api.attributes.AttributeContainer; | |||
|
|
6 | import groovy.lang.Closure; | |||
|
|
7 | import org.implab.gradle.common.core.lang.Closures; | |||
|
|
8 | ||||
|
|
9 | /** | |||
|
|
10 | * Materialized outgoing publication state of a single slot. | |||
|
|
11 | * | |||
|
|
12 | * <p>This type is a DSL facade to represent already created publication-facing state. Slot-specific | |||
|
|
13 | * publication tweaks should be applied here rather than through {@link OutgoingVariantSpec}, which | |||
|
|
14 | * is limited to the root outgoing configuration of the variant. | |||
|
|
15 | */ | |||
|
|
16 | public interface OutgoingArtifactSlotSpec { | |||
|
|
17 | /** | |||
|
|
18 | * Returns the published slot identity. | |||
|
|
19 | * | |||
|
|
20 | * @return slot identity | |||
|
|
21 | */ | |||
|
|
22 | ArtifactSlot getArtifactSlot(); | |||
|
|
23 | ||||
|
|
24 | /** | |||
|
|
25 | * Returns the assembly backing the published slot. | |||
|
|
26 | * | |||
|
|
27 | * @return slot assembly | |||
|
|
28 | */ | |||
|
|
29 | ArtifactAssembly getAssembly(); | |||
|
|
30 | ||||
|
|
31 | /** | |||
|
|
32 | * Returns whether this slot is the primary outgoing artifact set of the variant. | |||
|
|
33 | * | |||
|
|
34 | * @return {@code true} for the primary slot | |||
|
|
35 | */ | |||
|
|
36 | boolean isPrimary(); | |||
|
|
37 | ||||
|
|
38 | /** | |||
|
|
39 | * Configures the task producing the slot artifact. | |||
|
|
40 | * | |||
|
|
41 | * @param action task configuration action | |||
|
|
42 | */ | |||
|
|
43 | void assemblyTask(Action<? super Task> action); | |||
|
|
44 | ||||
|
|
45 | default void assemblyTask(Closure<?> closure) { | |||
|
|
46 | assemblyTask(Closures.action(closure)); | |||
|
|
47 | } | |||
|
|
48 | ||||
|
|
49 | /** | |||
|
|
50 | * Configures attributes of this slot publication. | |||
|
|
51 | * | |||
|
|
52 | * @param action artifact attribute configuration action | |||
|
|
53 | */ | |||
|
|
54 | void artifactAttributes(Action<? super AttributeContainer> action); | |||
|
|
55 | ||||
|
|
56 | default void artifactAttributes(Closure<?> closure) { | |||
|
|
57 | artifactAttributes(Closures.action(closure)); | |||
|
|
58 | } | |||
|
|
59 | } | |||
| @@ -0,0 +1,43 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Action; | |||
|
|
4 | import org.gradle.api.artifacts.Configuration; | |||
|
|
5 | import org.implab.gradle.common.core.lang.Closures; | |||
|
|
6 | import org.implab.gradle.variants.core.Variant; | |||
|
|
7 | ||||
|
|
8 | import groovy.lang.Closure; | |||
|
|
9 | ||||
|
|
10 | /** | |||
|
|
11 | * Materialized root outgoing configuration of a variant. | |||
|
|
12 | * | |||
|
|
13 | * <p>This is a variant-level publication hook. Slot-specific publication state is exposed separately via | |||
|
|
14 | * {@link OutgoingArtifactSlotSpec}. | |||
|
|
15 | */ | |||
|
|
16 | public interface OutgoingVariantSpec { | |||
|
|
17 | /** | |||
|
|
18 | * Returns the variant whose outgoing configuration is represented here. | |||
|
|
19 | * | |||
|
|
20 | * @return variant identity | |||
|
|
21 | */ | |||
|
|
22 | Variant getVariant(); | |||
|
|
23 | ||||
|
|
24 | /** | |||
|
|
25 | * Returns the root consumable outgoing configuration of the variant. | |||
|
|
26 | * | |||
|
|
27 | * @return outgoing configuration | |||
|
|
28 | */ | |||
|
|
29 | Configuration getConfiguration(); | |||
|
|
30 | ||||
|
|
31 | /** | |||
|
|
32 | * Applies a configuration action to the root outgoing configuration. | |||
|
|
33 | * | |||
|
|
34 | * @param action configuration action | |||
|
|
35 | */ | |||
|
|
36 | default void configuration(Action<? super Configuration> action) { | |||
|
|
37 | action.execute(getConfiguration()); | |||
|
|
38 | } | |||
|
|
39 | ||||
|
|
40 | default void configuration(Closure<?> closure) { | |||
|
|
41 | configuration(Closures.action(closure)); | |||
|
|
42 | } | |||
|
|
43 | } | |||
| @@ -0,0 +1,24 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | /** | |||
|
|
4 | * DSL model for selecting named outputs from a chosen source scope. | |||
|
|
5 | * | |||
|
|
6 | * <p>The selected outputs are inputs to slot assembly. They do not create additional outgoing slots or | |||
|
|
7 | * affect slot identity. | |||
|
|
8 | */ | |||
|
|
9 | public interface OutputSelectionSpec { | |||
|
|
10 | /** | |||
|
|
11 | * Selects one named output. | |||
|
|
12 | * | |||
|
|
13 | * @param name output name | |||
|
|
14 | */ | |||
|
|
15 | void output(String name); | |||
|
|
16 | ||||
|
|
17 | /** | |||
|
|
18 | * Selects several named outputs. | |||
|
|
19 | * | |||
|
|
20 | * @param name first output name | |||
|
|
21 | * @param extra additional output names | |||
|
|
22 | */ | |||
|
|
23 | void output(String name, String... extra); | |||
|
|
24 | } | |||
| @@ -0,0 +1,12 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Named; | |||
|
|
4 | ||||
|
|
5 | /** | |||
|
|
6 | * Named identity of a slot inside a variant outgoing contract. | |||
|
|
7 | * | |||
|
|
8 | * <p>A slot does not identify a published artifact on its own. Combine it with a variant to obtain an | |||
|
|
9 | * {@link ArtifactSlot}. | |||
|
|
10 | */ | |||
|
|
11 | public interface Slot extends Named { | |||
|
|
12 | } | |||
| @@ -0,0 +1,28 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.NamedDomainObjectContainer; | |||
|
|
4 | import org.gradle.api.NamedDomainObjectProvider; | |||
|
|
5 | import org.gradle.api.artifacts.Configuration; | |||
|
|
6 | import org.implab.gradle.variants.core.Variant; | |||
|
|
7 | ||||
|
|
8 | /** Описывает конфигурация варианта исходящей конфигурации */ | |||
|
|
9 | public interface VariantArtifactsConfiguration { | |||
|
|
10 | /** | |||
|
|
11 | * Исходный вариант для которого строится Outgoing конфигурация | |||
|
|
12 | */ | |||
|
|
13 | Variant getVariant(); | |||
|
|
14 | ||||
|
|
15 | /** | |||
|
|
16 | * Провайдер зарегистрированной конфигурации | |||
|
|
17 | */ | |||
|
|
18 | NamedDomainObjectProvider<Configuration> getOutgoingConfiguration(); | |||
|
|
19 | ||||
|
|
20 | /** | |||
|
|
21 | * Слоты конфигурации, данная коллекция живая, используется для | |||
|
|
22 | * получения информации об объявленных слотах, но эти слоты не | |||
|
|
23 | * обязаны быть сконфигурированы, т.е. это только Identity. | |||
|
|
24 | * | |||
|
|
25 | * @see {@link ArtifactSlot} | |||
|
|
26 | */ | |||
|
|
27 | NamedDomainObjectContainer<Slot> getSlots(); | |||
|
|
28 | } | |||
| @@ -0,0 +1,27 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import java.util.Optional; | |||
|
|
4 | ||||
|
|
5 | import org.gradle.api.Action; | |||
|
|
6 | import org.implab.gradle.variants.core.Variant; | |||
|
|
7 | import org.implab.gradle.variants.core.VariantsView; | |||
|
|
8 | ||||
|
|
9 | /** | |||
|
|
10 | * Контекст работы с вариантами публикации, становится доступным после | |||
|
|
11 | * финализации модели вариантов. Фактически является живой моделью | |||
|
|
12 | */ | |||
|
|
13 | public interface VariantArtifactsContext { | |||
|
|
14 | ||||
|
|
15 | /** | |||
|
|
16 | * Зафиксированное представление о вариантах на основе которого адаптеры могут | |||
|
|
17 | * конфигурировать артефакты и исходящие конфигурации | |||
|
|
18 | */ | |||
|
|
19 | VariantsView getVariants(); | |||
|
|
20 | ||||
|
|
21 | void all(Action<? super VariantArtifactsConfiguration> action); | |||
|
|
22 | ||||
|
|
23 | Optional<VariantArtifactsConfiguration> findArtifacts(Variant variant); | |||
|
|
24 | ||||
|
|
25 | VariantArtifactsConfiguration requireArtifacts(Variant variant); | |||
|
|
26 | ||||
|
|
27 | } | |||
| @@ -0,0 +1,59 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Action; | |||
|
|
4 | import org.implab.gradle.common.core.lang.Closures; | |||
|
|
5 | ||||
|
|
6 | import groovy.lang.Closure; | |||
|
|
7 | ||||
|
|
8 | /** | |||
|
|
9 | * Project-level DSL entry point for declaring outgoing artifacts per variant. | |||
|
|
10 | * | |||
|
|
11 | * <p>A variant represents one external outgoing contract. Slots declared inside a variant represent | |||
|
|
12 | * artifact sets within that contract. One slot is expected to materialize to one published artifact. | |||
|
|
13 | */ | |||
|
|
14 | public interface VariantArtifactsExtension { | |||
|
|
15 | /** | |||
|
|
16 | * Configures artifact slots of the named variant. | |||
|
|
17 | * | |||
|
|
18 | * @param variantName variant name | |||
|
|
19 | * @param action variant artifact declaration | |||
|
|
20 | */ | |||
|
|
21 | void variant(String variantName, Action<? super VariantArtifactsSpec> action); | |||
|
|
22 | ||||
|
|
23 | default void variant(String variantName, Closure<?> closure) { | |||
|
|
24 | variant(variantName, Closures.action(closure)); | |||
|
|
25 | } | |||
|
|
26 | ||||
|
|
27 | /** | |||
|
|
28 | * Registers a callback invoked with the finalized artifact model. | |||
|
|
29 | * | |||
|
|
30 | * @param action finalized-model callback | |||
|
|
31 | */ | |||
|
|
32 | void whenFinalized(Action<? super VariantArtifactsContext> action); | |||
|
|
33 | ||||
|
|
34 | default void whenFinalized(Closure<?> closure) { | |||
|
|
35 | whenFinalized(Closures.action(closure)); | |||
|
|
36 | } | |||
|
|
37 | ||||
|
|
38 | /** | |||
|
|
39 | * Registers a callback invoked for each materialized root outgoing configuration. | |||
|
|
40 | * | |||
|
|
41 | * @param action variant-level outgoing configuration callback | |||
|
|
42 | */ | |||
|
|
43 | void whenOutgoingVariant(Action<? super OutgoingVariantSpec> action); | |||
|
|
44 | ||||
|
|
45 | default void whenOutgoingVariant(Closure<?> closure) { | |||
|
|
46 | whenOutgoingVariant(Closures.action(closure)); | |||
|
|
47 | } | |||
|
|
48 | ||||
|
|
49 | /** | |||
|
|
50 | * Registers a callback invoked for each materialized outgoing slot publication. | |||
|
|
51 | * | |||
|
|
52 | * @param action slot-level outgoing publication callback | |||
|
|
53 | */ | |||
|
|
54 | void whenOutgoingSlot(Action<? super OutgoingArtifactSlotSpec> action); | |||
|
|
55 | ||||
|
|
56 | default void whenOutgoingSlot(Closure<?> closure) { | |||
|
|
57 | whenOutgoingSlot(Closures.action(closure)); | |||
|
|
58 | } | |||
|
|
59 | } | |||
| @@ -0,0 +1,40 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Action; | |||
|
|
4 | import groovy.lang.Closure; | |||
|
|
5 | import org.implab.gradle.common.core.lang.Closures; | |||
|
|
6 | ||||
|
|
7 | /** | |||
|
|
8 | * DSL model for declaring slots of a single variant. | |||
|
|
9 | * | |||
|
|
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 | |||
|
|
12 | * primary slot. | |||
|
|
13 | */ | |||
|
|
14 | public interface VariantArtifactsSpec { | |||
|
|
15 | /** | |||
|
|
16 | * Declares a non-primary slot of the current variant. | |||
|
|
17 | * | |||
|
|
18 | * @param name slot name | |||
|
|
19 | * @param action slot declaration | |||
|
|
20 | * @return slot identity | |||
|
|
21 | */ | |||
|
|
22 | Slot slot(String name, Action<? super ArtifactAssemblySpec> action); | |||
|
|
23 | ||||
|
|
24 | default Slot slot(String name, Closure<?> closure) { | |||
|
|
25 | return slot(name, Closures.action(closure)); | |||
|
|
26 | } | |||
|
|
27 | ||||
|
|
28 | /** | |||
|
|
29 | * Declares the primary slot of the current variant. | |||
|
|
30 | * | |||
|
|
31 | * @param name slot name | |||
|
|
32 | * @param action slot declaration | |||
|
|
33 | * @return slot identity | |||
|
|
34 | */ | |||
|
|
35 | Slot primarySlot(String name, Action<? super ArtifactAssemblySpec> action); | |||
|
|
36 | ||||
|
|
37 | default Slot primarySlot(String name, Closure<?> closure) { | |||
|
|
38 | return primarySlot(name, Closures.action(closure)); | |||
|
|
39 | } | |||
|
|
40 | } | |||
| @@ -0,0 +1,37 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts.internal; | |||
|
|
2 | ||||
|
|
3 | import java.util.Optional; | |||
|
|
4 | ||||
|
|
5 | import org.gradle.api.Action; | |||
|
|
6 | import org.implab.gradle.variants.artifacts.VariantArtifactsConfiguration; | |||
|
|
7 | import org.implab.gradle.variants.artifacts.VariantArtifactsContext; | |||
|
|
8 | import org.implab.gradle.variants.core.Variant; | |||
|
|
9 | import org.implab.gradle.variants.core.VariantsView; | |||
|
|
10 | ||||
|
|
11 | public class DefaultVariantArtifactsContext implements VariantArtifactsContext { | |||
|
|
12 | ||||
|
|
13 | @Override | |||
|
|
14 | public VariantsView getVariants() { | |||
|
|
15 | // TODO Auto-generated method stub | |||
|
|
16 | throw new UnsupportedOperationException("Unimplemented method 'getVariants'"); | |||
|
|
17 | } | |||
|
|
18 | ||||
|
|
19 | @Override | |||
|
|
20 | public void all(Action<? super VariantArtifactsConfiguration> action) { | |||
|
|
21 | // TODO Auto-generated method stub | |||
|
|
22 | throw new UnsupportedOperationException("Unimplemented method 'all'"); | |||
|
|
23 | } | |||
|
|
24 | ||||
|
|
25 | @Override | |||
|
|
26 | public Optional<VariantArtifactsConfiguration> findArtifacts(Variant variant) { | |||
|
|
27 | // TODO Auto-generated method stub | |||
|
|
28 | throw new UnsupportedOperationException("Unimplemented method 'findArtifacts'"); | |||
|
|
29 | } | |||
|
|
30 | ||||
|
|
31 | @Override | |||
|
|
32 | public VariantArtifactsConfiguration requireArtifacts(Variant variant) { | |||
|
|
33 | // TODO Auto-generated method stub | |||
|
|
34 | throw new UnsupportedOperationException("Unimplemented method 'requireArtifacts'"); | |||
|
|
35 | } | |||
|
|
36 | ||||
|
|
37 | } | |||
| @@ -0,0 +1,11 | |||||
|
|
1 | package org.implab.gradle.variants.artifacts.internal; | |||
|
|
2 | ||||
|
|
3 | import org.gradle.api.Action; | |||
|
|
4 | import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; | |||
|
|
5 | import org.implab.gradle.variants.core.Variant; | |||
|
|
6 | ||||
|
|
7 | public class VariantArtifactsRegistry { | |||
|
|
8 | public void configureVariant(Variant variant, Action<? super VariantArtifactsSpec> action) { | |||
|
|
9 | ||||
|
|
10 | } | |||
|
|
11 | } | |||
| @@ -0,0 +1,41 | |||||
|
|
1 | /** | |||
|
|
2 | * Variant-scoped outgoing artifacts. | |||
|
|
3 | * | |||
|
|
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 | |||
|
|
6 | * contract. | |||
|
|
7 | * | |||
|
|
8 | * <p>The model intentionally separates cheap identity objects from stateful build objects: | |||
|
|
9 | * | |||
|
|
10 | * <ul> | |||
|
|
11 | * <li>{@link org.implab.gradle.variants.artifacts.ArtifactSlot} identifies a published slot inside a | |||
|
|
12 | * variant;</li> | |||
|
|
13 | * <li>{@link org.implab.gradle.variants.artifacts.ArtifactAssembly} is the lazily materialized body of | |||
|
|
14 | * that slot.</li> | |||
|
|
15 | * </ul> | |||
|
|
16 | * | |||
|
|
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 | |||
|
|
19 | * belong to external artifact identity. | |||
|
|
20 | * | |||
|
|
21 | * <p>Typical usage: | |||
|
|
22 | * | |||
|
|
23 | * <pre>{@code | |||
|
|
24 | * variantArtifacts { | |||
|
|
25 | * variant("browser") { | |||
|
|
26 | * primarySlot("runtime") { | |||
|
|
27 | * fromRole("main") { output("js") } | |||
|
|
28 | * } | |||
|
|
29 | * slot("sources") { | |||
|
|
30 | * fromLayer("main") { output("sources") } | |||
|
|
31 | * } | |||
|
|
32 | * } | |||
|
|
33 | * } | |||
|
|
34 | * }</pre> | |||
|
|
35 | * | |||
|
|
36 | * <p>After finalization, slot identities can be observed through | |||
|
|
37 | * {@link org.implab.gradle.variants.artifacts.VariantArtifactsContext#getSlots()}, while slot bodies are | |||
|
|
38 | * obtained on demand through | |||
|
|
39 | * {@link org.implab.gradle.variants.artifacts.VariantArtifactsContext#getAssemblies()}. | |||
|
|
40 | */ | |||
|
|
41 | package org.implab.gradle.variants.artifacts; | |||
| @@ -10,6 +10,8 | |||||
| 10 | - `find*` рассматривается как синоним legacy `get*` (поиск без `fail-fast`). |
|
10 | - `find*` рассматривается как синоним legacy `get*` (поиск без `fail-fast`). | |
| 11 | - `require*` это `find*` + `fail-fast` с понятной ошибкой в месте вызова. |
|
11 | - `require*` это `find*` + `fail-fast` с понятной ошибкой в месте вызова. | |
| 12 | - Для нового API предпочтительны формы `find/require`; новые `get*` по возможности не добавлять. |
|
12 | - Для нового API предпочтительны формы `find/require`; новые `get*` по возможности не добавлять. | |
|
|
13 | - Интерфейсы и классы, описывающие модели DSL должны иметь суффикс `Spec` у моделей описывающих уровень сервисов и состояние сценария сборки такого суффикса не должно быть. | |||
|
|
14 | - Модель расширения на уровне проекта должна иметь суффикс `Extension`. | |||
| 13 |
|
15 | |||
| 14 | ### Документация |
|
16 | ### Документация | |
| 15 |
|
17 | |||
| @@ -64,7 +64,7 public final class CompileUnitsView { | |||||
| 64 | .collect(Collectors.toUnmodifiableSet()); |
|
64 | .collect(Collectors.toUnmodifiableSet()); | |
| 65 | } |
|
65 | } | |
| 66 |
|
66 | |||
| 67 |
public CompileUnit |
|
67 | public CompileUnit requireUnit(Variant variant, Layer layer) { | |
| 68 | return findUnit(variant, layer) |
|
68 | return findUnit(variant, layer) | |
| 69 | .orElseThrow(() -> new IllegalArgumentException( |
|
69 | .orElseThrow(() -> new IllegalArgumentException( | |
| 70 | "Compile unit for variant '" + variant.getName() |
|
70 | "Compile unit for variant '" + variant.getName() | |
| @@ -36,7 +36,7 class VariantSourcesPluginFunctionalTest | |||||
| 36 | def production = ctx.variants.roles.find { it.name == 'production' } |
|
36 | def production = ctx.variants.roles.find { it.name == 'production' } | |
| 37 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } |
|
37 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } | |
| 38 | def projection = ctx.roleProjections.getProjection(browser, production) |
|
38 | def projection = ctx.roleProjections.getProjection(browser, production) | |
| 39 |
def unit = ctx.compileUnits. |
|
39 | def unit = ctx.compileUnits.requireUnit(browser, mainLayer) | |
| 40 |
|
40 | |||
| 41 | def left = ctx.sourceSets.getSourceSet(unit) |
|
41 | def left = ctx.sourceSets.getSourceSet(unit) | |
| 42 | def right = ctx.sourceSets.getSourceSet(unit) |
|
42 | def right = ctx.sourceSets.getSourceSet(unit) | |
| @@ -113,9 +113,9 class VariantSourcesPluginFunctionalTest | |||||
| 113 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } |
|
113 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } | |
| 114 | def testLayer = ctx.variants.layers.find { it.name == 'test' } |
|
114 | def testLayer = ctx.variants.layers.find { it.name == 'test' } | |
| 115 |
|
115 | |||
| 116 |
def browserMain = ctx.sourceSets.getSourceSet(ctx.compileUnits. |
|
116 | def browserMain = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(browser, mainLayer)).get() | |
| 117 |
def browserTest = ctx.sourceSets.getSourceSet(ctx.compileUnits. |
|
117 | def browserTest = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(browser, testLayer)).get() | |
| 118 |
def nodeMain = ctx.sourceSets.getSourceSet(ctx.compileUnits. |
|
118 | def nodeMain = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(node, mainLayer)).get() | |
| 119 | def bySourceSet = events.groupBy { it.split(':', 2)[1] } |
|
119 | def bySourceSet = events.groupBy { it.split(':', 2)[1] } | |
| 120 |
|
120 | |||
| 121 | println("browserMain=" + bySourceSet[browserMain.name].collect { it.split(':', 2)[0] }.join(',')) |
|
121 | println("browserMain=" + bySourceSet[browserMain.name].collect { it.split(':', 2)[0] }.join(',')) | |
| @@ -149,7 +149,7 class VariantSourcesPluginFunctionalTest | |||||
| 149 | variantSources.whenFinalized { ctx -> |
|
149 | variantSources.whenFinalized { ctx -> | |
| 150 | def browser = ctx.variants.variants.find { it.name == 'browser' } |
|
150 | def browser = ctx.variants.variants.find { it.name == 'browser' } | |
| 151 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } |
|
151 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } | |
| 152 |
def unit = ctx.compileUnits. |
|
152 | def unit = ctx.compileUnits.requireUnit(browser, mainLayer) | |
| 153 |
|
153 | |||
| 154 | ctx.sourceSets.getSourceSet(unit).get() |
|
154 | ctx.sourceSets.getSourceSet(unit).get() | |
| 155 | variantSources.layer('main') { |
|
155 | variantSources.layer('main') { | |
| @@ -185,7 +185,7 class VariantSourcesPluginFunctionalTest | |||||
| 185 | variantSources.whenFinalized { ctx -> |
|
185 | variantSources.whenFinalized { ctx -> | |
| 186 | def browser = ctx.variants.variants.find { it.name == 'browser' } |
|
186 | def browser = ctx.variants.variants.find { it.name == 'browser' } | |
| 187 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } |
|
187 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } | |
| 188 |
def unit = ctx.compileUnits. |
|
188 | def unit = ctx.compileUnits.requireUnit(browser, mainLayer) | |
| 189 |
|
189 | |||
| 190 | def sourceSet = ctx.sourceSets.getSourceSet(unit).get() |
|
190 | def sourceSet = ctx.sourceSets.getSourceSet(unit).get() | |
| 191 | variantSources.layer('main') { |
|
191 | variantSources.layer('main') { | |
| @@ -224,7 +224,7 class VariantSourcesPluginFunctionalTest | |||||
| 224 | variantSources.whenFinalized { ctx -> |
|
224 | variantSources.whenFinalized { ctx -> | |
| 225 | def browser = ctx.variants.variants.find { it.name == 'browser' } |
|
225 | def browser = ctx.variants.variants.find { it.name == 'browser' } | |
| 226 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } |
|
226 | def mainLayer = ctx.variants.layers.find { it.name == 'main' } | |
| 227 |
def unit = ctx.compileUnits. |
|
227 | def unit = ctx.compileUnits.requireUnit(browser, mainLayer) | |
| 228 |
|
228 | |||
| 229 | def sourceSet = ctx.sourceSets.getSourceSet(unit).get() |
|
229 | def sourceSet = ctx.sourceSets.getSourceSet(unit).get() | |
| 230 | variantSources.layer('main') { |
|
230 | variantSources.layer('main') { | |
| @@ -321,8 +321,8 class VariantSourcesPluginFunctionalTest | |||||
| 321 | def variantBar = ctx.variants.layers.find { it.name == 'variantBar' } |
|
321 | def variantBar = ctx.variants.layers.find { it.name == 'variantBar' } | |
| 322 | def bar = ctx.variants.layers.find { it.name == 'bar' } |
|
322 | def bar = ctx.variants.layers.find { it.name == 'bar' } | |
| 323 |
|
323 | |||
| 324 |
def later = ctx.compileUnits. |
|
324 | def later = ctx.compileUnits.requireUnit(fooVariant, bar) | |
| 325 |
def earlier = ctx.compileUnits. |
|
325 | def earlier = ctx.compileUnits.requireUnit(foo, variantBar) | |
| 326 |
|
326 | |||
| 327 | println("map1=" + later.variant().name + ":" + later.layer().name + "->" + ctx.sourceSets.getSourceSet(later).name) |
|
327 | println("map1=" + later.variant().name + ":" + later.layer().name + "->" + ctx.sourceSets.getSourceSet(later).name) | |
| 328 | println("map2=" + earlier.variant().name + ":" + earlier.layer().name + "->" + ctx.sourceSets.getSourceSet(earlier).name) |
|
328 | println("map2=" + earlier.variant().name + ":" + earlier.layer().name + "->" + ctx.sourceSets.getSourceSet(earlier).name) | |
| @@ -33,8 +33,8 class CompileUnitsViewTest { | |||||
| 33 | new VariantRoleLayer(browser, qa, test))); |
|
33 | new VariantRoleLayer(browser, qa, test))); | |
| 34 |
|
34 | |||
| 35 | var units = CompileUnitsView.of(view); |
|
35 | var units = CompileUnitsView.of(view); | |
| 36 |
var browserMain = units. |
|
36 | var browserMain = units.requireUnit(browser, main); | |
| 37 |
var browserTest = units. |
|
37 | var browserTest = units.requireUnit(browser, test); | |
| 38 |
|
38 | |||
| 39 | assertEquals(2, units.getUnits().size()); |
|
39 | assertEquals(2, units.getUnits().size()); | |
| 40 | assertEquals(Set.of(browserMain, browserTest), units.getUnitsForVariant(browser)); |
|
40 | assertEquals(Set.of(browserMain, browserTest), units.getUnitsForVariant(browser)); | |
| @@ -59,7 +59,7 class CompileUnitsViewTest { | |||||
| 59 |
|
59 | |||
| 60 | var units = CompileUnitsView.of(view); |
|
60 | var units = CompileUnitsView.of(view); | |
| 61 |
|
61 | |||
| 62 |
var ex = assertThrows(IllegalArgumentException.class, () -> units. |
|
62 | var ex = assertThrows(IllegalArgumentException.class, () -> units.requireUnit(browser, missing)); | |
| 63 | assertTrue(ex.getMessage().contains("Compile unit for variant 'browser' and layer 'missing' not found")); |
|
63 | assertTrue(ex.getMessage().contains("Compile unit for variant 'browser' and layer 'missing' not found")); | |
| 64 | } |
|
64 | } | |
| 65 |
|
65 | |||
General Comments 0
You need to be logged in to leave comments.
Login now
