##// END OF EJS Templates
variants: validate source context identities
cin -
r57:1abf7dba60ee default
parent child
Show More
@@ -60,6 +60,25 public class VariantsView {
60 60 return roles;
61 61 }
62 62
63 /**
64 * Requires the layer to be declared in this view.
65 *
66 * @param layer layer identity
67 * @throws InvalidUserDataException if the layer is not declared
68 */
69 public void assertLayer(Layer layer) {
70 Objects.requireNonNull(layer, "The layer can't be null");
71
72 if (!layers.contains(layer))
73 throw new InvalidUserDataException("The specified layer '" + layer.getName() + "' isn't declared");
74 }
75
76 /**
77 * Requires the role to be declared in this view.
78 *
79 * @param role role identity
80 * @throws InvalidUserDataException if the role is not declared
81 */
63 82 public void assertRole(Role role) {
64 83 Objects.requireNonNull(role, "The role can't be null");
65 84
@@ -75,6 +94,19 public class VariantsView {
75 94 }
76 95
77 96 /**
97 * Requires the variant to be declared in this view.
98 *
99 * @param variant variant identity
100 * @throws InvalidUserDataException if the variant is not declared
101 */
102 public void assertVariant(Variant variant) {
103 Objects.requireNonNull(variant, "The variant can't be null");
104
105 if (!variants.contains(variant))
106 throw new InvalidUserDataException("The specified variant '" + variant.getName() + "' isn't declared");
107 }
108
109 /**
78 110 * Returns all resolved variant-role-layer bindings.
79 111 */
80 112 public Set<VariantRoleLayer> getEntries() {
@@ -8,6 +8,7 import java.util.Set;
8 8 import java.util.stream.Collectors;
9 9
10 10 import org.eclipse.jdt.annotation.NonNullByDefault;
11 import org.gradle.api.InvalidUserDataException;
11 12 import org.implab.gradle.variants.core.Layer;
12 13 import org.implab.gradle.variants.core.Role;
13 14 import org.implab.gradle.variants.core.Variant;
@@ -66,7 +67,7 public final class CompileUnitsView {
66 67
67 68 public CompileUnit requireUnit(Variant variant, Layer layer) {
68 69 return findUnit(variant, layer)
69 .orElseThrow(() -> new IllegalArgumentException(
70 .orElseThrow(() -> new InvalidUserDataException(
70 71 "Compile unit for variant '" + variant.getName()
71 72 + "' and layer '" + layer.getName() + "' not found"));
72 73 }
@@ -7,6 +7,7 import java.util.Optional;
7 7 import java.util.Set;
8 8 import java.util.stream.Collectors;
9 9
10 import org.gradle.api.InvalidUserDataException;
10 11 import org.implab.gradle.variants.core.Layer;
11 12 import org.implab.gradle.variants.core.Role;
12 13 import org.implab.gradle.variants.core.Variant;
@@ -66,7 +67,7 public final class RoleProjectionsView {
66 67
67 68 public RoleProjection requireProjection(Variant variant, Role role) {
68 69 return findProjection(variant, role)
69 .orElseThrow(() -> new IllegalArgumentException(
70 .orElseThrow(() -> new InvalidUserDataException(
70 71 "Role projection for variant '" + variant.getName()
71 72 + "' and role '" + role.getName() + "' not found"));
72 73 }
@@ -78,6 +79,7 public final class RoleProjectionsView {
78 79 }
79 80
80 81 public static RoleProjectionsView of(VariantsView variantsView) {
82 Objects.requireNonNull(variantsView, "variantsView can't be null");
81 83 return new RoleProjectionsView(variantsView);
82 84 }
83 85 }
@@ -15,6 +15,9 public interface SourceSetMaterializer {
15 15 * Returns a lazy provider for the source set corresponding to the compile unit.
16 16 *
17 17 * <p>The provider is stable and cached per compile unit.
18 *
19 * @throws org.gradle.api.InvalidUserDataException if the compile unit is not
20 * part of the finalized variant model
18 21 */
19 22 NamedDomainObjectProvider<GenericSourceSet> getSourceSet(CompileUnit unit);
20 23 }
@@ -48,6 +48,9 public interface VariantSourcesContext {
48 48 * {@link VariantSourcesExtension#lateConfigurationPolicy(org.gradle.api.Action)}.
49 49 * In warn/allow modes the action is applied as a late imperative step and does
50 50 * not retroactively restore selector precedence.
51 *
52 * @throws org.gradle.api.InvalidUserDataException if the layer is not part of
53 * the finalized variant model
51 54 */
52 55 void configureLayer(Layer layer, Action<? super GenericSourceSet> action);
53 56
@@ -57,6 +60,9 public interface VariantSourcesContext {
57 60 * <p>Late application semantics for already materialized source sets are
58 61 * governed by
59 62 * {@link VariantSourcesExtension#lateConfigurationPolicy(org.gradle.api.Action)}.
63 *
64 * @throws org.gradle.api.InvalidUserDataException if the variant is not part
65 * of the finalized variant model
60 66 */
61 67 void configureVariant(Variant variant, Action<? super GenericSourceSet> action);
62 68
@@ -66,6 +72,9 public interface VariantSourcesContext {
66 72 * <p>Late application semantics for already materialized source sets are
67 73 * governed by
68 74 * {@link VariantSourcesExtension#lateConfigurationPolicy(org.gradle.api.Action)}.
75 *
76 * @throws org.gradle.api.InvalidUserDataException if the compile unit is not
77 * part of the finalized variant model
69 78 */
70 79 void configureUnit(CompileUnit unit, Action<? super GenericSourceSet> action);
71 80
@@ -39,7 +39,7 public interface VariantSourcesExtension
39 39 *
40 40 * <p>This policy is single-valued:
41 41 * <ul>
42 * <li>it must be selected before the finalized
42 * <li>it must be selected before the
43 43 * {@link VariantSourcesContext} becomes observable through
44 44 * {@link #whenAvailable(Action)};</li>
45 45 * <li>once the context is being created, the policy is fixed and cannot be
@@ -76,7 +76,7 public interface CompileUnitNamer {
76 76 @Override
77 77 public String resolveName(CompileUnit unit) {
78 78 return Optional.ofNullable(unitNames.get(unit)).orElseThrow(
79 () -> new IllegalArgumentException(MessageFormat.format(
79 () -> new InvalidUserDataException(MessageFormat.format(
80 80 "Compile unit {0} doesn't have an associated name",
81 81 unit)));
82 82 }
@@ -1,5 +1,6
1 1 package org.implab.gradle.variants.sources.internal;
2 2
3 import org.gradle.api.InvalidUserDataException;
3 4 import org.implab.gradle.variants.sources.VariantSourcesExtension.NamingPolicySpec;
4 5
5 6 public class DefaultCompileUnitNamingPolicy implements NamingPolicySpec {
@@ -29,7 +30,7 public class DefaultCompileUnitNamingPol
29 30
30 31 private void assertApplyOnce() {
31 32 if (policyApplied)
32 throw new IllegalStateException("Naming policy already applied");
33 throw new InvalidUserDataException("Naming policy already applied");
33 34 policyApplied = true;
34 35
35 36 }
@@ -1,5 +1,6
1 1 package org.implab.gradle.variants.sources.internal;
2 2
3 import org.gradle.api.InvalidUserDataException;
3 4 import org.implab.gradle.variants.sources.VariantSourcesExtension.LateConfigurationPolicySpec;
4 5
5 6 public class DefaultLateConfigurationPolicySpec implements LateConfigurationPolicySpec {
@@ -36,7 +37,7 public class DefaultLateConfigurationPol
36 37
37 38 private void assertApplyOnce() {
38 39 if (policyApplied)
39 throw new IllegalStateException("Lazy configuration policy already applied");
40 throw new InvalidUserDataException("Lazy configuration policy already applied");
40 41 policyApplied = true;
41 42 }
42 43
@@ -2,6 +2,7 package org.implab.gradle.variants.sourc
2 2
3 3 import java.util.HashMap;
4 4 import java.util.Map;
5 import java.util.Objects;
5 6 import org.gradle.api.Action;
6 7 import org.gradle.api.NamedDomainObjectProvider;
7 8 import org.implab.gradle.variants.core.Layer;
@@ -62,24 +63,38 public class DefaultVariantSourcesContex
62 63
63 64 @Override
64 65 public void configureLayer(Layer layer, Action<? super GenericSourceSet> action) {
66 variantsView.assertLayer(layer);
67 Objects.requireNonNull(action, "action can't be null");
65 68 sourceSetConfigurationRegistry.addLayerAction(layer, action);
66 69 }
67 70
68 71 @Override
69 72 public void configureVariant(Variant variant, Action<? super GenericSourceSet> action) {
73 variantsView.assertVariant(variant);
74 Objects.requireNonNull(action, "action can't be null");
70 75 sourceSetConfigurationRegistry.addVariantAction(variant, action);
71 76 }
72 77
73 78 @Override
74 79 public void configureUnit(CompileUnit unit, Action<? super GenericSourceSet> action) {
80 assertCompileUnit(unit);
81 Objects.requireNonNull(action, "action can't be null");
75 82 sourceSetConfigurationRegistry.addCompileUnitAction(unit, action);
76 83 }
77 84
85 private void assertCompileUnit(CompileUnit unit) {
86 Objects.requireNonNull(unit, "unit can't be null");
87 variantsView.assertVariant(unit.variant());
88 variantsView.assertLayer(unit.layer());
89 compileUnitsView.requireUnit(unit.variant(), unit.layer());
90 }
91
78 92 class LocalSourceSetMaterializer implements SourceSetMaterializer {
79 93 private final Map<CompileUnit, NamedDomainObjectProvider<GenericSourceSet>> registeredSources = new HashMap<>();
80 94
81 95 @Override
82 96 public NamedDomainObjectProvider<GenericSourceSet> getSourceSet(CompileUnit unit) {
97 assertCompileUnit(unit);
83 98 return registeredSources.computeIfAbsent(unit, k -> {
84 99 var sourcesName = compileUnitNamer.resolveName(unit);
85 100 sourceSetRegistry.whenMaterialized(sourcesName,
@@ -9,6 +9,7 import java.util.stream.Collectors;
9 9
10 10 import org.eclipse.jdt.annotation.NonNullByDefault;
11 11 import org.gradle.api.Action;
12 import org.gradle.api.InvalidUserDataException;
12 13 import org.gradle.api.Named;
13 14 import org.gradle.api.logging.Logger;
14 15 import org.gradle.api.logging.Logging;
@@ -77,7 +78,7 public class SourceSetConfigurationRegis
77 78
78 79 switch (lateConfigurationMode.get()) {
79 80 case FAIL:
80 throw new IllegalStateException(message + " [" + names + "]");
81 throw new InvalidUserDataException(message + " [" + names + "]");
81 82 case WARN:
82 83 logger.warn(message + "\n\t" + names);
83 84 break;
@@ -360,6 +360,30 class VariantSourcesPluginFunctionalTest
360 360 }
361 361
362 362 @Test
363 void failsOnUnknownVariantContextSelectorTarget() throws Exception {
364 writeSettings("variant-sources-context-missing-variant");
365 writeBuildFile("""
366 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
367
368 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
369 variantsExt.layers.create('main')
370 variantsExt.roles.create('production')
371 variantsExt.variant('browser') {
372 role('production') { layers('main') }
373 }
374
375 variantSources.whenAvailable { ctx ->
376 def missing = objects.named(org.implab.gradle.variants.core.Variant, 'missing')
377 ctx.configureVariant(missing) {
378 declareOutputs('js')
379 }
380 }
381 """);
382
383 assertBuildFails("The specified variant 'missing' isn't declared", "help");
384 }
385
386 @Test
363 387 void failsOnUnknownLayerSelectorTarget() throws Exception {
364 388 writeSettings("variant-sources-missing-layer");
365 389 writeBuildFile("""
@@ -383,6 +407,30 class VariantSourcesPluginFunctionalTest
383 407 }
384 408
385 409 @Test
410 void failsOnUnknownLayerContextSelectorTarget() throws Exception {
411 writeSettings("variant-sources-context-missing-layer");
412 writeBuildFile("""
413 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
414
415 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
416 variantsExt.layers.create('main')
417 variantsExt.roles.create('production')
418 variantsExt.variant('browser') {
419 role('production') { layers('main') }
420 }
421
422 variantSources.whenAvailable { ctx ->
423 def missing = objects.named(org.implab.gradle.variants.core.Layer, 'missing')
424 ctx.configureLayer(missing) {
425 declareOutputs('js')
426 }
427 }
428 """);
429
430 assertBuildFails("The specified layer 'missing' isn't declared", "help");
431 }
432
433 @Test
386 434 void failsOnUndeclaredCompileUnitSelectorTarget() throws Exception {
387 435 writeSettings("variant-sources-missing-unit");
388 436 writeBuildFile("""
@@ -407,6 +455,58 class VariantSourcesPluginFunctionalTest
407 455 }
408 456
409 457 @Test
458 void failsOnUndeclaredCompileUnitContextSelectorTarget() throws Exception {
459 writeSettings("variant-sources-context-missing-unit");
460 writeBuildFile("""
461 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
462
463 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
464 variantsExt.layers.create('main')
465 variantsExt.layers.create('test')
466 variantsExt.roles.create('production')
467 variantsExt.variant('browser') {
468 role('production') { layers('main') }
469 }
470
471 variantSources.whenAvailable { ctx ->
472 def browser = ctx.variants.variants.find { it.name == 'browser' }
473 def testLayer = ctx.variants.layers.find { it.name == 'test' }
474 def unit = new org.implab.gradle.variants.sources.CompileUnit(browser, testLayer)
475 ctx.configureUnit(unit) {
476 declareOutputs('js')
477 }
478 }
479 """);
480
481 assertBuildFails("Compile unit for variant 'browser' and layer 'test' not found", "help");
482 }
483
484 @Test
485 void failsOnUndeclaredCompileUnitMaterializerTarget() throws Exception {
486 writeSettings("variant-sources-materializer-missing-unit");
487 writeBuildFile("""
488 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
489
490 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
491 variantsExt.layers.create('main')
492 variantsExt.layers.create('test')
493 variantsExt.roles.create('production')
494 variantsExt.variant('browser') {
495 role('production') { layers('main') }
496 }
497
498 variantSources.whenAvailable { ctx ->
499 def browser = ctx.variants.variants.find { it.name == 'browser' }
500 def testLayer = ctx.variants.layers.find { it.name == 'test' }
501 def unit = new org.implab.gradle.variants.sources.CompileUnit(browser, testLayer)
502 ctx.sourceSets.getSourceSet(unit)
503 }
504 """);
505
506 assertBuildFails("Compile unit for variant 'browser' and layer 'test' not found", "help");
507 }
508
509 @Test
410 510 void rejectsChangingNamingPolicyAfterContextBecomesObservable() throws Exception {
411 511 writeSettings("variant-sources-name-policy-fixed");
412 512 writeBuildFile("""
@@ -7,6 +7,7 import static org.junit.jupiter.api.Asse
7 7 import java.lang.reflect.Constructor;
8 8 import java.util.Set;
9 9
10 import org.gradle.api.InvalidUserDataException;
10 11 import org.implab.gradle.variants.core.Layer;
11 12 import org.implab.gradle.variants.core.Role;
12 13 import org.implab.gradle.variants.core.Variant;
@@ -59,7 +60,7 class CompileUnitsViewTest {
59 60
60 61 var units = CompileUnitsView.of(view);
61 62
62 var ex = assertThrows(IllegalArgumentException.class, () -> units.requireUnit(browser, missing));
63 var ex = assertThrows(InvalidUserDataException.class, () -> units.requireUnit(browser, missing));
63 64 assertTrue(ex.getMessage().contains("Compile unit for variant 'browser' and layer 'missing' not found"));
64 65 }
65 66
@@ -7,6 +7,7 import static org.junit.jupiter.api.Asse
7 7 import java.lang.reflect.Constructor;
8 8 import java.util.Set;
9 9
10 import org.gradle.api.InvalidUserDataException;
10 11 import org.implab.gradle.variants.core.Layer;
11 12 import org.implab.gradle.variants.core.Role;
12 13 import org.implab.gradle.variants.core.Variant;
@@ -60,7 +61,7 class RoleProjectionsViewTest {
60 61
61 62 var projections = RoleProjectionsView.of(view);
62 63
63 var ex = assertThrows(IllegalArgumentException.class, () -> projections.requireProjection(node, production));
64 var ex = assertThrows(InvalidUserDataException.class, () -> projections.requireProjection(node, production));
64 65 assertTrue(ex.getMessage().contains("Role projection for variant 'node' and role 'production' not found"));
65 66 }
66 67
@@ -63,7 +63,7 class CompileUnitNamerTest {
63 63 .addUnits(List.of(known))
64 64 .build();
65 65
66 var ex = assertThrows(IllegalArgumentException.class, () -> namer.resolveName(unknown));
66 var ex = assertThrows(InvalidUserDataException.class, () -> namer.resolveName(unknown));
67 67 assertTrue(ex.getMessage().contains("Compile unit"));
68 68 assertTrue(ex.getMessage().contains("associated name"));
69 69 }
@@ -3,6 +3,7 package org.implab.gradle.variants.sourc
3 3 import static org.junit.jupiter.api.Assertions.assertEquals;
4 4 import static org.junit.jupiter.api.Assertions.assertThrows;
5 5
6 import org.gradle.api.InvalidUserDataException;
6 7 import org.junit.jupiter.api.Test;
7 8
8 9 class DefaultCompileUnitNamingPolicyTest {
@@ -28,7 +29,7 class DefaultCompileUnitNamingPolicyTest
28 29
29 30 policy.resolveNameCollision();
30 31
31 assertThrows(IllegalStateException.class, policy::failOnNameCollision);
32 assertThrows(InvalidUserDataException.class, policy::failOnNameCollision);
32 33 }
33 34
34 35 @Test
@@ -37,6 +38,6 class DefaultCompileUnitNamingPolicyTest
37 38
38 39 policy.finalizePolicy();
39 40
40 assertThrows(IllegalStateException.class, policy::resolveNameCollision);
41 assertThrows(InvalidUserDataException.class, policy::resolveNameCollision);
41 42 }
42 43 }
@@ -3,6 +3,7 package org.implab.gradle.variants.sourc
3 3 import static org.junit.jupiter.api.Assertions.assertEquals;
4 4 import static org.junit.jupiter.api.Assertions.assertThrows;
5 5
6 import org.gradle.api.InvalidUserDataException;
6 7 import org.junit.jupiter.api.Test;
7 8
8 9 class DefaultLateConfigurationPolicySpecTest {
@@ -37,7 +38,7 class DefaultLateConfigurationPolicySpec
37 38
38 39 policy.warnOnLateConfiguration();
39 40
40 assertThrows(IllegalStateException.class, policy::failOnLateConfiguration);
41 assertThrows(InvalidUserDataException.class, policy::failOnLateConfiguration);
41 42 }
42 43
43 44 @Test
@@ -46,6 +47,6 class DefaultLateConfigurationPolicySpec
46 47
47 48 policy.finalizePolicy();
48 49
49 assertThrows(IllegalStateException.class, policy::allowLateConfiguration);
50 assertThrows(InvalidUserDataException.class, policy::allowLateConfiguration);
50 51 }
51 52 }
General Comments 0
You need to be logged in to leave comments. Login now