Model Rule if element exists

I am trying to write a rule that will be executed if a node in the software model exists.

this works fine if the component has been defined, but I can’t find a way to apply the rule
if the component exists.

i.e.

class Rules extends RuleSource {

@Default
public void applyDefault(@Path(“components.cpp”) NativeLibrarySpec component) {
// do something if a component named cpp has been defined
}

}

One way I can see of doing this would be to have the plugin rule apply the named action to the components container. https://docs.gradle.org/4.4.1/javadoc/org/gradle/model/ModelMap.html#named-java.lang.String-org.gradle.api.Action-

Such as this example:

@Default
public void applyDefault(@Path(“components”) ModelMap<NativeLibrarySpec> components) {
         components.named("cpp", new Action<NativeLibrarySpec>() {
                  public void execute(NativeLibrarySpec cppComponent) {
                           // do something if a component named cpp has been defined
                  }
         });
}

I tried that, it throws an error if the cpp component does not exist.

I think you did not even try my suggestion before rejecting it…

Here it is in plain terms. A build.gradle that proves it works.

apply plugin: 'cpp'
apply plugin: Rules

model {
    components {
        cpp(NativeLibrarySpec)
    }
}


class Rules extends RuleSource {
    @Defaults
    public void applyDefault(@Path('components') ModelMap<NativeLibrarySpec> components) {
        println "Running defaults"
         components.named('cpp', new Action<NativeLibrarySpec>() {
                  public void execute(NativeLibrarySpec cppComponent) {
                        println "Running against $cppComponent"
                  }
         });
    }
}

And as soon as I sent this it occurred to me that you want it to work when the component is not defined. So, this modification does that:

apply plugin: 'cpp'
apply plugin: Rules

model {
    components {
        cppFoo(NativeLibrarySpec)
    }
}


class Rules extends RuleSource {
    @Defaults
    public void applyDefault(@Path('components') ModelMap<NativeLibrarySpec> components) {
        println "Running defaults"
        components.all(new Action<NativeLibrarySpec>() {
            public void execute(NativeLibrarySpec cppComponent) {
                if ('cpp'.equals(cppComponent.getName()))
                    println "Running against $cppComponent"
            }
        });
    }
}

Note that the component is now named cppFoo

And if you wanted an even more slimmed down variant you can use the new @Each annotation either with the NativeLibrarySpec or going to plain ComponentSpec I think.

apply plugin: 'cpp'
apply plugin: Rules

model {
    components {
        cpp(NativeLibrarySpec)
    }
}


class Rules extends RuleSource {
    @Defaults
    public void applyDefault(@Each NativeLibrarySpec component) {
        if ('cpp'.equals(component.getName()))
            println "Running against $component"
    }
}