| @@ -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.Varian |
|
|
|
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 Varian |
|
|
|
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>> mapOutput |
|
|
|
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( |
|
|
|
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 Outgoing |
|
|
|
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> get |
|
|
|
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 Varian |
|
|
|
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 Outgoing |
|
|
|
27 | void all(Action<? super OutgoingVariant> action); | |
|
|
28 | 28 | |
|
|
29 |
Optional<Outgoing |
|
|
|
29 | Optional<OutgoingVariant> findOutgoing(Variant variant); | |
|
|
30 | 30 | |
|
|
31 |
default Outgoing |
|
|
|
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 Varian |
|
|
|
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 Outgoing |
|
|
|
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.Outgoing |
|
|
|
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 Outgoing |
|
|
|
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> get |
|
|
|
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.Outgoing |
|
|
|
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<Outgoing |
|
|
|
30 | public Optional<OutgoingVariant> findOutgoing(Variant variant) { | |
|
|
27 | 31 | return Optional.ofNullable(outgoingByVariant.get(variant)); |
|
|
28 | 32 | } |
|
|
29 | 33 | |
|
|
30 |
public Outgoing |
|
|
|
31 |
|
|
|
|
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.Varian |
|
|
|
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.Varian |
|
|
|
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
