##// END OF EJS Templates
WIP Added ArtifactAssemblyBridge to wire variants with slot assemblies
cin -
r49:e7554f6ac360 default
parent child
Show More
@@ -0,0 +1,54
1 package org.implab.gradle.variants.artifacts.internal;
2
3 import org.eclipse.jdt.annotation.NonNullByDefault;
4 import org.gradle.api.Action;
5 import org.implab.gradle.variants.artifacts.ArtifactAssemblies;
6 import org.implab.gradle.variants.artifacts.ArtifactSlot;
7 import org.implab.gradle.variants.artifacts.OutgoingVariant;
8
9 /**
10 * Связывает описание исходящих конфигураций gradle и сборку содержимого слотов
11 * из {@link ArtifactAssemblies}
12 */
13 @NonNullByDefault
14 public class ArtifactAssemblyBridge implements Action<OutgoingVariant> {
15
16 private final ArtifactAssemblies resolver;
17
18 public ArtifactAssemblyBridge(ArtifactAssemblies resolver) {
19 this.resolver = resolver;
20 }
21
22 @Override
23 public void execute(OutgoingVariant outgoingVariant) {
24 var slots = outgoingVariant.getSlots();
25 var primarySlotProvider = outgoingVariant.getPrimarySlot();
26 var variant = outgoingVariant.getVariant();
27
28 // связываем конфигурацию
29 outgoingVariant.configure(configuration -> {
30 var primarySlot = primarySlotProvider.get();
31 var outgoing = configuration.getOutgoing();
32
33 // связываем основной вариант конфигурации
34 resolver.when(
35 new ArtifactSlot(variant, primarySlot),
36 assembly -> outgoing.artifact(assembly.getArtifact()));
37
38 // для всех объявленных слотов
39 slots.all(slot -> {
40 // кроме основного
41 if (slot.equals(primarySlot))
42 return;
43
44 // связываем артефакты
45 resolver.when(
46 new ArtifactSlot(variant, slot),
47 assembly -> outgoing.getVariants()
48 .register(slot.getName())
49 .configure(cv -> cv.artifact(assembly.getArtifact())));
50 });
51 });
52 }
53
54 }
@@ -0,0 +1,55
1 package org.implab.gradle.variants.artifacts.internal;
2
3 import java.util.Collection;
4 import java.util.Set;
5 import java.util.function.Consumer;
6 import java.util.function.Function;
7
8 import org.implab.gradle.variants.artifacts.ArtifactSlot;
9 import org.implab.gradle.variants.core.VariantsView;
10 import org.implab.gradle.variants.sources.CompileUnit;
11 import org.implab.gradle.variants.sources.VariantSourcesContext;
12
13 public class SlotInputsAssembler implements SlotContributionVisitor {
14
15 VariantsView variantView;
16 VariantSourcesContext sources;
17 ArtifactSlot artifactSlot;
18
19 Set<SlotInputKey> seen;
20
21 @Override
22 public void visit(DirectContribution contribution) {
23 contribute(
24 SlotInputKey.newUniqueKey("Direct input for " + artifactSlot),
25 contribution.input());
26 }
27
28 @Override
29 public void visit(VariantOutputsContribution contribution) {
30 sources.getCompileUnits().getUnitsForVariant(artifactSlot.variant()).stream()
31 }
32
33 @Override
34 public void visit(RoleOutputsContribution contribution) {
35 // TODO Auto-generated method stub
36 throw new UnsupportedOperationException("Unimplemented method 'visit'");
37 }
38
39 @Override
40 public void visit(LayerOutputsContribution contribution) {
41 // TODO Auto-generated method stub
42 throw new UnsupportedOperationException("Unimplemented method 'visit'");
43 }
44
45 private void contribute(SlotInputKey key, Object input) {
46
47 }
48
49 private Function<CompileUnit, Object> resolveOutputs(Collection<? extends String> outputs) {
50 return unit -> {
51
52 };
53 }
54
55 }
@@ -1,31 +1,45
1 1 # design notes
2 2
3 3 ## core model
4 4
5 5 - OutgoingRegistry (Variant)
6 6 исходящая конфигурация
7 7 - [provider] configuration
8 8 - [container, live] slots
9 9 набор вариантов (слотов)
10 10 - [property] primarySlot
11 11 - AssemblyRegistry (Varaint, Slot)
12 12 содержимое слота может быть добавлено после появления слота в OutgoingRegistry
13 13 - assembleTask
14 14 - inputs
15 15 - compile unit output (CompileUnit, String)
16 16 - direct object (task, file collection, etc.)
17 17 - artifact: directory
18 18 - customTask
19 19 - artifact: FileSystemLocation
20 20
21 21 ## extension
22 22
23 23 - adapter
24 24 - whenFinalized
25 25 - dsl
26 26 - variant(name)
27 27 - slot(name)
28 28 - from***
29 29 - whenFinalized
30 30 - whenOutgoingConfiguration
31 31 - whenOutgoingSlot
32
33 outgoing = outgoings.maybeCreate(variant)
34
35 slot = outgoings.slots.maybeCreate(slotName)
36 assembly = assemblies.register(variantSlot, task, mapOutput)
37 outgoing.configure(configuration -> {
38 slots.all(slot -> {
39 assemblies.when(variant, slot) { assembly ->
40 configuration.variants.create(slot.name) {
41 artifact(assembly.artifact)
42 }
43 }
44 });
45 }); No newline at end of file
@@ -1,71 +1,75
1 1 package org.implab.gradle.variants;
2 2
3 3 import org.gradle.api.Action;
4 4 import org.gradle.api.Plugin;
5 5 import org.gradle.api.Project;
6 6 import org.implab.gradle.common.core.lang.Deferred;
7 7 import org.implab.gradle.variants.artifacts.ArtifactAssemblyRegistry;
8 import org.implab.gradle.variants.artifacts.OutgoingArtifactSlotSpec;
9 8 import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec;
10 import org.implab.gradle.variants.artifacts.VariantArtifactsContext;
9 import org.implab.gradle.variants.artifacts.OutgoingVariantsContext;
11 10 import org.implab.gradle.variants.artifacts.VariantArtifactsExtension;
12 11 import org.implab.gradle.variants.artifacts.VariantArtifactsSpec;
12 import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyBridge;
13 13 import org.implab.gradle.variants.artifacts.internal.OutgoingRegistry;
14 14 import org.implab.gradle.variants.core.Variant;
15 15 import org.implab.gradle.variants.core.VariantsExtension;
16 16
17 17 public abstract class VariantArtifactsPlugin implements Plugin<Project> {
18 18
19 19 @Override
20 20 public void apply(Project target) {
21 21 var extensions = target.getExtensions();
22 22 var objects = target.getObjects();
23 23 var providers = target.getProviders();
24 24 var configurations = target.getConfigurations();
25 25 var tasks = target.getTasks();
26 26
27 27 // Apply the main VariantsPlugin to ensure the core variant model is available.
28 28 target.getPlugins().apply(VariantsPlugin.class);
29 29 // Access the VariantsExtension to configure variant sources.
30 30 var variantsExtension = extensions.getByType(VariantsExtension.class);
31 31
32 32 var outgoing = new OutgoingRegistry(configurations, objects, providers);
33 33 var assemblies = new ArtifactAssemblyRegistry(objects, tasks);
34 34
35 var deferred = new Deferred<VariantArtifactsContext>();
35 var assembliesBridge = new ArtifactAssemblyBridge(assemblies);
36
37 var deferred = new Deferred<OutgoingVariantsContext>();
38
39 deferred.whenResolved(context -> context.all(assembliesBridge));
36 40
37 41 variantsExtension.whenFinalized(variants -> {
38 deferred.resolve(new VariantArtifactsRegistry(variants));
42
39 43 });
40 44
41 45 var variantArtifacts = new VariantArtifactsExtension() {
42 46
43 47 @Override
44 48 public void variant(String variantName, Action<? super VariantArtifactsSpec> action) {
45 49 deferred.whenResolved(context -> registry.configureVariant(
46 50 objects.named(Variant.class, variantName), action));
47 51 }
48 52
49 53 @Override
50 public void whenFinalized(Action<? super VariantArtifactsContext> action) {
54 public void whenFinalized(Action<? super OutgoingVariantsContext> action) {
51 55 deferred.whenResolved(registry -> action.execute(registry.variantsContext()));
52 56 }
53 57
54 58 @Override
55 59 public void whenOutgoingVariant(Action<? super OutgoingConfigurationSpec> action) {
56 60 deferred.whenResolved(registry -> registry.configureOutgoing(action));
57 61
58 62 }
59 63
60 64 @Override
61 65 public void whenOutgoingSlot(Action<? super OutgoingArtifactSlotSpec> action) {
62 66 deferred.whenResolved(registry -> registry.configureOutgoingSlot(action));
63 67 }
64 68
65 69 };
66 70
67 71 extensions.add(VariantArtifactsExtension.class, "variantArtifacts", variantArtifacts);
68 72
69 73 }
70 74
71 75 }
@@ -1,33 +1,54
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 3 import java.util.Optional;
4 4
5 5 import org.eclipse.jdt.annotation.NonNullByDefault;
6 import org.gradle.api.Action;
6 7 import org.gradle.api.InvalidUserDataException;
7 8
8 9 /**
9 10 * Resolves stateful slot assemblies from cheap slot identities.
10 11 *
11 12 * <p>
12 13 * The returned assembly is a materialized build-model handle. It may expose
13 14 * lazy Gradle providers, but
14 15 * it is no longer an identity object suitable for replayable discovery.
15 16 */
16 17 @NonNullByDefault
17 18 public interface ArtifactAssemblies {
18 19 /**
19 20 * Resolves the assembly for the given slot.
20 21 *
21 22 * <p>
22 23 * This call materializes the build-facing body of the slot from its identity.
23 24 *
24 25 * @param slot slot identity inside a variant outgoing contract
25 26 * @return assembly handle for the slot
26 27 */
27 28 default ArtifactAssembly require(ArtifactSlot slot) {
28 29 return find(slot)
29 30 .orElseThrow(() -> new InvalidUserDataException("Artifact assembly '" + slot + "' isn't registered"));
30 31 }
31 32
33 /**
34 * Регистрирует обработчик на конкретный слот. Если слот еще не зарегистрирован,
35 * то обработчик будет добавлен в очередь и будет вызван при регистрации слота.
36 * Порядок и точный момент вызова обработчиков не определен.
37 *
38 * @param slot Слот на который нужно зарегистрировать обработчик
39 * @param action Обработчик
40 */
41 void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action);
42
43 /**
44 * Регистрирует глобальный обработчик, который будет вызван для всех слотов.
45 * Обработчик будет вызван как для уже зарегистрированных слотов так и для тех,
46 * которые будут зарегистрированы в будущем.
47 *
48 * @param action Обработчик
49 */
50 void all(Action<? super ArtifactAssembly> action);
51
52 /** Ищет зарегистрированный слот */
32 53 Optional<ArtifactAssembly> find(ArtifactSlot slot);
33 54 }
@@ -1,99 +1,124
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 3 import java.util.LinkedHashMap;
4 4 import java.util.Map;
5 5 import java.util.Optional;
6 6 import java.util.function.Function;
7 7
8 8 import org.eclipse.jdt.annotation.NonNullByDefault;
9 import org.gradle.api.Action;
9 10 import org.gradle.api.InvalidUserDataException;
10 11 import org.gradle.api.Task;
11 12 import org.gradle.api.file.Directory;
12 13 import org.gradle.api.file.FileCollection;
13 14 import org.gradle.api.file.FileSystemLocation;
14 15 import org.gradle.api.model.ObjectFactory;
15 16 import org.gradle.api.provider.Provider;
16 17 import org.gradle.api.tasks.Copy;
17 18 import org.gradle.api.tasks.TaskContainer;
18 19 import org.gradle.api.tasks.TaskProvider;
19 20 import org.gradle.language.base.plugins.LifecycleBasePlugin;
21 import org.implab.gradle.common.core.lang.Deferred;
22 import org.implab.gradle.internal.ReplayableQueue;
20 23
21 24 @NonNullByDefault
22 25 public class ArtifactAssemblyRegistry implements ArtifactAssemblies {
23 26 private final ObjectFactory objects;
24 27 private final TaskContainer tasks;
25 private final Map<ArtifactSlot, ArtifactAssembly> assemblies = new LinkedHashMap<>();
28 private final Map<ArtifactSlot, Deferred<ArtifactAssembly>> assembliesBySlots = new LinkedHashMap<>();
29 private final ReplayableQueue<ArtifactAssembly> assemblies = new ReplayableQueue<>();
26 30
27 31 public ArtifactAssemblyRegistry(ObjectFactory objects, TaskContainer tasks) {
28 32 this.objects = objects;
29 33 this.tasks = tasks;
30 34 }
31 35
32 36 public ArtifactAssembly register(
33 37 ArtifactSlot slot,
34 38 String taskName,
35 39 Provider<Directory> outputDirectory,
36 40 FileCollection sources) {
37 41
38 42 var task = tasks.register(taskName, Copy.class, copy -> {
39 43 copy.setGroup(LifecycleBasePlugin.BUILD_GROUP);
40 44 copy.into(outputDirectory);
41 45 copy.from(sources);
42 46 });
43 47
44 48 return register(slot, task, t -> outputDirectory);
45 49 }
46 50
47 51 public <T extends Task> ArtifactAssembly register(
48 52 ArtifactSlot slot,
49 53 TaskProvider<T> task,
50 Function<? super T, ? extends Provider<? extends FileSystemLocation>> mapOutputDirectory) {
51 if (assemblies.containsKey(slot)) {
54 Function<? super T, ? extends Provider<? extends FileSystemLocation>> mapOutputArtifact) {
55
56 var deferred = getDeferred(slot);
57 if (deferred.resolved()) {
52 58 throw new InvalidUserDataException("Artifact assembly '" + slot + "' is already registered");
53 59 }
54 var outputArtifact = task.flatMap(t -> mapOutputDirectory.apply(t));
60 var outputArtifact = task.flatMap(mapOutputArtifact::apply);
55 61
56 62 var output = objects.fileCollection()
57 63 .from(outputArtifact)
58 64 .builtBy(task);
59 65
60 66 var assembly = new Assembly(outputArtifact, task, output);
61 assemblies.put(slot, assembly);
67 deferred.resolve(assembly);
68 assemblies.add(assembly);
62 69 return assembly;
63 70 }
64 71
65 72 @Override
66 73 public Optional<ArtifactAssembly> find(ArtifactSlot slot) {
67 return Optional.ofNullable(assemblies.get(slot));
74 // to prevent creation of map entries on lookup use the map directly
75 var deferred = assembliesBySlots.get(slot);
76 return deferred != null && deferred.resolved()
77 ? Optional.of(deferred.value())
78 : Optional.empty();
79 }
80
81 @Override
82 public void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action) {
83 getDeferred(slot).whenResolved(action::execute);
84 }
85
86 @Override
87 public void all(Action<? super ArtifactAssembly> action) {
88 assemblies.forEach(action::execute);
89 }
90
91 private Deferred<ArtifactAssembly> getDeferred(ArtifactSlot slot) {
92 return assembliesBySlots.computeIfAbsent(slot, k -> new Deferred<>());
68 93 }
69 94
70 95 static class Assembly implements ArtifactAssembly {
71 96
72 97 private final Provider<? extends FileSystemLocation> artifact;
73 98 private final TaskProvider<? extends Task> task;
74 99 private final FileCollection fileCollection;
75 100
76 101 Assembly(Provider<? extends FileSystemLocation> artifact, TaskProvider<? extends Task> task,
77 102 FileCollection fileCollection) {
78 103 this.artifact = artifact;
79 104 this.task = task;
80 105 this.fileCollection = fileCollection;
81 106 }
82 107
83 108 @Override
84 109 public Provider<? extends FileSystemLocation> getArtifact() {
85 110 return artifact;
86 111 }
87 112
88 113 @Override
89 114 public TaskProvider<? extends Task> getAssemblyTask() {
90 115 return task;
91 116 }
92 117
93 118 @Override
94 119 public FileCollection getFileCollection() {
95 120 return fileCollection;
96 121 }
97 122
98 123 }
99 124 }
@@ -1,59 +1,59
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 3 import org.gradle.api.Action;
4 4 import org.gradle.api.Task;
5 5 import org.gradle.api.attributes.AttributeContainer;
6 6 import groovy.lang.Closure;
7 7 import org.implab.gradle.common.core.lang.Closures;
8 8
9 9 /**
10 10 * Materialized outgoing publication state of a single slot.
11 11 *
12 12 * <p>This type is a DSL facade to represent already created publication-facing state. Slot-specific
13 13 * publication tweaks should be applied here rather than through {@link OutgoingConfigurationSpec}, which
14 14 * is limited to the root outgoing configuration of the variant.
15 15 */
16 public interface OutgoingArtifactSlotSpec {
16 public interface OutgoingConfigurationSlotSpec {
17 17 /**
18 18 * Returns the published slot identity.
19 19 *
20 20 * @return slot identity
21 21 */
22 22 ArtifactSlot getArtifactSlot();
23 23
24 24 /**
25 25 * Returns the assembly backing the published slot.
26 26 *
27 27 * @return slot assembly
28 28 */
29 29 ArtifactAssembly getAssembly();
30 30
31 31 /**
32 32 * Returns whether this slot is the primary outgoing artifact set of the variant.
33 33 *
34 34 * @return {@code true} for the primary slot
35 35 */
36 36 boolean isPrimary();
37 37
38 38 /**
39 39 * Configures the task producing the slot artifact.
40 40 *
41 41 * @param action task configuration action
42 42 */
43 43 void assemblyTask(Action<? super Task> action);
44 44
45 45 default void assemblyTask(Closure<?> closure) {
46 46 assemblyTask(Closures.action(closure));
47 47 }
48 48
49 49 /**
50 50 * Configures attributes of this slot publication.
51 51 *
52 52 * @param action artifact attribute configuration action
53 53 */
54 54 void artifactAttributes(Action<? super AttributeContainer> action);
55 55
56 56 default void artifactAttributes(Closure<?> closure) {
57 57 artifactAttributes(Closures.action(closure));
58 58 }
59 59 }
@@ -1,38 +1,50
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 import org.gradle.api.Action;
3 4 import org.gradle.api.NamedDomainObjectContainer;
4 5 import org.gradle.api.NamedDomainObjectProvider;
5 6 import org.gradle.api.artifacts.Configuration;
6 7 import org.gradle.api.provider.Property;
7 8 import org.implab.gradle.variants.core.Variant;
8 9
9 /** Описывает исходящую конфигурацию варианта */
10 public interface OutgoingConfiguration {
10 /**
11 * Описывает исходящую конфигурацию варианта
12 *
13 * Задает связь между моделью вариантов и моделью конфигураций gradle через
14 * свойство {@link #getConfiguration()}. Также задает отдельную ось слотов
15 * публикации, но не задает правил связывания этих слотов с самой конфигурацией
16 * и их содержимым. Самый простой вариант это {@link ArtifactAssemblies}.
17 */
18 public interface OutgoingVariant {
11 19 /**
12 20 * Исходный вариант для которого строится Outgoing конфигурация
13 21 */
14 22 Variant getVariant();
15 23
16 24 /**
17 25 * Провайдер зарегистрированной конфигурации
18 26 */
19 NamedDomainObjectProvider<Configuration> getOutgoingConfiguration();
27 NamedDomainObjectProvider<Configuration> getConfiguration();
28
29 default void configure(Action<? super Configuration> action) {
30 getConfiguration().configure(action);
31 }
20 32
21 33 /**
22 34 * Слоты конфигурации, данная коллекция живая, используется для
23 35 * получения информации об объявленных слотах, но эти слоты не
24 36 * обязаны быть сконфигурированы, т.е. это только Identity.
25 37 *
26 38 * @see {@link ArtifactSlot}
27 39 */
28 40 NamedDomainObjectContainer<Slot> getSlots();
29 41
30 42 /**
31 43 * Основной набор артефактов (primary variant) для исходящей конфигурации
32 44 *
33 45 * <p>
34 46 * Если в свойстве {@link #getSlots()} есть только один слой, то по конвенции он
35 47 * считается также основным.
36 48 */
37 49 Property<Slot> getPrimarySlot();
38 50 }
@@ -1,38 +1,38
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 3 import java.util.Optional;
4 4
5 5 import org.gradle.api.Action;
6 6 import org.gradle.api.InvalidUserDataException;
7 7 import org.implab.gradle.variants.core.Variant;
8 8 import org.implab.gradle.variants.core.VariantsView;
9 9
10 10 /**
11 11 * Контекст работы с вариантами публикации, становится доступным после
12 12 * финализации модели вариантов. Фактически является живой моделью
13 13 */
14 public interface VariantArtifactsContext {
14 public interface OutgoingVariantsContext {
15 15
16 16 /**
17 17 * Зафиксированное представление о вариантах на основе которого адаптеры могут
18 18 * конфигурировать артефакты и исходящие конфигурации
19 19 */
20 20 VariantsView getVariants();
21 21
22 22 ArtifactAssemblies getAssemblies();
23 23
24 24 /**
25 25 * Replayable hook для всех объявленных конфигураций
26 26 */
27 void all(Action<? super OutgoingConfiguration> action);
27 void all(Action<? super OutgoingVariant> action);
28 28
29 Optional<OutgoingConfiguration> findOutgoing(Variant variant);
29 Optional<OutgoingVariant> findOutgoing(Variant variant);
30 30
31 default OutgoingConfiguration requireOutgoing(Variant variant) {
31 default OutgoingVariant requireOutgoing(Variant variant) {
32 32 return findOutgoing(variant)
33 33 .orElseThrow(() -> new InvalidUserDataException("Outgoing variant '" + variant + "' isn't registered"));
34 34 }
35 35
36 36 ArtifactAssemblyRules slotRules(ArtifactSlot slot);
37 37
38 38 }
@@ -1,59 +1,59
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 3 import org.gradle.api.Action;
4 4 import org.implab.gradle.common.core.lang.Closures;
5 5
6 6 import groovy.lang.Closure;
7 7
8 8 /**
9 9 * Project-level DSL entry point for declaring outgoing artifacts per variant.
10 10 *
11 11 * <p>A variant represents one external outgoing contract. Slots declared inside a variant represent
12 12 * artifact sets within that contract. One slot is expected to materialize to one published artifact.
13 13 */
14 14 public interface VariantArtifactsExtension {
15 15 /**
16 16 * Configures artifact slots of the named variant.
17 17 *
18 18 * @param variantName variant name
19 19 * @param action variant artifact declaration
20 20 */
21 21 void variant(String variantName, Action<? super VariantArtifactsSpec> action);
22 22
23 23 default void variant(String variantName, Closure<?> closure) {
24 24 variant(variantName, Closures.action(closure));
25 25 }
26 26
27 27 /**
28 28 * Registers a callback invoked with the finalized artifact model.
29 29 *
30 30 * @param action finalized-model callback
31 31 */
32 void whenFinalized(Action<? super VariantArtifactsContext> action);
32 void whenFinalized(Action<? super OutgoingVariantsContext> action);
33 33
34 34 default void whenFinalized(Closure<?> closure) {
35 35 whenFinalized(Closures.action(closure));
36 36 }
37 37
38 38 /**
39 39 * Registers a callback invoked for each materialized root outgoing configuration.
40 40 *
41 41 * @param action variant-level outgoing configuration callback
42 42 */
43 43 void whenOutgoingVariant(Action<? super OutgoingConfigurationSpec> action);
44 44
45 45 default void whenOutgoingVariant(Closure<?> closure) {
46 46 whenOutgoingVariant(Closures.action(closure));
47 47 }
48 48
49 49 /**
50 50 * Registers a callback invoked for each materialized outgoing slot publication.
51 51 *
52 52 * @param action slot-level outgoing publication callback
53 53 */
54 void whenOutgoingSlot(Action<? super OutgoingArtifactSlotSpec> action);
54 void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action);
55 55
56 56 default void whenOutgoingSlot(Closure<?> closure) {
57 57 whenOutgoingSlot(Closures.action(closure));
58 58 }
59 59 }
@@ -1,62 +1,62
1 1 package org.implab.gradle.variants.artifacts.internal;
2 2
3 3 import org.gradle.api.NamedDomainObjectContainer;
4 4 import org.gradle.api.NamedDomainObjectProvider;
5 5 import org.gradle.api.artifacts.Configuration;
6 6 import org.gradle.api.model.ObjectFactory;
7 7 import org.gradle.api.provider.Property;
8 8 import org.gradle.api.provider.ProviderFactory;
9 9 import org.gradle.api.provider.Provider;
10 import org.implab.gradle.variants.artifacts.OutgoingConfiguration;
10 import org.implab.gradle.variants.artifacts.OutgoingVariant;
11 11 import org.implab.gradle.variants.artifacts.Slot;
12 12 import org.implab.gradle.variants.core.Variant;
13 13
14 class DefaultOutgoingConfiguration implements OutgoingConfiguration {
14 class DefaultOutgoingConfiguration implements OutgoingVariant {
15 15
16 16 private final Variant variant;
17 17
18 18 private final NamedDomainObjectProvider<Configuration> configurationProvider;
19 19
20 20 private final NamedDomainObjectContainer<Slot> slots;
21 21
22 22 private final Property<Slot> primarySlot;
23 23
24 24 public DefaultOutgoingConfiguration(
25 25 Variant variant,
26 26 NamedDomainObjectProvider<Configuration> configurationProvider,
27 27 ObjectFactory objectFactory,
28 28 ProviderFactory providerFactory) {
29 29 this.variant = variant;
30 30 this.configurationProvider = configurationProvider;
31 31 this.slots = objectFactory.domainObjectContainer(Slot.class);
32 32 this.primarySlot = objectFactory.property(Slot.class)
33 33 .convention(providerFactory
34 34 .provider(this::primarySlotConvention)
35 35 .flatMap(x -> x));
36 36 }
37 37
38 38 @Override
39 39 public Property<Slot> getPrimarySlot() {
40 40 return primarySlot;
41 41 }
42 42
43 43 @Override
44 44 public Variant getVariant() {
45 45 return variant;
46 46 }
47 47
48 48 @Override
49 public NamedDomainObjectProvider<Configuration> getOutgoingConfiguration() {
49 public NamedDomainObjectProvider<Configuration> getConfiguration() {
50 50 return configurationProvider;
51 51 }
52 52
53 53 @Override
54 54 public NamedDomainObjectContainer<Slot> getSlots() {
55 55 return slots;
56 56 }
57 57
58 58 private Provider<Slot> primarySlotConvention() {
59 59 return slots.size() == 1 ? slots.named(slots.getNames().first()) : null;
60 60 }
61 61
62 62 }
@@ -1,45 +1,56
1 1 package org.implab.gradle.variants.artifacts.internal;
2 2
3 3 import java.util.LinkedHashMap;
4 import java.util.LinkedList;
5 import java.util.List;
4 6 import java.util.Map;
5 7 import java.util.Optional;
8 import java.util.function.Consumer;
6 9
7 10 import org.gradle.api.artifacts.ConfigurationContainer;
8 11 import org.gradle.api.model.ObjectFactory;
9 12 import org.gradle.api.provider.ProviderFactory;
10 import org.implab.gradle.variants.artifacts.OutgoingConfiguration;
13 import org.implab.gradle.variants.artifacts.OutgoingVariant;
11 14 import org.implab.gradle.variants.core.Variant;
12 15
13 16 public class OutgoingRegistry {
14 17 private final Map<Variant, DefaultOutgoingConfiguration> outgoingByVariant = new LinkedHashMap<>();
18 private final List<Consumer<? super DefaultOutgoingConfiguration>> hooks = new LinkedList<>();
15 19
16 20 private final ConfigurationContainer configurations;
17 21 private final ObjectFactory objects;
18 22 private final ProviderFactory providers;
19 23
20 24 public OutgoingRegistry(ConfigurationContainer configurations, ObjectFactory objects, ProviderFactory providers) {
21 25 this.configurations = configurations;
22 26 this.objects = objects;
23 27 this.providers = providers;
24 28 }
25 29
26 public Optional<OutgoingConfiguration> findOutgoing(Variant variant) {
30 public Optional<OutgoingVariant> findOutgoing(Variant variant) {
27 31 return Optional.ofNullable(outgoingByVariant.get(variant));
28 32 }
29 33
30 public OutgoingConfiguration maybeCreate(Variant variant) {
31 return outgoingByVariant.computeIfAbsent(variant, this::newOutgoingConfiguration);
34 public OutgoingVariant maybeCreate(Variant variant) {
35 var outgoing = outgoingByVariant.computeIfAbsent(variant, this::newOutgoingConfiguration);
36 hooks.forEach(hook -> hook.accept(outgoing));
37 return outgoing;
38 }
39
40 public void all(Consumer<? super OutgoingVariant> action) {
41 outgoingByVariant.values().forEach(action);
42 hooks.add(action);
32 43 }
33 44
34 45 private DefaultOutgoingConfiguration newOutgoingConfiguration(Variant variant) {
35 46 var configuration = configurations.register(outgoingConfigurationName(variant));
36 47
37 48 return new DefaultOutgoingConfiguration(variant, configuration, objects, providers);
38 49 }
39 50
40 String outgoingConfigurationName(Variant variant) {
51 private String outgoingConfigurationName(Variant variant) {
41 52 return variant.getName() + "Elements";
42 53 }
43 54
44 55
45 56 }
@@ -1,41 +1,41
1 1 /**
2 2 * Variant-scoped outgoing artifacts.
3 3 *
4 4 * <p>This package models the external artifact contract of a project in terms of variant-local slots.
5 5 * A variant represents one outgoing contract, while a slot represents one artifact set inside that
6 6 * contract.
7 7 *
8 8 * <p>The model intentionally separates cheap identity objects from stateful build objects:
9 9 *
10 10 * <ul>
11 11 * <li>{@link org.implab.gradle.variants.artifacts.ArtifactSlot} identifies a published slot inside a
12 12 * variant;</li>
13 13 * <li>{@link org.implab.gradle.variants.artifacts.ArtifactAssembly} is the lazily materialized body of
14 14 * that slot.</li>
15 15 * </ul>
16 16 *
17 17 * <p>Each slot is expected to materialize to exactly one published artifact: either one file or one
18 18 * directory. Internal build topology such as roles may participate in slot assembly rules, but does not
19 19 * belong to external artifact identity.
20 20 *
21 21 * <p>Typical usage:
22 22 *
23 23 * <pre>{@code
24 24 * variantArtifacts {
25 25 * variant("browser") {
26 26 * primarySlot("runtime") {
27 27 * fromRole("main") { output("js") }
28 28 * }
29 29 * slot("sources") {
30 30 * fromLayer("main") { output("sources") }
31 31 * }
32 32 * }
33 33 * }
34 34 * }</pre>
35 35 *
36 36 * <p>After finalization, slot identities can be observed through
37 * {@link org.implab.gradle.variants.artifacts.VariantArtifactsContext#getSlots()}, while slot bodies are
37 * {@link org.implab.gradle.variants.artifacts.OutgoingVariantsContext#getSlots()}, while slot bodies are
38 38 * obtained on demand through
39 * {@link org.implab.gradle.variants.artifacts.VariantArtifactsContext#getAssemblies()}.
39 * {@link org.implab.gradle.variants.artifacts.OutgoingVariantsContext#getAssemblies()}.
40 40 */
41 41 package org.implab.gradle.variants.artifacts;
General Comments 0
You need to be logged in to leave comments. Login now