diff --git a/planetiler-core/src/main/java/com/onthegomap/planetiler/ForwardingProfile.java b/planetiler-core/src/main/java/com/onthegomap/planetiler/ForwardingProfile.java
index 83230c554a..1a7aa64afd 100644
--- a/planetiler-core/src/main/java/com/onthegomap/planetiler/ForwardingProfile.java
+++ b/planetiler-core/src/main/java/com/onthegomap/planetiler/ForwardingProfile.java
@@ -81,13 +81,38 @@ protected ForwardingProfile(Handler... handlers) {
}
private boolean caresAboutLayer(String layer) {
- return (onlyLayers.isEmpty() || onlyLayers.contains(layer)) && !excludeLayers.contains(layer);
+ var dependencies = dependsOnLayer();
+ return ((onlyLayers.isEmpty() || onlyLayers.contains(layer)) && !excludeLayers.contains(layer)) ||
+ this.handlers.stream()
+ .filter(HandlerForLayer.class::isInstance)
+ .map(HandlerForLayer.class::cast)
+ .filter(l -> !l.name().equals(layer))
+ .anyMatch(
+ existing -> dependencies.containsKey(existing.name()) && dependencies.get(existing.name()).contains(layer));
}
public boolean caresAboutLayer(Object obj) {
return !(obj instanceof HandlerForLayer l) || caresAboutLayer(l.name());
}
+ /**
+ * Indicate to {@link #caresAboutLayer(String)} what layers (dependents) rely on other layers (dependencies) so that
+ * methods like {@link #registerFeatureHandler(FeatureProcessor)}, {@link #registerHandler(Handler)} or
+ * {@link #registerSourceHandler(String, FeatureProcessor)} do not block registration of those dependencies.
+ *
+ * Dependencies are described as a map with dependent layer names as keys and lists containing dependency layer names
+ * as map values. Example: Layer named {@code transportation_name} depends on layer named {@code transportation}:
+ *
+ * {@snippet :
+ * Map.of("transportation_name", List.of("transportation"));
+ * }
+ *
+ * @return a map describing dependencies
+ */
+ public Map> dependsOnLayer() {
+ return Map.of();
+ }
+
/**
* Call {@code processor} for every element in {@code source}.
*
diff --git a/planetiler-core/src/test/java/com/onthegomap/planetiler/ForwardingProfileTests.java b/planetiler-core/src/test/java/com/onthegomap/planetiler/ForwardingProfileTests.java
index 76305f614f..dc96b7f28d 100644
--- a/planetiler-core/src/test/java/com/onthegomap/planetiler/ForwardingProfileTests.java
+++ b/planetiler-core/src/test/java/com/onthegomap/planetiler/ForwardingProfileTests.java
@@ -24,6 +24,7 @@
import java.util.TreeSet;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
class ForwardingProfileTests {
@@ -455,4 +456,51 @@ public void processFeature(SourceFeature sourceFeature, FeatureCollector feature
"_layer", "water"
)), a);
}
+
+ @ParameterizedTest
+ @CsvSource({
+ "'--only-layers=water', water",
+ "'--exclude-layers=land,transportation,transportation_name', water",
+ // transportation excluded but transportation_name NOT => transportation will be processed
+ "'--exclude-layers=land,transportation', water transportation_name transportation",
+ "'--exclude-layers=land,transportation_name', water transportation",
+ "'--exclude-layers=land --only-layers=water,land', water",
+ // transportation excluded but transportation_name NOT => transportation will be processed
+ "'--exclude-layers=transportation --only-layers=water,transportation,transportation_name', water transportation_name transportation",
+ "'--exclude-layers=transportation_name --only-layers=water,transportation,transportation_name', water transportation",
+ "'--exclude-layers=transportation,transportation_name --only-layers=water,transportation,transportation_name', water",
+ // transportation excluded but transportation_name NOT => transportation will be processed
+ "'--exclude-layers=transportation --only-layers=water,transportation_name', water transportation_name transportation",
+ "'--exclude-layers=transportation_name --only-layers=water,transportation', water transportation",
+ })
+ void testLayerWithDepsCliArgFilter(String args, String expectedLayers) {
+ profile = new ForwardingProfile(PlanetilerConfig.from(Arguments.fromArgs(args.split(" ")))) {
+ @Override
+ public Map> dependsOnLayer() {
+ return Map.of("transportation_name", List.of("transportation"));
+ }
+ };
+ record Processor(String name) implements ForwardingProfile.HandlerForLayer, ForwardingProfile.FeatureProcessor {
+
+ @Override
+ public void processFeature(SourceFeature sourceFeature, FeatureCollector features) {
+ features.point(name);
+ }
+ }
+
+ SourceFeature a = SimpleFeature.create(GeoUtils.EMPTY_POINT, Map.of("key", "value"), "source", "source layer", 1);
+ profile.registerHandler(new Processor("water"));
+ profile.registerHandler(new Processor("transportation"));
+ profile.registerHandler(new Processor("transportation_name"));
+ profile.registerHandler(new Processor("land"));
+ // profiles like OpenMapTiles will try to add "transportation" once again to cover for dependency
+ profile.registerHandler(new Processor("transportation"));
+
+ List