| @@ -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 | ### Публичное API библиотек |
|
7 | ### Публичное API библиотек | |
| 6 |
|
8 | |||
| 7 | - Предпочтителен `non-null` подход. |
|
9 | - Предпочтителен `non-null` подход. | |
| @@ -1,7 +1,5 | |||||
| 1 | package org.implab.gradle.common.core.lang; |
|
1 | package org.implab.gradle.common.core.lang; | |
| 2 |
|
2 | |||
| 3 | import java.util.function.Consumer; |
|
|||
| 4 | import java.util.function.Function; |
|
|||
| 5 | import java.util.regex.Pattern; |
|
3 | import java.util.regex.Pattern; | |
| 6 |
|
4 | |||
| 7 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
5 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| @@ -17,6 +17,7 | |||||
| 17 | - artifact: directory |
|
17 | - artifact: directory | |
| 18 | - customTask |
|
18 | - customTask | |
| 19 | - artifact: FileSystemLocation |
|
19 | - artifact: FileSystemLocation | |
|
|
20 | - when, all - replayable hooks для получения содержимого сборки | |||
| 20 |
|
21 | |||
| 21 | ## extension |
|
22 | ## extension | |
| 22 |
|
23 | |||
| @@ -30,16 +31,8 | |||||
| 30 | - whenOutgoingConfiguration |
|
31 | - whenOutgoingConfiguration | |
| 31 | - whenOutgoingSlot |
|
32 | - whenOutgoingSlot | |
| 32 |
|
33 | |||
| 33 | outgoing = outgoings.maybeCreate(variant) |
|
34 | - ArtifactAssemblyBridge | |
| 34 |
|
35 | связывает содержимое ArtifactAssembly и исходящей конфигурации OutgoingVariant | ||
| 35 | slot = outgoings.slots.maybeCreate(slotName) |
|
36 | - VariantArtifactsHandler | |
| 36 | assembly = assemblies.register(variantSlot, task, mapOutput) |
|
37 | управляет состоянием ArtifactAssembly, используется для DSL сборки | |
| 37 | outgoing.configure(configuration -> { |
|
38 | - configureVariant конфигурирует VariantArtifactsSpec No newline at end of file | |
| 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 |
|
|||
| @@ -4,6 +4,9 import java.util.LinkedList; | |||||
| 4 | import java.util.List; |
|
4 | import java.util.List; | |
| 5 | import java.util.function.Consumer; |
|
5 | import java.util.function.Consumer; | |
| 6 |
|
6 | |||
|
|
7 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
|
|
8 | ||||
|
|
9 | @NonNullByDefault | |||
| 7 | public class ReplayableQueue<T> { |
|
10 | public class ReplayableQueue<T> { | |
| 8 | private final List<Consumer<? super T>> consumers = new LinkedList<>(); |
|
11 | private final List<Consumer<? super T>> consumers = new LinkedList<>(); | |
| 9 | private final List<T> values = new LinkedList<>(); |
|
12 | private final List<T> values = new LinkedList<>(); | |
| @@ -4,16 +4,21 import org.gradle.api.Action; | |||||
| 4 | import org.gradle.api.Plugin; |
|
4 | import org.gradle.api.Plugin; | |
| 5 | import org.gradle.api.Project; |
|
5 | import org.gradle.api.Project; | |
| 6 | import org.implab.gradle.common.core.lang.Deferred; |
|
6 | import org.implab.gradle.common.core.lang.Deferred; | |
| 7 | import org.implab.gradle.variants.artifacts.ArtifactAssemblyRegistry; |
|
|||
| 8 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec; |
|
7 | import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec; | |
| 9 | import org.implab.gradle.variants.artifacts.OutgoingVariantsContext; |
|
8 | import org.implab.gradle.variants.artifacts.OutgoingVariantsContext; | |
| 10 | import org.implab.gradle.variants.artifacts.VariantArtifactsExtension; |
|
9 | import org.implab.gradle.variants.artifacts.VariantArtifactsExtension; | |
| 11 | import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; |
|
10 | import org.implab.gradle.variants.artifacts.VariantArtifactsSpec; | |
| 12 |
import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyB |
|
11 | import org.implab.gradle.variants.artifacts.internal.ArtifactAssemblyBinder; | |
| 13 |
import org.implab.gradle.variants.artifacts.internal. |
|
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 | import org.implab.gradle.variants.artifacts.internal.OutgoingRegistry; |
|
16 | import org.implab.gradle.variants.artifacts.internal.OutgoingRegistry; | |
|
|
17 | import org.implab.gradle.variants.artifacts.internal.SingleSlotConvention; | |||
| 15 | import org.implab.gradle.variants.core.Variant; |
|
18 | import org.implab.gradle.variants.core.Variant; | |
| 16 | import org.implab.gradle.variants.core.VariantsExtension; |
|
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 | public abstract class VariantArtifactsPlugin implements Plugin<Project> { |
|
23 | public abstract class VariantArtifactsPlugin implements Plugin<Project> { | |
| 19 |
|
24 | |||
| @@ -22,25 +27,53 public abstract class VariantArtifactsPl | |||||
| 22 | var extensions = target.getExtensions(); |
|
27 | var extensions = target.getExtensions(); | |
| 23 | var objects = target.getObjects(); |
|
28 | var objects = target.getObjects(); | |
| 24 | var providers = target.getProviders(); |
|
29 | var providers = target.getProviders(); | |
|
|
30 | var plugins = target.getPlugins(); | |||
| 25 | var configurations = target.getConfigurations(); |
|
31 | var configurations = target.getConfigurations(); | |
| 26 | var tasks = target.getTasks(); |
|
32 | var tasks = target.getTasks(); | |
|
|
33 | var layout = target.getLayout(); | |||
| 27 |
|
34 | |||
| 28 | // Apply the main VariantsPlugin to ensure the core variant model is available. |
|
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 | // Access the VariantsExtension to configure variant sources. |
|
38 | // Access the VariantsExtension to configure variant sources. | |
| 31 | var variantsExtension = extensions.getByType(VariantsExtension.class); |
|
39 | var variantsExtension = extensions.getByType(VariantsExtension.class); | |
| 32 |
|
40 | var sourcesExtension = extensions.getByType(VariantSourcesExtension.class); | ||
| 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); |
|
|||
| 38 |
|
41 | |||
| 39 | var deferred = new Deferred<OutgoingVariantsContext>(); |
|
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 | @Override |
|
82 | @Override | |
| 50 | public void variant(String variantName, Action<? super VariantArtifactsSpec> action) { |
|
83 | public void variant(String variantName, Action<? super VariantArtifactsSpec> action) { | |
| 51 | deferred.whenResolved(context -> { |
|
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 | @Override |
|
90 | @Override | |
| 57 |
public void when |
|
91 | public void whenAvailable(Action<? super OutgoingVariantsContext> action) { | |
| 58 |
deferred.whenResolved( |
|
92 | deferred.whenResolved(handler -> action.execute(handler)); | |
| 59 | } |
|
93 | } | |
| 60 |
|
94 | |||
| 61 | @Override |
|
95 | @Override | |
| 62 |
public void whenOutgoing |
|
96 | public void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action) { | |
| 63 |
deferred.whenResolved(registry -> registry. |
|
97 | deferred.whenResolved(registry -> registry.whenOutgoingConfiguration(action)); | |
| 64 |
|
98 | |||
| 65 | } |
|
99 | } | |
| 66 |
|
100 | |||
| 67 | @Override |
|
101 | @Override | |
| 68 |
public void whenOutgoingSlot(Action<? super Outgoing |
|
102 | public void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action) { | |
| 69 |
deferred.whenResolved(registry -> registry. |
|
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 | * Регистрирует обработчик на конкретный слот. Если слот еще не зарегистрирован, |
|
34 | * Registers a configuration action for the assembly of the given slot. | |
| 35 | * то обработчик будет добавлен в очередь и будет вызван при регистрации слота. |
|
|||
| 36 | * Порядок и точный момент вызова обработчиков не определен. |
|
|||
| 37 | * |
|
35 | * | |
| 38 | * @param slot Слот на который нужно зарегистрировать обработчик |
|
36 | * <p>If the assembly is already registered, the action is invoked immediately. | |
| 39 | * @param action Обработчик |
|
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 | void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action); |
|
43 | void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action); | |
| 42 |
|
44 | |||
| 43 | /** |
|
45 | /** | |
| 44 | * Регистрирует глобальный обработчик, который будет вызван для всех слотов. |
|
46 | * Adds global configuration action for all materialized assemblies. If some assemblies are | |
| 45 | * Обработчик будет вызван как для уже зарегистрированных слотов так и для тех, |
|
47 | * already registered, the action will be invoked for them immediately. For assemblies that | |
| 46 | * которые будут зарегистрированы в будущем. |
|
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 | Optional<ArtifactAssembly> find(ArtifactSlot slot); |
|
55 | Optional<ArtifactAssembly> find(ArtifactSlot slot); | |
| @@ -40,7 +40,9 public interface OutgoingConfigurationSl | |||||
| 40 | * |
|
40 | * | |
| 41 | * @param action task configuration action |
|
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 | default void assemblyTask(Closure<?> closure) { |
|
47 | default void assemblyTask(Closure<?> closure) { | |
| 46 | assemblyTask(Closures.action(closure)); |
|
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 | getConfiguration().configure(action); |
|
30 | getConfiguration().configure(action); | |
| 31 | } |
|
31 | } | |
| 32 |
|
32 | |||
| @@ -5,7 +5,6 import java.util.Optional; | |||||
| 5 | import org.gradle.api.Action; |
|
5 | import org.gradle.api.Action; | |
| 6 | import org.gradle.api.InvalidUserDataException; |
|
6 | import org.gradle.api.InvalidUserDataException; | |
| 7 | import org.implab.gradle.variants.core.Variant; |
|
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 | public interface OutgoingVariantsContext { |
|
13 | public interface OutgoingVariantsContext { | |
| 15 |
|
14 | |||
| 16 | /** |
|
15 | ArtifactAssemblies getAssemblies(); | |
| 17 | * Зафиксированное представление о вариантах на основе которого адаптеры могут |
|
|||
| 18 | * конфигурировать артефакты и исходящие конфигурации |
|
|||
| 19 | */ |
|
|||
| 20 | VariantsView getVariants(); |
|
|||
| 21 |
|
16 | |||
| 22 | ArtifactAssemblies getAssemblies(); |
|
17 | void configureVariant(Variant variant, Action<? super VariantArtifactsSpec> action); | |
| 23 |
|
18 | |||
| 24 | /** |
|
19 | /** | |
| 25 | * Replayable hook для всех объявленных конфигураций |
|
20 | * Replayable hook для всех объявленных конфигураций | |
| 26 | */ |
|
21 | */ | |
| 27 |
void |
|
22 | void configureEach(Action<? super OutgoingVariant> action); | |
| 28 |
|
23 | |||
| 29 | Optional<OutgoingVariant> findOutgoing(Variant variant); |
|
24 | Optional<OutgoingVariant> findOutgoing(Variant variant); | |
| 30 |
|
25 | |||
| @@ -33,6 +28,9 public interface OutgoingVariantsContext | |||||
| 33 | .orElseThrow(() -> new InvalidUserDataException("Outgoing variant '" + variant + "' isn't registered")); |
|
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 | * Project-level DSL entry point for declaring outgoing artifacts per variant. |
|
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 |
|
11 | * <p> | |
| 12 | * artifact sets within that contract. One slot is expected to materialize to one published artifact. |
|
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 | public interface VariantArtifactsExtension { |
|
17 | public interface VariantArtifactsExtension { | |
| 15 | /** |
|
18 | /** | |
| 16 | * Configures artifact slots of the named variant. |
|
19 | * Configures artifact slots of the named variant. | |
| 17 | * |
|
20 | * | |
| 18 | * @param variantName variant name |
|
21 | * @param variantName variant name | |
| 19 | * @param action variant artifact declaration |
|
22 | * @param action variant artifact declaration | |
| 20 | */ |
|
23 | */ | |
| 21 | void variant(String variantName, Action<? super VariantArtifactsSpec> action); |
|
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 |
|
38 | default void whenAvailable(Closure<?> closure) { | |
| 35 |
when |
|
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 | * @param action variant-level outgoing configuration callback |
|
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 |
|
50 | default void whenOutgoingConfiguration(Closure<?> closure) { | |
| 46 |
whenOutgoing |
|
51 | whenOutgoingConfiguration(Closures.action(closure)); | |
| 47 | } |
|
52 | } | |
| 48 |
|
53 | |||
| 49 | /** |
|
54 | /** | |
| @@ -11,11 +11,11 import org.implab.gradle.variants.artifa | |||||
| 11 | * из {@link ArtifactAssemblies} |
|
11 | * из {@link ArtifactAssemblies} | |
| 12 | */ |
|
12 | */ | |
| 13 | @NonNullByDefault |
|
13 | @NonNullByDefault | |
| 14 |
public class ArtifactAssemblyB |
|
14 | public class ArtifactAssemblyBinder implements Action<OutgoingVariant> { | |
| 15 |
|
15 | |||
| 16 | private final ArtifactAssemblies resolver; |
|
16 | private final ArtifactAssemblies resolver; | |
| 17 |
|
17 | |||
| 18 |
public ArtifactAssemblyB |
|
18 | public ArtifactAssemblyBinder(ArtifactAssemblies resolver) { | |
| 19 | this.resolver = resolver; |
|
19 | this.resolver = resolver; | |
| 20 | } |
|
20 | } | |
| 21 |
|
21 | |||
| @@ -26,7 +26,7 public class ArtifactAssemblyBridge impl | |||||
| 26 | var variant = outgoingVariant.getVariant(); |
|
26 | var variant = outgoingVariant.getVariant(); | |
| 27 |
|
27 | |||
| 28 | // связываем конфигурацию |
|
28 | // связываем конфигурацию | |
| 29 | outgoingVariant.configure(configuration -> { |
|
29 | outgoingVariant.configureOutgoing(configuration -> { | |
| 30 | var primarySlot = primarySlotProvider.get(); |
|
30 | var primarySlot = primarySlotProvider.get(); | |
| 31 | var outgoing = configuration.getOutgoing(); |
|
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 | import java.util.LinkedHashMap; |
|
3 | import java.util.LinkedHashMap; | |
| 4 | import java.util.Map; |
|
4 | import java.util.Map; | |
| @@ -14,6 +14,9 import org.gradle.api.provider.Provider; | |||||
| 14 | import org.gradle.api.tasks.TaskProvider; |
|
14 | import org.gradle.api.tasks.TaskProvider; | |
| 15 | import org.implab.gradle.common.core.lang.Deferred; |
|
15 | import org.implab.gradle.common.core.lang.Deferred; | |
| 16 | import org.implab.gradle.internal.ReplayableQueue; |
|
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 | @NonNullByDefault |
|
21 | @NonNullByDefault | |
| 19 | public class ArtifactAssemblyRegistry implements ArtifactAssemblies { |
|
22 | public class ArtifactAssemblyRegistry implements ArtifactAssemblies { | |
| @@ -55,7 +58,7 public class ArtifactAssemblyRegistry im | |||||
| 55 | } |
|
58 | } | |
| 56 |
|
59 | |||
| 57 | @Override |
|
60 | @Override | |
| 58 |
public void |
|
61 | public void configureEach(Action<? super ArtifactAssembly> action) { | |
| 59 | assemblies.forEach(action::execute); |
|
62 | assemblies.forEach(action::execute); | |
| 60 | } |
|
63 | } | |
| 61 |
|
64 | |||
| @@ -5,6 +5,7 import java.util.Set; | |||||
| 5 | import java.util.function.Consumer; |
|
5 | import java.util.function.Consumer; | |
| 6 | import java.util.stream.Stream; |
|
6 | import java.util.stream.Stream; | |
| 7 |
|
7 | |||
|
|
8 | import org.eclipse.jdt.annotation.NonNullByDefault; | |||
| 8 | import org.gradle.api.Action; |
|
9 | import org.gradle.api.Action; | |
| 9 | import org.gradle.api.model.ObjectFactory; |
|
10 | import org.gradle.api.model.ObjectFactory; | |
| 10 | import org.implab.gradle.common.core.lang.Strings; |
|
11 | import org.implab.gradle.common.core.lang.Strings; | |
| @@ -19,6 +20,7 import org.implab.gradle.variants.artifa | |||||
| 19 | * вызывает метод {@link #process(Consumer)} для обработки результатов. |
|
20 | * вызывает метод {@link #process(Consumer)} для обработки результатов. | |
| 20 | * |
|
21 | * | |
| 21 | */ |
|
22 | */ | |
|
|
23 | @NonNullByDefault | |||
| 22 | final class DefaultArtifactAssemblySpec implements ArtifactAssemblySpec { |
|
24 | final class DefaultArtifactAssemblySpec implements ArtifactAssemblySpec { | |
| 23 | private final Consumer<? super SlotContribution> consumer; |
|
25 | private final Consumer<? super SlotContribution> consumer; | |
| 24 | private final ObjectFactory objectFactory; |
|
26 | private final ObjectFactory objectFactory; | |
| @@ -1,56 +1,121 | |||||
| 1 | package org.implab.gradle.variants.artifacts.internal; |
|
1 | package org.implab.gradle.variants.artifacts.internal; | |
| 2 |
|
2 | |||
| 3 | import java.util.LinkedHashMap; |
|
3 | import java.util.LinkedHashMap; | |
| 4 | import java.util.LinkedList; |
|
|||
| 5 | import java.util.List; |
|
|||
| 6 | import java.util.Map; |
|
4 | import java.util.Map; | |
| 7 | import java.util.Optional; |
|
5 | import java.util.Optional; | |
|
|
6 | import java.util.Set; | |||
| 8 | import java.util.function.Consumer; |
|
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 | import org.gradle.api.artifacts.ConfigurationContainer; |
|
14 | import org.gradle.api.artifacts.ConfigurationContainer; | |
| 11 | import org.gradle.api.model.ObjectFactory; |
|
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 | import org.implab.gradle.variants.artifacts.OutgoingVariant; |
|
18 | import org.implab.gradle.variants.artifacts.OutgoingVariant; | |
|
|
19 | import org.implab.gradle.variants.artifacts.Slot; | |||
| 14 | import org.implab.gradle.variants.core.Variant; |
|
20 | import org.implab.gradle.variants.core.Variant; | |
| 15 |
|
21 | |||
|
|
22 | /** | |||
|
|
23 | * Реестр исходящих вариантов. Связывает исходящие конфигурации с вариантами | |||
|
|
24 | * сборки. Связь устанавливается 1:1. | |||
|
|
25 | */ | |||
|
|
26 | @NonNullByDefault | |||
| 16 | public class OutgoingRegistry { |
|
27 | public class OutgoingRegistry { | |
| 17 |
private final Map<Variant, |
|
28 | private final Map<Variant, OutgoingVariant> outgoingByVariant = new LinkedHashMap<>(); | |
| 18 | private final List<Consumer<? super DefaultOutgoingConfiguration>> hooks = new LinkedList<>(); |
|
29 | private final ReplayableQueue<OutgoingVariant> outgoingVariants = new ReplayableQueue<>(); | |
| 19 |
|
||||
| 20 | private final ConfigurationContainer configurations; |
|
30 | private final ConfigurationContainer configurations; | |
| 21 | private final ObjectFactory objects; |
|
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 | this.configurations = configurations; |
|
38 | this.configurations = configurations; | |
| 26 | this.objects = objects; |
|
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 | return Optional.ofNullable(outgoingByVariant.get(variant)); |
|
44 | return Optional.ofNullable(outgoingByVariant.get(variant)); | |
| 32 | } |
|
45 | } | |
| 33 |
|
46 | |||
| 34 | public OutgoingVariant maybeCreate(Variant variant) { |
|
47 | public OutgoingVariant maybeCreate(Variant variant) { | |
| 35 | var outgoing = outgoingByVariant.computeIfAbsent(variant, this::newOutgoingConfiguration); |
|
48 | return find(variant).orElseGet(() -> create(variant)); | |
| 36 | hooks.forEach(hook -> hook.accept(outgoing)); |
|
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 | return outgoing; |
|
64 | return outgoing; | |
| 38 | } |
|
65 | } | |
| 39 |
|
66 | |||
| 40 | public void all(Consumer<? super OutgoingVariant> action) { |
|
67 | /** | |
| 41 | outgoingByVariant.values().forEach(action); |
|
68 | * Replayable hook which is applied when an outgoing variant is defined | |
| 42 | hooks.add(action); |
|
69 | * | |
| 43 | } |
|
70 | * @param action | |
| 44 |
|
71 | */ | ||
| 45 | private DefaultOutgoingConfiguration newOutgoingConfiguration(Variant variant) { |
|
72 | public void configureEach(Consumer<? super OutgoingVariant> action) { | |
| 46 | var configuration = configurations.register(outgoingConfigurationName(variant)); |
|
73 | outgoingVariants.forEach(action); | |
| 47 |
|
||||
| 48 | return new DefaultOutgoingConfiguration(variant, configuration, objects, providers); |
|
|||
| 49 | } |
|
74 | } | |
| 50 |
|
75 | |||
| 51 | private String outgoingConfigurationName(Variant variant) { |
|
76 | private String outgoingConfigurationName(Variant variant) { | |
| 52 | return variant.getName() + "Elements"; |
|
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 | import org.eclipse.jdt.annotation.NonNullByDefault; |
|
3 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
| 4 |
|
4 | |||
| 5 | @NonNullByDefault |
|
5 | @NonNullByDefault | |
| 6 |
|
|
6 | interface SlotContribution { | |
| 7 |
|
7 | |||
| 8 | void accept(SlotContributionVisitor visitor); |
|
8 | void accept(SlotContributionVisitor visitor); | |
| 9 | } |
|
9 | } | |
| @@ -1,8 +1,9 | |||||
| 1 | package org.implab.gradle.variants.artifacts.internal; |
|
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 | void visit(DirectContribution contribution); |
|
7 | void visit(DirectContribution contribution); | |
| 7 |
|
8 | |||
| 8 | void visit(VariantOutputsContribution contribution); |
|
9 | void visit(VariantOutputsContribution contribution); | |
| @@ -11,7 +12,4 public interface SlotContributionVisitor | |||||
| 11 |
|
12 | |||
| 12 | void visit(LayerOutputsContribution contribution); |
|
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 |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now
