diff --git a/build.sbt b/build.sbt index fe70d1d5d..0f24a0767 100644 --- a/build.sbt +++ b/build.sbt @@ -16,7 +16,7 @@ ThisBuild / versionScheme := Some("early-semver") ThisBuild / scalafmtOnCompile := !(Global / insideCI).value ThisBuild / Test / scalafmtOnCompile := !(Global / insideCI).value ThisBuild / turbo := true -ThisBuild / usePipelining := !(Global / insideCI).value +ThisBuild / usePipelining := false // !(Global / insideCI).value val excludeLint = SettingKey[Set[Def.KeyedInitialize[_]]]("excludeLintKeys") Global / excludeLint := (Global / excludeLint).?.value.getOrElse(Set.empty) diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index b00fed740..14b3d54dc 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -386,6 +386,7 @@ object Keys { val pushRemoteCacheArtifact = settingKey[Boolean]("Enables publishing an artifact to remote cache.") val pushRemoteCacheConfiguration = taskKey[PublishConfiguration]("") val pushRemoteCacheTo = settingKey[Option[Resolver]]("The resolver to publish remote cache to.") + val remoteCacheResolvers = settingKey[Seq[Resolver]]("Resolvers for remote cache.") val remoteCachePom = taskKey[File]("Generates a pom for publishing when publishing Maven-style.") val usePipelining = settingKey[Boolean]("Use subproject pipelining for compilation.").withRank(BSetting) val exportPipelining = settingKey[Boolean]("Product early output so downstream subprojects can do pipelining.").withRank(BSetting) diff --git a/main/src/main/scala/sbt/internal/RemoteCache.scala b/main/src/main/scala/sbt/internal/RemoteCache.scala index cea7abecd..be3b29b82 100644 --- a/main/src/main/scala/sbt/internal/RemoteCache.scala +++ b/main/src/main/scala/sbt/internal/RemoteCache.scala @@ -14,10 +14,15 @@ import Keys._ import SlashSyntax0._ import ScopeFilter.Make._ import Project._ // for tag and inTask() + +import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact, DefaultArtifact } +import org.apache.ivy.core.resolve.DownloadOptions +import org.apache.ivy.core.report.DownloadStatus +import org.apache.ivy.plugins.resolver.DependencyResolver import std.TaskExtra._ // for join import sbt.coursierint.LMCoursier import sbt.librarymanagement._ -import sbt.librarymanagement.ivy.Credentials +import sbt.librarymanagement.ivy.{ Credentials, IvyPaths, UpdateOptions } import sbt.librarymanagement.syntax._ import sbt.nio.FileStamp import sbt.nio.Keys.{ inputFileStamps, outputFileStamps } @@ -52,94 +57,43 @@ object RemoteCache { ) lazy val projectSettings: Seq[Def.Setting[_]] = (Seq( - remoteCacheId := (Def.taskDyn { - val filter = - ScopeFilter(configurations = inConfigurations(Compile, Test), tasks = inTasks(packageCache)) + pushRemoteCache := (Def.taskDyn { + val arts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value + val configs = arts flatMap { art => + art.packaged.scopedKey.scope match { + case Scope(_, Select(c), _, _) => Some(c) + case _ => None + } + } + val filter = ScopeFilter(configurations = inConfigurationsByKeys(configs: _*)) Def.task { - val allHashes = remoteCacheId.all(filter).value - combineHash(allHashes.toVector) + val _ = pushRemoteCache.all(filter).value + () + } + }).value, + pullRemoteCache := (Def.taskDyn { + val arts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value + val configs = arts flatMap { art => + art.packaged.scopedKey.scope match { + case Scope(_, Select(c), _, _) => Some(c) + case _ => None + } + } + val filter = ScopeFilter(configurations = inConfigurationsByKeys(configs: _*)) + Def.task { + val _ = pullRemoteCache.all(filter).value + () } }).value, - remoteCacheIdCandidates := List(remoteCacheId.value), - remoteCacheProjectId := { - val o = organization.value - val m = moduleName.value - val id = remoteCacheId.value - val c = (projectID / crossVersion).value - val v = toVersion(id) - ModuleID(o, m, v).cross(c) - }, - pushRemoteCacheConfiguration / publishMavenStyle := true, - pushRemoteCacheConfiguration / packagedArtifacts := Def.taskDyn { - val artifacts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value - - artifacts - .map(a => a.packaged.map(file => (a.artifact, file))) - .join - .apply(_.join.map(_.toMap)) - }.value, pushRemoteCacheConfiguration / remoteCacheArtifacts := { enabledOnly(remoteCacheArtifact.toSettingKey, defaultArtifactTasks).apply(_.join).value }, + pushRemoteCacheConfiguration / publishMavenStyle := true, Compile / packageCache / pushRemoteCacheArtifact := true, Test / packageCache / pushRemoteCacheArtifact := true, Compile / packageCache / artifact := Artifact(moduleName.value, cachedCompileClassifier), Test / packageCache / artifact := Artifact(moduleName.value, cachedTestClassifier), remoteCachePom / pushRemoteCacheArtifact := true, - pushRemoteCacheConfiguration := { - Classpaths.publishConfig( - (pushRemoteCacheConfiguration / publishMavenStyle).value, - Classpaths.deliverPattern(crossTarget.value), - if (isSnapshot.value) "integration" else "release", - ivyConfigurations.value.map(c => ConfigRef(c.name)).toVector, - (pushRemoteCacheConfiguration / packagedArtifacts).value.toVector, - (pushRemoteCacheConfiguration / checksums).value.toVector, - Classpaths.getPublishTo(pushRemoteCacheTo.value).name, - ivyLoggingLevel.value, - isSnapshot.value - ) - }, - pullRemoteCache := { - val log = streams.value.log - val smi = scalaModuleInfo.value - val dr = (pullRemoteCache / dependencyResolution).value - val is = (pushRemoteCache / ivySbt).value - val t = crossTarget.value / "cache-download" - val p = remoteCacheProjectId.value - val ids = remoteCacheIdCandidates.value - val artifacts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value - val applicable = artifacts.filterNot(isPomArtifact) - val classifiers = applicable.flatMap(_.artifact.classifier).toVector - - var found = false - ids foreach { - id: String => - val v = toVersion(id) - val modId = p.withRevision(v) - if (found) () - else - pullFromMavenRepo0(modId, classifiers, smi, is, dr, t, log) match { - case Right(xs0) => - val jars = xs0.distinct - - applicable.foreach { art => - val classifier = art.artifact.classifier - - findJar(classifier, v, jars) match { - case Some(jar) => - extractJar(art, jar) - log.info(s"remote cache artifact extracted for $p $classifier") - - case None => - log.info(s"remote cache artifact not found for $p $classifier") - } - } - found = true - case Left(unresolvedWarning) => - log.info(s"remote cache not found for ${v}") - } - } - }, remoteCachePom := { val s = streams.value val config = (remoteCachePom / makePomConfiguration).value @@ -156,62 +110,43 @@ object RemoteCache { }, remoteCachePom / remoteCacheArtifact := { PomRemoteCacheArtifact((makePom / artifact).value, remoteCachePom) - } + }, + remoteCacheResolvers := pushRemoteCacheTo.value.toVector, ) ++ inTask(pushRemoteCache)( Seq( + ivyPaths := IvyPaths(baseDirectory.value, crossTarget.value / "remote-cache"), ivyConfiguration := { - val other = pushRemoteCacheTo.value.toVector val config0 = Classpaths.mkIvyConfiguration.value config0 - .withOtherResolvers(other) + .withResolvers(remoteCacheResolvers.value.toVector) + .withOtherResolvers(pushRemoteCacheTo.value.toVector) .withResolutionCacheDir(crossTarget.value / "alt-resolution") + .withPaths(ivyPaths.value) + .withUpdateOptions(UpdateOptions().withGigahorse(true)) }, ivySbt := { - val config0 = ivyConfiguration.value Credentials.register(credentials.value, streams.value.log) + val config0 = ivyConfiguration.value new IvySbt(config0, CustomHttp.okhttpClient.value) }, - ivyModule := { - val is = ivySbt.value - new is.Module(moduleSettings.value) - }, - moduleSettings := { - val smi = scalaModuleInfo.value - ModuleDescriptorConfiguration(remoteCacheProjectId.value, projectInfo.value) - .withScalaModuleInfo(smi) - }, - pushRemoteCache.in(Defaults.TaskZero) := (Def.task { - val s = streams.value - val config = pushRemoteCacheConfiguration.value - IvyActions.publish(ivyModule.value, config, s.log) - } tag (Tags.Publish, Tags.Network)).value ) ) ++ inTask(pullRemoteCache)( Seq( dependencyResolution := Defaults.dependencyResolutionTask.value, csrConfiguration := { - val rs = pushRemoteCacheTo.value.toVector + val rs = pushRemoteCacheTo.value.toVector ++ remoteCacheResolvers.value.toVector LMCoursier.scalaCompilerBridgeConfigurationTask.value .withResolvers(rs) } ) - ) ++ inConfig(Compile)(packageCacheSettings(compileArtifact(Compile, cachedCompileClassifier))) - ++ inConfig(Test)(packageCacheSettings(testArtifact(Test, cachedTestClassifier)))) + ) ++ inConfig(Compile)(configCacheSettings(compileArtifact(Compile, cachedCompileClassifier))) + ++ inConfig(Test)(configCacheSettings(testArtifact(Test, cachedTestClassifier)))) - def packageCacheSettings[A <: RemoteCacheArtifact]( - cacheArtifact: Def.Initialize[Task[A]] + def configCacheSettings[A <: RemoteCacheArtifact]( + cacheArtifactTask: Def.Initialize[Task[A]] ): Seq[Def.Setting[_]] = inTask(packageCache)( Seq( - remoteCacheId := { - val inputs = (unmanagedSources / inputFileStamps).value - val cp = (externalDependencyClasspath / outputFileStamps).value - val extraInc = (extraIncOptions.value) flatMap { - case (k, v) => - Vector(k, v) - } - combineHash(extractHash(inputs) ++ extractHash(cp) ++ extraInc) - }, packageCache.in(Defaults.TaskZero) := { val original = packageBin.in(Defaults.TaskZero).value val artp = artifactPath.value @@ -229,10 +164,128 @@ object RemoteCache { // } artp }, - remoteCacheArtifact := cacheArtifact.value, + pushRemoteCacheArtifact := true, + remoteCacheArtifact := cacheArtifactTask.value, packagedArtifact := (artifact.value -> packageCache.value), artifactPath := Defaults.artifactPathSetting(artifact).value ) + ) ++ inTask(pushRemoteCache)( + Seq( + moduleSettings := { + val smi = scalaModuleInfo.value + ModuleDescriptorConfiguration(remoteCacheProjectId.value, projectInfo.value) + .withScalaModuleInfo(smi) + }, + pushRemoteCache.in(Defaults.TaskZero) := (Def.task { + val s = streams.value + val config = pushRemoteCacheConfiguration.value + val is = (pushRemoteCache / ivySbt).value + val m = new is.Module(moduleSettings.value) + IvyActions.publish(m, config, s.log) + } tag (Tags.Publish, Tags.Network)).value, + ) + ) ++ Seq( + remoteCacheIdCandidates := List(remoteCacheId.value), + remoteCacheProjectId := { + val o = organization.value + val m = moduleName.value + val id = remoteCacheId.value + val c = (projectID / crossVersion).value + val v = toVersion(id) + ModuleID(o, m, v).cross(c) + }, + remoteCacheId := { + val inputs = (unmanagedSources / inputFileStamps).value + val cp = (externalDependencyClasspath / outputFileStamps).?.value.getOrElse(Nil) + val extraInc = (extraIncOptions.value) flatMap { + case (k, v) => + Vector(k, v) + } + combineHash(extractHash(inputs) ++ extractHash(cp) ++ extraInc) + }, + pushRemoteCacheConfiguration := { + Classpaths.publishConfig( + (pushRemoteCacheConfiguration / publishMavenStyle).value, + Classpaths.deliverPattern(crossTarget.value), + if (isSnapshot.value) "integration" else "release", + ivyConfigurations.value.map(c => ConfigRef(c.name)).toVector, + (pushRemoteCacheConfiguration / packagedArtifacts).value.toVector, + (pushRemoteCacheConfiguration / checksums).value.toVector, + Classpaths.getPublishTo(pushRemoteCacheTo.value).name, + ivyLoggingLevel.value, + isSnapshot.value + ) + }, + pushRemoteCacheConfiguration / packagedArtifacts := Def.taskDyn { + val artifacts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value + artifacts + .map(a => a.packaged.map(file => (a.artifact, file))) + .join + .apply(_.join.map(_.toMap)) + }.value, + pushRemoteCacheConfiguration / remoteCacheArtifacts := { + List((packageCache / remoteCacheArtifact).value) + }, + pullRemoteCache := { + import scala.collection.JavaConverters._ + val log = streams.value.log + val r = remoteCacheResolvers.value.head + val p = remoteCacheProjectId.value + val ids = remoteCacheIdCandidates.value + val is = (pushRemoteCache / ivySbt).value + val m = new is.Module((pushRemoteCache / moduleSettings).value) + val smi = scalaModuleInfo.value + val artifacts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value + val nonPom = artifacts.filterNot(isPomArtifact).toVector + m.withModule(log) { + case (ivy, md, _) => + val resolver = ivy.getSettings.getResolver(r.name) + if (resolver eq null) sys.error(s"undefined resolver '${r.name}'") + val cross = CrossVersion(p, smi) + val crossf: String => String = cross.getOrElse(identity _) + var found = false + ids foreach { + id: String => + val v = toVersion(id) + val modId = p.withRevision(v).withName(crossf(p.name)) + val ivyId = IvySbt.toID(modId) + if (found) () + else { + val rawa = nonPom map { _.artifact } + val seqa = CrossVersion.substituteCross(rawa, cross) + val as = seqa map { a => + val extra = a.classifier match { + case Some(c) => Map("e:classifier" -> c) + case None => Map.empty + } + new DefaultArtifact(ivyId, null, a.name, a.`type`, a.extension, extra.asJava) + } + pullFromMavenRepo0(as, resolver, log) match { + case Right(xs0) => + val jars = xs0.distinct + + nonPom.foreach { art => + val classifier = art.artifact.classifier + + findJar(classifier, v, jars) match { + case Some(jar) => + extractJar(art, jar) + log.info(s"remote cache artifact extracted for $p $classifier") + + case None => + log.info(s"remote cache artifact not found for $p $classifier") + } + } + found = true + case Left(e) => + log.info(s"remote cache not found for ${v}") + log.debug(e.getMessage) + } + } + } + () + } + }, ) def isPomArtifact(artifact: RemoteCacheArtifact): Boolean = @@ -268,26 +321,35 @@ object RemoteCache { private def toVersion(v: String): String = s"0.0.0-$v" + private lazy val doption = new DownloadOptions private def pullFromMavenRepo0( - modId: ModuleID, - classifiers: Vector[String], - smi: Option[ScalaModuleInfo], - is: IvySbt, - dr: DependencyResolution, - cacheDir: File, + artifacts: Vector[IArtifact], + r: DependencyResolver, log: Logger - ): Either[UnresolvedWarning, Vector[File]] = { - def dummyModule(deps: Vector[ModuleID]): ModuleDescriptorConfiguration = { - val module = ModuleID("com.example.temp", "fake", "0.1.0-SNAPSHOT") - val info = ModuleInfo("fake", "", None, None, Vector(), "", None, None, Vector()) - ModuleDescriptorConfiguration(module, info) - .withScalaModuleInfo(smi) - .withDependencies(deps) + ): Either[Throwable, Vector[File]] = { + try { + val files = r.download(artifacts.toArray, doption).getArtifactsReports.toVector map { + report => + if (report == null) sys.error(s"failed to download $artifacts: " + r.toString) + else + report.getDownloadStatus match { + case DownloadStatus.NO => + val o = report.getArtifactOrigin + if (o.isLocal) { + val localFile = new File(o.getLocation) + if (!localFile.exists) sys.error(s"$localFile doesn't exist") + else localFile + } else report.getLocalFile + case DownloadStatus.SUCCESSFUL => + report.getLocalFile + case DownloadStatus.FAILED => + sys.error(s"failed to download $artifacts: " + r.toString) + } + } + Right(files) + } catch { + case e: Throwable => Left(e) } - val deps = classifiers.map(modId.classifier) - val mconfig = dummyModule(deps) - val m = new is.Module(mconfig) - dr.retrieve(m, cacheDir, log) } private def findJar(classifier: Option[String], ver: String, jars: Vector[File]): Option[File] = { @@ -345,7 +407,7 @@ object RemoteCache { } private def defaultArtifactTasks: Seq[TaskKey[File]] = - Seq(remoteCachePom, Compile / packageCache, Test / packageCache) + Seq(Compile / packageCache, Test / packageCache) private def enabledOnly[A]( key: SettingKey[A], diff --git a/sbt/src/sbt-test/actions/remote-cache-semanticdb/build.sbt b/sbt/src/sbt-test/actions/remote-cache-semanticdb/build.sbt index d35dd9ea0..374410229 100644 --- a/sbt/src/sbt-test/actions/remote-cache-semanticdb/build.sbt +++ b/sbt/src/sbt-test/actions/remote-cache-semanticdb/build.sbt @@ -10,8 +10,9 @@ pushRemoteCacheTo := Some( MavenCache("local-cache", (ThisBuild / baseDirectory).value / "remote-cache-semanticdb") ) -remoteCacheId := "fixed-id" - -remoteCacheIdCandidates := Seq(remoteCacheId.value) - -pushRemoteCacheConfiguration := pushRemoteCacheConfiguration.value.withOverwrite(true) +Compile / remoteCacheId := "fixed-id" +Compile / remoteCacheIdCandidates := Seq((Compile / remoteCacheId).value) +Test / remoteCacheId := "fixed-id" +Test / remoteCacheIdCandidates := Seq((Test / remoteCacheId).value) +Compile / pushRemoteCacheConfiguration := (Compile / pushRemoteCacheConfiguration).value.withOverwrite(true) +Test / pushRemoteCacheConfiguration := (Test / pushRemoteCacheConfiguration).value.withOverwrite(true) diff --git a/sbt/src/sbt-test/actions/remote-cache-semanticdb/test b/sbt/src/sbt-test/actions/remote-cache-semanticdb/test index bb3bff980..3875dd2ea 100644 --- a/sbt/src/sbt-test/actions/remote-cache-semanticdb/test +++ b/sbt/src/sbt-test/actions/remote-cache-semanticdb/test @@ -10,11 +10,6 @@ $ exists target/scala-2.12/test-classes/MyTest$.class $ exists target/scala-2.12/test-classes/META-INF/semanticdb/src/test/scala/MyTest.scala.semanticdb $ exists target/scala-2.12/test-zinc/inc_compile_2.12.zip -# Pom file -$ exists remote-cache-semanticdb/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id.pom -$ exists remote-cache-semanticdb/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id.pom.md5 -$ exists remote-cache-semanticdb/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id.pom.sha1 - # Compile $ exists remote-cache-semanticdb/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-compile.jar $ exists remote-cache-semanticdb/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-compile.jar.md5 diff --git a/sbt/src/sbt-test/actions/remote-cache/build.sbt b/sbt/src/sbt-test/actions/remote-cache/build.sbt index 8682caad0..6ea9d9f49 100644 --- a/sbt/src/sbt-test/actions/remote-cache/build.sbt +++ b/sbt/src/sbt-test/actions/remote-cache/build.sbt @@ -10,27 +10,27 @@ val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterati ThisBuild / scalaVersion := "2.12.12" ThisBuild / pushRemoteCacheTo := Some( - MavenCache("local-cache", (ThisBuild / baseDirectory).value / "remote-cache") + MavenCache("local-cache", (ThisBuild / baseDirectory).value / "r") ) lazy val root = (project in file(".")) .configs(CustomArtifact) .settings( name := "my-project", - pushRemoteCacheConfiguration := pushRemoteCacheConfiguration.value.withOverwrite(true), - pushRemoteCacheConfiguration / remoteCacheArtifacts += { - val art = (CustomArtifact / artifact).value - val packaged = CustomArtifact / packageCache - val extractDirectory = (CustomArtifact / sourceManaged).value - CustomRemoteCacheArtifact(art, packaged, extractDirectory, preserveLastModified = false) - }, + + customArtifactSettings, + pushRemoteCacheConfiguration / remoteCacheArtifacts += (CustomArtifact / packageCache / remoteCacheArtifact).value, + + Compile / pushRemoteCacheConfiguration := (Compile / pushRemoteCacheConfiguration).value.withOverwrite(true), + Test / pushRemoteCacheConfiguration := (Test / pushRemoteCacheConfiguration).value.withOverwrite(true), + Compile / sourceGenerators += Def.task { val extractDirectory = (CustomArtifact / sourceManaged).value val output = extractDirectory / "HelloWorld.scala" IO.write(output, "class HelloWorld") Seq(output) }.taskValue, - customArtifactSettings, + // test tasks recordPreviousIterations := { val log = streams.value.log @@ -54,7 +54,14 @@ lazy val root = (project in file(".")) def customArtifactSettings: Seq[Def.Setting[_]] = { val classifier = "custom-artifact" + def cachedArtifactTask = Def.task { + val art = (CustomArtifact / artifact).value + val packaged = CustomArtifact / packageCache + val extractDirectory = (CustomArtifact / sourceManaged).value + CustomRemoteCacheArtifact(art, packaged, extractDirectory, preserveLastModified = false) + } inConfig(CustomArtifact)( + sbt.internal.RemoteCache.configCacheSettings(cachedArtifactTask) ++ Seq( packageOptions := { val n = name.value + "-" + classifier diff --git a/sbt/src/sbt-test/actions/remote-cache/test b/sbt/src/sbt-test/actions/remote-cache/test index ff1289d45..feab2a060 100644 --- a/sbt/src/sbt-test/actions/remote-cache/test +++ b/sbt/src/sbt-test/actions/remote-cache/test @@ -13,19 +13,19 @@ $ exists target/scala-2.12/test-classes/MyTest$.class $ exists target/scala-2.12/test-zinc/inc_compile_2.12.zip # Compile -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-cached-compile.jar -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-cached-compile.jar.md5 -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-cached-compile.jar.sha1 +$ exists r/my-project/my-project_2.12/0.0.0-789740d77fd44aa9/my-project_2.12-0.0.0-789740d77fd44aa9-cached-compile.jar +$ exists r/my-project/my-project_2.12/0.0.0-789740d77fd44aa9/my-project_2.12-0.0.0-789740d77fd44aa9-cached-compile.jar.md5 +$ exists r/my-project/my-project_2.12/0.0.0-789740d77fd44aa9/my-project_2.12-0.0.0-789740d77fd44aa9-cached-compile.jar.sha1 # Test -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-cached-test.jar -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-cached-test.jar.md5 -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-cached-test.jar.sha1 +$ exists r/my-project/my-project_2.12/0.0.0-9cd077da3ad28ae5/my-project_2.12-0.0.0-9cd077da3ad28ae5-cached-test.jar +$ exists r/my-project/my-project_2.12/0.0.0-9cd077da3ad28ae5/my-project_2.12-0.0.0-9cd077da3ad28ae5-cached-test.jar.md5 +$ exists r/my-project/my-project_2.12/0.0.0-9cd077da3ad28ae5/my-project_2.12-0.0.0-9cd077da3ad28ae5-cached-test.jar.sha1 # Custom artifact -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-custom-artifact.jar -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-custom-artifact.jar.md5 -$ exists remote-cache/my-project/my-project_2.12/0.0.0-b63e5c6efa2d0fd2/my-project_2.12-0.0.0-b63e5c6efa2d0fd2-custom-artifact.jar.sha1 +$ exists r/my-project/my-project_2.12/0.0.0-1497188b634e2cd0/my-project_2.12-0.0.0-1497188b634e2cd0-custom-artifact.jar +$ exists r/my-project/my-project_2.12/0.0.0-1497188b634e2cd0/my-project_2.12-0.0.0-1497188b634e2cd0-custom-artifact.jar.md5 +$ exists r/my-project/my-project_2.12/0.0.0-1497188b634e2cd0/my-project_2.12-0.0.0-1497188b634e2cd0-custom-artifact.jar.sha1 > clean