Code Monkey home page Code Monkey logo

Comments (5)

liutikas avatar liutikas commented on July 19, 2024 1

@jjohannes since you added the Gradle module metadata support in the first place

from guava.

liutikas avatar liutikas commented on July 19, 2024

What would work better in this case is to use available-at instead of files

If guava-32.1.3-android.module instead has this:

{
      "name": "jreApiElements",
      "attributes": {
        "org.gradle.category": "library",
        "org.gradle.dependency.bundling": "external",
        "org.gradle.jvm.version": "8",
        "org.gradle.jvm.environment": "standard-jvm",
        "org.gradle.libraryelements": "jar",
        "org.gradle.usage": "java-api"
      },
      "available-at": {
        "url": "../32.1.3-jre/guava-32.1.3-jre.module",
        "group": "com.google.guava",
        "module": "guava",
        "version": "32.1.3-jre"
      }
    },
    {
      "name": "jreRuntimeElements",
      "attributes": {
        "org.gradle.category": "library",
        "org.gradle.dependency.bundling": "external",
        "org.gradle.jvm.version": "8",
        "org.gradle.jvm.environment": "standard-jvm",
        "org.gradle.libraryelements": "jar",
        "org.gradle.usage": "java-runtime"
      },
      "available-at": {
        "url": "../32.1.3-jre/guava-32.1.3-jre.module",
        "group": "com.google.guava",
        "module": "guava",
        "version": "32.1.3-jre"
      }
    }

signature verification succeeds.

it also reduces redundancy of declared dependencies.

from guava.

liutikas avatar liutikas commented on July 19, 2024

Note that available-at matches how Kotlin Multiplatform artifacts handle disambiguation in gradle module metadata.

See https://repo1.maven.org/maven2/com/squareup/okio/okio/3.9.0/okio-3.9.0.module as an example

from guava.

jjohannes avatar jjohannes commented on July 19, 2024

Thank you for investigating and sharing @liutikas.

I am afraid that available-at cannot be used in this case.

The difference between how Guava does variants compared to how it is done elsewhere (e.g. Kotlin Multiplatform) is that Guava uses different versions of the same component to represent the variants.

(1) In Guava you have

com/google/guava                      // group
└── guava                             // name
    ├── 33.1.0-android                // version (!)
    │   └── guava-33.1.0-android.jar
    └── 33.1.0-jre                    // version (!)
        └── guava-33.1.0-jre.jar

(2) If Guava would represent the android variant as classified Jar

Ideally, you would use just multiple artifacts with classifiers. That what I would do for a Java library today if I would publish it with two variants for "jre" and "android". (And the metadata we have now is very close to it, just that it hast to point into the other version folder – ../32.1.0-jre/ – to find the other variant Jar file.)

com/google/guava                      // group
└── guava                             // name
    └── 33.1.0                        // version
        └── guava-33.1.0.jar          // standard/fallback without classifier (jre)
        └── guava-33.1.0-android.jar

(3) If Guava would represent its variants as Kotlin Multiplatform does

If there is a specific reason to have each variant in a separate component (like in Kotlin Multiplatform) you can do that and use available-at to "connect" these components as "variants of one main component":

com/google/guava                      // group
├── guava                             // name (main component)
│   └── 33.1.0                        // version
│       └── guava-33.1.0.module       // only metadata (no Jar) with 'availbale-at'
│
├── guava-android                     // name (separate component that is also used as variant)
│   └── 33.1.0                        // version
│      └── guava-android-33.1.0.jar
└── guava-jre                         // name (separate component that is also used as variant)
    └── 33.1.0                        // version
        └── guava-jre-33.1.0.jar

I can still emphasize with why solution (1) was chosen years ago. It is "misusing" the version conflict resolution of the build tools to make sure that never both variants are selected together. Today, Gradle is "variant aware" and solution (2) would be better and the metadata we have tries to get to that as close as possible. (But even if it would be reinvented today, what about Maven which does not have such variant awareness? yet?)

In the current setup (1), we cannot use available-at, because it would point at another version of itself. Which is weird, because not both versions can be selected together. But in the available-at is treated as an edge between two nodes in the dependency graph. But these two nodes can not both exist. I haven't tried, but you might get an "invalid metadata" error directly, because the spec explicitly states that this is not possible here: https://github.com/gradle/gradle/blob/master/platforms/documentation/docs/src/docs/design/gradle-module-metadata-latest-specification.md#available-at-value

Note that the group:module cannot be the same as the group:module of the root component element.

from guava.

liutikas avatar liutikas commented on July 19, 2024

If I add the following diff to https://github.com/liutikas/guava-signature-repro repro project

diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 901027d..c611b39 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -500,5 +500,21 @@
             <sha256 value="b51f8867c92b6a722499557fc3a1fdea77bdf9ef574722fe90ce436a29559454"/>
          </artifact>
       </component>
+      <component group="com.google.guava" name="guava" version="32.1.3-jre">
+         <artifact name="guava-32.1.3-jre.module">
+            <ignored-keys>
+               <ignored-key id="BDB5FA4FE719D787FB3D3197F6D4A1D411E9D1AE" />
+            </ignored-keys>
+            <sha256 value="e43870007081e972b73a57fe1ad840ed469290c47bb5d51dac5939756258064d"/>
+         </artifact>
+      </component>
+      <component group="com.google.guava" name="guava" version="32.1.3-android">
+         <artifact name="guava-32.1.3-android.module">
+            <ignored-keys>
+               <ignored-key id="BDB5FA4FE719D787FB3D3197F6D4A1D411E9D1AE" />
+            </ignored-keys>
+            <sha256 value="79b98e8056a24d271609ab9e9b8dc73da2dd3d980aadd9a85021ce3def21beee"/>
+         </artifact>
+      </component>
    </components>
 </verification-metadata>
diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts
new file mode 100644
index 0000000..d261c86
--- /dev/null
+++ b/lib/build.gradle.kts
@@ -0,0 +1,7 @@
+plugins {
+    id("java-library")
+}
+
+dependencies {
+    implementation("com.google.guava:guava:32.1.3-android")
+}
\ No newline at end of file
diff --git a/lib/src/main/java/com/example/lib/MyClass.java b/lib/src/main/java/com/example/lib/MyClass.java
new file mode 100644
index 0000000..58f7288
--- /dev/null
+++ b/lib/src/main/java/com/example/lib/MyClass.java
@@ -0,0 +1,4 @@
+package com.example.lib;
+
+public class MyClass {
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 7e67774..a997ab2 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -14,6 +14,9 @@ pluginManagement {
 dependencyResolutionManagement {
     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
     repositories {
+        maven {
+            url = uri("/usr/local/google/home/aurimas/Code/androidx-main/prebuilts/androidx/external")
+        }
         google()
         mavenCentral()
     }
@@ -21,4 +24,4 @@ dependencyResolutionManagement {
 
 rootProject.name = "My Application"
 include(":app")
- 
\ No newline at end of file
+include(":lib")

and the local copy maven has the following diff

diff --git a/com/google/guava/guava/32.1.3-android/guava-32.1.3-android.module b/com/google/guava/guava/32.1.3-android/guava-32.1.3-android.module
index efc9b8ca6..6bb088cc4 100644
--- a/com/google/guava/guava/32.1.3-android/guava-32.1.3-android.module
+++ b/com/google/guava/guava/32.1.3-android/guava-32.1.3-android.module
@@ -164,68 +164,12 @@
         "org.gradle.libraryelements": "jar",
         "org.gradle.usage": "java-api"
       },
-      "dependencies": [
-        {
-          "group": "com.google.guava",
-          "module": "failureaccess",
-          "version": {
-            "requires": "1.0.1"
-          }
-        },
-        {
-          "group": "com.google.guava",
-          "module": "listenablefuture",
-          "version": {
-            "requires": "9999.0-empty-to-avoid-conflict-with-guava"
-          }
-        },
-        {
-          "group": "com.google.code.findbugs",
-          "module": "jsr305",
-          "version": {
-            "requires": "3.0.2"
-          }
-        },
-        {
-          "group": "org.checkerframework",
-          "module": "checker-qual",
-          "version": {
-            "requires": "3.37.0"
-          }
-        },
-        {
-          "group": "com.google.errorprone",
-          "module": "error_prone_annotations",
-          "version": {
-            "requires": "2.21.1"
-          }
-        },
-        {
-          "group": "com.google.j2objc",
-          "module": "j2objc-annotations",
-          "version": {
-            "requires": "2.8"
-          }
-        }
-      ],
-      "files": [
-        {
-          "name": "guava-32.1.3-jre.jar",
-          "url": "../32.1.3-jre/guava-32.1.3-jre.jar"
-        }
-      ],
-      "capabilities": [
-        {
-          "group": "com.google.guava",
-          "name": "guava",
-          "version": "32.1.3-android"
-        },
-        {
-          "group": "com.google.collections",
-          "name": "google-collections",
-          "version": "32.1.3-android"
-        }
-      ]
+      "available-at": {
+        "url": "../32.1.3-jre/guava-32.1.3-jre.module",
+        "group": "com.google.guava",
+        "module": "guava",
+        "version": "32.1.3-jre"
+      }
     },
     {
       "name": "jreRuntimeElements",
@@ -237,61 +181,12 @@
         "org.gradle.libraryelements": "jar",
         "org.gradle.usage": "java-runtime"
       },
-      "dependencies": [
-        {
-          "group": "com.google.guava",
-          "module": "failureaccess",
-          "version": {
-            "requires": "1.0.1"
-          }
-        },
-        {
-          "group": "com.google.guava",
-          "module": "listenablefuture",
-          "version": {
-            "requires": "9999.0-empty-to-avoid-conflict-with-guava"
-          }
-        },
-        {
-          "group": "com.google.code.findbugs",
-          "module": "jsr305",
-          "version": {
-            "requires": "3.0.2"
-          }
-        },
-        {
-          "group": "org.checkerframework",
-          "module": "checker-qual",
-          "version": {
-            "requires": "3.37.0"
-          }
-        },
-        {
-          "group": "com.google.errorprone",
-          "module": "error_prone_annotations",
-          "version": {
-            "requires": "2.21.1"
-          }
-        }
-      ],
-      "files": [
-        {
-          "name": "guava-32.1.3-jre.jar",
-          "url": "../32.1.3-jre/guava-32.1.3-jre.jar"
-        }
-      ],
-      "capabilities": [
-        {
-          "group": "com.google.guava",
-          "name": "guava",
-          "version": "32.1.3-android"
-        },
-        {
-          "group": "com.google.collections",
-          "name": "google-collections",
-          "version": "32.1.3-android"
-        }
-      ]
+      "available-at": {
+        "url": "../32.1.3-jre/guava-32.1.3-jre.module",
+        "group": "com.google.guava",
+        "module": "guava",
+        "version": "32.1.3-jre"
+      }
     }
   ]
 }
diff --git a/com/google/guava/guava/32.1.3-jre/guava-32.1.3-jre.module b/com/google/guava/guava/32.1.3-jre/guava-32.1.3-jre.module
index 98d7896af..705815cc9 100644
--- a/com/google/guava/guava/32.1.3-jre/guava-32.1.3-jre.module
+++ b/com/google/guava/guava/32.1.3-jre/guava-32.1.3-jre.module
@@ -164,68 +164,12 @@
         "org.gradle.libraryelements": "jar",
         "org.gradle.usage": "java-api"
       },
-      "dependencies": [
-        {
-          "group": "com.google.guava",
-          "module": "failureaccess",
-          "version": {
-            "requires": "1.0.1"
-          }
-        },
-        {
-          "group": "com.google.guava",
-          "module": "listenablefuture",
-          "version": {
-            "requires": "9999.0-empty-to-avoid-conflict-with-guava"
-          }
-        },
-        {
-          "group": "com.google.code.findbugs",
-          "module": "jsr305",
-          "version": {
-            "requires": "3.0.2"
-          }
-        },
-        {
-          "group": "org.checkerframework",
-          "module": "checker-qual",
-          "version": {
-            "requires": "3.37.0"
-          }
-        },
-        {
-          "group": "com.google.errorprone",
-          "module": "error_prone_annotations",
-          "version": {
-            "requires": "2.21.1"
-          }
-        },
-        {
-          "group": "com.google.j2objc",
-          "module": "j2objc-annotations",
-          "version": {
-            "requires": "2.8"
-          }
-        }
-      ],
-      "files": [
-        {
-          "name": "guava-32.1.3-android.jar",
-          "url": "../32.1.3-android/guava-32.1.3-android.jar"
-        }
-      ],
-      "capabilities": [
-        {
-          "group": "com.google.guava",
-          "name": "guava",
-          "version": "32.1.3-jre"
-        },
-        {
-          "group": "com.google.collections",
-          "name": "google-collections",
-          "version": "32.1.3-jre"
-        }
-      ]
+      "available-at": {
+        "url": "../32.1.3-android/guava-32.1.3-android.module",
+        "group": "com.google.guava",
+        "module": "guava",
+        "version": "32.1.3-android"
+      }
     },
     {
       "name": "androidRuntimeElements",
@@ -237,61 +181,12 @@
         "org.gradle.libraryelements": "jar",
         "org.gradle.usage": "java-runtime"
       },
-      "dependencies": [
-        {
-          "group": "com.google.guava",
-          "module": "failureaccess",
-          "version": {
-            "requires": "1.0.1"
-          }
-        },
-        {
-          "group": "com.google.guava",
-          "module": "listenablefuture",
-          "version": {
-            "requires": "9999.0-empty-to-avoid-conflict-with-guava"
-          }
-        },
-        {
-          "group": "com.google.code.findbugs",
-          "module": "jsr305",
-          "version": {
-            "requires": "3.0.2"
-          }
-        },
-        {
-          "group": "org.checkerframework",
-          "module": "checker-qual",
-          "version": {
-            "requires": "3.37.0"
-          }
-        },
-        {
-          "group": "com.google.errorprone",
-          "module": "error_prone_annotations",
-          "version": {
-            "requires": "2.21.1"
-          }
-        }
-      ],
-      "files": [
-        {
-          "name": "guava-32.1.3-android.jar",
-          "url": "../32.1.3-android/guava-32.1.3-android.jar"
-        }
-      ],
-      "capabilities": [
-        {
-          "group": "com.google.guava",
-          "name": "guava",
-          "version": "32.1.3-jre"
-        },
-        {
-          "group": "com.google.collections",
-          "name": "google-collections",
-          "version": "32.1.3-jre"
-        }
-      ]
+      "available-at": {
+        "url": "../32.1.3-android/guava-32.1.3-android.module",
+        "group": "com.google.guava",
+        "module": "guava",
+        "version": "32.1.3-android"
+      }
     }
   ]
 }

both ./gradlew app:assembleDebug and ./gradlew lib:jar succeeds.

However, I do see that the spec does seem to forbid this :/

from guava.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.