Conditional Gradle dependency based on task output

0

I’m working on a project which has a bunch of flavors (dynamically generated) and each of those flavors has a task with configuration downloading. And based on that configuration, I want to exclude/include several libraries.

Example flow:

  1. My custom task executes and writes library type to extras
tasks.register<...>{
  doLast{
     extras["lib_type"] = "Lib_A"
     // or project.properties.setProperty("lib_type", "Lib_A")
  }
}
  1. Dependency block kicks in and checks which library it should include
dependencies{
   ...
   if (extras["lib_type"] == "Lib_A")
     implementation("lib:a:1.0.0")
   else
     implementation("lib:b:1.0.0")
   ...
}

Unfortunately, that doesn’t work because dependency resolution happens way before task execution.

What I’ve tried:

  1. Adding another dependencies{} block into doLast() call - FAIL, you can’t do another dependency after the initial configuration is complete.
  2. Trying to create some additional configurations - FAIL, there’s no way to disable them.

Are there any other approaches to this?

Note: I’m using Kodlin DSL instead of Groovy if it changes something.

Dependencies really should not be dynamic. If you have code to generate flavors, use the same code to add the appropriate dependencies. When you create a flavor, there are also configurations created specifically for that flavor. Rather than conditionally adding to implementation, if you have flavorA, add the dependencies to the flavorAImplementation configuration.

Dependency resolution also should not happen way before task execution. So, if it’s a case where you really need the result of the task to determine something else, it really should be a different part of the build domain model that influences the classpath and possible use of additional configurations that don’t get resolved too eagerly if that’s actually happening in your build.

Thanks for the response.

Re flavor configurations (ie flavorAImplementation) - it’s not possible in my case. There are too many flavors and they are dynamic. So it wouldn’t really be maintainable to have ~100 configurations.

Dependency resolution also should not happen way before task execution. So, if it’s a case where you really need the result of the task to determine something else, it really should be a different part of the build domain model that influences the classpath and possible use of additional configurations that don’t get resolved too eagerly if that’s actually happening in your build.

Not really sure if I understand what do you mean here. Is there any guide/doc for that?

@Ekalips How is the dynamic information generated/retrieved? Is it coming from Gradle itself in the same process?

The key, I think, would be to separate getting the list of what the flavors are from the Gradle process that needs to use them for configuring. If you can give more details about how you are getting the list of flavors, I might be able to make some suggestions on what to do.

Configurations can be created dynamically, they do not need to be created and managed manually, so having 100s of them should be no problem at all. Then these dynamically created configurations can have the desired dependencies.

  1. Flavors are stored in an Enum which is located in the buildSrc
  2. In the app-level build.gradle.kts file following code creates flavors from that enum
    for (flavorConfig in FlavorConfigs.values()) {
        productFlavors.register(flavorConfig.name) {
            require(this is ExtensionAware)
            dimension("...")
            applicationId = flavorConfig.flavorInfo.applicationId
        }
        ... 
    }
  1. Another piece of code in build.gradle.kts registers a task for each of those flavors. Task is responsible for downloading build-time configs from the server.
tasks.register<tasks.configs_obtainer.ObtainBuildTimeConfigsTask>("obtainBuildTimeConfigsFor${flavorConfig.name.capitalize()}") {
            flavorId = flavorConfig.flavorInfo.id
            flavorName = flavorConfig.name
        }

And basically what I want is to include/exclude some dependencies based on that task output. Ie task can output value for “lib_type” and then app somehow uses it to include/exclude dependencies. That “lib_type” can only be known after the task is complete, but it’ll always be one of 5 string values.

To do this, you will not be able to use tasks to download config information for the flavors. It will be necessary to do that during the the set-up phase of Gradle (when tasks and configurations are being defined). When tasks are running, it is already too late.

That’s bad. Thanks for the help anyways!