Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: handling of the Guava component rule with custom configurations #46

Closed
kmoens opened this issue Apr 7, 2023 · 2 comments
Closed
Labels
a:question Further information is requested

Comments

@kmoens
Copy link
Contributor

kmoens commented Apr 7, 2023

I've got a special project which is only used to use Gradle's dependency resolution logic to collect a number of dependencies and store them in an archive.

For this purpose I don't make use of the java plugin. However I would like to use this plugin since I do want the dependencies properly resolved using the capabilities logic.

However when I apply the plugin, the capabilities logic works as expected, only the Guava component rule acts up completely.

The project is setup as follows:

  • I don't apply the java plugin.
  • I have a custom configuration called autodeploy to which I add the dependencies.
  • I have a custom Copy task, which copies the configuration towards a directory under the build.
  • I have a custom Zip task which packages this directory.

So far, so good. This works perfectly until I apply the java-ecosystem-capabilities.

One of my dependencies is as follows:

dependencies {
    ...
    autodeploy 'com.google.guava:guava:31.1-jre'
    ...
}

If I then perform a build, I get the following error:

com.google.guava:guava:31.1-jre FAILED
   Failures:
      - Could not resolve com.google.guava:guava:31.1-jre.
          - The consumer was configured to find attribute 'org.gradle.usage' with value 'java-runtime', attribute 'org.gradle.libraryelements' with value 'jar', attribute 'org.gradle.category' with value 'library'. However we cannot choose between the following variants of com.google.guava:guava:31.1-jre:
              - androidCompile
              - androidRuntime
            All of them match the consumer attributes:
              - Variant 'androidCompile' capabilities com.google.collections:google-collections:31.1 and com.google.collections:google-collections:31.1 and com.google.guava:guava:31.1-jre and com.google.guava:listenablefuture:1.0 and com.google.guava:listenablefuture:1.0:
                  - Unmatched attributes:
                      - Doesn't say anything about org.gradle.category (required 'library')
                      - Provides org.gradle.jvm.environment 'android' but the consumer didn't ask for it
                      - Doesn't say anything about org.gradle.libraryelements (required 'jar')
                      - Provides org.gradle.status 'release' but the consumer didn't ask for it
                      - Doesn't say anything about org.gradle.usage (required 'java-runtime')
              - Variant 'androidRuntime' capabilities com.google.collections:google-collections:31.1 and com.google.collections:google-collections:31.1 and com.google.guava:guava:31.1-jre and com.google.guava:listenablefuture:1.0 and com.google.guava:listenablefuture:1.0:
                  - Unmatched attributes:
                      - Doesn't say anything about org.gradle.category (required 'library')
                      - Provides org.gradle.jvm.environment 'android' but the consumer didn't ask for it
                      - Doesn't say anything about org.gradle.libraryelements (required 'jar')
                      - Provides org.gradle.status 'release' but the consumer didn't ask for it
                      - Doesn't say anything about org.gradle.usage (required 'java-runtime')

com.google.guava:guava:31.1-jre FAILED

Since I have made custom configurations, I thought the easy trick was to add the attributes (which Gradle adds to its own configurations) towards my custom configuration too as follows:

configurations.autodeploy {
    attributes.attribute( Attribute.of("org.gradle.usage", String), 'java-runtime' )
    attributes.attribute( Attribute.of("org.gradle.libraryelements", String), 'jar' )
    attributes.attribute( Attribute.of("org.gradle.category", String), 'library' )
    attributes.attribute( Attribute.of("org.gradle.jvm.environment", String), 'standard-jvm' )                                                                                                
}

However that does not solve the issue, this triggers:

com.google.guava:guava:31.1-jre FAILED
   Failures:
      - Could not resolve com.google.guava:guava:31.1-jre.
          - No matching variant of com.google.guava:guava:31.1-jre was found. The consumer was configured to find attribute 'org.gradle.usage' with value 'java-runtime', attribute 'org.gradle.libraryelements' with value 'jar', attribute 'org.gradle.category' with value 'library', attribute 'org.gradle.jvm.environment' with value 'standard-jvm' but:
              - Variant 'androidCompile' capabilities com.google.collections:google-collections:31.1 and com.google.collections:google-collections:31.1 and com.google.guava:guava:31.1-jre and com.google.guava:listenablefuture:1.0 and com.google.guava:listenablefuture:1.0:
                  - Incompatible because this component declares attribute 'org.gradle.jvm.environment' with value 'android' and the consumer needed attribute 'org.gradle.jvm.environment' with value 'standard-jvm'
                  - Other compatible attributes:
                      - Doesn't say anything about org.gradle.category (required 'library')
                      - Doesn't say anything about org.gradle.libraryelements (required 'jar')
                      - Doesn't say anything about org.gradle.usage (required 'java-runtime')
              - Variant 'androidRuntime' capabilities com.google.collections:google-collections:31.1 and com.google.collections:google-collections:31.1 and com.google.guava:guava:31.1-jre and com.google.guava:listenablefuture:1.0 and com.google.guava:listenablefuture:1.0:
                  - Incompatible because this component declares attribute 'org.gradle.jvm.environment' with value 'android' and the consumer needed attribute 'org.gradle.jvm.environment' with value 'standard-jvm'
                  - Other compatible attributes:
                      - Doesn't say anything about org.gradle.category (required 'library')
                      - Doesn't say anything about org.gradle.libraryelements (required 'jar')
                      - Doesn't say anything about org.gradle.usage (required 'java-runtime')

Looking at its error message, I conclude that he's right: I don't want the Android variant, I want the JVM variant.

I was thinking to add the other attributes (especially org.gradle.usage), but that will not solve the problem since I only have the android variants.

So I thought... what if I change my dependency towards the android one:

dependencies {
    ...
    autodeploy 'com.google.guava:guava:31.1-android'    
    ...
}

And, at the same time at the org.gradle.usage attribute:

dependencies.components.withModule('com.google.guava:guava') {
    withVariant('standardJvmCompile') {
        attributes {
            attribute Attribute.of("org.gradle.usage", String.class), 'java-api'
        }
    }
    
    withVariant('standardJvmRuntime') {
        attributes {
            attribute Attribute.of("org.gradle.usage", String.class), 'java-runtime'
        }

    }
}

And bingo, it works now:

com.google.guava:guava:31.1-android
  Variant standardJvmRuntime:
    | Attribute Name             | Provided     | Requested    |
    |----------------------------|--------------|--------------|
    | org.gradle.status          | release      |              |
    | org.gradle.jvm.environment | standard-jvm | standard-jvm |
    | org.gradle.usage           | java-runtime | java-runtime |
    | org.gradle.category        |              | library      |
    | org.gradle.libraryelements |              | jar          |

But this doesn't feel right, since I have picked the wrong dependency.
Any advise on how to fix this properly with custom configurations which are totally unrelated from the regular Gradle configurations?

@jjohannes
Copy link
Member

The problem is most likely that the Attributes we rely on are not known to Gradle if you are outside of a "Java" project. Then only default/fallback strategies are used when there are multiple compatible variants.

It's one of the not so well documented things that typically, for each attribute, there is also a so-called "Attribute Schema" that defines how values are compatible and which to prefer in case of multiple choices. For example things like: Java 8 is compatible with Java 11, but prefer 11 is possible.

In the case of Java, these rules are made known by the jvm-ecosystem plugin (implicitly added by all Java/Android plugins). Can you try adding that plugin – id("jvm-ecosystem") – to your project?

I think we should probably make sure that the plugin is always applied. I think there should be now issue with that. I created a PR: #47 47

@jjohannes jjohannes added the a:question Further information is requested label Apr 11, 2023
@kmoens
Copy link
Contributor Author

kmoens commented Apr 13, 2023

OK, that does the trick. If I apply the jvm-ecosystem plugin it works correctly without my workarounds.
Thanks !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants