| @@ -0,0 +1,218 | |||
|
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
|
|
2 | ||
|
|
3 | import java.util.HashMap; | |
|
|
4 | import java.util.HashSet; | |
|
|
5 | import java.util.Map; | |
|
|
6 | import java.util.Set; | |
|
|
7 | ||
|
|
8 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
|
|
9 | import org.gradle.api.Action; | |
|
|
10 | import org.gradle.api.file.ConfigurableFileCollection; | |
|
|
11 | import org.gradle.api.file.Directory; | |
|
|
12 | import org.gradle.api.file.DirectoryProperty; | |
|
|
13 | import org.gradle.api.file.FileCollection; | |
|
|
14 | import org.gradle.api.model.ObjectFactory; | |
|
|
15 | import org.gradle.api.provider.Provider; | |
|
|
16 | import org.gradle.api.tasks.Sync; | |
|
|
17 | import org.gradle.api.tasks.TaskContainer; | |
|
|
18 | import org.gradle.language.base.plugins.LifecycleBasePlugin; | |
|
|
19 | import org.implab.gradle.common.core.lang.FilePaths; | |
|
|
20 | import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec; | |
|
|
21 | import org.implab.gradle.variants.artifacts.ArtifactSlot; | |
|
|
22 | import org.implab.gradle.variants.sources.CompileUnit; | |
|
|
23 | import org.implab.gradle.variants.sources.CompileUnitsView; | |
|
|
24 | import org.implab.gradle.variants.sources.RoleProjectionsView; | |
|
|
25 | import org.implab.gradle.variants.sources.SourceSetMaterializer; | |
|
|
26 | ||
|
|
27 | /** | |
|
|
28 | * Адаптер между фрагментами артефактов, представленными в виде | |
|
|
29 | * {@link SlotContribution}, | |
|
|
30 | * и ArtifactAssemblyRegistry, который оперирует уже собранными | |
|
|
31 | * {@link ArtifactAssembly}. | |
|
|
32 | * | |
|
|
33 | * Данный класс отвечает за сборку отдельных фрагментов артефактов в единый | |
|
|
34 | * каталог, который затем регистрируется в ArtifactAssemblyRegistry в виде | |
|
|
35 | * {@link ArtifactAssembly}. Сборка конечного артефакта происходит при помощи | |
|
|
36 | * задачи, которая копирует все входные файлы в выходной каталог. Задача | |
|
|
37 | * создается для каждого {@link ArtifactSlot} и использует | |
|
|
38 | * {@link SlotAssembly#inputs()} как источник входных данных. | |
|
|
39 | * | |
|
|
40 | * Для сборки используется паттерн Visitor: каждый фрагмент артефакта | |
|
|
41 | * представлен в виде реализации интерфейса {@link SlotContribution}, который | |
|
|
42 | * имеет метод accept, принимающий Visitor. | |
|
|
43 | * Visitor реализован во внутреннем классе {@link ContributionVisitor}, который | |
|
|
44 | * знает, как обрабатывать каждый тип фрагмента и добавлять его в сборку. | |
|
|
45 | * Для каждого {@link SlotContribution} создается ключ {@link SlotInputKey}, | |
|
|
46 | * который используется для дедупликации: если фрагмент с таким же ключом уже | |
|
|
47 | * был добавлен, то он игнорируется. | |
|
|
48 | */ | |
|
|
49 | @NonNullByDefault | |
|
|
50 | public class ArtifactAssemblyHandler { | |
|
|
51 | private final ObjectFactory objects; | |
|
|
52 | ||
|
|
53 | private final ArtifactAssemblyRegistry assemblyRegistry; | |
|
|
54 | ||
|
|
55 | private final DirectoryProperty assembliesDirectory; | |
|
|
56 | ||
|
|
57 | private final TaskContainer tasks; | |
|
|
58 | ||
|
|
59 | private final CompileUnitsView compileUnitsView; | |
|
|
60 | ||
|
|
61 | private final RoleProjectionsView roleProjectionsView; | |
|
|
62 | ||
|
|
63 | private final SourceSetMaterializer sourceSetMaterializer; | |
|
|
64 | ||
|
|
65 | private final Map<ArtifactSlot, SlotAssembly> slotInputs = new HashMap<>(); | |
|
|
66 | ||
|
|
67 | public ArtifactAssemblyHandler( | |
|
|
68 | ObjectFactory objects, | |
|
|
69 | TaskContainer tasks, | |
|
|
70 | ArtifactAssemblyRegistry assemblyRegistry, | |
|
|
71 | CompileUnitsView compileUnitsView, | |
|
|
72 | RoleProjectionsView roleProjectionsView, | |
|
|
73 | SourceSetMaterializer sourceSetMaterializer) { | |
|
|
74 | this.objects = objects; | |
|
|
75 | this.tasks = tasks; | |
|
|
76 | this.assemblyRegistry = assemblyRegistry; | |
|
|
77 | this.compileUnitsView = compileUnitsView; | |
|
|
78 | this.roleProjectionsView = roleProjectionsView; | |
|
|
79 | this.sourceSetMaterializer = sourceSetMaterializer; | |
|
|
80 | ||
|
|
81 | assembliesDirectory = objects.directoryProperty(); | |
|
|
82 | } | |
|
|
83 | ||
|
|
84 | public DirectoryProperty getAssembliesDirectory() { | |
|
|
85 | return assembliesDirectory; | |
|
|
86 | } | |
|
|
87 | ||
|
|
88 | public void configureAssembly(ArtifactSlot artifactSlot, Action<? super ArtifactAssemblySpec> action) { | |
|
|
89 | var visitor = contributionVisitor(artifactSlot); | |
|
|
90 | var spec = new DefaultArtifactAssemblySpec(objects, c -> c.accept(visitor)); | |
|
|
91 | action.execute(spec); | |
|
|
92 | } | |
|
|
93 | ||
|
|
94 | public SlotContributionVisitor contributionVisitor(ArtifactSlot artifactSlot) { | |
|
|
95 | var assembly = slotInputs.computeIfAbsent(artifactSlot, this::createSlotAssembly); | |
|
|
96 | return new ContributionVisitor(artifactSlot, assembly); | |
|
|
97 | } | |
|
|
98 | ||
|
|
99 | /** | |
|
|
100 | * Создает сборку для указанного слота артефакта, сборка регистрируется в | |
|
|
101 | * ArtifactAssemblyRegistry, если для слота сборка уже была зарегистрирована | |
|
|
102 | * кем-то еще, то возникает ошибка. | |
|
|
103 | */ | |
|
|
104 | private SlotAssembly createSlotAssembly(ArtifactSlot artifactSlot) { | |
|
|
105 | var assembly = new SlotAssembly(); | |
|
|
106 | var fileCollection = assembly.inputs(); | |
|
|
107 | ||
|
|
108 | var outputDirectory = outputDirectory(artifactSlot); | |
|
|
109 | ||
|
|
110 | var task = tasks.register(assembleTaskName(artifactSlot), Sync.class, copy -> { | |
|
|
111 | copy.setGroup(LifecycleBasePlugin.BUILD_GROUP); | |
|
|
112 | copy.into(outputDirectory); | |
|
|
113 | copy.from(fileCollection); | |
|
|
114 | }); | |
|
|
115 | ||
|
|
116 | assemblyRegistry.register(artifactSlot, task, t -> outputDirectory); | |
|
|
117 | ||
|
|
118 | return assembly; | |
|
|
119 | } | |
|
|
120 | ||
|
|
121 | private String assembleTaskName(ArtifactSlot artifactSlot) { | |
|
|
122 | var variantName = artifactSlot.variant().getName(); | |
|
|
123 | var slotName = artifactSlot.slot().getName(); | |
|
|
124 | ||
|
|
125 | return "assembleVariantArtifactSlot" | |
|
|
126 | + "_v" + variantName.length() + "_" + variantName | |
|
|
127 | + "_s" + slotName.length() + "_" + slotName; | |
|
|
128 | } | |
|
|
129 | ||
|
|
130 | private Provider<Directory> outputDirectory(ArtifactSlot artifactSlot) { | |
|
|
131 | return assembliesDirectory.dir( | |
|
|
132 | FilePaths.cat( | |
|
|
133 | artifactSlot.variant().getName(), | |
|
|
134 | artifactSlot.slot().getName())); | |
|
|
135 | } | |
|
|
136 | ||
|
|
137 | /** | |
|
|
138 | * Собирает отдельные фрагменты артефактов в единый источник | |
|
|
139 | * {@link ConfigurableFileCollection}. | |
|
|
140 | * Для фрагментов {@link SlotContribution} используется механизм дедупликации: | |
|
|
141 | * для каждого | |
|
|
142 | * водящего фрагмента создается ключ {@link SlotInputKey} и добавляются | |
|
|
143 | * фрагменты только | |
|
|
144 | * с уникальным ключом, повторы игнорируются. | |
|
|
145 | */ | |
|
|
146 | private class ContributionVisitor implements SlotContributionVisitor { | |
|
|
147 | // artifact slot for this assembly | |
|
|
148 | private final ArtifactSlot artifactSlot; | |
|
|
149 | ||
|
|
150 | // seen inputs, used for deduplication | |
|
|
151 | private final SlotAssembly assembly; | |
|
|
152 | ||
|
|
153 | ContributionVisitor(ArtifactSlot artifactSlot, SlotAssembly assembly) { | |
|
|
154 | this.artifactSlot = artifactSlot; | |
|
|
155 | this.assembly = assembly; | |
|
|
156 | } | |
|
|
157 | ||
|
|
158 | @Override | |
|
|
159 | public void visit(DirectContribution contribution) { | |
|
|
160 | contribute( | |
|
|
161 | SlotInputKey.newUniqueKey("Direct input for " + artifactSlot), | |
|
|
162 | contribution.input()); | |
|
|
163 | } | |
|
|
164 | ||
|
|
165 | @Override | |
|
|
166 | public void visit(VariantOutputsContribution contribution) { | |
|
|
167 | var units = compileUnitsView.getUnitsForVariant(artifactSlot.variant()); | |
|
|
168 | contributeCompileUnits(units, contribution.outputs()); | |
|
|
169 | } | |
|
|
170 | ||
|
|
171 | @Override | |
|
|
172 | public void visit(RoleOutputsContribution contribution) { | |
|
|
173 | var roleProjection = roleProjectionsView.requireProjection(artifactSlot.variant(), | |
|
|
174 | contribution.role()); | |
|
|
175 | var units = roleProjectionsView.getUnits(roleProjection); | |
|
|
176 | ||
|
|
177 | contributeCompileUnits(units, contribution.outputs()); | |
|
|
178 | ||
|
|
179 | } | |
|
|
180 | ||
|
|
181 | @Override | |
|
|
182 | public void visit(LayerOutputsContribution contribution) { | |
|
|
183 | var unit = compileUnitsView.requireUnit(artifactSlot.variant(), contribution.layer()); | |
|
|
184 | contributeCompileUnits(Set.of(unit), contribution.outputs()); | |
|
|
185 | } | |
|
|
186 | ||
|
|
187 | private void contributeCompileUnits(Set<CompileUnit> units, Set<String> outputs) { | |
|
|
188 | units.stream() | |
|
|
189 | // expand variant compile units, make (compileUnit, outputName) pairs | |
|
|
190 | .flatMap(unit -> outputs.stream() | |
|
|
191 | .map(output -> new CompileUnitOutputKey(unit, output))) | |
|
|
192 | .forEach(key -> contribute( | |
|
|
193 | key, | |
|
|
194 | sourceSetMaterializer.getSourceSet(key.unit()) | |
|
|
195 | .map(s -> s.output(key.outputName())))); | |
|
|
196 | } | |
|
|
197 | ||
|
|
198 | private void contribute(SlotInputKey key, Object resolvedInput) { | |
|
|
199 | assembly.addSlotInput(key, resolvedInput); | |
|
|
200 | } | |
|
|
201 | } | |
|
|
202 | ||
|
|
203 | /** Состояние для отдельного слота */ | |
|
|
204 | class SlotAssembly { | |
|
|
205 | private final ConfigurableFileCollection inputs = objects.fileCollection(); | |
|
|
206 | private final Set<SlotInputKey> seen = new HashSet<>(); | |
|
|
207 | ||
|
|
208 | public void addSlotInput(SlotInputKey key, Object input) { | |
|
|
209 | if (!seen.add(key)) | |
|
|
210 | return; | |
|
|
211 | inputs.from(input); | |
|
|
212 | } | |
|
|
213 | ||
|
|
214 | public FileCollection inputs() { | |
|
|
215 | return inputs; | |
|
|
216 | } | |
|
|
217 | } | |
|
|
218 | } | |
| @@ -0,0 +1,94 | |||
|
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
|
|
2 | ||
|
|
3 | import java.util.Optional; | |
|
|
4 | ||
|
|
5 | import org.gradle.api.Action; | |
|
|
6 | import org.implab.gradle.variants.artifacts.ArtifactAssemblies; | |
|
|
7 | import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec; | |
|
|
8 | import org.implab.gradle.variants.artifacts.ArtifactSlot; | |
|
|
9 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSlotSpec; | |
|
|
10 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec; | |
|
|
11 | import org.implab.gradle.variants.artifacts.OutgoingVariant; | |
|
|
12 | import org.implab.gradle.variants.artifacts.OutgoingVariantsContext; | |
|
|
13 | import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; | |
|
|
14 | import org.implab.gradle.variants.core.Variant; | |
|
|
15 | ||
|
|
16 | public class DefaultOutgoingVariantsContext implements OutgoingVariantsContext { | |
|
|
17 | private final ArtifactAssemblies assemblies; | |
|
|
18 | ||
|
|
19 | private final ArtifactAssemblyHandler assemblyHandler; | |
|
|
20 | ||
|
|
21 | private final OutgoingRegistry outgoingVariants; | |
|
|
22 | ||
|
|
23 | private final MaterializationPolicyHandler materializationHandler; | |
|
|
24 | ||
|
|
25 | public DefaultOutgoingVariantsContext( | |
|
|
26 | ArtifactAssemblies assemblies, | |
|
|
27 | OutgoingRegistry outgoingVariants, | |
|
|
28 | ArtifactAssemblyHandler assemblyHandler, | |
|
|
29 | MaterializationPolicyHandler materializationHandler) { | |
|
|
30 | this.assemblies = assemblies; | |
|
|
31 | this.outgoingVariants = outgoingVariants; | |
|
|
32 | this.assemblyHandler = assemblyHandler; | |
|
|
33 | this.materializationHandler = materializationHandler; | |
|
|
34 | } | |
|
|
35 | ||
|
|
36 | @Override | |
|
|
37 | public ArtifactAssemblies getAssemblies() { | |
|
|
38 | return assemblies; | |
|
|
39 | } | |
|
|
40 | ||
|
|
41 | @Override | |
|
|
42 | public void configureVariant(Variant variant, Action<? super VariantArtifactsSpec> action) { | |
|
|
43 | var outgoingVariant = outgoingVariants.maybeCreate(variant); | |
|
|
44 | var variantSpec = new VariantSpec(outgoingVariant); | |
|
|
45 | action.execute(variantSpec); | |
|
|
46 | } | |
|
|
47 | ||
|
|
48 | @Override | |
|
|
49 | public void configureEach(Action<? super OutgoingVariant> action) { | |
|
|
50 | outgoingVariants.configureEach(action::execute); | |
|
|
51 | } | |
|
|
52 | ||
|
|
53 | @Override | |
|
|
54 | public Optional<OutgoingVariant> findOutgoing(Variant variant) { | |
|
|
55 | return outgoingVariants.find(variant); | |
|
|
56 | } | |
|
|
57 | ||
|
|
58 | @Override | |
|
|
59 | public void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action) { | |
|
|
60 | materializationHandler.whenVariantMaterialized(action); | |
|
|
61 | } | |
|
|
62 | ||
|
|
63 | @Override | |
|
|
64 | public void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action) { | |
|
|
65 | materializationHandler.whenSlotMaterialized(action); | |
|
|
66 | } | |
|
|
67 | ||
|
|
68 | class VariantSpec implements VariantArtifactsSpec { | |
|
|
69 | ||
|
|
70 | private final OutgoingVariant outgoingVariant; | |
|
|
71 | ||
|
|
72 | VariantSpec(OutgoingVariant outgoingVariant) { | |
|
|
73 | this.outgoingVariant = outgoingVariant; | |
|
|
74 | } | |
|
|
75 | ||
|
|
76 | @Override | |
|
|
77 | public void slot(String name, Action<? super ArtifactAssemblySpec> action) { | |
|
|
78 | var slot = outgoingVariant.getSlots().maybeCreate(name); | |
|
|
79 | var artifactSlot = new ArtifactSlot(outgoingVariant.getVariant(), slot); | |
|
|
80 | assemblyHandler.configureAssembly(artifactSlot, action); | |
|
|
81 | } | |
|
|
82 | ||
|
|
83 | @Override | |
|
|
84 | public void primarySlot(String name, Action<? super ArtifactAssemblySpec> action) { | |
|
|
85 | var slot = outgoingVariant.getSlots().maybeCreate(name); | |
|
|
86 | var artifactSlot = new ArtifactSlot(outgoingVariant.getVariant(), slot); | |
|
|
87 | assemblyHandler.configureAssembly(artifactSlot, action); | |
|
|
88 | ||
|
|
89 | outgoingVariant.getPrimarySlot().set(slot); | |
|
|
90 | } | |
|
|
91 | ||
|
|
92 | } | |
|
|
93 | ||
|
|
94 | } | |
| @@ -0,0 +1,118 | |||
|
|
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.gradle.api.artifacts.Configuration; | |
|
|
6 | import org.gradle.api.attributes.AttributeContainer; | |
|
|
7 | import org.implab.gradle.internal.ReplayableQueue; | |
|
|
8 | import org.implab.gradle.variants.artifacts.ArtifactAssemblies; | |
|
|
9 | import org.implab.gradle.variants.artifacts.ArtifactAssembly; | |
|
|
10 | import org.implab.gradle.variants.artifacts.ArtifactSlot; | |
|
|
11 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSlotSpec; | |
|
|
12 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec; | |
|
|
13 | import org.implab.gradle.variants.artifacts.OutgoingVariant; | |
|
|
14 | import org.implab.gradle.variants.core.Variant; | |
|
|
15 | ||
|
|
16 | /** | |
|
|
17 | * Handles outgoing artifact materialization policy. | |
|
|
18 | * | |
|
|
19 | * <p>Materialization is the phase where the plugin interprets variant artifact | |
|
|
20 | * declarations as Gradle outgoing publication state: a consumable configuration, | |
|
|
21 | * its primary artifact set, secondary artifact variants, attributes, and backing | |
|
|
22 | * assembly tasks. | |
|
|
23 | * | |
|
|
24 | * <p>The handler provides extension points for customizing the materialized | |
|
|
25 | * Gradle-facing objects. These hooks intentionally expose Gradle API objects. | |
|
|
26 | * This allows advanced customization, but also means that callers can bypass | |
|
|
27 | * the plugin model. Such customizations are considered caller responsibility. | |
|
|
28 | * | |
|
|
29 | * <p>The internal binding mechanics are not part of the public contract. The | |
|
|
30 | * contract is the materialized outgoing state exposed through the specification | |
|
|
31 | * objects. | |
|
|
32 | */ | |
|
|
33 | @NonNullByDefault | |
|
|
34 | public class MaterializationPolicyHandler implements Action<OutgoingVariant> { | |
|
|
35 | ||
|
|
36 | private final ArtifactAssemblies resolver; | |
|
|
37 | ||
|
|
38 | private final ReplayableQueue<OutgoingConfigurationSpec> variantMaterialization = new ReplayableQueue<>(); | |
|
|
39 | private final ReplayableQueue<OutgoingConfigurationSlotSpec> slotMaterialization = new ReplayableQueue<>(); | |
|
|
40 | ||
|
|
41 | public MaterializationPolicyHandler(ArtifactAssemblies resolver) { | |
|
|
42 | this.resolver = resolver; | |
|
|
43 | } | |
|
|
44 | ||
|
|
45 | @Override | |
|
|
46 | public void execute(OutgoingVariant outgoingVariant) { | |
|
|
47 | var slots = outgoingVariant.getSlots(); | |
|
|
48 | var primarySlotProvider = outgoingVariant.getPrimarySlot(); | |
|
|
49 | var variant = outgoingVariant.getVariant(); | |
|
|
50 | ||
|
|
51 | // связываем конфигурацию | |
|
|
52 | outgoingVariant.configureOutgoing(configuration -> { | |
|
|
53 | var primarySlot = primarySlotProvider.get(); | |
|
|
54 | var outgoing = configuration.getOutgoing(); | |
|
|
55 | ||
|
|
56 | variantMaterialized(variant, configuration); | |
|
|
57 | ||
|
|
58 | slotMaterialized(new ArtifactSlot(variant, primarySlot), true, outgoing.getAttributes()); | |
|
|
59 | ||
|
|
60 | outgoing.getVariants().configureEach(variantConfiguration -> { | |
|
|
61 | var slotName = variantConfiguration.getName(); | |
|
|
62 | var slot = slots.findByName(slotName); | |
|
|
63 | if (slot != null) { | |
|
|
64 | slotMaterialized(new ArtifactSlot(variant, slot), false, variantConfiguration.getAttributes()); | |
|
|
65 | } | |
|
|
66 | }); | |
|
|
67 | }); | |
|
|
68 | }; | |
|
|
69 | ||
|
|
70 | public void whenVariantMaterialized(Action<? super OutgoingConfigurationSpec> action) { | |
|
|
71 | variantMaterialization.forEach(action::execute); | |
|
|
72 | } | |
|
|
73 | ||
|
|
74 | public void whenSlotMaterialized(Action<? super OutgoingConfigurationSlotSpec> action) { | |
|
|
75 | slotMaterialization.forEach(action::execute); | |
|
|
76 | } | |
|
|
77 | ||
|
|
78 | private void variantMaterialized(Variant variant, Configuration configuration) { | |
|
|
79 | variantMaterialization.add(new OutgoingConfigurationSpec() { | |
|
|
80 | ||
|
|
81 | @Override | |
|
|
82 | public Variant getVariant() { | |
|
|
83 | return variant; | |
|
|
84 | } | |
|
|
85 | ||
|
|
86 | @Override | |
|
|
87 | public Configuration getConfiguration() { | |
|
|
88 | return configuration; | |
|
|
89 | } | |
|
|
90 | ||
|
|
91 | }); | |
|
|
92 | } | |
|
|
93 | ||
|
|
94 | private void slotMaterialized(ArtifactSlot slot, boolean primary, AttributeContainer attributes) { | |
|
|
95 | slotMaterialization.add(new OutgoingConfigurationSlotSpec() { | |
|
|
96 | @Override | |
|
|
97 | public boolean isPrimary() { | |
|
|
98 | return primary; | |
|
|
99 | } | |
|
|
100 | ||
|
|
101 | @Override | |
|
|
102 | public ArtifactSlot getArtifactSlot() { | |
|
|
103 | return slot; | |
|
|
104 | } | |
|
|
105 | ||
|
|
106 | @Override | |
|
|
107 | public ArtifactAssembly getAssembly() { | |
|
|
108 | return resolver.require(slot); | |
|
|
109 | } | |
|
|
110 | ||
|
|
111 | @Override | |
|
|
112 | public void artifactAttributes(Action<? super AttributeContainer> action) { | |
|
|
113 | action.execute(attributes); | |
|
|
114 | } | |
|
|
115 | }); | |
|
|
116 | } | |
|
|
117 | ||
|
|
118 | } | |
| @@ -0,0 +1,33 | |||
|
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
|
|
2 | ||
|
|
3 | import org.gradle.api.Action; | |
|
|
4 | import org.gradle.api.InvalidUserDataException; | |
|
|
5 | import org.gradle.api.provider.ProviderFactory; | |
|
|
6 | import org.implab.gradle.variants.artifacts.OutgoingVariant; | |
|
|
7 | ||
|
|
8 | public class SingleSlotConvention implements Action<OutgoingVariant> { | |
|
|
9 | ||
|
|
10 | private final ProviderFactory providers; | |
|
|
11 | ||
|
|
12 | public SingleSlotConvention(ProviderFactory providers) { | |
|
|
13 | this.providers = providers; | |
|
|
14 | } | |
|
|
15 | ||
|
|
16 | @Override | |
|
|
17 | public void execute(OutgoingVariant outgoingVariant) { | |
|
|
18 | var slots = outgoingVariant.getSlots(); | |
|
|
19 | ||
|
|
20 | outgoingVariant.getPrimarySlot().convention( | |
|
|
21 | // если есть ровно один слот, то он считается primary | |
|
|
22 | providers.provider(() -> { | |
|
|
23 | if (slots.size() == 0) | |
|
|
24 | throw new InvalidUserDataException("No slots declared for " + outgoingVariant.getVariant()); | |
|
|
25 | if (slots.size() > 1) | |
|
|
26 | throw new InvalidUserDataException("Multiple slots declared for " + outgoingVariant.getVariant() + | |
|
|
27 | ", please specify primary slot explicitly"); | |
|
|
28 | ||
|
|
29 | return slots.stream().findAny().get(); | |
|
|
30 | })); | |
|
|
31 | } | |
|
|
32 | ||
|
|
33 | } | |
| @@ -0,0 +1,9 | |||
|
|
1 | /** | |
|
|
2 | * Internal implementation of the variant artifacts plugin. | |
|
|
3 | * | |
|
|
4 | * <p>Types in this package are not part of the public API. They may change, | |
|
|
5 | * move, or be removed without compatibility guarantees. Build logic should use | |
|
|
6 | * the public contracts from {@link org.implab.gradle.variants.artifacts} | |
|
|
7 | * instead. | |
|
|
8 | */ | |
|
|
9 | package org.implab.gradle.variants.artifacts.internal; | |
| @@ -2,6 +2,8 | |||
|
|
2 | 2 | |
|
|
3 | 3 | ## Проектные договоренности |
|
|
4 | 4 | |
|
|
5 | - для управления исходным кодом используется Mercurial | |
|
|
6 | ||
|
|
5 | 7 | ### Публичное API библиотек |
|
|
6 | 8 | |
|
|
7 | 9 | - Предпочтителен `non-null` подход. |
| @@ -1,7 +1,5 | |||
|
|
1 | 1 | package org.implab.gradle.common.core.lang; |
|
|
2 | 2 | |
|
|
3 | import java.util.function.Consumer; | |
|
|
4 | import java.util.function.Function; | |
|
|
5 | 3 | import java.util.regex.Pattern; |
|
|
6 | 4 | |
|
|
7 | 5 | import org.eclipse.jdt.annotation.NonNullByDefault; |
| @@ -17,6 +17,7 | |||
|
|
17 | 17 | - artifact: directory |
|
|
18 | 18 | - customTask |
|
|
19 | 19 | - artifact: FileSystemLocation |
|
|
20 | - when, all - replayable hooks для получения содержимого сборки | |
|
|
20 | 21 | |
|
|
21 | 22 | ## extension |
|
|
22 | 23 | |
| @@ -30,16 +31,8 | |||
|
|
30 | 31 | - whenOutgoingConfiguration |
|
|
31 | 32 | - whenOutgoingSlot |
|
|
32 | 33 | |
|
|
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 | |
|
|
34 | - ArtifactAssemblyBridge | |
|
|
35 | связывает содержимое ArtifactAssembly и исходящей конфигурации OutgoingVariant | |
|
|
36 | - VariantArtifactsHandler | |
|
|
37 | управляет состоянием ArtifactAssembly, используется для DSL сборки | |
|
|
38 | - configureVariant конфигурирует VariantArtifactsSpec No newline at end of file | |
| @@ -4,6 +4,9 import java.util.LinkedList; | |||
|
|
4 | 4 | import java.util.List; |
|
|
5 | 5 | import java.util.function.Consumer; |
|
|
6 | 6 | |
|
|
7 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
|
|
8 | ||
|
|
9 | @NonNullByDefault | |
|
|
7 | 10 | public class ReplayableQueue<T> { |
|
|
8 | 11 | private final List<Consumer<? super T>> consumers = new LinkedList<>(); |
|
|
9 | 12 | private final List<T> values = new LinkedList<>(); |
| @@ -4,16 +4,21 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; | |
|
|
8 | 7 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec; |
|
|
9 | 8 | import org.implab.gradle.variants.artifacts.OutgoingVariantsContext; |
|
|
10 | 9 | import org.implab.gradle.variants.artifacts.VariantArtifactsExtension; |
|
|
11 | 10 | import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; |
|
|
12 |
import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyB |
|
|
|
13 |
import org.implab.gradle.variants.artifacts.internal. |
|
|
|
11 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyBinder; | |
|
|
12 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyHandler; | |
|
|
13 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyRegistry; | |
|
|
14 | import org.implab.gradle.variants.artifacts.internal.DefaultOutgoingVariantsContext; | |
|
|
15 | import org.implab.gradle.variants.artifacts.internal.MaterializationPolicyHandler; | |
|
|
14 | 16 | import org.implab.gradle.variants.artifacts.internal.OutgoingRegistry; |
|
|
17 | import org.implab.gradle.variants.artifacts.internal.SingleSlotConvention; | |
|
|
15 | 18 | import org.implab.gradle.variants.core.Variant; |
|
|
16 | 19 | import org.implab.gradle.variants.core.VariantsExtension; |
|
|
20 | import org.implab.gradle.variants.sources.VariantSourcesExtension; | |
|
|
21 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSlotSpec; | |
|
|
17 | 22 | |
|
|
18 | 23 | public abstract class VariantArtifactsPlugin implements Plugin<Project> { |
|
|
19 | 24 | |
| @@ -22,25 +27,53 public abstract class VariantArtifactsPl | |||
|
|
22 | 27 | var extensions = target.getExtensions(); |
|
|
23 | 28 | var objects = target.getObjects(); |
|
|
24 | 29 | var providers = target.getProviders(); |
|
|
30 | var plugins = target.getPlugins(); | |
|
|
25 | 31 | var configurations = target.getConfigurations(); |
|
|
26 | 32 | var tasks = target.getTasks(); |
|
|
33 | var layout = target.getLayout(); | |
|
|
27 | 34 | |
|
|
28 | 35 | // Apply the main VariantsPlugin to ensure the core variant model is available. |
|
|
29 |
|
|
|
|
36 | plugins.apply(VariantsPlugin.class); | |
|
|
37 | plugins.apply(VariantSourcesPlugin.class); | |
|
|
30 | 38 | // Access the VariantsExtension to configure variant sources. |
|
|
31 | 39 | var variantsExtension = extensions.getByType(VariantsExtension.class); |
|
|
32 | ||
|
|
33 | var outgoing = new OutgoingRegistry(configurations, objects, providers); | |
|
|
34 | var assemblies = new ArtifactAssemblyRegistry(objects, tasks); | |
|
|
35 | ||
|
|
36 | // wire artifact assemblies to configuration variants | |
|
|
37 | var assembliesBridge = new ArtifactAssemblyBridge(assemblies); | |
|
|
40 | var sourcesExtension = extensions.getByType(VariantSourcesExtension.class); | |
|
|
38 | 41 | |
|
|
39 | 42 | var deferred = new Deferred<OutgoingVariantsContext>(); |
|
|
40 | 43 | |
|
|
41 | deferred.whenResolved(context -> context.all(assembliesBridge)); | |
|
|
44 | variantsExtension.whenFinalized(variants -> { | |
|
|
45 | ||
|
|
46 | var outgoing = new OutgoingRegistry(configurations, objects, variants.getVariants()); | |
|
|
47 | var assemblies = new ArtifactAssemblyRegistry(); | |
|
|
48 | ||
|
|
49 | // wire artifact assemblies to configuration variants | |
|
|
50 | var assembliesBridge = new ArtifactAssemblyBinder(assemblies); | |
|
|
51 | var primarySlotConvention = new SingleSlotConvention(providers); | |
|
|
52 | var materializationHandler = new MaterializationPolicyHandler(assemblies); | |
|
|
53 | ||
|
|
54 | // bind slot assemblies to outgoing variants | |
|
|
55 | outgoing.configureEach(assembliesBridge::execute); | |
|
|
56 | // apply primary slot convention when outgoing variant has a single slot | |
|
|
57 | outgoing.configureEach(primarySlotConvention::execute); | |
|
|
58 | // apply materialization policy hooks to outgoing variants | |
|
|
59 | outgoing.configureEach(materializationHandler::execute); | |
|
|
42 | 60 | |
|
|
43 |
|
|
|
|
61 | sourcesExtension.whenFinalized(sources -> { | |
|
|
62 | var assemblyHandler = new ArtifactAssemblyHandler( | |
|
|
63 | objects, | |
|
|
64 | tasks, | |
|
|
65 | assemblies, | |
|
|
66 | sources.getCompileUnits(), | |
|
|
67 | sources.getRoleProjections(), | |
|
|
68 | sources.getSourceSets()); | |
|
|
69 | assemblyHandler.getAssembliesDirectory().set(layout.getBuildDirectory().dir("variant-assemblies")); | |
|
|
70 | ||
|
|
71 | deferred.resolve(new DefaultOutgoingVariantsContext( | |
|
|
72 | assemblies, | |
|
|
73 | outgoing, | |
|
|
74 | assemblyHandler, | |
|
|
75 | materializationHandler)); | |
|
|
76 | }); | |
|
|
44 | 77 | |
|
|
45 | 78 | }); |
|
|
46 | 79 | |
| @@ -49,24 +82,25 public abstract class VariantArtifactsPl | |||
|
|
49 | 82 | @Override |
|
|
50 | 83 | public void variant(String variantName, Action<? super VariantArtifactsSpec> action) { |
|
|
51 | 84 | deferred.whenResolved(context -> { |
|
|
52 | new DefaultVariantArtifactSpec(); | |
|
|
85 | var variant = objects.named(Variant.class, variantName); | |
|
|
86 | context.configureVariant(variant, action); | |
|
|
53 | 87 | }); |
|
|
54 | 88 | } |
|
|
55 | 89 | |
|
|
56 | 90 | @Override |
|
|
57 |
public void when |
|
|
|
58 |
deferred.whenResolved( |
|
|
|
91 | public void whenAvailable(Action<? super OutgoingVariantsContext> action) { | |
|
|
92 | deferred.whenResolved(handler -> action.execute(handler)); | |
|
|
59 | 93 | } |
|
|
60 | 94 | |
|
|
61 | 95 | @Override |
|
|
62 |
public void whenOutgoing |
|
|
|
63 |
deferred.whenResolved(registry -> registry. |
|
|
|
96 | public void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action) { | |
|
|
97 | deferred.whenResolved(registry -> registry.whenOutgoingConfiguration(action)); | |
|
|
64 | 98 | |
|
|
65 | 99 | } |
|
|
66 | 100 | |
|
|
67 | 101 | @Override |
|
|
68 |
public void whenOutgoingSlot(Action<? super Outgoing |
|
|
|
69 |
deferred.whenResolved(registry -> registry. |
|
|
|
102 | public void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action) { | |
|
|
103 | deferred.whenResolved(registry -> registry.whenOutgoingSlot(action)); | |
|
|
70 | 104 | } |
|
|
71 | 105 | |
|
|
72 | 106 | }; |
| @@ -31,23 +31,25 public interface ArtifactAssemblies { | |||
|
|
31 | 31 | } |
|
|
32 | 32 | |
|
|
33 | 33 | /** |
|
|
34 | * Регистрирует обработчик на конкретный слот. Если слот еще не зарегистрирован, | |
|
|
35 | * то обработчик будет добавлен в очередь и будет вызван при регистрации слота. | |
|
|
36 | * Порядок и точный момент вызова обработчиков не определен. | |
|
|
34 | * Registers a configuration action for the assembly of the given slot. | |
|
|
37 | 35 | * |
|
|
38 | * @param slot Слот на который нужно зарегистрировать обработчик | |
|
|
39 | * @param action Обработчик | |
|
|
36 | * <p>If the assembly is already registered, the action is invoked immediately. | |
|
|
37 | * Otherwise, it is queued and invoked when slot materialization registers the | |
|
|
38 | * assembly handle. | |
|
|
39 | * | |
|
|
40 | * @param slot slot identity inside a variant outgoing contract | |
|
|
41 | * @param action assembly configuration action | |
|
|
40 | 42 | */ |
|
|
41 | 43 | void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action); |
|
|
42 | 44 | |
|
|
43 | 45 | /** |
|
|
44 | * Регистрирует глобальный обработчик, который будет вызван для всех слотов. | |
|
|
45 | * Обработчик будет вызван как для уже зарегистрированных слотов так и для тех, | |
|
|
46 | * которые будут зарегистрированы в будущем. | |
|
|
46 | * Adds global configuration action for all materialized assemblies. If some assemblies are | |
|
|
47 | * already registered, the action will be invoked for them immediately. For assemblies that | |
|
|
48 | * are materialized later, the action will be invoked when they are registered. | |
|
|
47 | 49 | * |
|
|
48 | * @param action Обработчик | |
|
|
50 | * @param action assembly configuration action. | |
|
|
49 | 51 | */ |
|
|
50 |
void |
|
|
|
52 | void configureEach(Action<? super ArtifactAssembly> action); | |
|
|
51 | 53 | |
|
|
52 | 54 | /** Ищет зарегистрированный слот */ |
|
|
53 | 55 | Optional<ArtifactAssembly> find(ArtifactSlot slot); |
| @@ -40,7 +40,9 public interface OutgoingConfigurationSl | |||
|
|
40 | 40 | * |
|
|
41 | 41 | * @param action task configuration action |
|
|
42 | 42 | */ |
|
|
43 |
void assemblyTask(Action<? super Task> action) |
|
|
|
43 | default void assemblyTask(Action<? super Task> action) { | |
|
|
44 | getAssembly().getAssemblyTask().configure(action); | |
|
|
45 | } | |
|
|
44 | 46 | |
|
|
45 | 47 | default void assemblyTask(Closure<?> closure) { |
|
|
46 | 48 | assemblyTask(Closures.action(closure)); |
| @@ -24,9 +24,9 public interface OutgoingVariant { | |||
|
|
24 | 24 | /** |
|
|
25 | 25 | * Провайдер зарегистрированной конфигурации |
|
|
26 | 26 | */ |
|
|
27 | NamedDomainObjectProvider<Configuration> getConfiguration(); | |
|
|
27 | NamedDomainObjectProvider<? extends Configuration> getConfiguration(); | |
|
|
28 | 28 | |
|
|
29 | default void configure(Action<? super Configuration> action) { | |
|
|
29 | default void configureOutgoing(Action<? super Configuration> action) { | |
|
|
30 | 30 | getConfiguration().configure(action); |
|
|
31 | 31 | } |
|
|
32 | 32 | |
| @@ -5,7 +5,6 import java.util.Optional; | |||
|
|
5 | 5 | import org.gradle.api.Action; |
|
|
6 | 6 | import org.gradle.api.InvalidUserDataException; |
|
|
7 | 7 | import org.implab.gradle.variants.core.Variant; |
|
|
8 | import org.implab.gradle.variants.core.VariantsView; | |
|
|
9 | 8 | |
|
|
10 | 9 | /** |
|
|
11 | 10 | * Контекст работы с вариантами публикации, становится доступным после |
| @@ -13,18 +12,14 import org.implab.gradle.variants.core.V | |||
|
|
13 | 12 | */ |
|
|
14 | 13 | public interface OutgoingVariantsContext { |
|
|
15 | 14 | |
|
|
16 | /** | |
|
|
17 | * Зафиксированное представление о вариантах на основе которого адаптеры могут | |
|
|
18 | * конфигурировать артефакты и исходящие конфигурации | |
|
|
19 | */ | |
|
|
20 | VariantsView getVariants(); | |
|
|
15 | ArtifactAssemblies getAssemblies(); | |
|
|
21 | 16 | |
|
|
22 | ArtifactAssemblies getAssemblies(); | |
|
|
17 | void configureVariant(Variant variant, Action<? super VariantArtifactsSpec> action); | |
|
|
23 | 18 | |
|
|
24 | 19 | /** |
|
|
25 | 20 | * Replayable hook для всех объявленных конфигураций |
|
|
26 | 21 | */ |
|
|
27 |
void |
|
|
|
22 | void configureEach(Action<? super OutgoingVariant> action); | |
|
|
28 | 23 | |
|
|
29 | 24 | Optional<OutgoingVariant> findOutgoing(Variant variant); |
|
|
30 | 25 | |
| @@ -33,6 +28,9 public interface OutgoingVariantsContext | |||
|
|
33 | 28 | .orElseThrow(() -> new InvalidUserDataException("Outgoing variant '" + variant + "' isn't registered")); |
|
|
34 | 29 | } |
|
|
35 | 30 | |
|
|
36 | ArtifactAssemblyRules slotRules(ArtifactSlot slot); | |
|
|
31 | void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action); | |
|
|
32 | ||
|
|
33 | void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action); | |
|
|
34 | ||
|
|
37 | 35 | |
|
|
38 | 36 | } |
| @@ -8,15 +8,18 import groovy.lang.Closure; | |||
|
|
8 | 8 | /** |
|
|
9 | 9 | * Project-level DSL entry point for declaring outgoing artifacts per variant. |
|
|
10 | 10 | * |
|
|
11 | * <p>A variant represents one external outgoing contract. Slots declared inside a variant represent | |
|
|
12 | * artifact sets within that contract. One slot is expected to materialize to one published artifact. | |
|
|
11 | * <p> | |
|
|
12 | * A variant represents one external outgoing contract. Slots declared inside a | |
|
|
13 | * variant represent | |
|
|
14 | * artifact sets within that contract. One slot is expected to materialize to | |
|
|
15 | * one published artifact. | |
|
|
13 | 16 | */ |
|
|
14 | 17 | public interface VariantArtifactsExtension { |
|
|
15 | 18 | /** |
|
|
16 | 19 | * Configures artifact slots of the named variant. |
|
|
17 | 20 | * |
|
|
18 | 21 | * @param variantName variant name |
|
|
19 | * @param action variant artifact declaration | |
|
|
22 | * @param action variant artifact declaration | |
|
|
20 | 23 | */ |
|
|
21 | 24 | void variant(String variantName, Action<? super VariantArtifactsSpec> action); |
|
|
22 | 25 | |
| @@ -25,25 +28,27 public interface VariantArtifactsExtensi | |||
|
|
25 | 28 | } |
|
|
26 | 29 | |
|
|
27 | 30 | /** |
|
|
28 |
* Registers a callback invoked w |
|
|
|
31 | * Registers a callback invoked when the outgoing variants context becomes | |
|
|
32 | * available. | |
|
|
29 | 33 | * |
|
|
30 |
* @param action |
|
|
|
34 | * @param action outgoing variants context callback | |
|
|
31 | 35 | */ |
|
|
32 |
void when |
|
|
|
36 | void whenAvailable(Action<? super OutgoingVariantsContext> action); | |
|
|
33 | 37 | |
|
|
34 |
default void when |
|
|
|
35 |
when |
|
|
|
38 | default void whenAvailable(Closure<?> closure) { | |
|
|
39 | whenAvailable(Closures.action(closure)); | |
|
|
36 | 40 | } |
|
|
37 | 41 | |
|
|
38 | 42 | /** |
|
|
39 |
* Registers a callback invoked for each materialized root outgoing |
|
|
|
43 | * Registers a callback invoked for each materialized root outgoing | |
|
|
44 | * configuration. | |
|
|
40 | 45 | * |
|
|
41 | 46 | * @param action variant-level outgoing configuration callback |
|
|
42 | 47 | */ |
|
|
43 |
void whenOutgoing |
|
|
|
48 | void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action); | |
|
|
44 | 49 | |
|
|
45 |
default void whenOutgoing |
|
|
|
46 |
whenOutgoing |
|
|
|
50 | default void whenOutgoingConfiguration(Closure<?> closure) { | |
|
|
51 | whenOutgoingConfiguration(Closures.action(closure)); | |
|
|
47 | 52 | } |
|
|
48 | 53 | |
|
|
49 | 54 | /** |
| @@ -11,11 +11,11 import org.implab.gradle.variants.artifa | |||
|
|
11 | 11 | * из {@link ArtifactAssemblies} |
|
|
12 | 12 | */ |
|
|
13 | 13 | @NonNullByDefault |
|
|
14 |
public class ArtifactAssemblyB |
|
|
|
14 | public class ArtifactAssemblyBinder implements Action<OutgoingVariant> { | |
|
|
15 | 15 | |
|
|
16 | 16 | private final ArtifactAssemblies resolver; |
|
|
17 | 17 | |
|
|
18 |
public ArtifactAssemblyB |
|
|
|
18 | public ArtifactAssemblyBinder(ArtifactAssemblies resolver) { | |
|
|
19 | 19 | this.resolver = resolver; |
|
|
20 | 20 | } |
|
|
21 | 21 | |
| @@ -26,7 +26,7 public class ArtifactAssemblyBridge impl | |||
|
|
26 | 26 | var variant = outgoingVariant.getVariant(); |
|
|
27 | 27 | |
|
|
28 | 28 | // связываем конфигурацию |
|
|
29 | outgoingVariant.configure(configuration -> { | |
|
|
29 | outgoingVariant.configureOutgoing(configuration -> { | |
|
|
30 | 30 | var primarySlot = primarySlotProvider.get(); |
|
|
31 | 31 | var outgoing = configuration.getOutgoing(); |
|
|
32 | 32 | |
| @@ -51,4 +51,6 public class ArtifactAssemblyBridge impl | |||
|
|
51 | 51 | }); |
|
|
52 | 52 | } |
|
|
53 | 53 | |
|
|
54 | ||
|
|
55 | ||
|
|
54 | 56 | } |
| @@ -1,4 +1,4 | |||
|
|
1 | package org.implab.gradle.variants.artifacts; | |
|
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
|
|
2 | 2 | |
|
|
3 | 3 | import java.util.LinkedHashMap; |
|
|
4 | 4 | import java.util.Map; |
| @@ -14,6 +14,9 import org.gradle.api.provider.Provider; | |||
|
|
14 | 14 | import org.gradle.api.tasks.TaskProvider; |
|
|
15 | 15 | import org.implab.gradle.common.core.lang.Deferred; |
|
|
16 | 16 | import org.implab.gradle.internal.ReplayableQueue; |
|
|
17 | import org.implab.gradle.variants.artifacts.ArtifactAssemblies; | |
|
|
18 | import org.implab.gradle.variants.artifacts.ArtifactAssembly; | |
|
|
19 | import org.implab.gradle.variants.artifacts.ArtifactSlot; | |
|
|
17 | 20 | |
|
|
18 | 21 | @NonNullByDefault |
|
|
19 | 22 | public class ArtifactAssemblyRegistry implements ArtifactAssemblies { |
| @@ -55,7 +58,7 public class ArtifactAssemblyRegistry im | |||
|
|
55 | 58 | } |
|
|
56 | 59 | |
|
|
57 | 60 | @Override |
|
|
58 |
public void |
|
|
|
61 | public void configureEach(Action<? super ArtifactAssembly> action) { | |
|
|
59 | 62 | assemblies.forEach(action::execute); |
|
|
60 | 63 | } |
|
|
61 | 64 | |
| @@ -5,6 +5,7 import java.util.Set; | |||
|
|
5 | 5 | import java.util.function.Consumer; |
|
|
6 | 6 | import java.util.stream.Stream; |
|
|
7 | 7 | |
|
|
8 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
|
|
8 | 9 | import org.gradle.api.Action; |
|
|
9 | 10 | import org.gradle.api.model.ObjectFactory; |
|
|
10 | 11 | import org.implab.gradle.common.core.lang.Strings; |
| @@ -19,6 +20,7 import org.implab.gradle.variants.artifa | |||
|
|
19 | 20 | * вызывает метод {@link #process(Consumer)} для обработки результатов. |
|
|
20 | 21 | * |
|
|
21 | 22 | */ |
|
|
23 | @NonNullByDefault | |
|
|
22 | 24 | final class DefaultArtifactAssemblySpec implements ArtifactAssemblySpec { |
|
|
23 | 25 | private final Consumer<? super SlotContribution> consumer; |
|
|
24 | 26 | private final ObjectFactory objectFactory; |
| @@ -1,56 +1,121 | |||
|
|
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; | |
|
|
6 | 4 | import java.util.Map; |
|
|
7 | 5 | import java.util.Optional; |
|
|
6 | import java.util.Set; | |
|
|
8 | 7 | import java.util.function.Consumer; |
|
|
9 | 8 | |
|
|
9 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
|
|
10 | import org.gradle.api.InvalidUserDataException; | |
|
|
11 | import org.gradle.api.NamedDomainObjectContainer; | |
|
|
12 | import org.gradle.api.NamedDomainObjectProvider; | |
|
|
13 | import org.gradle.api.artifacts.Configuration; | |
|
|
10 | 14 | import org.gradle.api.artifacts.ConfigurationContainer; |
|
|
11 | 15 | import org.gradle.api.model.ObjectFactory; |
|
|
12 |
import org.gradle.api.provider.Pro |
|
|
|
16 | import org.gradle.api.provider.Property; | |
|
|
17 | import org.implab.gradle.internal.ReplayableQueue; | |
|
|
13 | 18 | import org.implab.gradle.variants.artifacts.OutgoingVariant; |
|
|
19 | import org.implab.gradle.variants.artifacts.Slot; | |
|
|
14 | 20 | import org.implab.gradle.variants.core.Variant; |
|
|
15 | 21 | |
|
|
22 | /** | |
|
|
23 | * Реестр исходящих вариантов. Связывает исходящие конфигурации с вариантами | |
|
|
24 | * сборки. Связь устанавливается 1:1. | |
|
|
25 | */ | |
|
|
26 | @NonNullByDefault | |
|
|
16 | 27 | public class OutgoingRegistry { |
|
|
17 |
private final Map<Variant, |
|
|
|
18 | private final List<Consumer<? super DefaultOutgoingConfiguration>> hooks = new LinkedList<>(); | |
|
|
19 | ||
|
|
28 | private final Map<Variant, OutgoingVariant> outgoingByVariant = new LinkedHashMap<>(); | |
|
|
29 | private final ReplayableQueue<OutgoingVariant> outgoingVariants = new ReplayableQueue<>(); | |
|
|
20 | 30 | private final ConfigurationContainer configurations; |
|
|
21 | 31 | private final ObjectFactory objects; |
|
|
22 | private final ProviderFactory providers; | |
|
|
32 | private final Set<Variant> declaredVariants; | |
|
|
23 | 33 | |
|
|
24 | public OutgoingRegistry(ConfigurationContainer configurations, ObjectFactory objects, ProviderFactory providers) { | |
|
|
34 | public OutgoingRegistry( | |
|
|
35 | ConfigurationContainer configurations, | |
|
|
36 | ObjectFactory objects, | |
|
|
37 | Set<Variant> declaredVariants) { | |
|
|
25 | 38 | this.configurations = configurations; |
|
|
26 | 39 | this.objects = objects; |
|
|
27 | this.providers = providers; | |
|
|
40 | this.declaredVariants = declaredVariants; | |
|
|
28 | 41 | } |
|
|
29 | 42 | |
|
|
30 |
public Optional<OutgoingVariant> find |
|
|
|
43 | public Optional<OutgoingVariant> find(Variant variant) { | |
|
|
31 | 44 | return Optional.ofNullable(outgoingByVariant.get(variant)); |
|
|
32 | 45 | } |
|
|
33 | 46 | |
|
|
34 | 47 | public OutgoingVariant maybeCreate(Variant variant) { |
|
|
35 | var outgoing = outgoingByVariant.computeIfAbsent(variant, this::newOutgoingConfiguration); | |
|
|
36 | hooks.forEach(hook -> hook.accept(outgoing)); | |
|
|
48 | return find(variant).orElseGet(() -> create(variant)); | |
|
|
49 | } | |
|
|
50 | ||
|
|
51 | public OutgoingVariant create(Variant variant) { | |
|
|
52 | if (!declaredVariants.contains(variant)) | |
|
|
53 | throw new InvalidUserDataException("Variant " + variant + " isn't declared"); | |
|
|
54 | if (outgoingByVariant.containsKey(variant)) | |
|
|
55 | throw new InvalidUserDataException("Outgoing variant " + variant + " already exists"); | |
|
|
56 | ||
|
|
57 | var configuration = configurations.consumable(outgoingConfigurationName(variant)); | |
|
|
58 | var outgoing = new Outgoing(variant, configuration); | |
|
|
59 | ||
|
|
60 | outgoingByVariant.put(variant, outgoing); | |
|
|
61 | ||
|
|
62 | outgoingVariants.add(outgoing); | |
|
|
63 | ||
|
|
37 | 64 | return outgoing; |
|
|
38 | 65 | } |
|
|
39 | 66 | |
|
|
40 | public void all(Consumer<? super OutgoingVariant> action) { | |
|
|
41 | outgoingByVariant.values().forEach(action); | |
|
|
42 | hooks.add(action); | |
|
|
43 | } | |
|
|
44 | ||
|
|
45 | private DefaultOutgoingConfiguration newOutgoingConfiguration(Variant variant) { | |
|
|
46 | var configuration = configurations.register(outgoingConfigurationName(variant)); | |
|
|
47 | ||
|
|
48 | return new DefaultOutgoingConfiguration(variant, configuration, objects, providers); | |
|
|
67 | /** | |
|
|
68 | * Replayable hook which is applied when an outgoing variant is defined | |
|
|
69 | * | |
|
|
70 | * @param action | |
|
|
71 | */ | |
|
|
72 | public void configureEach(Consumer<? super OutgoingVariant> action) { | |
|
|
73 | outgoingVariants.forEach(action); | |
|
|
49 | 74 | } |
|
|
50 | 75 | |
|
|
51 | 76 | private String outgoingConfigurationName(Variant variant) { |
|
|
52 | 77 | return variant.getName() + "Elements"; |
|
|
53 | 78 | } |
|
|
54 | 79 | |
|
|
80 | private class Outgoing implements OutgoingVariant { | |
|
|
81 | ||
|
|
82 | private final Variant variant; | |
|
|
83 | ||
|
|
84 | private final NamedDomainObjectProvider<? extends Configuration> configurationProvider; | |
|
|
85 | ||
|
|
86 | private final NamedDomainObjectContainer<Slot> slots; | |
|
|
87 | ||
|
|
88 | private final Property<Slot> primarySlot; | |
|
|
89 | ||
|
|
90 | public Outgoing( | |
|
|
91 | Variant variant, | |
|
|
92 | NamedDomainObjectProvider<? extends Configuration> configurationProvider) { | |
|
|
93 | this.variant = variant; | |
|
|
94 | this.configurationProvider = configurationProvider; | |
|
|
95 | this.slots = objects.domainObjectContainer(Slot.class); | |
|
|
96 | this.primarySlot = objects.property(Slot.class); | |
|
|
97 | primarySlot.finalizeValueOnRead(); | |
|
|
98 | } | |
|
|
99 | ||
|
|
100 | @Override | |
|
|
101 | public Property<Slot> getPrimarySlot() { | |
|
|
102 | return primarySlot; | |
|
|
103 | } | |
|
|
104 | ||
|
|
105 | @Override | |
|
|
106 | public Variant getVariant() { | |
|
|
107 | return variant; | |
|
|
108 | } | |
|
|
109 | ||
|
|
110 | @Override | |
|
|
111 | public NamedDomainObjectProvider<? extends Configuration> getConfiguration() { | |
|
|
112 | return configurationProvider; | |
|
|
113 | } | |
|
|
114 | ||
|
|
115 | @Override | |
|
|
116 | public NamedDomainObjectContainer<Slot> getSlots() { | |
|
|
117 | return slots; | |
|
|
118 | } | |
|
|
119 | } | |
|
|
55 | 120 | |
|
|
56 | 121 | } |
| @@ -3,7 +3,7 package org.implab.gradle.variants.artif | |||
|
|
3 | 3 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
|
4 | 4 | |
|
|
5 | 5 | @NonNullByDefault |
|
|
6 |
|
|
|
|
6 | interface SlotContribution { | |
|
|
7 | 7 | |
|
|
8 | 8 | void accept(SlotContributionVisitor visitor); |
|
|
9 | 9 | } |
| @@ -1,8 +1,9 | |||
|
|
1 | 1 | package org.implab.gradle.variants.artifacts.internal; |
|
|
2 | 2 | |
|
|
3 | import java.util.function.Consumer; | |
|
|
3 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
|
|
4 | 4 | |
|
|
5 | public interface SlotContributionVisitor { | |
|
|
5 | @NonNullByDefault | |
|
|
6 | interface SlotContributionVisitor { | |
|
|
6 | 7 | void visit(DirectContribution contribution); |
|
|
7 | 8 | |
|
|
8 | 9 | void visit(VariantOutputsContribution contribution); |
| @@ -11,7 +12,4 public interface SlotContributionVisitor | |||
|
|
11 | 12 | |
|
|
12 | 13 | void visit(LayerOutputsContribution contribution); |
|
|
13 | 14 | |
|
|
14 | default Consumer<SlotContribution> consumer() { | |
|
|
15 | return slot -> slot.accept(this); | |
|
|
16 | } | |
|
|
17 | 15 | } |
|
|
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
