Java

SlowShield serves Maven repositories at https://slowshield.example.com/maven/, for Maven, Gradle, sbt and Coursier, and so for Java, Kotlin and Scala projects. Builds keep their dependencies and plugins as they are; only where they come from changes.

PathServesFor
/maven/all/Google's groups from Google Maven, everything else from Maven CentralMaven's mirror, sbt, Coursier
/maven/central/Maven CentralGradle mavenCentral()
/maven/google/Google MavenGradle google()
/maven/gradle-plugins/the Gradle Plugin PortalGradle gradlePluginPortal() and plugin resolution
/maven/<id>/a repository your administrator adds (JitPack, Confluent, …)anything else

Set it up

Maven and Gradle don't read environment variables for this: each needs a file in your home directory, which covers every project on the machine.

Maven

~/.m2/settings.xml

<settings>
  <mirrors>
    <mirror>
      <id>slowshield</id>
      <!-- private repositories stay direct: *,!their-id -->
      <mirrorOf>*</mirrorOf>
      <url>https://slowshield.example.com/maven/all/</url>
    </mirror>
  </mirrors>
</settings>

Gradle

~/.gradle/init.d/slowshield.init.gradle

def slowshield = [
  'https://repo.maven.apache.org/maven2': 'https://slowshield.example.com/maven/central/',
  'https://repo1.maven.org/maven2': 'https://slowshield.example.com/maven/central/',
  'https://dl.google.com/dl/android/maven2': 'https://slowshield.example.com/maven/google/',
  'https://plugins.gradle.org/m2': 'https://slowshield.example.com/maven/gradle-plugins/',
]
def rewrite = { repo ->
  if (repo instanceof MavenArtifactRepository) {
    def to = slowshield[repo.url.toString().replaceAll('/$', '')]
    if (to) { repo.url = new URI(to) }
  }
}
beforeSettings { s -> s.pluginManagement.repositories.all(rewrite) }
settingsEvaluated { s ->
  s.pluginManagement.repositories.all(rewrite)
  s.dependencyResolutionManagement.repositories.all(rewrite)
}
allprojects { p ->
  p.buildscript.repositories.all(rewrite)
  p.repositories.all(rewrite)
}

sbt

~/.sbt/repositories

[repositories]
  local
  slowshield: https://slowshield.example.com/maven/all/

environment

export SBT_OPTS="-Dsbt.override.build.repos=true $SBT_OPTS"

Coursier

environment

export COURSIER_REPOSITORIES="ivy2Local|https://slowshield.example.com/maven/all/"

What changes

The second layer

Maven, Gradle, sbt and Coursier have no release-age setting, so SlowShield is the only layer.

In Docker and CI

Write the mirror into the build container's settings.xml. With a build argument, the same Dockerfile still builds without SlowShield when the argument is empty:

FROM maven:3.9-eclipse-temurin-21 AS build
ARG MAVEN_MIRROR=https://slowshield.example.com/maven/all/
RUN if [ -n "$MAVEN_MIRROR" ]; then mkdir -p /root/.m2 && printf '%s' \
      "<settings><mirrors><mirror><id>slowshield</id><mirrorOf>*</mirrorOf><url>$MAVEN_MIRROR</url></mirror></mirrors></settings>" \
      > /root/.m2/settings.xml; fi
WORKDIR /src
COPY pom.xml .
COPY src src
RUN mvn -B package

This one mirror also covers Maven's own plugins: a test build of a small project fetched 107 artifacts through SlowShield, plugins included. For Gradle, copy the init script above to /root/.gradle/init.d/slowshield.gradle. Building images covers the base image too, and how to check that nothing in a build goes around SlowShield.

Limits

For agents: this page as Markdown · llms.txt · the SlowShield skill