Unable to resolve artifacts defined in a custom configuration

I am trying to create my own configuration from within a plugin, like this

Configuration configuration = project.getConfigurations().add("servicebuilder");
  configuration.setVisible(false);
configuration.setTransitive(true);
configuration.setDescription("The servicebuilder configuration");
  DependencySet dependencies = servicebuilderConfiguration.getDependencies();
dependencies.add(new DefaultExternalModuleDependency("com.thoughtworks.qdox", "qdox", "1.12"));
  servicebuilderConfiguration.getFiles()

When servicebuilderConfiguration.getFiles() is called , org.gradle.api.artifacts.ResolveException is thrown But it seems like the repositories i defined in my buildscript are not taken into account. How do i get it to look at these repositories ?

In most cases you shouldn’t (and don’t need to) resolve a configuration at configuration time. And if you do, you have to defer it to the end of the configuration phase. Otherwise, build scripts won’t have been fully evaluated yet.

Ok let me briedly touch upon what it is I am trying to do,

I am trying to write a plugin that, when configured adds a task. This task depends on a number of external libraries. What i am trying to do is load these libraries into a configuration, then configure it on the task as a FileCollection.

This seems to be what the jdepend plugin is doing, but then in groovy code

https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/JDependPlugin.groovy

I thought i’d mimic this, but i am running into the problem i described. How should I be dealing with this ?

Just pass the configuration straight to the task, without calling ‘resolve()’ (which wouldn’t return a FileCollection anyway). It will get resolved automatically when needed.

Nowhere was i calling resolve() though calling getFiles() will change the status to resolved.

Configuration itself implements FileCollection

I am now trying to set it from a convention mapping callback like this :

private void configureBuildServiceTask(final Project project) {
        buildService.getConventionMapping().map("classpath", new Callable<FileCollection>() {
            public FileCollection call() throws Exception {
                Configuration servicebuilderConfiguration = project.getConfigurations().getByName("servicebuilder");
                if (servicebuilderConfiguration.getDependencies().isEmpty()) {
                    project.getDependencies().add("servicebuilder", "com.thoughtworks.qdox:qdox:1.12");
                }
                return servicebuilderConfiguration;
            }
        });
    }

Because the code is defined in a callback i think this stuff is not part of the configuration phase, correct ?

Then in the plugin i am calling getFiles() on this configuration, and it fails with the aforementioned exception

How can i call getFiles on a configuration, from within a task and not have it fail because the userresolverchain is empty

‘resolve()’ and ‘getFiles()’ are the same. Don’t call them. It’s almost always wrong for a plugin to do so. Apart from the problems you already noticed, it will result in the configuration being resolved for every build, even if it isn’t needed (for example because an entirely unrelated task gets executed).

Configuration itself implements FileCollection

Yes it does. My point was that ‘getFiles()’ does not return a ‘FileCollection’ but a ‘Set’.

As you can see in the code sample above, I am not calling getFiles from the plugin, i am injecting the configuration into the task by using a getConventionMapping And from the task i call getFiles. So I don’t resolve these files for every build. I only resolve them when the task is run and the getter that returns the classpath is invoked from the task

The reason I am calling getFiles is so that i can add these jars to an ant classpath, used to invoke an ant task. like this

Project antProject = getAnt().getAntProject();
Path antClassPath = new Path(antProject);
for (File dep : getClassPath()) {
    antClassPath.createPathElement()
        .setLocation(dep);
}

So I iterate over the files in a Configuration

The jdepend plugin uses this :

def antBuilder = services.get(IsolatedAntBuilder)
antBuilder.withClasspath(getJdependClasspath()).execute {
...

But i can’t use that since IsolatedAntBuilder is only designed to be used from groovy code

As you can see in the code sample above, I am not calling getFiles from the plugin

All I see is one method. You certainly called ‘getFiles()’ from the plugin in your initial post, and later you said “Then in the plugin i am calling getFiles() on this configuration”.

The reason I am calling getFiles is so that i can add these jars to an ant classpath, used to invoke an ant task.

Makes sense. I think the problem is somewhere else. Try to run the build with ‘–refresh-dependencies’. If you need further help, please post all relevant code (including build script that applies the plugin) along with output of ‘gradle -v’, full error message, and stack trace.

The jdepend plugin uses this :

I don’t think it makes a difference, at least not with regard to resolving the configuration.

Ok the --refresh-dependencies setting did nothing for me, but I think i finally figured it out

The script i was using to test my plugin was based on the configuration outlined in

http://gradle.org/docs/current/userguide/custom_plugins.html#N15172

I was assuming that the repositories i define in the buildscript closure would also be used to resolve dependencies i added to my own dependencyset.

This does not seem to be the case. It seems they are only used to resolve the plugin jar. Once I added this section

repositories {
    mavenLocal()
    mavenCentral()
}

to my buildscript, the dependencies got resolved. Since the findbugs / jdepend etc plugins seem to work in the same way, i guess this is how things are supposed to work.

I guess this would have been obvious to most, but I am still very much a novice gradle user :slight_smile:

Thank you for your help

Yes that’s correct. Build script dependencies are managed separately from “regular” dependencies.