##// END OF EJS Templates
variants: enforce source configuration policies
cin -
r54:3469331e3c4b default
parent child
Show More
@@ -1,156 +1,157
1 package org.implab.gradle.variants;
1 package org.implab.gradle.variants;
2
2
3 import java.util.Objects;
3 import java.util.Objects;
4 import java.util.function.Predicate;
4 import java.util.function.Predicate;
5
5
6 import org.eclipse.jdt.annotation.NonNullByDefault;
6 import org.eclipse.jdt.annotation.NonNullByDefault;
7 import org.gradle.api.Action;
7 import org.gradle.api.Action;
8 import org.gradle.api.InvalidUserDataException;
8 import org.gradle.api.InvalidUserDataException;
9 import org.gradle.api.Named;
9 import org.gradle.api.Named;
10 import org.gradle.api.Plugin;
10 import org.gradle.api.Plugin;
11 import org.gradle.api.Project;
11 import org.gradle.api.Project;
12 import org.implab.gradle.common.core.lang.Deferred;
12 import org.implab.gradle.common.core.lang.Deferred;
13 import org.implab.gradle.common.core.lang.Strings;
13 import org.implab.gradle.common.core.lang.Strings;
14 import org.implab.gradle.variants.core.Layer;
14 import org.implab.gradle.variants.core.Layer;
15 import org.implab.gradle.variants.core.Variant;
15 import org.implab.gradle.variants.core.Variant;
16 import org.implab.gradle.variants.core.VariantsExtension;
16 import org.implab.gradle.variants.core.VariantsExtension;
17 import org.implab.gradle.variants.core.VariantsView;
17 import org.implab.gradle.variants.core.VariantsView;
18 import org.implab.gradle.variants.sources.CompileUnit;
18 import org.implab.gradle.variants.sources.CompileUnit;
19 import org.implab.gradle.variants.sources.CompileUnitsView;
19 import org.implab.gradle.variants.sources.CompileUnitsView;
20 import org.implab.gradle.variants.sources.GenericSourceSet;
20 import org.implab.gradle.variants.sources.GenericSourceSet;
21 import org.implab.gradle.variants.sources.RoleProjectionsView;
21 import org.implab.gradle.variants.sources.RoleProjectionsView;
22 import org.implab.gradle.variants.sources.VariantSourcesContext;
22 import org.implab.gradle.variants.sources.VariantSourcesContext;
23 import org.implab.gradle.variants.sources.VariantSourcesExtension;
23 import org.implab.gradle.variants.sources.VariantSourcesExtension;
24 import org.implab.gradle.variants.sources.internal.CompileUnitNamer;
24 import org.implab.gradle.variants.sources.internal.CompileUnitNamer;
25 import org.implab.gradle.variants.sources.internal.DefaultCompileUnitNamingPolicy;
25 import org.implab.gradle.variants.sources.internal.DefaultCompileUnitNamingPolicy;
26 import org.implab.gradle.variants.sources.internal.DefaultLateConfigurationPolicySpec;
26 import org.implab.gradle.variants.sources.internal.DefaultLateConfigurationPolicySpec;
27 import org.implab.gradle.variants.sources.internal.DefaultVariantSourcesContext;
27 import org.implab.gradle.variants.sources.internal.DefaultVariantSourcesContext;
28 import org.implab.gradle.variants.sources.internal.SourceSetConfigurationRegistry;
28 import org.implab.gradle.variants.sources.internal.SourceSetConfigurationRegistry;
29 import org.implab.gradle.variants.sources.internal.SourceSetRegistry;
29 import org.implab.gradle.variants.sources.internal.SourceSetRegistry;
30
30
31 @NonNullByDefault
31 @NonNullByDefault
32 public abstract class VariantSourcesPlugin implements Plugin<Project> {
32 public abstract class VariantSourcesPlugin implements Plugin<Project> {
33 public static final String VARIANT_SOURCES_EXTENSION = "variantSources";
33 public static final String VARIANT_SOURCES_EXTENSION = "variantSources";
34
34
35 @Override
35 @Override
36 public void apply(Project target) {
36 public void apply(Project target) {
37 var extensions = target.getExtensions();
37 var extensions = target.getExtensions();
38
38
39 // Apply the main VariantsPlugin to ensure the core variant model is available.
39 // Apply the main VariantsPlugin to ensure the core variant model is available.
40 target.getPlugins().apply(VariantsPlugin.class);
40 target.getPlugins().apply(VariantsPlugin.class);
41 // Access the VariantsExtension to configure variant sources.
41 // Access the VariantsExtension to configure variant sources.
42 var variantsExtension = extensions.getByType(VariantsExtension.class);
42 var variantsExtension = extensions.getByType(VariantsExtension.class);
43 var objectFactory = target.getObjects();
43 var objectFactory = target.getObjects();
44
44
45 var deferred = new Deferred<VariantSourcesContext>();
45 var deferred = new Deferred<VariantSourcesContext>();
46
46
47 var lateConfigurationPolicy = new DefaultLateConfigurationPolicySpec();
47 var lateConfigurationPolicy = new DefaultLateConfigurationPolicySpec();
48 var namingPolicy = new DefaultCompileUnitNamingPolicy();
48 var namingPolicy = new DefaultCompileUnitNamingPolicy();
49
49
50 variantsExtension.whenFinalized(variants -> {
50 variantsExtension.whenFinalized(variants -> {
51 // create variant views
51 // create variant views
52 var compileUnits = CompileUnitsView.of(variants);
52 var compileUnits = CompileUnitsView.of(variants);
53 var roleProjections = RoleProjectionsView.of(variants);
53 var roleProjections = RoleProjectionsView.of(variants);
54
54
55 // create registries
55 // create registries
56 var sourceSetRegistry = new SourceSetRegistry(objectFactory);
56 var sourceSetRegistry = new SourceSetRegistry(objectFactory);
57 lateConfigurationPolicy.finalizePolicy();
57 var sourceSetConfiguration = new SourceSetConfigurationRegistry(lateConfigurationPolicy::mode);
58 var sourceSetConfiguration = new SourceSetConfigurationRegistry(lateConfigurationPolicy::mode);
58
59
59 // build compile unit namer
60 // build compile unit namer
60 var compileUnitNamer = CompileUnitNamer.builder()
61 var compileUnitNamer = CompileUnitNamer.builder()
61 .addUnits(compileUnits.getUnits())
62 .addUnits(compileUnits.getUnits())
62 .nameCollisionPolicy(namingPolicy.policy())
63 .nameCollisionPolicy(namingPolicy.policy())
63 .build();
64 .build();
64
65
65 // create the context
66 // create the context
66 var context = new DefaultVariantSourcesContext(
67 var context = new DefaultVariantSourcesContext(
67 variants,
68 variants,
68 compileUnits,
69 compileUnits,
69 roleProjections,
70 roleProjections,
70 compileUnitNamer,
71 compileUnitNamer,
71 sourceSetRegistry,
72 sourceSetRegistry,
72 sourceSetConfiguration
73 sourceSetConfiguration
73 );
74 );
74 deferred.resolve(context);
75 deferred.resolve(context);
75 });
76 });
76
77
77 var variantSourcesExtension = new VariantSourcesExtension() {
78 var variantSourcesExtension = new VariantSourcesExtension() {
78 @Override
79 @Override
79 public void whenFinalized(Action<? super VariantSourcesContext> action) {
80 public void whenFinalized(Action<? super VariantSourcesContext> action) {
80 deferred.whenResolved(action::execute);
81 deferred.whenResolved(action::execute);
81 }
82 }
82
83
83 @Override
84 @Override
84 public void lateConfigurationPolicy(Action<? super LateConfigurationPolicySpec> action) {
85 public void lateConfigurationPolicy(Action<? super LateConfigurationPolicySpec> action) {
85 action.execute(lateConfigurationPolicy);
86 action.execute(lateConfigurationPolicy);
86 }
87 }
87
88
88 @Override
89 @Override
89 public void namingPolicy(Action<? super NamingPolicySpec> action) {
90 public void namingPolicy(Action<? super NamingPolicySpec> action) {
90 action.execute(namingPolicy);
91 action.execute(namingPolicy);
91 }
92 }
92
93
93 @Override
94 @Override
94 public void variant(String variantName, Action<? super GenericSourceSet> action) {
95 public void variant(String variantName, Action<? super GenericSourceSet> action) {
95 Strings.argumentNotNullOrBlank(variantName, "variantName");
96 Strings.argumentNotNullOrBlank(variantName, "variantName");
96 Objects.requireNonNull(action, "action can't be null");
97 Objects.requireNonNull(action, "action can't be null");
97
98
98 lateConfigurationPolicy.finalizePolicy();
99 lateConfigurationPolicy.finalizePolicy();
99
100
100 whenFinalized(ctx -> ctx.configureVariant(resolveVariant(ctx.getVariants(), variantName), action));
101 whenFinalized(ctx -> ctx.configureVariant(resolveVariant(ctx.getVariants(), variantName), action));
101 }
102 }
102
103
103 @Override
104 @Override
104 public void layer(String layerName, Action<? super GenericSourceSet> action) {
105 public void layer(String layerName, Action<? super GenericSourceSet> action) {
105 // protect external DSL
106 // protect external DSL
106 Strings.argumentNotNullOrBlank(layerName, "layerName");
107 Strings.argumentNotNullOrBlank(layerName, "layerName");
107 Objects.requireNonNull(action, "action can't be null");
108 Objects.requireNonNull(action, "action can't be null");
108
109
109 lateConfigurationPolicy.finalizePolicy();
110 lateConfigurationPolicy.finalizePolicy();
110
111
111 whenFinalized(ctx -> ctx.configureLayer(resolveLayer(ctx.getVariants(), layerName), action));
112 whenFinalized(ctx -> ctx.configureLayer(resolveLayer(ctx.getVariants(), layerName), action));
112 }
113 }
113
114
114 @Override
115 @Override
115 public void unit(String variantName, String layerName, Action<? super GenericSourceSet> action) {
116 public void unit(String variantName, String layerName, Action<? super GenericSourceSet> action) {
116 Strings.argumentNotNullOrBlank(layerName, "layerName");
117 Strings.argumentNotNullOrBlank(layerName, "layerName");
117 Strings.argumentNotNullOrBlank(variantName, "variantName");
118 Strings.argumentNotNullOrBlank(variantName, "variantName");
118 Objects.requireNonNull(action, "action can't be null");
119 Objects.requireNonNull(action, "action can't be null");
119
120
120 lateConfigurationPolicy.finalizePolicy();
121 lateConfigurationPolicy.finalizePolicy();
121
122
122 whenFinalized(ctx -> ctx.configureUnit(resolveCompileUnit(ctx, variantName, layerName), action));
123 whenFinalized(ctx -> ctx.configureUnit(resolveCompileUnit(ctx, variantName, layerName), action));
123 }
124 }
124 };
125 };
125
126
126 extensions.add(VariantSourcesExtension.class, VARIANT_SOURCES_EXTENSION, variantSourcesExtension);
127 extensions.add(VariantSourcesExtension.class, VARIANT_SOURCES_EXTENSION, variantSourcesExtension);
127
128
128 }
129 }
129
130
130 private static Layer resolveLayer(VariantsView variants, String name) {
131 private static Layer resolveLayer(VariantsView variants, String name) {
131 return variants.getLayers().stream()
132 return variants.getLayers().stream()
132 .filter(named(name))
133 .filter(named(name))
133 .findAny()
134 .findAny()
134 .orElseThrow(() -> new IllegalArgumentException("Layer '" + name + "' isn't declared"));
135 .orElseThrow(() -> new InvalidUserDataException("Layer '" + name + "' isn't declared"));
135 }
136 }
136
137
137 private static Variant resolveVariant(VariantsView variants, String name) {
138 private static Variant resolveVariant(VariantsView variants, String name) {
138 return variants.getVariants().stream()
139 return variants.getVariants().stream()
139 .filter(named(name))
140 .filter(named(name))
140 .findAny()
141 .findAny()
141 .orElseThrow(() -> new IllegalArgumentException("Variant '" + name + "' is't declared"));
142 .orElseThrow(() -> new InvalidUserDataException("Variant '" + name + "' isn't declared"));
142 }
143 }
143
144
144 private static CompileUnit resolveCompileUnit(VariantSourcesContext ctx, String variantName, String layerName) {
145 private static CompileUnit resolveCompileUnit(VariantSourcesContext ctx, String variantName, String layerName) {
145 return ctx.getCompileUnits().findUnit(
146 return ctx.getCompileUnits().findUnit(
146 resolveVariant(ctx.getVariants(), variantName),
147 resolveVariant(ctx.getVariants(), variantName),
147 resolveLayer(ctx.getVariants(), layerName))
148 resolveLayer(ctx.getVariants(), layerName))
148 .orElseThrow(() -> new InvalidUserDataException(
149 .orElseThrow(() -> new InvalidUserDataException(
149 "The CompileUnit isn't declared for variant '" + variantName + "', layer '" + layerName + "'"));
150 "The CompileUnit isn't declared for variant '" + variantName + "', layer '" + layerName + "'"));
150 }
151 }
151
152
152 private static Predicate<Named> named(String name) {
153 private static Predicate<Named> named(String name) {
153 return named -> named.getName().equals(name);
154 return named -> named.getName().equals(name);
154 }
155 }
155
156
156 }
157 }
@@ -1,167 +1,170
1 package org.implab.gradle.variants.sources;
1 package org.implab.gradle.variants.sources;
2
2
3 import org.eclipse.jdt.annotation.NonNullByDefault;
3 import org.eclipse.jdt.annotation.NonNullByDefault;
4 import org.gradle.api.Action;
4 import org.gradle.api.Action;
5 import org.implab.gradle.common.core.lang.Closures;
5 import org.implab.gradle.common.core.lang.Closures;
6 import groovy.lang.Closure;
6 import groovy.lang.Closure;
7
7
8 @NonNullByDefault
8 @NonNullByDefault
9 public interface VariantSourcesExtension {
9 public interface VariantSourcesExtension {
10
10
11 /**
11 /**
12 * Selects how selector rules behave when they target an already materialized
12 * Selects how selector rules behave when they target an already materialized
13 * {@link GenericSourceSet}.
13 * {@link GenericSourceSet}.
14 *
14 *
15 * <p>This policy is single-valued:
15 * <p>This policy is single-valued:
16 * <ul>
16 * <ul>
17 * <li>it must be selected before the first selector rule is registered via
17 * <li>it must be selected before the first selector rule is registered via
18 * {@link #variant(String, Action)}, {@link #layer(String, Action)} or
18 * {@link #variant(String, Action)}, {@link #layer(String, Action)} or
19 * {@link #unit(String, String, Action)};</li>
19 * {@link #unit(String, String, Action)};</li>
20 * <li>once selected, it cannot be changed later;</li>
20 * <li>it must be selected before the finalized context becomes observable via
21 * {@link #whenFinalized(Action)};</li>
22 * <li>once selected or once the finalized context is being created, it cannot
23 * be changed later;</li>
21 * <li>the policy controls both diagnostics and late-application semantics.</li>
24 * <li>the policy controls both diagnostics and late-application semantics.</li>
22 * </ul>
25 * </ul>
23 *
26 *
24 * <p>If not selected explicitly, the default is
27 * <p>If not selected explicitly, the default is
25 * {@link LateConfigurationPolicySpec#failOnLateConfiguration()}.
28 * {@link LateConfigurationPolicySpec#failOnLateConfiguration()}.
26 */
29 */
27 void lateConfigurationPolicy(Action<? super LateConfigurationPolicySpec> action);
30 void lateConfigurationPolicy(Action<? super LateConfigurationPolicySpec> action);
28
31
29 default void lateConfigurationPolicy(Closure<?> closure) {
32 default void lateConfigurationPolicy(Closure<?> closure) {
30 lateConfigurationPolicy(Closures.action(closure));
33 lateConfigurationPolicy(Closures.action(closure));
31 }
34 }
32
35
33 /**
36 /**
34 * Selects how compile-unit name collisions are handled when the finalized
37 * Selects how compile-unit name collisions are handled when the finalized
35 * source context is created.
38 * source context is created.
36 *
39 *
37 * <p>This policy is single-valued:
40 * <p>This policy is single-valued:
38 * <ul>
41 * <ul>
39 * <li>it must be selected before the finalized
42 * <li>it must be selected before the finalized
40 * {@link VariantSourcesContext} becomes observable through
43 * {@link VariantSourcesContext} becomes observable through
41 * {@link #whenFinalized(Action)};</li>
44 * {@link #whenFinalized(Action)};</li>
42 * <li>once the context is being created, the policy is fixed and cannot be
45 * <li>once the context is being created, the policy is fixed and cannot be
43 * changed later;</li>
46 * changed later;</li>
44 * <li>the policy governs validation of compile-unit names produced by the
47 * <li>the policy governs validation of compile-unit names produced by the
45 * source-set materializer.</li>
48 * source-set materializer.</li>
46 * </ul>
49 * </ul>
47 *
50 *
48 * <p>If not selected explicitly, the default is
51 * <p>If not selected explicitly, the default is
49 * {@link NamingPolicySpec#failOnNameCollision()}.
52 * {@link NamingPolicySpec#failOnNameCollision()}.
50 */
53 */
51 void namingPolicy(Action<? super NamingPolicySpec> action);
54 void namingPolicy(Action<? super NamingPolicySpec> action);
52
55
53 default void namingPolicy(Closure<?> closure) {
56 default void namingPolicy(Closure<?> closure) {
54 namingPolicy(Closures.action(closure));
57 namingPolicy(Closures.action(closure));
55 }
58 }
56
59
57 /**
60 /**
58 * Registers a selector rule for all compile units of the given layer.
61 * Registers a selector rule for all compile units of the given layer.
59 *
62 *
60 * <p>Registering the first selector rule fixes the selected
63 * <p>Registering the first selector rule fixes the selected
61 * {@link #lateConfigurationPolicy(Action)} for the remaining extension
64 * {@link #lateConfigurationPolicy(Action)} for the remaining extension
62 * lifecycle.
65 * lifecycle.
63 */
66 */
64 void layer(String layerName, Action<? super GenericSourceSet> action);
67 void layer(String layerName, Action<? super GenericSourceSet> action);
65
68
66 default void layer(String layerName, Closure<?> closure) {
69 default void layer(String layerName, Closure<?> closure) {
67 layer(layerName, Closures.action(closure));
70 layer(layerName, Closures.action(closure));
68 }
71 }
69
72
70 /**
73 /**
71 * Registers a selector rule for all compile units of the given variant.
74 * Registers a selector rule for all compile units of the given variant.
72 *
75 *
73 * <p>Registering the first selector rule fixes the selected
76 * <p>Registering the first selector rule fixes the selected
74 * {@link #lateConfigurationPolicy(Action)} for the remaining extension
77 * {@link #lateConfigurationPolicy(Action)} for the remaining extension
75 * lifecycle.
78 * lifecycle.
76 */
79 */
77 void variant(String variantName, Action<? super GenericSourceSet> action);
80 void variant(String variantName, Action<? super GenericSourceSet> action);
78
81
79 default void variant(String variantName, Closure<?> closure) {
82 default void variant(String variantName, Closure<?> closure) {
80 variant(variantName, Closures.action(closure));
83 variant(variantName, Closures.action(closure));
81 }
84 }
82
85
83 /**
86 /**
84 * Registers a selector rule for one exact compile unit.
87 * Registers a selector rule for one exact compile unit.
85 *
88 *
86 * <p>Registering the first selector rule fixes the selected
89 * <p>Registering the first selector rule fixes the selected
87 * {@link #lateConfigurationPolicy(Action)} for the remaining extension
90 * {@link #lateConfigurationPolicy(Action)} for the remaining extension
88 * lifecycle.
91 * lifecycle.
89 */
92 */
90 void unit(String variantName, String layerName, Action<? super GenericSourceSet> action);
93 void unit(String variantName, String layerName, Action<? super GenericSourceSet> action);
91
94
92 default void unit(String variantName, String layerName, Closure<?> closure) {
95 default void unit(String variantName, String layerName, Closure<?> closure) {
93 unit(variantName, layerName, Closures.action(closure));
96 unit(variantName, layerName, Closures.action(closure));
94 }
97 }
95
98
96 /**
99 /**
97 * Invoked when finalized variants-derived source context becomes available.
100 * Invoked when finalized variants-derived source context becomes available.
98 *
101 *
99 * Replayable:
102 * Replayable:
100 * <ul>
103 * <ul>
101 * <li>if called before variants finalization, action is queued
104 * <li>if called before variants finalization, action is queued
102 * <li>if called after variants finalization, action is invoked immediately
105 * <li>if called after variants finalization, action is invoked immediately
103 * </ul>
106 * </ul>
104 *
107 *
105 * <p>By the time this callback becomes observable, compile-unit naming
108 * <p>By the time this callback becomes observable, compile-unit naming
106 * policy has already been fixed and symbolic source-set names for finalized
109 * policy has already been fixed and symbolic source-set names for finalized
107 * compile units are determined.
110 * compile units are determined.
108 */
111 */
109 void whenFinalized(Action<? super VariantSourcesContext> action);
112 void whenFinalized(Action<? super VariantSourcesContext> action);
110
113
111 default void whenFinalized(Closure<?> closure) {
114 default void whenFinalized(Closure<?> closure) {
112 whenFinalized(Closures.action(closure));
115 whenFinalized(Closures.action(closure));
113 }
116 }
114
117
115
118
116 /**
119 /**
117 * Imperative selector for the late-configuration mode.
120 * Imperative selector for the late-configuration mode.
118 *
121 *
119 * <p>Exactly one mode is expected to be chosen for the extension lifecycle.
122 * <p>Exactly one mode is expected to be chosen for the extension lifecycle.
120 */
123 */
121 interface LateConfigurationPolicySpec {
124 interface LateConfigurationPolicySpec {
122 /**
125 /**
123 * Rejects selector registration if it targets any already materialized
126 * Rejects selector registration if it targets any already materialized
124 * source set.
127 * source set.
125 */
128 */
126 void failOnLateConfiguration();
129 void failOnLateConfiguration();
127
130
128 /**
131 /**
129 * Allows late selector registration, but emits a warning when it targets an
132 * Allows late selector registration, but emits a warning when it targets an
130 * already materialized source set.
133 * already materialized source set.
131 *
134 *
132 * <p>For such targets, selector precedence is not re-established
135 * <p>For such targets, selector precedence is not re-established
133 * retroactively. The action is applied as a late imperative step, after the
136 * retroactively. The action is applied as a late imperative step, after the
134 * state already produced at the materialization moment.
137 * state already produced at the materialization moment.
135 */
138 */
136 void warnOnLateConfiguration();
139 void warnOnLateConfiguration();
137
140
138 /**
141 /**
139 * Allows late selector registration without a warning when it targets an
142 * Allows late selector registration without a warning when it targets an
140 * already materialized source set.
143 * already materialized source set.
141 *
144 *
142 * <p>For such targets, selector precedence is not re-established
145 * <p>For such targets, selector precedence is not re-established
143 * retroactively. The action is applied as a late imperative step, after the
146 * retroactively. The action is applied as a late imperative step, after the
144 * state already produced at the materialization moment.
147 * state already produced at the materialization moment.
145 */
148 */
146 void allowLateConfiguration();
149 void allowLateConfiguration();
147 }
150 }
148
151
149 interface NamingPolicySpec {
152 interface NamingPolicySpec {
150 /**
153 /**
151 * Rejects finalized compile-unit models that project the same source-set
154 * Rejects finalized compile-unit models that project the same source-set
152 * name for different compile units.
155 * name for different compile units.
153 */
156 */
154 void failOnNameCollision();
157 void failOnNameCollision();
155
158
156 /**
159 /**
157 * Resolves name collisions deterministically for the finalized
160 * Resolves name collisions deterministically for the finalized
158 * compile-unit model.
161 * compile-unit model.
159 *
162 *
160 * <p>Conflicting compile units are ordered canonically by
163 * <p>Conflicting compile units are ordered canonically by
161 * {@code (variant.name, layer.name)}. The first unit keeps the base
164 * {@code (variant.name, layer.name)}. The first unit keeps the base
162 * projected name, and each next unit receives a numeric suffix
165 * projected name, and each next unit receives a numeric suffix
163 * ({@code 2}, {@code 3}, ...).
166 * ({@code 2}, {@code 3}, ...).
164 */
167 */
165 void resolveNameCollision();
168 void resolveNameCollision();
166 }
169 }
167 }
170 }
@@ -1,42 +1,43
1 package org.implab.gradle.variants.sources.internal;
1 package org.implab.gradle.variants.sources.internal;
2
2
3 import org.implab.gradle.variants.sources.VariantSourcesExtension.LateConfigurationPolicySpec;
3 import org.implab.gradle.variants.sources.VariantSourcesExtension.LateConfigurationPolicySpec;
4
4
5 public class DefaultLateConfigurationPolicySpec implements LateConfigurationPolicySpec {
5 public class DefaultLateConfigurationPolicySpec implements LateConfigurationPolicySpec {
6
6
7 private LateConfigurationMode policyMode = LateConfigurationMode.FAIL;
7 private LateConfigurationMode policyMode = LateConfigurationMode.FAIL;
8 private boolean policyApplied = false;
8 private boolean policyApplied = false;
9
9
10 public LateConfigurationMode mode() {
10 public LateConfigurationMode mode() {
11 finalizePolicy();
11 return policyMode;
12 return policyMode;
12 }
13 }
13
14
14 public void finalizePolicy() {
15 public void finalizePolicy() {
15 policyApplied = true;
16 policyApplied = true;
16 }
17 }
17
18
18 @Override
19 @Override
19 public void failOnLateConfiguration() {
20 public void failOnLateConfiguration() {
20 assertApplyOnce();
21 assertApplyOnce();
21 policyMode = LateConfigurationMode.FAIL;
22 policyMode = LateConfigurationMode.FAIL;
22 }
23 }
23
24
24 @Override
25 @Override
25 public void warnOnLateConfiguration() {
26 public void warnOnLateConfiguration() {
26 assertApplyOnce();
27 assertApplyOnce();
27 policyMode = LateConfigurationMode.WARN;
28 policyMode = LateConfigurationMode.WARN;
28 }
29 }
29
30
30 @Override
31 @Override
31 public void allowLateConfiguration() {
32 public void allowLateConfiguration() {
32 assertApplyOnce();
33 assertApplyOnce();
33 policyMode = LateConfigurationMode.APPLY;
34 policyMode = LateConfigurationMode.APPLY;
34 }
35 }
35
36
36 private void assertApplyOnce() {
37 private void assertApplyOnce() {
37 if (policyApplied)
38 if (policyApplied)
38 throw new IllegalStateException("Lazy configuration policy already applied");
39 throw new IllegalStateException("Lazy configuration policy already applied");
39 policyApplied = true;
40 policyApplied = true;
40 }
41 }
41
42
42 }
43 }
@@ -1,431 +1,454
1 package org.implab.gradle.variants;
1 package org.implab.gradle.variants;
2
2
3 import static org.junit.jupiter.api.Assertions.assertTrue;
3 import static org.junit.jupiter.api.Assertions.assertTrue;
4
4
5 import org.gradle.testkit.runner.BuildResult;
5 import org.gradle.testkit.runner.BuildResult;
6 import org.junit.jupiter.api.Test;
6 import org.junit.jupiter.api.Test;
7
7
8 class VariantSourcesPluginFunctionalTest extends AbstractFunctionalTest {
8 class VariantSourcesPluginFunctionalTest extends AbstractFunctionalTest {
9
9
10 @Test
10 @Test
11 void exposesDerivedViewsAndStableSourceSetProvider() throws Exception {
11 void exposesDerivedViewsAndStableSourceSetProvider() throws Exception {
12 writeSettings("variant-sources-derived-views");
12 writeSettings("variant-sources-derived-views");
13 writeBuildFile("""
13 writeBuildFile("""
14 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
14 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
15
15
16 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
16 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
17 variantsExt.layers.create('main')
17 variantsExt.layers.create('main')
18 variantsExt.layers.create('test')
18 variantsExt.layers.create('test')
19 variantsExt.roles.create('production')
19 variantsExt.roles.create('production')
20 variantsExt.roles.create('test')
20 variantsExt.roles.create('test')
21
21
22 variantsExt.variant('browser') {
22 variantsExt.variant('browser') {
23 role('production') { layers('main') }
23 role('production') { layers('main') }
24 role('test') { layers('main', 'test') }
24 role('test') { layers('main', 'test') }
25 }
25 }
26
26
27 def lines = []
27 def lines = []
28
28
29 variantSources.whenFinalized { ctx ->
29 variantSources.whenFinalized { ctx ->
30 lines << "units=" + ctx.compileUnits.units
30 lines << "units=" + ctx.compileUnits.units
31 .collect { "${it.variant().name}:${it.layer().name}" }
31 .collect { "${it.variant().name}:${it.layer().name}" }
32 .sort()
32 .sort()
33 .join(',')
33 .join(',')
34
34
35 def browser = ctx.variants.variants.find { it.name == 'browser' }
35 def browser = ctx.variants.variants.find { it.name == 'browser' }
36 def production = ctx.variants.roles.find { it.name == 'production' }
36 def production = ctx.variants.roles.find { it.name == 'production' }
37 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
37 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
38 def projection = ctx.roleProjections.requireProjection(browser, production)
38 def projection = ctx.roleProjections.requireProjection(browser, production)
39 def unit = ctx.compileUnits.requireUnit(browser, mainLayer)
39 def unit = ctx.compileUnits.requireUnit(browser, mainLayer)
40
40
41 def left = ctx.sourceSets.getSourceSet(unit)
41 def left = ctx.sourceSets.getSourceSet(unit)
42 def right = ctx.sourceSets.getSourceSet(unit)
42 def right = ctx.sourceSets.getSourceSet(unit)
43
43
44 lines << "projectionUnits=" + ctx.roleProjections.getUnits(projection)
44 lines << "projectionUnits=" + ctx.roleProjections.getUnits(projection)
45 .collect { it.layer().name }
45 .collect { it.layer().name }
46 .sort()
46 .sort()
47 .join(',')
47 .join(',')
48 lines << "mainSourceSet=" + left.name
48 lines << "mainSourceSet=" + left.name
49 lines << "sameProvider=" + left.is(right)
49 lines << "sameProvider=" + left.is(right)
50 }
50 }
51
51
52 afterEvaluate {
52 afterEvaluate {
53 variantSources.whenFinalized { ctx ->
53 variantSources.whenFinalized { ctx ->
54 lines << "late:variants=" + ctx.variants.variants.collect { it.name }.sort().join(',')
54 lines << "late:variants=" + ctx.variants.variants.collect { it.name }.sort().join(',')
55 }
55 }
56 }
56 }
57
57
58 tasks.register('probe') {
58 tasks.register('probe') {
59 doLast {
59 doLast {
60 lines.each { println(it) }
60 lines.each { println(it) }
61 }
61 }
62 }
62 }
63 """);
63 """);
64
64
65 BuildResult result = runner("probe").build();
65 BuildResult result = runner("probe").build();
66
66
67 assertTrue(result.getOutput().contains("units=browser:main,browser:test"));
67 assertTrue(result.getOutput().contains("units=browser:main,browser:test"));
68 assertTrue(result.getOutput().contains("projectionUnits=main"));
68 assertTrue(result.getOutput().contains("projectionUnits=main"));
69 assertTrue(result.getOutput().contains("mainSourceSet=browserMain"));
69 assertTrue(result.getOutput().contains("mainSourceSet=browserMain"));
70 assertTrue(result.getOutput().contains("sameProvider=true"));
70 assertTrue(result.getOutput().contains("sameProvider=true"));
71 assertTrue(result.getOutput().contains("late:variants=browser"));
71 assertTrue(result.getOutput().contains("late:variants=browser"));
72 }
72 }
73
73
74 @Test
74 @Test
75 void appliesSelectorPrecedenceForFutureMaterialization() throws Exception {
75 void appliesSelectorPrecedenceForFutureMaterialization() throws Exception {
76 writeSettings("variant-sources-precedence");
76 writeSettings("variant-sources-precedence");
77 writeBuildFile("""
77 writeBuildFile("""
78 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
78 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
79
79
80 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
80 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
81 variantsExt.layers.create('main')
81 variantsExt.layers.create('main')
82 variantsExt.layers.create('test')
82 variantsExt.layers.create('test')
83 variantsExt.roles.create('production')
83 variantsExt.roles.create('production')
84 variantsExt.roles.create('test')
84 variantsExt.roles.create('test')
85
85
86 variantsExt.variant('browser') {
86 variantsExt.variant('browser') {
87 role('production') { layers('main') }
87 role('production') { layers('main') }
88 role('test') { layers('main', 'test') }
88 role('test') { layers('main', 'test') }
89 }
89 }
90
90
91 variantsExt.variant('node') {
91 variantsExt.variant('node') {
92 role('production') { layers('main') }
92 role('production') { layers('main') }
93 }
93 }
94
94
95 def events = []
95 def events = []
96
96
97 variantSources {
97 variantSources {
98 variant('browser') {
98 variant('browser') {
99 events << "variant:" + name
99 events << "variant:" + name
100 }
100 }
101 layer('main') {
101 layer('main') {
102 events << "layer:" + name
102 events << "layer:" + name
103 }
103 }
104 unit('browser', 'main') {
104 unit('browser', 'main') {
105 events << "unit:" + name
105 events << "unit:" + name
106 }
106 }
107 }
107 }
108
108
109 afterEvaluate {
109 afterEvaluate {
110 variantSources.whenFinalized { ctx ->
110 variantSources.whenFinalized { ctx ->
111 def browser = ctx.variants.variants.find { it.name == 'browser' }
111 def browser = ctx.variants.variants.find { it.name == 'browser' }
112 def node = ctx.variants.variants.find { it.name == 'node' }
112 def node = ctx.variants.variants.find { it.name == 'node' }
113 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
113 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
114 def testLayer = ctx.variants.layers.find { it.name == 'test' }
114 def testLayer = ctx.variants.layers.find { it.name == 'test' }
115
115
116 def browserMain = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(browser, mainLayer)).get()
116 def browserMain = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(browser, mainLayer)).get()
117 def browserTest = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(browser, testLayer)).get()
117 def browserTest = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(browser, testLayer)).get()
118 def nodeMain = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(node, mainLayer)).get()
118 def nodeMain = ctx.sourceSets.getSourceSet(ctx.compileUnits.requireUnit(node, mainLayer)).get()
119 def bySourceSet = events.groupBy { it.split(':', 2)[1] }
119 def bySourceSet = events.groupBy { it.split(':', 2)[1] }
120
120
121 println("browserMain=" + bySourceSet[browserMain.name].collect { it.split(':', 2)[0] }.join(','))
121 println("browserMain=" + bySourceSet[browserMain.name].collect { it.split(':', 2)[0] }.join(','))
122 println("browserTest=" + bySourceSet[browserTest.name].collect { it.split(':', 2)[0] }.join(','))
122 println("browserTest=" + bySourceSet[browserTest.name].collect { it.split(':', 2)[0] }.join(','))
123 println("nodeMain=" + bySourceSet[nodeMain.name].collect { it.split(':', 2)[0] }.join(','))
123 println("nodeMain=" + bySourceSet[nodeMain.name].collect { it.split(':', 2)[0] }.join(','))
124 }
124 }
125 }
125 }
126 """);
126 """);
127
127
128 BuildResult result = runner("help").build();
128 BuildResult result = runner("help").build();
129
129
130 assertTrue(result.getOutput().contains("browserMain=variant,layer,unit"));
130 assertTrue(result.getOutput().contains("browserMain=variant,layer,unit"));
131 assertTrue(result.getOutput().contains("browserTest=variant"));
131 assertTrue(result.getOutput().contains("browserTest=variant"));
132 assertTrue(result.getOutput().contains("nodeMain=layer"));
132 assertTrue(result.getOutput().contains("nodeMain=layer"));
133 }
133 }
134
134
135 @Test
135 @Test
136 void failsLateConfigurationByDefaultAfterMaterialization() throws Exception {
136 void failsLateConfigurationByDefaultAfterMaterialization() throws Exception {
137 writeSettings("variant-sources-late-fail");
137 writeSettings("variant-sources-late-fail");
138 writeBuildFile("""
138 writeBuildFile("""
139 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
139 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
140
140
141 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
141 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
142 variantsExt.layers.create('main')
142 variantsExt.layers.create('main')
143 variantsExt.roles.create('production')
143 variantsExt.roles.create('production')
144 variantsExt.variant('browser') {
144 variantsExt.variant('browser') {
145 role('production') { layers('main') }
145 role('production') { layers('main') }
146 }
146 }
147
147
148 afterEvaluate {
148 afterEvaluate {
149 variantSources.whenFinalized { ctx ->
149 variantSources.whenFinalized { ctx ->
150 def browser = ctx.variants.variants.find { it.name == 'browser' }
150 def browser = ctx.variants.variants.find { it.name == 'browser' }
151 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
151 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
152 def unit = ctx.compileUnits.requireUnit(browser, mainLayer)
152 def unit = ctx.compileUnits.requireUnit(browser, mainLayer)
153
153
154 ctx.sourceSets.getSourceSet(unit).get()
154 ctx.sourceSets.getSourceSet(unit).get()
155 variantSources.layer('main') {
155 variantSources.layer('main') {
156 declareOutputs('late')
156 declareOutputs('late')
157 }
157 }
158 }
158 }
159 }
159 }
160 """);
160 """);
161
161
162 assertBuildFails("Source sets for [layer=main] layer already materialized", "help");
162 assertBuildFails("Source sets for [layer=main] layer already materialized", "help");
163 }
163 }
164
164
165 @Test
165 @Test
166 void allowsLateConfigurationWhenSelectedBeforeFirstSelector() throws Exception {
166 void allowsLateConfigurationWhenSelectedBeforeFirstSelector() throws Exception {
167 writeSettings("variant-sources-late-allow");
167 writeSettings("variant-sources-late-allow");
168 writeBuildFile("""
168 writeBuildFile("""
169 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
169 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
170
170
171 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
171 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
172 variantsExt.layers.create('main')
172 variantsExt.layers.create('main')
173 variantsExt.roles.create('production')
173 variantsExt.roles.create('production')
174 variantsExt.variant('browser') {
174 variantsExt.variant('browser') {
175 role('production') { layers('main') }
175 role('production') { layers('main') }
176 }
176 }
177
177
178 variantSources {
178 variantSources {
179 lateConfigurationPolicy {
179 lateConfigurationPolicy {
180 allowLateConfiguration()
180 allowLateConfiguration()
181 }
181 }
182 }
182 }
183
183
184 afterEvaluate {
184 afterEvaluate {
185 variantSources.whenFinalized { ctx ->
185 variantSources.whenFinalized { ctx ->
186 def browser = ctx.variants.variants.find { it.name == 'browser' }
186 def browser = ctx.variants.variants.find { it.name == 'browser' }
187 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
187 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
188 def unit = ctx.compileUnits.requireUnit(browser, mainLayer)
188 def unit = ctx.compileUnits.requireUnit(browser, mainLayer)
189
189
190 def sourceSet = ctx.sourceSets.getSourceSet(unit).get()
190 def sourceSet = ctx.sourceSets.getSourceSet(unit).get()
191 variantSources.layer('main') {
191 variantSources.layer('main') {
192 declareOutputs('late')
192 declareOutputs('late')
193 }
193 }
194 sourceSet.output('late')
194 sourceSet.output('late')
195 println('lateAllowed=ok')
195 println('lateAllowed=ok')
196 }
196 }
197 }
197 }
198 """);
198 """);
199
199
200 BuildResult result = runner("help").build();
200 BuildResult result = runner("help").build();
201 assertTrue(result.getOutput().contains("lateAllowed=ok"));
201 assertTrue(result.getOutput().contains("lateAllowed=ok"));
202 }
202 }
203
203
204 @Test
204 @Test
205 void warnsAndAppliesLateConfigurationWhenWarnModeSelected() throws Exception {
205 void warnsAndAppliesLateConfigurationWhenWarnModeSelected() throws Exception {
206 writeSettings("variant-sources-late-warn");
206 writeSettings("variant-sources-late-warn");
207 writeBuildFile("""
207 writeBuildFile("""
208 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
208 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
209
209
210 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
210 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
211 variantsExt.layers.create('main')
211 variantsExt.layers.create('main')
212 variantsExt.roles.create('production')
212 variantsExt.roles.create('production')
213 variantsExt.variant('browser') {
213 variantsExt.variant('browser') {
214 role('production') { layers('main') }
214 role('production') { layers('main') }
215 }
215 }
216
216
217 variantSources {
217 variantSources {
218 lateConfigurationPolicy {
218 lateConfigurationPolicy {
219 warnOnLateConfiguration()
219 warnOnLateConfiguration()
220 }
220 }
221 }
221 }
222
222
223 afterEvaluate {
223 afterEvaluate {
224 variantSources.whenFinalized { ctx ->
224 variantSources.whenFinalized { ctx ->
225 def browser = ctx.variants.variants.find { it.name == 'browser' }
225 def browser = ctx.variants.variants.find { it.name == 'browser' }
226 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
226 def mainLayer = ctx.variants.layers.find { it.name == 'main' }
227 def unit = ctx.compileUnits.requireUnit(browser, mainLayer)
227 def unit = ctx.compileUnits.requireUnit(browser, mainLayer)
228
228
229 def sourceSet = ctx.sourceSets.getSourceSet(unit).get()
229 def sourceSet = ctx.sourceSets.getSourceSet(unit).get()
230 variantSources.layer('main') {
230 variantSources.layer('main') {
231 declareOutputs('late')
231 declareOutputs('late')
232 }
232 }
233 sourceSet.output('late')
233 sourceSet.output('late')
234 println('lateWarn=ok')
234 println('lateWarn=ok')
235 }
235 }
236 }
236 }
237 """);
237 """);
238
238
239 BuildResult result = runner("help").build();
239 BuildResult result = runner("help").build();
240
240
241 assertTrue(result.getOutput().contains("Source sets for [layer=main] layer already materialized"));
241 assertTrue(result.getOutput().contains("Source sets for [layer=main] layer already materialized"));
242 assertTrue(result.getOutput().contains("lateWarn=ok"));
242 assertTrue(result.getOutput().contains("lateWarn=ok"));
243 }
243 }
244
244
245 @Test
245 @Test
246 void rejectsChangingLateConfigurationPolicyAfterFirstSelector() throws Exception {
246 void rejectsChangingLateConfigurationPolicyAfterFirstSelector() throws Exception {
247 writeSettings("variant-sources-late-policy-fixed");
247 writeSettings("variant-sources-late-policy-fixed");
248 writeBuildFile("""
248 writeBuildFile("""
249 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
249 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
250
250
251 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
251 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
252 variantsExt.layers.create('main')
252 variantsExt.layers.create('main')
253 variantsExt.roles.create('production')
253 variantsExt.roles.create('production')
254 variantsExt.variant('browser') {
254 variantsExt.variant('browser') {
255 role('production') { layers('main') }
255 role('production') { layers('main') }
256 }
256 }
257
257
258 variantSources {
258 variantSources {
259 variant('browser') {
259 variant('browser') {
260 declareOutputs('js')
260 declareOutputs('js')
261 }
261 }
262 lateConfigurationPolicy {
262 lateConfigurationPolicy {
263 allowLateConfiguration()
263 allowLateConfiguration()
264 }
264 }
265 }
265 }
266 """);
266 """);
267
267
268 assertBuildFails("Lazy configuration policy already applied", "help");
268 assertBuildFails("Lazy configuration policy already applied", "help");
269 }
269 }
270
270
271 @Test
271 @Test
272 void failsOnProjectedNameCollisionByDefault() throws Exception {
272 void failsOnProjectedNameCollisionByDefault() throws Exception {
273 writeSettings("variant-sources-name-collision-fail");
273 writeSettings("variant-sources-name-collision-fail");
274 writeBuildFile("""
274 writeBuildFile("""
275 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
275 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
276
276
277 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
277 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
278 variantsExt.layers.create('variantBar')
278 variantsExt.layers.create('variantBar')
279 variantsExt.layers.create('bar')
279 variantsExt.layers.create('bar')
280 variantsExt.roles.create('production')
280 variantsExt.roles.create('production')
281
281
282 variantsExt.variant('foo') {
282 variantsExt.variant('foo') {
283 role('production') { layers('variantBar') }
283 role('production') { layers('variantBar') }
284 }
284 }
285 variantsExt.variant('fooVariant') {
285 variantsExt.variant('fooVariant') {
286 role('production') { layers('bar') }
286 role('production') { layers('bar') }
287 }
287 }
288 """);
288 """);
289
289
290 assertBuildFails("The same source set names are produced by different compile units", "help");
290 assertBuildFails("The same source set names are produced by different compile units", "help");
291 }
291 }
292
292
293 @Test
293 @Test
294 void resolvesProjectedNameCollisionDeterministicallyWhenConfigured() throws Exception {
294 void resolvesProjectedNameCollisionDeterministicallyWhenConfigured() throws Exception {
295 writeSettings("variant-sources-name-collision-resolve");
295 writeSettings("variant-sources-name-collision-resolve");
296 writeBuildFile("""
296 writeBuildFile("""
297 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
297 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
298
298
299 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
299 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
300 variantsExt.layers.create('variantBar')
300 variantsExt.layers.create('variantBar')
301 variantsExt.layers.create('bar')
301 variantsExt.layers.create('bar')
302 variantsExt.roles.create('production')
302 variantsExt.roles.create('production')
303
303
304 variantsExt.variant('foo') {
304 variantsExt.variant('foo') {
305 role('production') { layers('variantBar') }
305 role('production') { layers('variantBar') }
306 }
306 }
307 variantsExt.variant('fooVariant') {
307 variantsExt.variant('fooVariant') {
308 role('production') { layers('bar') }
308 role('production') { layers('bar') }
309 }
309 }
310
310
311 variantSources {
311 variantSources {
312 namingPolicy {
312 namingPolicy {
313 resolveNameCollision()
313 resolveNameCollision()
314 }
314 }
315 }
315 }
316
316
317 afterEvaluate {
317 afterEvaluate {
318 variantSources.whenFinalized { ctx ->
318 variantSources.whenFinalized { ctx ->
319 def foo = ctx.variants.variants.find { it.name == 'foo' }
319 def foo = ctx.variants.variants.find { it.name == 'foo' }
320 def fooVariant = ctx.variants.variants.find { it.name == 'fooVariant' }
320 def fooVariant = ctx.variants.variants.find { it.name == 'fooVariant' }
321 def variantBar = ctx.variants.layers.find { it.name == 'variantBar' }
321 def variantBar = ctx.variants.layers.find { it.name == 'variantBar' }
322 def bar = ctx.variants.layers.find { it.name == 'bar' }
322 def bar = ctx.variants.layers.find { it.name == 'bar' }
323
323
324 def later = ctx.compileUnits.requireUnit(fooVariant, bar)
324 def later = ctx.compileUnits.requireUnit(fooVariant, bar)
325 def earlier = ctx.compileUnits.requireUnit(foo, variantBar)
325 def earlier = ctx.compileUnits.requireUnit(foo, variantBar)
326
326
327 println("map1=" + later.variant().name + ":" + later.layer().name + "->" + ctx.sourceSets.getSourceSet(later).name)
327 println("map1=" + later.variant().name + ":" + later.layer().name + "->" + ctx.sourceSets.getSourceSet(later).name)
328 println("map2=" + earlier.variant().name + ":" + earlier.layer().name + "->" + ctx.sourceSets.getSourceSet(earlier).name)
328 println("map2=" + earlier.variant().name + ":" + earlier.layer().name + "->" + ctx.sourceSets.getSourceSet(earlier).name)
329 }
329 }
330 }
330 }
331 """);
331 """);
332
332
333 BuildResult result = runner("help").build();
333 BuildResult result = runner("help").build();
334
334
335 assertTrue(result.getOutput().contains("map1=fooVariant:bar->fooVariantBar2"));
335 assertTrue(result.getOutput().contains("map1=fooVariant:bar->fooVariantBar2"));
336 assertTrue(result.getOutput().contains("map2=foo:variantBar->fooVariantBar"));
336 assertTrue(result.getOutput().contains("map2=foo:variantBar->fooVariantBar"));
337 }
337 }
338
338
339 @Test
339 @Test
340 void failsOnUnknownVariantSelectorTarget() throws Exception {
340 void failsOnUnknownVariantSelectorTarget() throws Exception {
341 writeSettings("variant-sources-missing-variant");
341 writeSettings("variant-sources-missing-variant");
342 writeBuildFile("""
342 writeBuildFile("""
343 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
343 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
344
344
345 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
345 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
346 variantsExt.layers.create('main')
346 variantsExt.layers.create('main')
347 variantsExt.roles.create('production')
347 variantsExt.roles.create('production')
348 variantsExt.variant('browser') {
348 variantsExt.variant('browser') {
349 role('production') { layers('main') }
349 role('production') { layers('main') }
350 }
350 }
351
351
352 variantSources {
352 variantSources {
353 variant('missing') {
353 variant('missing') {
354 declareOutputs('js')
354 declareOutputs('js')
355 }
355 }
356 }
356 }
357 """);
357 """);
358
358
359 assertBuildFails("Variant 'missing' is't declared", "help");
359 assertBuildFails("Variant 'missing' isn't declared", "help");
360 }
360 }
361
361
362 @Test
362 @Test
363 void failsOnUnknownLayerSelectorTarget() throws Exception {
363 void failsOnUnknownLayerSelectorTarget() throws Exception {
364 writeSettings("variant-sources-missing-layer");
364 writeSettings("variant-sources-missing-layer");
365 writeBuildFile("""
365 writeBuildFile("""
366 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
366 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
367
367
368 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
368 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
369 variantsExt.layers.create('main')
369 variantsExt.layers.create('main')
370 variantsExt.roles.create('production')
370 variantsExt.roles.create('production')
371 variantsExt.variant('browser') {
371 variantsExt.variant('browser') {
372 role('production') { layers('main') }
372 role('production') { layers('main') }
373 }
373 }
374
374
375 variantSources {
375 variantSources {
376 layer('missing') {
376 layer('missing') {
377 declareOutputs('js')
377 declareOutputs('js')
378 }
378 }
379 }
379 }
380 """);
380 """);
381
381
382 assertBuildFails("Layer 'missing' isn't declared", "help");
382 assertBuildFails("Layer 'missing' isn't declared", "help");
383 }
383 }
384
384
385 @Test
385 @Test
386 void failsOnUndeclaredCompileUnitSelectorTarget() throws Exception {
386 void failsOnUndeclaredCompileUnitSelectorTarget() throws Exception {
387 writeSettings("variant-sources-missing-unit");
387 writeSettings("variant-sources-missing-unit");
388 writeBuildFile("""
388 writeBuildFile("""
389 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
389 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
390
390
391 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
391 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
392 variantsExt.layers.create('main')
392 variantsExt.layers.create('main')
393 variantsExt.layers.create('test')
393 variantsExt.layers.create('test')
394 variantsExt.roles.create('production')
394 variantsExt.roles.create('production')
395 variantsExt.variant('browser') {
395 variantsExt.variant('browser') {
396 role('production') { layers('main') }
396 role('production') { layers('main') }
397 }
397 }
398
398
399 variantSources {
399 variantSources {
400 unit('browser', 'test') {
400 unit('browser', 'test') {
401 declareOutputs('js')
401 declareOutputs('js')
402 }
402 }
403 }
403 }
404 """);
404 """);
405
405
406 assertBuildFails("The CompileUnit isn't declared for variant 'browser', layer 'test'", "help");
406 assertBuildFails("The CompileUnit isn't declared for variant 'browser', layer 'test'", "help");
407 }
407 }
408
408
409 @Test
409 @Test
410 void rejectsChangingNamingPolicyAfterContextBecomesObservable() throws Exception {
410 void rejectsChangingNamingPolicyAfterContextBecomesObservable() throws Exception {
411 writeSettings("variant-sources-name-policy-fixed");
411 writeSettings("variant-sources-name-policy-fixed");
412 writeBuildFile("""
412 writeBuildFile("""
413 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
413 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
414
414
415 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
415 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
416 variantsExt.layers.create('main')
416 variantsExt.layers.create('main')
417 variantsExt.roles.create('production')
417 variantsExt.roles.create('production')
418 variantsExt.variant('browser') {
418 variantsExt.variant('browser') {
419 role('production') { layers('main') }
419 role('production') { layers('main') }
420 }
420 }
421
421
422 variantSources.whenFinalized {
422 variantSources.whenFinalized {
423 variantSources.namingPolicy {
423 variantSources.namingPolicy {
424 resolveNameCollision()
424 resolveNameCollision()
425 }
425 }
426 }
426 }
427 """);
427 """);
428
428
429 assertBuildFails("Naming policy already applied", "help");
429 assertBuildFails("Naming policy already applied", "help");
430 }
430 }
431
432 @Test
433 void rejectsChangingLateConfigurationPolicyAfterContextBecomesObservable() throws Exception {
434 writeSettings("variant-sources-late-policy-context-fixed");
435 writeBuildFile("""
436 apply plugin: org.implab.gradle.variants.VariantSourcesPlugin
437
438 def variantsExt = extensions.getByType(org.implab.gradle.variants.core.VariantsExtension)
439 variantsExt.layers.create('main')
440 variantsExt.roles.create('production')
441 variantsExt.variant('browser') {
442 role('production') { layers('main') }
443 }
444
445 variantSources.whenFinalized {
446 variantSources.lateConfigurationPolicy {
447 allowLateConfiguration()
448 }
449 }
450 """);
451
452 assertBuildFails("Lazy configuration policy already applied", "help");
453 }
431 }
454 }
General Comments 0
You need to be logged in to leave comments. Login now