- `<version>` is the artifact version - can be either `<base-version>`
or `<version-base>-<timestamp>-<build-num>` (`2.0.9` for normal
artifacts, and either `2.2.1-SNAPSHOT` or `2.2.1-20230117.075740-16`
for snapshots)
- `<version-base>` - `<base-version>` without the `-SNAPSHOT` suffix
- `<timestamp>` - artifact build timestamp in the `YYYYMMDD.HHMMSS`
format (UTC)
- `<build-num>` - a counter that's incremented by 1 for each new
snapshot build
- `<classifier>` is an optional classifier for allowing a single .pom to
refer to multiple .jar files. .pom files don't have classifiers, as
they describe metadata.
- `<ext>` is the extension. .pom
Note that the artifact ID can contain `-`, so you can't extract the
artifact ID and version from just the file name.
Additionally, the files in the repository may have associated signature
files, formed by appending `.asc` to the filename, and hashsum files,
formed by appending `.md5` or `.sha1` to the filename. The signatures
are harmless, but the `.md5`/`.sha1` files are rejected.
The reasoning is as follows - consider two files `a.jar` and `b.jar`,
that have the same hash. Gradle will fetch `a.jar.sha1`, find out that
it hasn't yet downloaded a file with this hash, and then fetch `a.jar`,
and finally download `b.jar.sha1`, locate it in its cache, and then
*not* download `b.jar`. This means `b.jar` won't be stored in the MITM
cache. Then, consider that on a later invocation, the fetching order
changed, whether it was because of running on a different system,
changed behavior after a Gradle update, or any other source of
nondeterminism - `b.jar` is fetched before `a.jar`. Gradle will first
fetch `b.jar.sha1`, not find it in its cache, attempt to fetch `b.jar`,
and fail, as the cache doesn't have that file.
For the same reason, the proxy strips all checksum/etag headers. An
alternative would be to make the proxy remember previous checksums and
etags, but that would complicate the implementation - however, such a
feature can be implemented if necessary. Note that checksum/etag header
stripping is hardcoded, but `.md5/.sha1` file rejection is configured
via CLI arguments.
**Caveat**: Gradle .module files also contain file hashes, in md5, sha1,
sha256, sha512 formats. It has posed no problem as of yet, but it might in
the future. If it does pose problems, the deps derivation code can be
extended to find all checksums in .module files and copy existing files
there if their hash matches.
## Snapshots
Snapshots are a way to publish the very latest, unstable version of a
dependency that constantly changes. Any project that depends on a
snapshot will depend on this rolling version, rather than a fixed
version. It's easy to understand why this is a bad idea for reproducible
builds. Still, they can be dealt with by the logic in `gradle.fetchDeps`
and `gradle.updateDeps`.
First, as you can see above, while normal artifacts have the same
`base-version` and `version`, for snapshots it usually (but not
necessarily) differs.
Second, for figuring out where to download the snapshot, Gradle consults
`maven-metadata.xml`. With that in mind...
## Maven Metadata
(Reference: [Maven
Metadata](https://maven.apache.org/repositories/metadata.html),
[Metadata](https://maven.apache.org/ref/3.9.8/maven-repository-metadata/repository-metadata.html)
Maven metadata files are called `maven-metadata.xml`.
There are three levels of metadata: "G level", "A level", "V level",
representing group, artifact, or version metadata.
G level metadata is currently unsupported. It's only used for Maven
plugins, which Gradle presumably doesn't use.
A level metadata is used for getting the version list for an artifact.
It's an xml with the following items:
- `<groupId>` - group ID
- `<artifactId>` - artifact ID
- `<versioning>`
- `<latest>` - the very latest base version (e.g. `2.2.1-SNAPSHOT`)