# HG changeset patch # User cin # Date 2026-03-27 06:26:42 # Node ID d67a4d2c04cf6b800a2e5a9c7670252968a62965 # Parent f19d2b751aa975baa35bf5958015b4052a5d974b WIP stable versions CompileUnitsView, RoleProjectionsView, VariantSourcesExtension diff --git a/variants/src/main/java/org/implab/gradle/variants/VariantSourcesPlugin.java b/variants/src/main/java/org/implab/gradle/variants/VariantSourcesPlugin.java --- a/variants/src/main/java/org/implab/gradle/variants/VariantSourcesPlugin.java +++ b/variants/src/main/java/org/implab/gradle/variants/VariantSourcesPlugin.java @@ -1,11 +1,20 @@ package org.implab.gradle.variants; import org.eclipse.jdt.annotation.NonNullByDefault; +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.common.sources.GenericSourceSet; import org.implab.gradle.common.sources.SourcesPlugin; +import org.implab.gradle.variants.core.Layer; +import org.implab.gradle.variants.core.Variant; import org.implab.gradle.variants.core.VariantsExtension; +import org.implab.gradle.variants.core.VariantsView; +import org.implab.gradle.variants.sources.CompileUnit; +import org.implab.gradle.variants.sources.CompileUnitsView; +import org.implab.gradle.variants.sources.RoleProjectionsView; +import org.implab.gradle.variants.sources.SourceSetMaterializer; import org.implab.gradle.variants.sources.VariantSourcesContext; @NonNullByDefault @@ -23,6 +32,71 @@ public abstract class VariantSourcesPlug var deferred = new Deferred(); + variantsExtension.whenFinalized(variants -> { + var compileUnits = CompileUnitsView.of(variants); + var roleProjections = RoleProjectionsView.of(variants); + + var context = new Context(variants, compileUnits, roleProjections); + + deferred.resolve(context); + }); + + // var + } + private static class Context implements VariantSourcesContext { + + private final VariantsView variantsView; + private final CompileUnitsView compileUnitsView; + private final RoleProjectionsView roleProjectionsView; + + Context(VariantsView variantsView, CompileUnitsView compileUnitsView, RoleProjectionsView roleProjectionsView) { + this.variantsView = variantsView; + this.compileUnitsView = compileUnitsView; + this.roleProjectionsView = roleProjectionsView; + } + + @Override + public VariantsView getVariants() { + return variantsView; + } + + @Override + public CompileUnitsView getCompileUnits() { + return compileUnitsView; + } + + @Override + public RoleProjectionsView getRoleProjections() { + return roleProjectionsView; + } + + @Override + public SourceSetMaterializer getSourceSets() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getSourceSets'"); + } + + @Override + public void configureLayer(Layer layer, Action action) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'configureLayer'"); + } + + @Override + public void configureVariant(Variant variant, Action action) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'configureVariant'"); + } + + @Override + public void configureUnit(CompileUnit unit, Action action) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'configureUnit'"); + } + + } + + } diff --git a/variants/src/main/java/org/implab/gradle/variants/derived/CompileUnit.java b/variants/src/main/java/org/implab/gradle/variants/sources/CompileUnit.java rename from variants/src/main/java/org/implab/gradle/variants/derived/CompileUnit.java rename to variants/src/main/java/org/implab/gradle/variants/sources/CompileUnit.java --- a/variants/src/main/java/org/implab/gradle/variants/derived/CompileUnit.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/CompileUnit.java @@ -1,7 +1,12 @@ -package org.implab.gradle.variants.derived; +package org.implab.gradle.variants.sources; import org.implab.gradle.variants.core.Layer; import org.implab.gradle.variants.core.Variant; +import org.implab.gradle.variants.core.VariantsView.VariantRoleLayer; public record CompileUnit(Variant variant, Layer layer) { + + public static CompileUnit of(VariantRoleLayer entry) { + return new CompileUnit(entry.variant(), entry.layer()); + } } diff --git a/variants/src/main/java/org/implab/gradle/variants/derived/CompileUnitsView.java b/variants/src/main/java/org/implab/gradle/variants/sources/CompileUnitsView.java rename from variants/src/main/java/org/implab/gradle/variants/derived/CompileUnitsView.java rename to variants/src/main/java/org/implab/gradle/variants/sources/CompileUnitsView.java --- a/variants/src/main/java/org/implab/gradle/variants/derived/CompileUnitsView.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/CompileUnitsView.java @@ -1,32 +1,78 @@ -package org.implab.gradle.variants.derived; +package org.implab.gradle.variants.sources; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNullByDefault; import org.implab.gradle.variants.core.Layer; import org.implab.gradle.variants.core.Role; import org.implab.gradle.variants.core.Variant; +import org.implab.gradle.variants.core.VariantsView; +import org.implab.gradle.variants.core.VariantsView.VariantRoleLayer; @NonNullByDefault -public interface CompileUnitsView { - Set getUnits(); +public final class CompileUnitsView { + + private final VariantsView variants; + private final Map> unitsByVariant = new HashMap<>(); + + private CompileUnitsView(VariantsView variants) { + this.variants = variants; + } + + public Set getUnits() { + return variants.getEntries().stream() + .map(CompileUnit::of) + .collect(Collectors.toUnmodifiableSet()); + } + + public Set getUnitsForVariant(Variant variant) { + Objects.requireNonNull(variant, "Variant can't be null"); + + return unitsByVariant.computeIfAbsent(variant, key -> variants + .getEntriesForVariant(variant).stream() + .map(CompileUnit::of) + .collect(Collectors.toUnmodifiableSet())); + } - Set getUnitsForVariant(Variant variant); + public Optional findUnit(Variant variant, Layer layer) { + Objects.requireNonNull(variant, "Variant can't be null"); + Objects.requireNonNull(layer, "Layer can't be null"); + + return getUnitsForVariant(variant).stream() + .filter(u -> u.layer().equals(layer)) + .findAny(); + } + + public boolean contains(Variant variant, Layer layer) { + return findUnit(variant, layer).isPresent(); + } - Optional findUnit(Variant variant, Layer layer); + /** + * In which logical roles this compile unit participates. + */ - default CompileUnit getUnit(Variant variant, Layer layer) { + public Set getRoles(CompileUnit unit) { + Objects.requireNonNull(unit, "Compile unit can't be null"); + return variants.getEntriesForVariant(unit.variant()).stream() + .filter(entry -> entry.layer().equals(unit.layer())) + .map(VariantRoleLayer::role) + .collect(Collectors.toUnmodifiableSet()); + } + + public CompileUnit getUnit(Variant variant, Layer layer) { return findUnit(variant, layer) .orElseThrow(() -> new IllegalArgumentException( "Compile unit for variant '" + variant.getName() + "' and layer '" + layer.getName() + "' not found")); } - boolean contains(Variant variant, Layer layer); - - /** - * In which logical roles this compile unit participates. - */ - Set getRoles(CompileUnit unit); + public static CompileUnitsView of(VariantsView variantsView) { + Objects.requireNonNull(variantsView, "variantsView can't be null"); + return new CompileUnitsView(variantsView); + } } \ No newline at end of file diff --git a/variants/src/main/java/org/implab/gradle/variants/derived/RoleProjection.java b/variants/src/main/java/org/implab/gradle/variants/sources/RoleProjection.java rename from variants/src/main/java/org/implab/gradle/variants/derived/RoleProjection.java rename to variants/src/main/java/org/implab/gradle/variants/sources/RoleProjection.java --- a/variants/src/main/java/org/implab/gradle/variants/derived/RoleProjection.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/RoleProjection.java @@ -1,7 +1,12 @@ -package org.implab.gradle.variants.derived; +package org.implab.gradle.variants.sources; import org.implab.gradle.variants.core.Role; import org.implab.gradle.variants.core.Variant; +import org.implab.gradle.variants.core.VariantsView.VariantRoleLayer; public record RoleProjection(Variant variant, Role role) { + + public static RoleProjection of(VariantRoleLayer entry) { + return new RoleProjection(entry.variant(), entry.role()); + } } diff --git a/variants/src/main/java/org/implab/gradle/variants/derived/RoleProjectionsView.java b/variants/src/main/java/org/implab/gradle/variants/sources/RoleProjectionsView.java rename from variants/src/main/java/org/implab/gradle/variants/derived/RoleProjectionsView.java rename to variants/src/main/java/org/implab/gradle/variants/sources/RoleProjectionsView.java --- a/variants/src/main/java/org/implab/gradle/variants/derived/RoleProjectionsView.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/RoleProjectionsView.java @@ -1,35 +1,83 @@ -package org.implab.gradle.variants.derived; +package org.implab.gradle.variants.sources; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import org.implab.gradle.variants.core.Layer; import org.implab.gradle.variants.core.Role; import org.implab.gradle.variants.core.Variant; +import org.implab.gradle.variants.core.VariantsView; -public interface RoleProjectionsView { - Set getProjections(); +public final class RoleProjectionsView { + private final VariantsView variants; + + private final Map> projectionsByVariant = new HashMap<>(); + + private RoleProjectionsView(VariantsView variants) { + this.variants = variants; + } - Set getProjectionsForVariant(Variant variant); + public Set getProjections() { + return variants.getEntries().stream() + .map(RoleProjection::of) + .collect(Collectors.toUnmodifiableSet()); + } + + public Set getProjectionsForVariant(Variant variant) { + Objects.requireNonNull(variant, "Variant can't be null"); + return projectionsByVariant.computeIfAbsent(variant, key -> variants + .getEntriesForVariant(variant).stream() + .map(RoleProjection::of) + .collect(Collectors.toUnmodifiableSet())); + } - Set getProjectionsForRole(Role role); + public Set getProjectionsForRole(Role role) { + Objects.requireNonNull(role, "Role can't be null"); + return variants.getEntriesForRole(role).stream() + .map(RoleProjection::of) + .collect(Collectors.toUnmodifiableSet()); + } - Optional findProjection(Variant variant, Role role); + public Optional findProjection(Variant variant, Role role) { + Objects.requireNonNull(variant, "Variant can't be null"); + Objects.requireNonNull(role, "Role can't be null"); + return variants.getEntriesForVariant(variant).stream() + .filter(entry -> entry.role().equals(role)) + .map(RoleProjection::of) + .findAny(); + } - default RoleProjection getProjection(Variant variant, Role role) { + public boolean contains(Variant variant, Role role) { + return findProjection(variant, role).isPresent(); + } + + public Set getUnits(RoleProjection projection) { + Objects.requireNonNull(projection, "Role projection can't be null"); + return variants.getEntriesForVariant(projection.variant()).stream() + .filter(entry -> entry.role().equals(projection.role())) + .map(CompileUnit::of) + .collect(Collectors.toUnmodifiableSet()); + + } + + public RoleProjection getProjection(Variant variant, Role role) { return findProjection(variant, role) .orElseThrow(() -> new IllegalArgumentException( "Role projection for variant '" + variant.getName() + "' and role '" + role.getName() + "' not found")); } - boolean contains(Variant variant, Role role); - - Set getUnits(RoleProjection projection); - - default Set getLayers(RoleProjection projection) { + public Set getLayers(RoleProjection projection) { return getUnits(projection).stream() .map(CompileUnit::layer) .collect(java.util.stream.Collectors.toUnmodifiableSet()); } + + public static RoleProjectionsView of(VariantsView variantsView) { + return new RoleProjectionsView(variantsView); + } } \ No newline at end of file diff --git a/variants/src/main/java/org/implab/gradle/variants/sources/SourceSetMaterializer.java b/variants/src/main/java/org/implab/gradle/variants/sources/SourceSetMaterializer.java --- a/variants/src/main/java/org/implab/gradle/variants/sources/SourceSetMaterializer.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/SourceSetMaterializer.java @@ -2,7 +2,6 @@ package org.implab.gradle.variants.sourc import org.gradle.api.NamedDomainObjectProvider; import org.implab.gradle.common.sources.GenericSourceSet; -import org.implab.gradle.variants.derived.CompileUnit; /** * Materializes symbolic source set names into actual GenericSourceSet diff --git a/variants/src/main/java/org/implab/gradle/variants/sources/VariantSourcesContext.java b/variants/src/main/java/org/implab/gradle/variants/sources/VariantSourcesContext.java --- a/variants/src/main/java/org/implab/gradle/variants/sources/VariantSourcesContext.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/VariantSourcesContext.java @@ -1,14 +1,10 @@ package org.implab.gradle.variants.sources; -import java.util.Set; - import org.gradle.api.Action; -import org.gradle.api.NamedDomainObjectCollection; import org.implab.gradle.common.sources.GenericSourceSet; import org.implab.gradle.variants.core.Layer; +import org.implab.gradle.variants.core.Variant; import org.implab.gradle.variants.core.VariantsView; -import org.implab.gradle.variants.derived.CompileUnitsView; -import org.implab.gradle.variants.derived.RoleProjectionsView; /** * Registry of symbolic source set names produced by sources projection. @@ -47,4 +43,9 @@ public interface VariantSourcesContext { * Actions are applied in registration order. */ void configureLayer(Layer layer, Action action); + + void configureVariant(Variant variant, Action action); + + void configureUnit(CompileUnit unit, Action action); + } \ No newline at end of file diff --git a/variants/src/main/java/org/implab/gradle/variants/sources/VariantSourcesExtension.java b/variants/src/main/java/org/implab/gradle/variants/sources/VariantSourcesExtension.java --- a/variants/src/main/java/org/implab/gradle/variants/sources/VariantSourcesExtension.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/VariantSourcesExtension.java @@ -1,22 +1,93 @@ package org.implab.gradle.variants.sources; +import java.util.Objects; +import java.util.function.Predicate; + +import org.eclipse.jdt.annotation.NonNullByDefault; import org.gradle.api.Action; +import org.gradle.api.InvalidUserDataException; +import org.gradle.api.Named; import org.implab.gradle.common.core.lang.Closures; +import org.implab.gradle.common.core.lang.Strings; +import org.implab.gradle.common.sources.GenericSourceSet; +import org.implab.gradle.variants.core.Layer; +import org.implab.gradle.variants.core.Variant; +import org.implab.gradle.variants.core.VariantsView; import groovy.lang.Closure; +@NonNullByDefault public interface VariantSourcesExtension { + default void layer(String layerName, Action action) { + // protect external DSL + Strings.argumentNotNullOrBlank(layerName, "layerName"); + Objects.requireNonNull(action, "action can't be null"); + + whenFinalized(ctx -> ctx.configureLayer(resolveLayer(ctx.getVariants(), layerName), action)); + } + + default void layer(String layerName, Closure closure) { + layer(layerName, Closures.action(closure)); + } + + default void variant(String variantName, Action action) { + Strings.argumentNotNullOrBlank(variantName, "variantName"); + Objects.requireNonNull(action, "action can't be null"); + + whenFinalized(ctx -> ctx.configureVariant(resolveVariant(ctx.getVariants(), variantName), action)); + } + + default void variant(String variantName, Closure closure) { + variant(variantName, Closures.action(closure)); + } + + default void unit(String variantName, String layerName, Action action) { + Strings.argumentNotNullOrBlank(layerName, "layerName"); + Strings.argumentNotNullOrBlank(variantName, "variantName"); + Objects.requireNonNull(action, "action can't be null"); + + whenFinalized(ctx -> ctx.configureUnit(resolveCompileUnit(ctx, variantName, layerName), action)); + } + /** * Invoked when finalized variants-derived source context becomes available. * * Replayable: - * - if called before variants finalization, action is queued - * - if called after variants finalization, action is invoked immediately + *
    + *
  • if called before variants finalization, action is queued + *
  • if called after variants finalization, action is invoked immediately + *
*/ void whenFinalized(Action action); default void whenFinalized(Closure closure) { whenFinalized(Closures.action(closure)); } + + private static Layer resolveLayer(VariantsView variants, String name) { + return variants.getLayers().stream() + .filter(named(name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Layer '" + name + "' isn't declared")); + } + + private static Variant resolveVariant(VariantsView variants, String name) { + return variants.getVariants().stream() + .filter(named(name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Variant '" + name + "' is't declared")); + } + + private static CompileUnit resolveCompileUnit(VariantSourcesContext ctx, String variantName, String layerName) { + return ctx.getCompileUnits().findUnit( + resolveVariant(ctx.getVariants(), variantName), + resolveLayer(ctx.getVariants(), layerName)) + .orElseThrow(() -> new InvalidUserDataException( + "The CompileUnit isn't declared for variant '" + variantName + "', layer '" + layerName + "'")); + } + + private static Predicate named(String name) { + return named -> named.getName().equals(name); + } } \ No newline at end of file diff --git a/variants/src/main/java/org/implab/gradle/variants/sources/internal/DefaultLayerConfigurationRegistry.java b/variants/src/main/java/org/implab/gradle/variants/sources/internal/DefaultLayerConfigurationRegistry.java --- a/variants/src/main/java/org/implab/gradle/variants/sources/internal/DefaultLayerConfigurationRegistry.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/internal/DefaultLayerConfigurationRegistry.java @@ -4,23 +4,32 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.gradle.api.Action; import org.implab.gradle.common.sources.GenericSourceSet; import org.implab.gradle.variants.core.Layer; -import org.implab.gradle.variants.derived.CompileUnit; +import org.implab.gradle.variants.core.Variant; +import org.implab.gradle.variants.sources.CompileUnit; +@NonNullByDefault public class DefaultLayerConfigurationRegistry implements LayerConfigurationRegistry { private final Map>> actionsByLayer = new LinkedHashMap<>(); + private final Map>> actionsByVariant = new LinkedHashMap<>(); + private final Map>> actionsByUnit = new LinkedHashMap<>(); - @Override - public void add(Layer layer, Action action) { - Objects.requireNonNull(layer, "layer can't be null"); - Objects.requireNonNull(action, "action can't be null"); + public void addLayerAction(Layer layer, Action action) { actionsByLayer.computeIfAbsent(layer, key -> new ArrayList<>()).add(action); } + public void addVariantAction(Variant variant, Action action) { + actionsByVariant.computeIfAbsent(variant, key -> new ArrayList<>()).add(action); + } + + public void addUnitAction(CompileUnit unit, Action action) { + actionsByUnit.computeIfAbsent(unit, key -> new ArrayList<>()).add(action); + } + @Override public void applyLayer(Layer layer, GenericSourceSet sourceSet) { var actions = actionsByLayer.get(layer); diff --git a/variants/src/main/java/org/implab/gradle/variants/sources/internal/LayerConfigurationRegistry.java b/variants/src/main/java/org/implab/gradle/variants/sources/internal/LayerConfigurationRegistry.java --- a/variants/src/main/java/org/implab/gradle/variants/sources/internal/LayerConfigurationRegistry.java +++ b/variants/src/main/java/org/implab/gradle/variants/sources/internal/LayerConfigurationRegistry.java @@ -3,11 +3,11 @@ package org.implab.gradle.variants.sourc import org.gradle.api.Action; import org.implab.gradle.common.sources.GenericSourceSet; import org.implab.gradle.variants.core.Layer; -import org.implab.gradle.variants.derived.CompileUnit; +import org.implab.gradle.variants.sources.CompileUnit; public interface LayerConfigurationRegistry { - void add(Layer layer, Action action); + void addLayerAction(Layer layer, Action action); void applyLayer(Layer layer, GenericSourceSet sourceSet);