diff --git a/design_notes.md b/design_notes.md new file mode 100644 --- /dev/null +++ b/design_notes.md @@ -0,0 +1,31 @@ +# design notes + +## core model + +- OutgoingRegistry (Variant) + исходящая конфигурация + - [provider] configuration + - [container, live] slots + набор вариантов (слотов) + - [property] primarySlot +- AssemblyRegistry (Varaint, Slot) + содержимое слота может быть добавлено после появления слота в OutgoingRegistry + - assembleTask + - inputs + - compile unit output (CompileUnit, String) + - direct object (task, file collection, etc.) + - artifact: directory + - customTask + - artifact: FileSystemLocation + +## extension + +- adapter + - whenFinalized +- dsl + - variant(name) + - slot(name) + - from*** + - whenFinalized + - whenOutgoingConfiguration + - whenOutgoingSlot diff --git a/variants/src/main/java/org/implab/gradle/variants/VariantArtifactsPlugin.java b/variants/src/main/java/org/implab/gradle/variants/VariantArtifactsPlugin.java --- a/variants/src/main/java/org/implab/gradle/variants/VariantArtifactsPlugin.java +++ b/variants/src/main/java/org/implab/gradle/variants/VariantArtifactsPlugin.java @@ -4,12 +4,13 @@ import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.implab.gradle.common.core.lang.Deferred; +import org.implab.gradle.variants.artifacts.ArtifactAssemblyRegistry; import org.implab.gradle.variants.artifacts.OutgoingArtifactSlotSpec; import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec; import org.implab.gradle.variants.artifacts.VariantArtifactsContext; import org.implab.gradle.variants.artifacts.VariantArtifactsExtension; import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; -import org.implab.gradle.variants.artifacts.internal.VariantArtifactsRegistry; +import org.implab.gradle.variants.artifacts.internal.OutgoingRegistry; import org.implab.gradle.variants.core.Variant; import org.implab.gradle.variants.core.VariantsExtension; @@ -19,13 +20,19 @@ public abstract class VariantArtifactsPl public void apply(Project target) { var extensions = target.getExtensions(); var objects = target.getObjects(); + var providers = target.getProviders(); + var configurations = target.getConfigurations(); + var tasks = target.getTasks(); // Apply the main VariantsPlugin to ensure the core variant model is available. target.getPlugins().apply(VariantsPlugin.class); // Access the VariantsExtension to configure variant sources. var variantsExtension = extensions.getByType(VariantsExtension.class); - var deferred = new Deferred(); + var outgoing = new OutgoingRegistry(configurations, objects, providers); + var assemblies = new ArtifactAssemblyRegistry(objects, tasks); + + var deferred = new Deferred(); variantsExtension.whenFinalized(variants -> { deferred.resolve(new VariantArtifactsRegistry(variants)); @@ -35,7 +42,7 @@ public abstract class VariantArtifactsPl @Override public void variant(String variantName, Action action) { - deferred.whenResolved(registry -> registry.configureVariant( + deferred.whenResolved(context -> registry.configureVariant( objects.named(Variant.class, variantName), action)); } diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssemblies.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssemblies.java --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssemblies.java +++ b/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssemblies.java @@ -1,11 +1,16 @@ package org.implab.gradle.variants.artifacts; +import java.util.Optional; + import org.eclipse.jdt.annotation.NonNullByDefault; +import org.gradle.api.InvalidUserDataException; /** * Resolves stateful slot assemblies from cheap slot identities. * - *

The returned assembly is a materialized build-model handle. It may expose lazy Gradle providers, but + *

+ * The returned assembly is a materialized build-model handle. It may expose + * lazy Gradle providers, but * it is no longer an identity object suitable for replayable discovery. */ @NonNullByDefault @@ -13,10 +18,16 @@ public interface ArtifactAssemblies { /** * Resolves the assembly for the given slot. * - *

This call materializes the build-facing body of the slot from its identity. + *

+ * This call materializes the build-facing body of the slot from its identity. * * @param slot slot identity inside a variant outgoing contract * @return assembly handle for the slot */ - ArtifactAssembly resolveSlot(ArtifactSlot slot); + default ArtifactAssembly require(ArtifactSlot slot) { + return find(slot) + .orElseThrow(() -> new InvalidUserDataException("Artifact assembly '" + slot + "' isn't registered")); + } + + Optional find(ArtifactSlot slot); } diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssembly.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssembly.java --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssembly.java +++ b/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssembly.java @@ -1,6 +1,7 @@ package org.implab.gradle.variants.artifacts; import org.gradle.api.Task; +import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileSystemLocation; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.TaskProvider; @@ -8,8 +9,10 @@ import org.gradle.api.tasks.TaskProvider /** * Materialized body of an {@link ArtifactSlot}. * - *

An assembly is a stateful build object obtained on demand from - * {@link ArtifactAssemblies#resolveSlot(ArtifactSlot)}. It describes how the slot artifact is produced and + *

+ * An assembly is a stateful build object obtained on demand from + * {@link ArtifactAssemblies#require(ArtifactSlot)}. It describes how the + * slot artifact is produced and * where that single published artifact will appear. */ public interface ArtifactAssembly { @@ -17,7 +20,9 @@ public interface ArtifactAssembly { /** * Returns the published artifact produced for the slot. * - *

A slot is expected to produce exactly one artifact represented by one file or one directory. + *

+ * A slot is expected to produce exactly one artifact represented by one file or + * one directory. * * @return provider of the produced artifact location */ @@ -29,4 +34,10 @@ public interface ArtifactAssembly { * @return provider of the assembly task */ TaskProvider getAssemblyTask(); + + /** + * File collection, contains {@link #getArtifact()} and build dependency on + * {@link #getAssemblyTask()}. This is a conventional property. + */ + FileCollection getFileCollection(); } diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssemblyRegistry.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssemblyRegistry.java new file mode 100644 --- /dev/null +++ b/variants/src/main/java/org/implab/gradle/variants/artifacts/ArtifactAssemblyRegistry.java @@ -0,0 +1,99 @@ +package org.implab.gradle.variants.artifacts; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.gradle.api.InvalidUserDataException; +import org.gradle.api.Task; +import org.gradle.api.file.Directory; +import org.gradle.api.file.FileCollection; +import org.gradle.api.file.FileSystemLocation; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Copy; +import org.gradle.api.tasks.TaskContainer; +import org.gradle.api.tasks.TaskProvider; +import org.gradle.language.base.plugins.LifecycleBasePlugin; + +@NonNullByDefault +public class ArtifactAssemblyRegistry implements ArtifactAssemblies { + private final ObjectFactory objects; + private final TaskContainer tasks; + private final Map assemblies = new LinkedHashMap<>(); + + public ArtifactAssemblyRegistry(ObjectFactory objects, TaskContainer tasks) { + this.objects = objects; + this.tasks = tasks; + } + + public ArtifactAssembly register( + ArtifactSlot slot, + String taskName, + Provider outputDirectory, + FileCollection sources) { + + var task = tasks.register(taskName, Copy.class, copy -> { + copy.setGroup(LifecycleBasePlugin.BUILD_GROUP); + copy.into(outputDirectory); + copy.from(sources); + }); + + return register(slot, task, t -> outputDirectory); + } + + public ArtifactAssembly register( + ArtifactSlot slot, + TaskProvider task, + Function> mapOutputDirectory) { + if (assemblies.containsKey(slot)) { + throw new InvalidUserDataException("Artifact assembly '" + slot + "' is already registered"); + } + var outputArtifact = task.flatMap(t -> mapOutputDirectory.apply(t)); + + var output = objects.fileCollection() + .from(outputArtifact) + .builtBy(task); + + var assembly = new Assembly(outputArtifact, task, output); + assemblies.put(slot, assembly); + return assembly; + } + + @Override + public Optional find(ArtifactSlot slot) { + return Optional.ofNullable(assemblies.get(slot)); + } + + static class Assembly implements ArtifactAssembly { + + private final Provider artifact; + private final TaskProvider task; + private final FileCollection fileCollection; + + Assembly(Provider artifact, TaskProvider task, + FileCollection fileCollection) { + this.artifact = artifact; + this.task = task; + this.fileCollection = fileCollection; + } + + @Override + public Provider getArtifact() { + return artifact; + } + + @Override + public TaskProvider getAssemblyTask() { + return task; + } + + @Override + public FileCollection getFileCollection() { + return fileCollection; + } + + } +} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/OutputSelectionSpec.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/OutputSelectionSpec.java --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/OutputSelectionSpec.java +++ b/variants/src/main/java/org/implab/gradle/variants/artifacts/OutputSelectionSpec.java @@ -8,13 +8,6 @@ package org.implab.gradle.variants.artif */ public interface OutputSelectionSpec { /** - * Selects one named output. - * - * @param name output name - */ - void output(String name); - - /** * Selects several named outputs. * * @param name first output name diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/VariantArtifactsContext.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/VariantArtifactsContext.java --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/VariantArtifactsContext.java +++ b/variants/src/main/java/org/implab/gradle/variants/artifacts/VariantArtifactsContext.java @@ -3,6 +3,7 @@ package org.implab.gradle.variants.artif import java.util.Optional; import org.gradle.api.Action; +import org.gradle.api.InvalidUserDataException; import org.implab.gradle.variants.core.Variant; import org.implab.gradle.variants.core.VariantsView; @@ -25,9 +26,12 @@ public interface VariantArtifactsContext */ void all(Action action); - Optional findArtifacts(Variant variant); + Optional findOutgoing(Variant variant); - OutgoingConfiguration requireArtifacts(Variant variant); + default OutgoingConfiguration requireOutgoing(Variant variant) { + return findOutgoing(variant) + .orElseThrow(() -> new InvalidUserDataException("Outgoing variant '" + variant + "' isn't registered")); + } ArtifactAssemblyRules slotRules(ArtifactSlot slot); diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/ArtifactInputsResolver.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/ArtifactInputsResolver.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/ArtifactInputsResolver.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.gradle.api.Action; -import org.implab.gradle.variants.artifacts.ArtifactSlot; - -@NonNullByDefault -interface ArtifactInputsResolver { - void observeInputs(ArtifactSlot slot, Action action); -} \ No newline at end of file diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/BoundArtifactAssemblySpec.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/BoundArtifactAssemblySpec.java --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/BoundArtifactAssemblySpec.java +++ b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/BoundArtifactAssemblySpec.java @@ -1,52 +1,82 @@ package org.implab.gradle.variants.artifacts.internal; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Stream; import org.gradle.api.Action; -import org.implab.gradle.variants.artifacts.ArtifactAssemblyRules; +import org.gradle.api.model.ObjectFactory; +import org.implab.gradle.common.core.lang.Strings; import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec; -import org.implab.gradle.variants.core.Variant; +import org.implab.gradle.variants.core.Layer; +import org.implab.gradle.variants.core.Role; import org.implab.gradle.variants.artifacts.OutputSelectionSpec; +/** + * Реализация DSL модели, строит набор {@link SlotContribution}. При построении набора + * правила и корректность не проверяются. По окончании использования клиент + * вызывает метод {@link #process(Consumer)} для обработки результатов. + * + */ final class BoundArtifactAssemblySpec implements ArtifactAssemblySpec { - private final VariantArtifactsRegistry registry; - private final Variant variant; - private final ArtifactAssemblyRules rules; + private final List contributions = new LinkedList<>(); + private final ObjectFactory objectFactory; - BoundArtifactAssemblySpec( - VariantArtifactsRegistry registry, - Variant variant, - ArtifactAssemblyRules rules) { - this.registry = registry; - this.variant = variant; - this.rules = rules; + BoundArtifactAssemblySpec(ObjectFactory objectFactory) { + this.objectFactory = objectFactory; } @Override public void from(Object artifact) { - rules.addDirectInput(artifact); + contributions.add(new DirectContribution(artifact)); } @Override public void fromVariant(Action action) { - rules.addVariantOutputs(outputs(action)); + contributions.add(new VariantOutputsContribution(outputs(action))); } @Override public void fromRole(String roleName, Action action) { - var role = registry.requireRole(variant, roleName); - rules.addRoleOutputs(role, outputs(action)); + + contributions.add(new RoleOutputsContribution( + objectFactory.named(Role.class, roleName), + outputs(action))); } @Override public void fromLayer(String layerName, Action action) { - var layer = registry.requireLayer(variant, layerName); - rules.addLayerOutputs(layer, outputs(action)); + contributions.add(new LayerOutputsContribution( + objectFactory.named(Layer.class, layerName), + outputs(action))); + } + + void process(Consumer consumer) { + contributions.forEach(consumer); } private static Set outputs(Action action) { - var spec = new DefaultOutputSelectionSpec(); + var spec = new OutputsSetSpec(); action.execute(spec); return spec.outputs(); } + + private static class OutputsSetSpec implements OutputSelectionSpec { + private final Set outputs = new HashSet<>(); + + @Override + public void output(String name, String... extra) { + Stream.concat(Stream.of(name), Stream.of(extra)) + .map(Strings::requireNonBlank) + .forEach(outputs::add); + } + + Set outputs() { + return Set.copyOf(outputs); + } + + } } diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/BoundVariantArtifactsSpec.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/BoundVariantArtifactsSpec.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/BoundVariantArtifactsSpec.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import org.gradle.api.Action; -import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; -import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec; -import org.implab.gradle.variants.artifacts.ArtifactSlot; - -/** - * DSL фасад для описания исходящей конфигурации варианта - */ -final class BoundVariantArtifactsSpec implements VariantArtifactsSpec { - private final VariantArtifactsRegistry registry; - private final DefaultOutgoingConfiguration outgoing; - - BoundVariantArtifactsSpec(VariantArtifactsRegistry registry, DefaultOutgoingConfiguration outgoing) { - this.registry = registry; - this.outgoing = outgoing; - } - - @Override - public void slot(String name, Action action) { - var slot = outgoing.getSlots().maybeCreate(name); - var artifactSlot = new ArtifactSlot(outgoing.getVariant(), slot); - var rules = registry.slotRules(artifactSlot); - - action.execute(new BoundArtifactAssemblySpec(registry, outgoing.getVariant(), rules)); - } - - @Override - public void primarySlot(String name, Action action) { - var slot = outgoing.getSlots().maybeCreate(name); - outgoing.getPrimarySlot().set(slot); - - var artifactSlot = new ArtifactSlot(outgoing.getVariant(), slot); - var rules = registry.slotRules(artifactSlot); - - action.execute(new BoundArtifactAssemblySpec(registry, outgoing.getVariant(), rules)); - } -} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactAssemblies.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactAssemblies.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactAssemblies.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import java.util.LinkedHashMap; -import java.util.Map; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.gradle.api.file.ProjectLayout; -import org.gradle.api.model.ObjectFactory; -import org.gradle.api.tasks.TaskContainer; -import org.implab.gradle.variants.artifacts.ArtifactAssemblies; -import org.implab.gradle.variants.artifacts.ArtifactAssembly; -import org.implab.gradle.variants.artifacts.ArtifactSlot; -import org.implab.gradle.variants.sources.VariantSourcesContext; - -@NonNullByDefault -final class DefaultArtifactAssemblies implements ArtifactAssemblies { - private final ArtifactInputsResolver inputs; - private final ObjectFactory objects; - - private final VariantArtifactsRegistry registry; - private final VariantSourcesContext sources; - private final TaskContainer tasks; - private final ProjectLayout layout; - - private final Map assemblies = new LinkedHashMap<>(); - - DefaultArtifactAssemblies( - VariantArtifactsRegistry registry, - VariantSourcesContext sources, - TaskContainer tasks, - ProjectLayout layout) { - this.registry = registry; - this.sources = sources; - this.tasks = tasks; - this.layout = layout; - } - - @Override - public ArtifactAssembly resolveSlot(ArtifactSlot slot) { - return assemblies.computeIfAbsent(slot, this::createAssembly); - } - - private ArtifactAssembly createAssembly(ArtifactSlot slot) { - var files = objects.fileCollection(); - - inputs.observeInputs(slot, input -> files.from(input.input())); - - // register task + wire live inputs - // return DefaultArtifactAssembly(...) - } -} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactAssemblyRules.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactAssemblyRules.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactAssemblyRules.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.gradle.api.Action; -import org.implab.gradle.variants.artifacts.ArtifactAssemblyRules; -import org.implab.gradle.variants.core.Layer; -import org.implab.gradle.variants.core.Role; - -@NonNullByDefault -final class DefaultArtifactAssemblyRules implements ArtifactAssemblyRules { - private final List contributions = new ArrayList<>(); - - @Override - public void addDirectInput(Object input) { - contributions.add(new DirectContribution(Objects.requireNonNull(input, "input"))); - } - - @Override - public void addVariantOutputs(Set outputs) { - contributions.add(new VariantOutputsContribution(Set.copyOf(outputs))); - } - - @Override - public void addRoleOutputs(Role role, Set outputs) { - contributions.add(new RoleOutputsContribution(role, Set.copyOf(outputs))); - } - - @Override - public void addLayerOutputs(Layer layer, Set outputs) { - contributions.add(new LayerOutputsContribution(layer, Set.copyOf(outputs))); - } - - @Override - public void all(Action action) { - contributions.forEach(action::execute); - } -} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactInputsResolver.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactInputsResolver.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/DefaultArtifactInputsResolver.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.gradle.api.Action; -import org.implab.gradle.internal.ReplayableQueue; -import org.implab.gradle.variants.artifacts.ArtifactSlot; -import org.implab.gradle.variants.sources.CompileUnit; -import org.implab.gradle.variants.sources.VariantSourcesContext; - -@NonNullByDefault -final class DefaultArtifactInputsResolver implements ArtifactInputsResolver { - private final VariantArtifactsRegistry registry; - private final VariantSourcesContext sources; - private final SlotInputDedupPolicy dedupPolicy; - - private final Map> resolved = new LinkedHashMap<>(); - - DefaultArtifactInputsResolver( - VariantArtifactsRegistry registry, - VariantSourcesContext sources, - SlotInputDedupPolicy dedupPolicy) { - this.registry = registry; - this.sources = sources; - this.dedupPolicy = dedupPolicy; - } - - /** - * ставит replayble-hook на registry.slotRules(slot).all(action) - */ - @Override - public void observeInputs(ArtifactSlot slot, Action action) { - resolvedInputs(slot).forEach(action::execute); - } - - private ReplayableQueue resolvedInputs(ArtifactSlot slot) { - return resolved.computeIfAbsent(slot, this::bindSlot); - } - - private ReplayableQueue bindSlot(ArtifactSlot slot) { - var queue = new ReplayableQueue(); - var filter = dedupPolicy.newFilter(slot); - - // TODO: жесть какая-то нужно переписать - registry.slotRules(slot).all(contribution -> { - var processor = new ContributionProcessor(slot, input -> { - if (filter.accept(input)) { - queue.add(input); - } - }); - contribution.accept(processor); - }); - - return queue; - } - - private void emitUnitOutputs( - ArtifactSlot slot, - Set units, - Set outputs, - Consumer sink) { - for (var unit : units) { - var sourceSet = sources.getSourceSets().getSourceSet(unit); - for (var output : outputs) { - sink.accept(new ResolvedSlotInput( - slot, - new CompileUnitOutputKey(unit, output), - sourceSet.map(ss -> ss.output(output)))); - } - } - } - - - - class ContributionProcessor implements SlotContributionVisitor { - private final ArtifactSlot slot; - private final Consumer sink; - - ContributionProcessor(ArtifactSlot slot, Consumer sink) { - this.slot = slot; - this.sink = sink; - } - - @Override - public void visit(DirectContribution contribution) { - sink.accept(new ResolvedSlotInput( - slot, - SlotInputKey.newUniqueKey("Direct slot for " + slot), - contribution.input())); - } - - @Override - public void visit(VariantOutputsContribution contribution) { - var units = sources.getCompileUnits().getUnitsForVariant(slot.variant()); - emitUnitOutputs(slot, units, contribution.outputs(), sink); - } - - @Override - public void visit(RoleOutputsContribution contribution) { - var projection = sources.getRoleProjections().getProjection(slot.variant(), contribution.role()); - var units = sources.getRoleProjections().getUnits(projection); - emitUnitOutputs(slot, units, contribution.outputs(), sink); - } - - @Override - public void visit(LayerOutputsContribution contribution) { - var unit = sources.getCompileUnits().requireUnit(slot.variant(), contribution.layer()); - emitUnitOutputs(slot, Set.of(unit), contribution.outputs(), sink); - } - - } -} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/OutgoingRegistry.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/OutgoingRegistry.java new file mode 100644 --- /dev/null +++ b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/OutgoingRegistry.java @@ -0,0 +1,45 @@ +package org.implab.gradle.variants.artifacts.internal; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + +import org.gradle.api.artifacts.ConfigurationContainer; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ProviderFactory; +import org.implab.gradle.variants.artifacts.OutgoingConfiguration; +import org.implab.gradle.variants.core.Variant; + +public class OutgoingRegistry { + private final Map outgoingByVariant = new LinkedHashMap<>(); + + private final ConfigurationContainer configurations; + private final ObjectFactory objects; + private final ProviderFactory providers; + + public OutgoingRegistry(ConfigurationContainer configurations, ObjectFactory objects, ProviderFactory providers) { + this.configurations = configurations; + this.objects = objects; + this.providers = providers; + } + + public Optional findOutgoing(Variant variant) { + return Optional.ofNullable(outgoingByVariant.get(variant)); + } + + public OutgoingConfiguration maybeCreate(Variant variant) { + return outgoingByVariant.computeIfAbsent(variant, this::newOutgoingConfiguration); + } + + private DefaultOutgoingConfiguration newOutgoingConfiguration(Variant variant) { + var configuration = configurations.register(outgoingConfigurationName(variant)); + + return new DefaultOutgoingConfiguration(variant, configuration, objects, providers); + } + + String outgoingConfigurationName(Variant variant) { + return variant.getName() + "Elements"; + } + + +} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/ResolvedSlotInput.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/ResolvedSlotInput.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/ResolvedSlotInput.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.implab.gradle.variants.artifacts.ArtifactSlot; - -@NonNullByDefault -record ResolvedSlotInput( - ArtifactSlot slot, - SlotInputKey key, - Object input) { -} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotContributionVisitor.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotContributionVisitor.java --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotContributionVisitor.java +++ b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotContributionVisitor.java @@ -1,5 +1,7 @@ package org.implab.gradle.variants.artifacts.internal; +import java.util.function.Consumer; + public interface SlotContributionVisitor { void visit(DirectContribution contribution); @@ -8,4 +10,8 @@ public interface SlotContributionVisitor void visit(RoleOutputsContribution contribution); void visit(LayerOutputsContribution contribution); + + default Consumer consumer() { + return slot -> slot.accept(this); + } } diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotInputDedupPolicy.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotInputDedupPolicy.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotInputDedupPolicy.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.implab.gradle.variants.artifacts.ArtifactSlot; - -@NonNullByDefault -interface SlotInputDedupPolicy { - SlotInputFilter newFilter(ArtifactSlot slot); -} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotInputFilter.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotInputFilter.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/SlotInputFilter.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -@NonNullByDefault -interface SlotInputFilter { - boolean accept(ResolvedSlotInput input); -} diff --git a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/VariantArtifactsRegistry.java b/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/VariantArtifactsRegistry.java deleted file mode 100644 --- a/variants/src/main/java/org/implab/gradle/variants/artifacts/internal/VariantArtifactsRegistry.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.implab.gradle.variants.artifacts.internal; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.gradle.api.Action; -import org.gradle.api.InvalidUserDataException; -import org.gradle.api.file.ProjectLayout; -import org.gradle.api.model.ObjectFactory; -import org.gradle.api.tasks.TaskContainer; -import org.implab.gradle.variants.artifacts.ArtifactAssemblies; -import org.implab.gradle.variants.artifacts.ArtifactAssemblyRules; -import org.implab.gradle.variants.artifacts.ArtifactSlot; -import org.implab.gradle.variants.artifacts.Slot; -import org.implab.gradle.variants.artifacts.OutgoingConfiguration; -import org.implab.gradle.variants.artifacts.VariantArtifactsContext; -import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; -import org.implab.gradle.variants.core.Variant; -import org.implab.gradle.variants.core.VariantsView; -import org.implab.gradle.variants.sources.VariantSourcesContext; - -@NonNullByDefault -public final class VariantArtifactsRegistry { - private final VariantsView variants; - private final ArtifactAssemblies assemblies; - - private final Map outgoingByVariant = new LinkedHashMap<>(); - private final Map rulesBySlot = new LinkedHashMap<>(); - - private final VariantArtifactsContext context = new ContextView(); - - - VariantArtifactsRegistry( - ObjectFactory objects, - VariantsView variants, - VariantSourcesContext sources, - TaskContainer tasks, - ProjectLayout layout) { - this.variants = variants; - this.assemblies = new DefaultArtifactAssemblies(this, sources, tasks, layout); - } - - public VariantArtifactsContext context() { - return context; - } - - - ArtifactAssemblyRules slotRules(ArtifactSlot slot) { - assertDeclaredSlot(slot); - return rulesBySlot.computeIfAbsent(slot, key -> new DefaultArtifactAssemblyRules()); - } - - void configureVariant(Variant variant, Action action) { - var outgoing = outgoingByVariant.computeIfAbsent(variant, this::newOutgoingConfiguration); - action.execute(new BoundVariantArtifactsSpec(this, outgoing)); - } - - private DefaultOutgoingConfiguration newOutgoingConfiguration(Variant variant) { - // register Elements eagerly - } - - private void assertDeclaredSlot(ArtifactSlot slot) { - var outgoing = context.requireArtifacts(slot.variant()); - if (outgoing.getSlots().findByName(slot.slot().getName()) == null) { - throw new InvalidUserDataException( - "Slot '" + slot.slot().getName() + "' isn't declared for variant '" + slot.variant().getName() + "'"); - } - } - - private final class ContextView implements VariantArtifactsContext { - @Override - public VariantsView getVariants() { - return variants; - } - - @Override - public ArtifactAssemblies getAssemblies() { - return assemblies; - } - - @Override - public void all(Action action) { - outgoingByVariant.values().forEach(action::execute); - } - - @Override - public Optional findArtifacts(Variant variant) { - return Optional.ofNullable(outgoingByVariant.get(variant)); - } - - @Override - public OutgoingConfiguration requireArtifacts(Variant variant) { - return findArtifacts(variant) - .orElseThrow(() -> new InvalidUserDataException( - "Outgoing configuration for variant '" + variant.getName() + "' isn't declared")); - } - - @Override - public ArtifactAssemblyRules slotRules(ArtifactSlot slot) { - return VariantArtifactsRegistry.this.slotRules(slot); - } - } -}