Obtaining the name of a component in model rules

Continuing the discussion from New model confusion:

Let’s by example say that we have a model for creating multiple Docker containers and we wat to have a directory specified where all of the files are.

My build script might be something like the following

model {
    dockerComponents {
        // In this container we use the default source dir <- See question below
        webserver(DockerContainer) {

        }
        // And in this one we override it <- Easy peasy
        mysql(DockerContainer) {
            dockerDir 'src/mysql'
        }
    }
}

My managed object is pretty straight forward.

@Managed
interface DockerContainer  {
    void setDockerDir(String location)
    String getDockerDir()
}

Setting up the rules is where the problem lies,

class ModelMapExampleRules extends RuleSource{
    @Model
    void dockerComponents(ModelMap<DockerContainer> components) {
    }

    @Mutate
    void defaultLocations(@Each DockerContainer component) {
       // ... Need some code here ... 
      // Somehow set dockerDir = 'src/docker/${name}'
    }
}
  1. How can I in a @Mutate section know what the name of the element is, so that I can apply it in an assignment?
  2. Should DockerContainer implement the Named interface?

(An alternative could be use a non-managed implementaton based upon NamedDomainObjectContainer as is the case for model.repositories, but that is not really the point of the exercise).

After banging my head on this a lot, I don’t think you can, at least, currently. The ModelMap<DockerComponent> is what actually knows the mapping of name -> each component.

Even with this, I was unable to find a way to use a component’s name to set any value on it. Changing defaultLocations to accept ModelMap<DockerComponent> components did not help, as apparently this is a write-only view, so you can’t actually use it to read the names. I tried various other approaches, such as having the first parameter be @Each DockerContainer component and the second be ModelMap<DockerContainer>, and trying to use ModelMap’s afterEach, but no luck.

If you do find a way, I’d be curious how you pulled it off.

(Funny enough, I’m also here, also trying to use the new software model to experiment with managing Docker containers, so I got very confused why I was reading my own code in your forum post before the coffee kicked in ;))

1 Like

Thanks, at least it shows I’m not the only one trying this out.

I thought using Docker as an example would a relatively well understood metaphor. I’m actually using it in a couple of places in writing my new Gradle book. Anyhow if you make your code open-source, it would also be good to have a look.

1 Like

Will do - right now it’s very much in the ‘can I even bend the @Managed types to model this’ phase, but if I get anything of value working from it, I’ll be sure to ship it your way. :slight_smile:

I ran into another issue, whilst trying an alternative solution - https://discuss.gradle.org/t/why-does-this-rule-not-get-called/17810

A @Managed type can extend Named, which will allow you to get at the name. This is probably the simplest way to do this at the moment.

The plan (but this isn’t possible yet) is to add some ways to query the name, path, etc of any element - regardless of whether it’s managed or not, or whether the declared type of the element extends Named.

2 Likes

Thanks @adammurdoch, it is a good enough solution for now.

@rhencke, this definitely solved it for me

interface DockerContainer extends Named {
    void setDockerDir(String location) 
    String getDockerDir()
}
1 Like

Awesome - thanks! That’ll definitely work for me, too. :slight_smile:

@rhencke, on a side note, If you are interested in building an open-source Docker plugin using the new model, it would be worthwhile getting together with @gesellix, whose existing Docker plugin is the most complete (and platform-independent) implementation.

1 Like

that’s actually a nice idea - I didn’t have a chance to look into the new model, yet. Hints are very welcome!

1 Like