##// END OF EJS Templates
WIP code cleanup after AI... never again!
cin -
r48:1f2da15fa080 default
parent child
Show More
@@ -0,0 +1,31
1 # design notes
2
3 ## core model
4
5 - OutgoingRegistry (Variant)
6 исходящая конфигурация
7 - [provider] configuration
8 - [container, live] slots
9 набор вариантов (слотов)
10 - [property] primarySlot
11 - AssemblyRegistry (Varaint, Slot)
12 содержимое слота может быть добавлено после появления слота в OutgoingRegistry
13 - assembleTask
14 - inputs
15 - compile unit output (CompileUnit, String)
16 - direct object (task, file collection, etc.)
17 - artifact: directory
18 - customTask
19 - artifact: FileSystemLocation
20
21 ## extension
22
23 - adapter
24 - whenFinalized
25 - dsl
26 - variant(name)
27 - slot(name)
28 - from***
29 - whenFinalized
30 - whenOutgoingConfiguration
31 - whenOutgoingSlot
@@ -0,0 +1,99
1 package org.implab.gradle.variants.artifacts;
2
3 import java.util.LinkedHashMap;
4 import java.util.Map;
5 import java.util.Optional;
6 import java.util.function.Function;
7
8 import org.eclipse.jdt.annotation.NonNullByDefault;
9 import org.gradle.api.InvalidUserDataException;
10 import org.gradle.api.Task;
11 import org.gradle.api.file.Directory;
12 import org.gradle.api.file.FileCollection;
13 import org.gradle.api.file.FileSystemLocation;
14 import org.gradle.api.model.ObjectFactory;
15 import org.gradle.api.provider.Provider;
16 import org.gradle.api.tasks.Copy;
17 import org.gradle.api.tasks.TaskContainer;
18 import org.gradle.api.tasks.TaskProvider;
19 import org.gradle.language.base.plugins.LifecycleBasePlugin;
20
21 @NonNullByDefault
22 public class ArtifactAssemblyRegistry implements ArtifactAssemblies {
23 private final ObjectFactory objects;
24 private final TaskContainer tasks;
25 private final Map<ArtifactSlot, ArtifactAssembly> assemblies = new LinkedHashMap<>();
26
27 public ArtifactAssemblyRegistry(ObjectFactory objects, TaskContainer tasks) {
28 this.objects = objects;
29 this.tasks = tasks;
30 }
31
32 public ArtifactAssembly register(
33 ArtifactSlot slot,
34 String taskName,
35 Provider<Directory> outputDirectory,
36 FileCollection sources) {
37
38 var task = tasks.register(taskName, Copy.class, copy -> {
39 copy.setGroup(LifecycleBasePlugin.BUILD_GROUP);
40 copy.into(outputDirectory);
41 copy.from(sources);
42 });
43
44 return register(slot, task, t -> outputDirectory);
45 }
46
47 public <T extends Task> ArtifactAssembly register(
48 ArtifactSlot slot,
49 TaskProvider<T> task,
50 Function<? super T, ? extends Provider<? extends FileSystemLocation>> mapOutputDirectory) {
51 if (assemblies.containsKey(slot)) {
52 throw new InvalidUserDataException("Artifact assembly '" + slot + "' is already registered");
53 }
54 var outputArtifact = task.flatMap(t -> mapOutputDirectory.apply(t));
55
56 var output = objects.fileCollection()
57 .from(outputArtifact)
58 .builtBy(task);
59
60 var assembly = new Assembly(outputArtifact, task, output);
61 assemblies.put(slot, assembly);
62 return assembly;
63 }
64
65 @Override
66 public Optional<ArtifactAssembly> find(ArtifactSlot slot) {
67 return Optional.ofNullable(assemblies.get(slot));
68 }
69
70 static class Assembly implements ArtifactAssembly {
71
72 private final Provider<? extends FileSystemLocation> artifact;
73 private final TaskProvider<? extends Task> task;
74 private final FileCollection fileCollection;
75
76 Assembly(Provider<? extends FileSystemLocation> artifact, TaskProvider<? extends Task> task,
77 FileCollection fileCollection) {
78 this.artifact = artifact;
79 this.task = task;
80 this.fileCollection = fileCollection;
81 }
82
83 @Override
84 public Provider<? extends FileSystemLocation> getArtifact() {
85 return artifact;
86 }
87
88 @Override
89 public TaskProvider<? extends Task> getAssemblyTask() {
90 return task;
91 }
92
93 @Override
94 public FileCollection getFileCollection() {
95 return fileCollection;
96 }
97
98 }
99 }
@@ -0,0 +1,45
1 package org.implab.gradle.variants.artifacts.internal;
2
3 import java.util.LinkedHashMap;
4 import java.util.Map;
5 import java.util.Optional;
6
7 import org.gradle.api.artifacts.ConfigurationContainer;
8 import org.gradle.api.model.ObjectFactory;
9 import org.gradle.api.provider.ProviderFactory;
10 import org.implab.gradle.variants.artifacts.OutgoingConfiguration;
11 import org.implab.gradle.variants.core.Variant;
12
13 public class OutgoingRegistry {
14 private final Map<Variant, DefaultOutgoingConfiguration> outgoingByVariant = new LinkedHashMap<>();
15
16 private final ConfigurationContainer configurations;
17 private final ObjectFactory objects;
18 private final ProviderFactory providers;
19
20 public OutgoingRegistry(ConfigurationContainer configurations, ObjectFactory objects, ProviderFactory providers) {
21 this.configurations = configurations;
22 this.objects = objects;
23 this.providers = providers;
24 }
25
26 public Optional<OutgoingConfiguration> findOutgoing(Variant variant) {
27 return Optional.ofNullable(outgoingByVariant.get(variant));
28 }
29
30 public OutgoingConfiguration maybeCreate(Variant variant) {
31 return outgoingByVariant.computeIfAbsent(variant, this::newOutgoingConfiguration);
32 }
33
34 private DefaultOutgoingConfiguration newOutgoingConfiguration(Variant variant) {
35 var configuration = configurations.register(outgoingConfigurationName(variant));
36
37 return new DefaultOutgoingConfiguration(variant, configuration, objects, providers);
38 }
39
40 String outgoingConfigurationName(Variant variant) {
41 return variant.getName() + "Elements";
42 }
43
44
45 }
@@ -1,64 +1,71
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 import org.implab.gradle.variants.artifacts.ArtifactAssemblyRegistry;
7 8 import org.implab.gradle.variants.artifacts.OutgoingArtifactSlotSpec;
8 9 import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec;
9 10 import org.implab.gradle.variants.artifacts.VariantArtifactsContext;
10 11 import org.implab.gradle.variants.artifacts.VariantArtifactsExtension;
11 12 import org.implab.gradle.variants.artifacts.VariantArtifactsSpec;
12 import org.implab.gradle.variants.artifacts.internal.VariantArtifactsRegistry;
13 import org.implab.gradle.variants.artifacts.internal.OutgoingRegistry;
13 14 import org.implab.gradle.variants.core.Variant;
14 15 import org.implab.gradle.variants.core.VariantsExtension;
15 16
16 17 public abstract class VariantArtifactsPlugin implements Plugin<Project> {
17 18
18 19 @Override
19 20 public void apply(Project target) {
20 21 var extensions = target.getExtensions();
21 22 var objects = target.getObjects();
23 var providers = target.getProviders();
24 var configurations = target.getConfigurations();
25 var tasks = target.getTasks();
22 26
23 27 // Apply the main VariantsPlugin to ensure the core variant model is available.
24 28 target.getPlugins().apply(VariantsPlugin.class);
25 29 // Access the VariantsExtension to configure variant sources.
26 30 var variantsExtension = extensions.getByType(VariantsExtension.class);
27 31
28 var deferred = new Deferred<VariantArtifactsRegistry>();
32 var outgoing = new OutgoingRegistry(configurations, objects, providers);
33 var assemblies = new ArtifactAssemblyRegistry(objects, tasks);
34
35 var deferred = new Deferred<VariantArtifactsContext>();
29 36
30 37 variantsExtension.whenFinalized(variants -> {
31 38 deferred.resolve(new VariantArtifactsRegistry(variants));
32 39 });
33 40
34 41 var variantArtifacts = new VariantArtifactsExtension() {
35 42
36 43 @Override
37 44 public void variant(String variantName, Action<? super VariantArtifactsSpec> action) {
38 deferred.whenResolved(registry -> registry.configureVariant(
45 deferred.whenResolved(context -> registry.configureVariant(
39 46 objects.named(Variant.class, variantName), action));
40 47 }
41 48
42 49 @Override
43 50 public void whenFinalized(Action<? super VariantArtifactsContext> action) {
44 51 deferred.whenResolved(registry -> action.execute(registry.variantsContext()));
45 52 }
46 53
47 54 @Override
48 55 public void whenOutgoingVariant(Action<? super OutgoingConfigurationSpec> action) {
49 56 deferred.whenResolved(registry -> registry.configureOutgoing(action));
50 57
51 58 }
52 59
53 60 @Override
54 61 public void whenOutgoingSlot(Action<? super OutgoingArtifactSlotSpec> action) {
55 62 deferred.whenResolved(registry -> registry.configureOutgoingSlot(action));
56 63 }
57 64
58 65 };
59 66
60 67 extensions.add(VariantArtifactsExtension.class, "variantArtifacts", variantArtifacts);
61 68
62 69 }
63 70
64 71 }
@@ -1,22 +1,33
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 import java.util.Optional;
4
3 5 import org.eclipse.jdt.annotation.NonNullByDefault;
6 import org.gradle.api.InvalidUserDataException;
4 7
5 8 /**
6 9 * Resolves stateful slot assemblies from cheap slot identities.
7 10 *
8 * <p>The returned assembly is a materialized build-model handle. It may expose lazy Gradle providers, but
11 * <p>
12 * The returned assembly is a materialized build-model handle. It may expose
13 * lazy Gradle providers, but
9 14 * it is no longer an identity object suitable for replayable discovery.
10 15 */
11 16 @NonNullByDefault
12 17 public interface ArtifactAssemblies {
13 18 /**
14 19 * Resolves the assembly for the given slot.
15 20 *
16 * <p>This call materializes the build-facing body of the slot from its identity.
21 * <p>
22 * This call materializes the build-facing body of the slot from its identity.
17 23 *
18 24 * @param slot slot identity inside a variant outgoing contract
19 25 * @return assembly handle for the slot
20 26 */
21 ArtifactAssembly resolveSlot(ArtifactSlot slot);
27 default ArtifactAssembly require(ArtifactSlot slot) {
28 return find(slot)
29 .orElseThrow(() -> new InvalidUserDataException("Artifact assembly '" + slot + "' isn't registered"));
30 }
31
32 Optional<ArtifactAssembly> find(ArtifactSlot slot);
22 33 }
@@ -1,32 +1,43
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 3 import org.gradle.api.Task;
4 import org.gradle.api.file.FileCollection;
4 5 import org.gradle.api.file.FileSystemLocation;
5 6 import org.gradle.api.provider.Provider;
6 7 import org.gradle.api.tasks.TaskProvider;
7 8
8 9 /**
9 10 * Materialized body of an {@link ArtifactSlot}.
10 11 *
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
12 * <p>
13 * An assembly is a stateful build object obtained on demand from
14 * {@link ArtifactAssemblies#require(ArtifactSlot)}. It describes how the
15 * slot artifact is produced and
13 16 * where that single published artifact will appear.
14 17 */
15 18 public interface ArtifactAssembly {
16 19
17 20 /**
18 21 * Returns the published artifact produced for the slot.
19 22 *
20 * <p>A slot is expected to produce exactly one artifact represented by one file or one directory.
23 * <p>
24 * A slot is expected to produce exactly one artifact represented by one file or
25 * one directory.
21 26 *
22 27 * @return provider of the produced artifact location
23 28 */
24 29 Provider<? extends FileSystemLocation> getArtifact();
25 30
26 31 /**
27 32 * Returns the task that assembles the slot artifact.
28 33 *
29 34 * @return provider of the assembly task
30 35 */
31 36 TaskProvider<? extends Task> getAssemblyTask();
37
38 /**
39 * File collection, contains {@link #getArtifact()} and build dependency on
40 * {@link #getAssemblyTask()}. This is a conventional property.
41 */
42 FileCollection getFileCollection();
32 43 }
@@ -1,24 +1,17
1 1 package org.implab.gradle.variants.artifacts;
2 2
3 3 /**
4 4 * DSL model for selecting named outputs from a chosen source scope.
5 5 *
6 6 * <p>The selected outputs are inputs to slot assembly. They do not create additional outgoing slots or
7 7 * affect slot identity.
8 8 */
9 9 public interface OutputSelectionSpec {
10 10 /**
11 * Selects one named output.
12 *
13 * @param name output name
14 */
15 void output(String name);
16
17 /**
18 11 * Selects several named outputs.
19 12 *
20 13 * @param name first output name
21 14 * @param extra additional output names
22 15 */
23 16 void output(String name, String... extra);
24 17 }
@@ -1,34 +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 import org.gradle.api.InvalidUserDataException;
6 7 import org.implab.gradle.variants.core.Variant;
7 8 import org.implab.gradle.variants.core.VariantsView;
8 9
9 10 /**
10 11 * Контекст работы с вариантами публикации, становится доступным после
11 12 * финализации модели вариантов. Фактически является живой моделью
12 13 */
13 14 public interface VariantArtifactsContext {
14 15
15 16 /**
16 17 * Зафиксированное представление о вариантах на основе которого адаптеры могут
17 18 * конфигурировать артефакты и исходящие конфигурации
18 19 */
19 20 VariantsView getVariants();
20 21
21 22 ArtifactAssemblies getAssemblies();
22 23
23 24 /**
24 25 * Replayable hook для всех объявленных конфигураций
25 26 */
26 27 void all(Action<? super OutgoingConfiguration> action);
27 28
28 Optional<OutgoingConfiguration> findArtifacts(Variant variant);
29 Optional<OutgoingConfiguration> findOutgoing(Variant variant);
29 30
30 OutgoingConfiguration requireArtifacts(Variant variant);
31 default OutgoingConfiguration requireOutgoing(Variant variant) {
32 return findOutgoing(variant)
33 .orElseThrow(() -> new InvalidUserDataException("Outgoing variant '" + variant + "' isn't registered"));
34 }
31 35
32 36 ArtifactAssemblyRules slotRules(ArtifactSlot slot);
33 37
34 38 }
@@ -1,52 +1,82
1 1 package org.implab.gradle.variants.artifacts.internal;
2 2
3 import java.util.HashSet;
4 import java.util.LinkedList;
5 import java.util.List;
3 6 import java.util.Set;
7 import java.util.function.Consumer;
8 import java.util.stream.Stream;
4 9
5 10 import org.gradle.api.Action;
6 import org.implab.gradle.variants.artifacts.ArtifactAssemblyRules;
11 import org.gradle.api.model.ObjectFactory;
12 import org.implab.gradle.common.core.lang.Strings;
7 13 import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec;
8 import org.implab.gradle.variants.core.Variant;
14 import org.implab.gradle.variants.core.Layer;
15 import org.implab.gradle.variants.core.Role;
9 16 import org.implab.gradle.variants.artifacts.OutputSelectionSpec;
10 17
18 /**
19 * Реализация DSL модели, строит набор {@link SlotContribution}. При построении набора
20 * правила и корректность не проверяются. По окончании использования клиент
21 * вызывает метод {@link #process(Consumer)} для обработки результатов.
22 *
23 */
11 24 final class BoundArtifactAssemblySpec implements ArtifactAssemblySpec {
12 private final VariantArtifactsRegistry registry;
13 private final Variant variant;
14 private final ArtifactAssemblyRules rules;
25 private final List<SlotContribution> contributions = new LinkedList<>();
26 private final ObjectFactory objectFactory;
15 27
16 BoundArtifactAssemblySpec(
17 VariantArtifactsRegistry registry,
18 Variant variant,
19 ArtifactAssemblyRules rules) {
20 this.registry = registry;
21 this.variant = variant;
22 this.rules = rules;
28 BoundArtifactAssemblySpec(ObjectFactory objectFactory) {
29 this.objectFactory = objectFactory;
23 30 }
24 31
25 32 @Override
26 33 public void from(Object artifact) {
27 rules.addDirectInput(artifact);
34 contributions.add(new DirectContribution(artifact));
28 35 }
29 36
30 37 @Override
31 38 public void fromVariant(Action<? super OutputSelectionSpec> action) {
32 rules.addVariantOutputs(outputs(action));
39 contributions.add(new VariantOutputsContribution(outputs(action)));
33 40 }
34 41
35 42 @Override
36 43 public void fromRole(String roleName, Action<? super OutputSelectionSpec> action) {
37 var role = registry.requireRole(variant, roleName);
38 rules.addRoleOutputs(role, outputs(action));
44
45 contributions.add(new RoleOutputsContribution(
46 objectFactory.named(Role.class, roleName),
47 outputs(action)));
39 48 }
40 49
41 50 @Override
42 51 public void fromLayer(String layerName, Action<? super OutputSelectionSpec> action) {
43 var layer = registry.requireLayer(variant, layerName);
44 rules.addLayerOutputs(layer, outputs(action));
52 contributions.add(new LayerOutputsContribution(
53 objectFactory.named(Layer.class, layerName),
54 outputs(action)));
55 }
56
57 void process(Consumer<? super SlotContribution> consumer) {
58 contributions.forEach(consumer);
45 59 }
46 60
47 61 private static Set<String> outputs(Action<? super OutputSelectionSpec> action) {
48 var spec = new DefaultOutputSelectionSpec();
62 var spec = new OutputsSetSpec();
49 63 action.execute(spec);
50 64 return spec.outputs();
51 65 }
66
67 private static class OutputsSetSpec implements OutputSelectionSpec {
68 private final Set<String> outputs = new HashSet<>();
69
70 @Override
71 public void output(String name, String... extra) {
72 Stream.concat(Stream.of(name), Stream.of(extra))
73 .map(Strings::requireNonBlank)
74 .forEach(outputs::add);
75 }
76
77 Set<String> outputs() {
78 return Set.copyOf(outputs);
79 }
80
81 }
52 82 }
@@ -1,11 +1,17
1 1 package org.implab.gradle.variants.artifacts.internal;
2 2
3 import java.util.function.Consumer;
4
3 5 public interface SlotContributionVisitor {
4 6 void visit(DirectContribution contribution);
5 7
6 8 void visit(VariantOutputsContribution contribution);
7 9
8 10 void visit(RoleOutputsContribution contribution);
9 11
10 12 void visit(LayerOutputsContribution contribution);
13
14 default Consumer<SlotContribution> consumer() {
15 return slot -> slot.accept(this);
16 }
11 17 }
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now