diff --git a/common/build.gradle b/common/build.gradle
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -6,7 +6,7 @@ plugins {
java {
withJavadocJar()
withSourcesJar()
- toolchain {
+ toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
diff --git a/common/src/main/java/org/implab/gradle/common/dsl/TaskEnvSpecMixin.java b/common/src/main/java/org/implab/gradle/common/dsl/TaskEnvSpecMixin.java
--- a/common/src/main/java/org/implab/gradle/common/dsl/TaskEnvSpecMixin.java
+++ b/common/src/main/java/org/implab/gradle/common/dsl/TaskEnvSpecMixin.java
@@ -7,6 +7,7 @@ import org.gradle.api.Action;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
+import org.gradle.api.provider.Provider;
import org.implab.gradle.common.utils.Closures;
import org.implab.gradle.common.utils.Values;
@@ -31,19 +32,13 @@ public interface TaskEnvSpecMixin {
/**
* Configures the environment variable using the specified action. The
* action is called when the value is calculated;
+ *
+ *
+ * The configuration action is called immediately. To support lazy evaluation,
+ * properties may be assigned to providers.
*/
- default void env(Action> configure) {
- var provider = getEnvironment()
- .orElse(Map.of())
- .map((base) -> {
- var props = new HashMap(base);
-
- configure.execute(props);
-
- return Values.mapValues(props, Values::toString);
- });
-
- getEnvironment().set(provider);
+ default void env(Action> configure) {
+ Values.configureMap(getEnvironment(), configure, Object.class, Values::toString);
}
default void env(Closure> configure) {
diff --git a/common/src/main/java/org/implab/gradle/common/utils/ExtraProps.java b/common/src/main/java/org/implab/gradle/common/utils/ExtraProps.java
--- a/common/src/main/java/org/implab/gradle/common/utils/ExtraProps.java
+++ b/common/src/main/java/org/implab/gradle/common/utils/ExtraProps.java
@@ -1,16 +1,25 @@
package org.implab.gradle.common.utils;
-import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import org.gradle.api.plugins.ExtensionAware;
-public class ExtraProps {
+public interface ExtraProps {
+
+ Set keys();
+
+ boolean has(String name);
+
+ Optional get(String name, Class clazz);
- public static Map of(Object target) {
- if (target instanceof ExtensionAware ext)
- return ext.getExtensions().getExtraProperties().getProperties();
- else
- return Map.of();
+ void put(String name, Object value);
+
+ void remove(String name);
+
+ public static ExtraProps of(Object target) {
+ return target instanceof ExtensionAware ext
+ ? new ExtraPropsExtension(ext.getExtensions().getExtraProperties())
+ : new ExtraPropsNone();
}
-
}
diff --git a/common/src/main/java/org/implab/gradle/common/utils/ExtraPropsExtension.java b/common/src/main/java/org/implab/gradle/common/utils/ExtraPropsExtension.java
new file mode 100644
--- /dev/null
+++ b/common/src/main/java/org/implab/gradle/common/utils/ExtraPropsExtension.java
@@ -0,0 +1,43 @@
+package org.implab.gradle.common.utils;
+
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.gradle.api.plugins.ExtraPropertiesExtension;
+
+@NonNullByDefault
+class ExtraPropsExtension implements ExtraProps {
+
+ private final ExtraPropertiesExtension ext;
+
+ public ExtraPropsExtension(ExtraPropertiesExtension ext) {
+ this.ext = ext;
+ }
+
+ @Override
+ public Set keys() {
+ return ext.getProperties().keySet();
+ }
+
+ @Override
+ public boolean has(String name) {
+ return ext.has(name);
+ }
+
+ @Override
+ public Optional get(String name, Class clazz) {
+ return Optional.ofNullable(ext.get(name)).map(clazz::cast);
+ }
+
+ @Override
+ public void put(String name, Object value) {
+ ext.set(name, value);
+ }
+
+ @Override
+ public void remove(String name) {
+ ext.set(name, null);
+ }
+
+}
diff --git a/common/src/main/java/org/implab/gradle/common/utils/ExtraPropsNone.java b/common/src/main/java/org/implab/gradle/common/utils/ExtraPropsNone.java
new file mode 100644
--- /dev/null
+++ b/common/src/main/java/org/implab/gradle/common/utils/ExtraPropsNone.java
@@ -0,0 +1,31 @@
+package org.implab.gradle.common.utils;
+
+import java.util.Optional;
+import java.util.Set;
+
+public class ExtraPropsNone implements ExtraProps {
+
+ @Override
+ public Set keys() {
+ return Set.of();
+ }
+
+ @Override
+ public boolean has(String name) {
+ return false;
+ }
+
+ @Override
+ public Optional get(String name, Class clazz) {
+ return Optional.empty();
+ }
+
+ @Override
+ public void put(String name, Object value) {
+ }
+
+ @Override
+ public void remove(String name) {
+ }
+
+}
diff --git a/common/src/main/java/org/implab/gradle/common/utils/Values.java b/common/src/main/java/org/implab/gradle/common/utils/Values.java
--- a/common/src/main/java/org/implab/gradle/common/utils/Values.java
+++ b/common/src/main/java/org/implab/gradle/common/utils/Values.java
@@ -1,5 +1,6 @@
package org.implab.gradle.common.utils;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Spliterators;
@@ -11,6 +12,8 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import org.gradle.api.Action;
+import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Provider;
public final class Values {
@@ -20,7 +23,7 @@ public final class Values {
/**
* Converts values in the specified map
- *
+ *
* @param
* @param
* @param
@@ -35,6 +38,33 @@ public final class Values {
.collect(Collectors.toMap(Entry::getKey, getter.andThen(mapper)));
}
+ public static void mergeMap(MapProperty prop, Map map, Class clazz) {
+ map.forEach((k,v) -> {
+ if(v instanceof Provider>)
+ prop.put(k, ((Provider>)v).map(clazz::cast));
+ else
+ prop.put(k, clazz.cast(v));
+ });
+ }
+
+ public static void mergeMap(MapProperty prop, Map map, Class clazz, Function mapper) {
+ Function caster = clazz::cast;
+ var castMap = caster.andThen(mapper);
+
+ map.forEach((k,v) -> {
+ if(v instanceof Provider>)
+ prop.put(k, ((Provider>)v).map(x -> castMap.apply(x)));
+ else
+ prop.put(k, castMap.apply(v));
+ });
+ }
+
+ public static void configureMap(MapProperty prop, Action> configure, Class clazz, Function mapper) {
+ var map = new HashMap();
+ configure.execute(map);
+ mergeMap(prop, map, clazz, mapper);
+ }
+
/**
* Converts the supplied value to a string.
*/