From 98ec0fd8d7069ae4545d945ecc6dbd649d36a1c8 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 26 Oct 2020 00:08:18 -0400 Subject: [PATCH 1/6] 1.4.2-SNAPSHOT --- .travis.yml | 2 +- build.sbt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e7247c4c0..88c2bed03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ matrix: include: - env: - SBT_LOCAL=true - - SBT_VERSION_PROP=-Dsbt.version=1.4.1-SNAPSHOT + - SBT_VERSION_PROP=-Dsbt.version=1.4.2-SNAPSHOT - TRAVIS_JDK=adopt@1.8.0-222 - SBT_CMD="++$SCALA_213; $UTIL_TESTS; ++$SCALA_212; $UTIL_TESTS; scripted actions/* source-dependencies/*1of3 dependency-management/*1of4 java/*" diff --git a/build.sbt b/build.sbt index 9a3265239..fe70d1d5d 100644 --- a/build.sbt +++ b/build.sbt @@ -8,7 +8,8 @@ import java.nio.file.{ Files, Path => JPath } import scala.util.Try ThisBuild / version := { - val v = "1.4.1-SNAPSHOT" + // update .travis.yml too for dog fooding + val v = "1.4.2-SNAPSHOT" nightlyVersion.getOrElse(v) } ThisBuild / versionScheme := Some("early-semver") From 86e793cd743c42ef46937f36eac16f0ad2d94140 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 26 Oct 2020 00:11:23 -0400 Subject: [PATCH 2/6] Make remoteCacheId content-based Fixes https://github.com/sbt/sbt/issues/5842 --- main/src/main/scala/sbt/Defaults.scala | 8 ++++ .../main/scala/sbt/internal/RemoteCache.scala | 38 +++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 00dec4d37..be2fe3bb2 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -2519,6 +2519,14 @@ object Classpaths { excludeFilter in unmanagedJars value ) ).map(exportClasspath) ++ Seq( + externalDependencyClasspath / outputFileStamps := { + val stamper = timeWrappedStamper.value + val converter = fileConverter.value + externalDependencyClasspath.value flatMap { file0 => + val p = file0.data.toPath + FileStamp(stamper.library(converter.toVirtualFile(p))).map(p -> _) + } + }, dependencyClasspathFiles := data(dependencyClasspath.value).map(_.toPath), dependencyClasspathFiles / outputFileStamps := { val stamper = timeWrappedStamper.value diff --git a/main/src/main/scala/sbt/internal/RemoteCache.scala b/main/src/main/scala/sbt/internal/RemoteCache.scala index a6f24cb81..78977ff61 100644 --- a/main/src/main/scala/sbt/internal/RemoteCache.scala +++ b/main/src/main/scala/sbt/internal/RemoteCache.scala @@ -9,6 +9,7 @@ package sbt package internal import java.io.File +import java.nio.file.Path import Keys._ import SlashSyntax0._ import Project._ // for tag and inTask() @@ -17,11 +18,14 @@ import sbt.coursierint.LMCoursier import sbt.librarymanagement._ import sbt.librarymanagement.ivy.Credentials import sbt.librarymanagement.syntax._ +import sbt.nio.FileStamp +import sbt.nio.Keys.{ inputFileStamps, outputFileStamps } import sbt.internal.librarymanagement._ import sbt.io.IO import sbt.io.syntax._ import sbt.internal.remotecache._ -import sbt.internal.inc.JarUtils +import sbt.internal.inc.{ HashUtil, JarUtils } +import sbt.util.InterfaceUtil.toOption import sbt.util.Logger object RemoteCache { @@ -41,12 +45,30 @@ object RemoteCache { .map(_.take(commitLength)) lazy val globalSettings: Seq[Def.Setting[_]] = Seq( - remoteCacheId := gitCommitId, - remoteCacheIdCandidates := gitCommitIds(5), + remoteCacheId := "", + remoteCacheIdCandidates := Nil, pushRemoteCacheTo :== None ) lazy val projectSettings: Seq[Def.Setting[_]] = (Seq( + remoteCacheId := { + val compileExtraInc = (Compile / extraIncOptions).value + val compileInputs = (Compile / unmanagedSources / inputFileStamps).value + val compileCp = (Compile / externalDependencyClasspath / outputFileStamps).value + val testExtraInc = (Compile / extraIncOptions).value + val testInputs = (Test / unmanagedSources / inputFileStamps).value + val testCp = (Test / externalDependencyClasspath / outputFileStamps).value + val extraInc = (compileExtraInc.toVector ++ testExtraInc.toVector) flatMap { + case (k, v) => + Vector(k, v) + } + combineHash( + extractHash(compileInputs) ++ extractHash(compileCp) ++ extractHash(testInputs) ++ extractHash( + testCp + ) ++ extraInc + ) + }, + remoteCacheIdCandidates := List(remoteCacheId.value), remoteCacheProjectId := { val o = organization.value val m = moduleName.value @@ -332,4 +354,14 @@ object RemoteCache { Classpaths.forallIn(pushRemoteCacheArtifact, pkgTasks))(_ zip _ collect { case (a, true) => a }) + + private def extractHash(inputs: Seq[(Path, FileStamp)]): Vector[String] = + inputs.toVector map { + case (_, stamp0) => toOption(stamp0.stamp.getHash).getOrElse("cafe") + } + + private def combineHash(vs: Vector[String]): String = { + val hashValue = HashUtil.farmHash(vs.sorted.mkString("").getBytes("UTF-8")) + java.lang.Long.toHexString(hashValue) + } } From 6a356c61e06731fa43037dcf477d8a82bf193ae9 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 29 Oct 2020 09:47:27 -0400 Subject: [PATCH 3/6] Refactor remoteCacheId --- .../main/scala/sbt/internal/RemoteCache.scala | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/main/src/main/scala/sbt/internal/RemoteCache.scala b/main/src/main/scala/sbt/internal/RemoteCache.scala index 78977ff61..cea7abecd 100644 --- a/main/src/main/scala/sbt/internal/RemoteCache.scala +++ b/main/src/main/scala/sbt/internal/RemoteCache.scala @@ -12,6 +12,7 @@ import java.io.File import java.nio.file.Path import Keys._ import SlashSyntax0._ +import ScopeFilter.Make._ import Project._ // for tag and inTask() import std.TaskExtra._ // for join import sbt.coursierint.LMCoursier @@ -51,23 +52,14 @@ object RemoteCache { ) lazy val projectSettings: Seq[Def.Setting[_]] = (Seq( - remoteCacheId := { - val compileExtraInc = (Compile / extraIncOptions).value - val compileInputs = (Compile / unmanagedSources / inputFileStamps).value - val compileCp = (Compile / externalDependencyClasspath / outputFileStamps).value - val testExtraInc = (Compile / extraIncOptions).value - val testInputs = (Test / unmanagedSources / inputFileStamps).value - val testCp = (Test / externalDependencyClasspath / outputFileStamps).value - val extraInc = (compileExtraInc.toVector ++ testExtraInc.toVector) flatMap { - case (k, v) => - Vector(k, v) + remoteCacheId := (Def.taskDyn { + val filter = + ScopeFilter(configurations = inConfigurations(Compile, Test), tasks = inTasks(packageCache)) + Def.task { + val allHashes = remoteCacheId.all(filter).value + combineHash(allHashes.toVector) } - combineHash( - extractHash(compileInputs) ++ extractHash(compileCp) ++ extractHash(testInputs) ++ extractHash( - testCp - ) ++ extraInc - ) - }, + }).value, remoteCacheIdCandidates := List(remoteCacheId.value), remoteCacheProjectId := { val o = organization.value @@ -206,11 +198,20 @@ object RemoteCache { ) ++ inConfig(Compile)(packageCacheSettings(compileArtifact(Compile, cachedCompileClassifier))) ++ inConfig(Test)(packageCacheSettings(testArtifact(Test, cachedTestClassifier)))) - private def packageCacheSettings[A <: RemoteCacheArtifact]( + def packageCacheSettings[A <: RemoteCacheArtifact]( cacheArtifact: 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 From 078280ac47cad409150aa9fe95d692d8e3f565a1 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 31 Oct 2020 07:26:33 -0400 Subject: [PATCH 4/6] Make sure we test the caching effect --- .../sbt-test/actions/remote-cache/build.sbt | 44 ++++++++++++++----- .../remote-cache/project/CompileState.scala | 4 ++ sbt/src/sbt-test/actions/remote-cache/test | 27 ++++++------ 3 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 sbt/src/sbt-test/actions/remote-cache/project/CompileState.scala diff --git a/sbt/src/sbt-test/actions/remote-cache/build.sbt b/sbt/src/sbt-test/actions/remote-cache/build.sbt index e14afca15..8682caad0 100644 --- a/sbt/src/sbt-test/actions/remote-cache/build.sbt +++ b/sbt/src/sbt-test/actions/remote-cache/build.sbt @@ -1,21 +1,27 @@ import sbt.internal.remotecache.CustomRemoteCacheArtifact +import sbt.internal.inc.Analysis +import complete.DefaultParsers._ + +lazy val CustomArtifact = config("custom-artifact") + +// Reset compiler iterations, necessary because tests run in batch mode +val recordPreviousIterations = taskKey[Unit]("Record previous iterations.") +val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.") + +ThisBuild / scalaVersion := "2.12.12" +ThisBuild / pushRemoteCacheTo := Some( + MavenCache("local-cache", (ThisBuild / baseDirectory).value / "remote-cache") +) lazy val root = (project in file(".")) .configs(CustomArtifact) .settings( name := "my-project", - scalaVersion := "2.12.12", - pushRemoteCacheTo := Some( - MavenCache("local-cache", (ThisBuild / baseDirectory).value / "remote-cache") - ), - remoteCacheId := "fixed-id", - remoteCacheIdCandidates := Seq("fixed-id"), 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) }, Compile / sourceGenerators += Def.task { @@ -23,11 +29,27 @@ lazy val root = (project in file(".")) val output = extractDirectory / "HelloWorld.scala" IO.write(output, "class HelloWorld") Seq(output) - }.taskValue + }.taskValue, + customArtifactSettings, + // test tasks + recordPreviousIterations := { + val log = streams.value.log + CompileState.previousIterations = { + val previousAnalysis = (previousCompile in Compile).value.analysis.asScala + previousAnalysis match { + case None => + log.info("No previous analysis detected") + 0 + case Some(a: Analysis) => a.compilations.allCompilations.size + } + } + }, + checkIterations := { + val expected: Int = (Space ~> NatBasic).parsed + val actual: Int = ((compile in Compile).value match { case a: Analysis => a.compilations.allCompilations.size }) - CompileState.previousIterations + assert(expected == actual, s"Expected $expected compilations, got $actual") + } ) - .settings(customArtifactSettings) - -lazy val CustomArtifact = config("custom-artifact") def customArtifactSettings: Seq[Def.Setting[_]] = { val classifier = "custom-artifact" diff --git a/sbt/src/sbt-test/actions/remote-cache/project/CompileState.scala b/sbt/src/sbt-test/actions/remote-cache/project/CompileState.scala new file mode 100644 index 000000000..078db9c7b --- /dev/null +++ b/sbt/src/sbt-test/actions/remote-cache/project/CompileState.scala @@ -0,0 +1,4 @@ +// This is necessary because tests are run in batch mode +object CompileState { + @volatile var previousIterations: Int = -1 +} diff --git a/sbt/src/sbt-test/actions/remote-cache/test b/sbt/src/sbt-test/actions/remote-cache/test index e90fade3e..ff1289d45 100644 --- a/sbt/src/sbt-test/actions/remote-cache/test +++ b/sbt/src/sbt-test/actions/remote-cache/test @@ -1,3 +1,4 @@ +> recordPreviousIterations > compile > pushRemoteCache @@ -11,25 +12,20 @@ $ exists target/scala-2.12/test-classes/MyTest.class $ exists target/scala-2.12/test-classes/MyTest$.class $ exists target/scala-2.12/test-zinc/inc_compile_2.12.zip -# Pom file -$ exists remote-cache/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id.pom -$ exists remote-cache/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/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/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/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-compile.jar.md5 -$ exists remote-cache/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-compile.jar.sha1 +$ 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 # Test -$ exists remote-cache/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-test.jar -$ exists remote-cache/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-test.jar.md5 -$ exists remote-cache/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-test.jar.sha1 +$ 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 # Custom artifact -$ exists remote-cache/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-custom-artifact.jar -$ exists remote-cache/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-custom-artifact.jar.md5 -$ exists remote-cache/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-custom-artifact.jar.sha1 +$ 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 > clean @@ -54,5 +50,8 @@ $ exists target/scala-2.12/test-classes/MyTest.class $ exists target/scala-2.12/test-classes/MyTest$.class $ exists target/scala-2.12/test-zinc/inc_compile_2.12.zip +> debug +> checkIterations 1 + # Artifacts can be pushed twice (enabled overriding) > pushRemoteCache \ No newline at end of file From 744cfefa6c118a309d44b3b2ffd638c89083fd36 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 1 Nov 2020 15:08:46 -0500 Subject: [PATCH 5/6] Refactor remote cache to per-config Refactor remote caching to be scoped to configuration. In addition, this avoid the use of dependency resolver (since I'm not resolving anything) and directly invoke the Ivy resolver for the artifact, somewhat analogus to publishing process. This should speed up the `pullRemoteCache` since it avoids the POM download as well. For sbt-binrary-remote-cache this created a bit of complication since the (publishing) resolver doesn't act correctly as (downloading) resolver in terms of the credentials, so I had to create a new key `remoteCacheResolvers` to have asymmetric resolver. --- build.sbt | 2 +- main/src/main/scala/sbt/Keys.scala | 1 + .../main/scala/sbt/internal/RemoteCache.scala | 320 +++++++++++------- .../actions/remote-cache-semanticdb/build.sbt | 11 +- .../actions/remote-cache-semanticdb/test | 5 - .../sbt-test/actions/remote-cache/build.sbt | 25 +- sbt/src/sbt-test/actions/remote-cache/test | 18 +- 7 files changed, 224 insertions(+), 158 deletions(-) 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 From 6c344830df204a69dae3ff51669a72ad6dae6f20 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 1 Nov 2020 19:51:57 -0500 Subject: [PATCH 6/6] Bring back fixed-id for testing --- .../sbt-test/actions/remote-cache/build.sbt | 7 +++++++ sbt/src/sbt-test/actions/remote-cache/test | 18 +++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/sbt/src/sbt-test/actions/remote-cache/build.sbt b/sbt/src/sbt-test/actions/remote-cache/build.sbt index 6ea9d9f49..920bc2e0c 100644 --- a/sbt/src/sbt-test/actions/remote-cache/build.sbt +++ b/sbt/src/sbt-test/actions/remote-cache/build.sbt @@ -30,6 +30,13 @@ lazy val root = (project in file(".")) IO.write(output, "class HelloWorld") Seq(output) }.taskValue, + // bring back fixed-id because JDK 8/11 would be different intentionally + Compile / remoteCacheId := "fixed-id", + Compile / remoteCacheIdCandidates := Seq((Compile / remoteCacheId).value), + Test / remoteCacheId := "fixed-id", + Test / remoteCacheIdCandidates := Seq((Test / remoteCacheId).value), + CustomArtifact / remoteCacheId := "fixed-id", + CustomArtifact / remoteCacheIdCandidates := Seq((CustomArtifact / remoteCacheId).value), // test tasks recordPreviousIterations := { diff --git a/sbt/src/sbt-test/actions/remote-cache/test b/sbt/src/sbt-test/actions/remote-cache/test index feab2a060..5c81f25a5 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 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 +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-compile.jar +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-compile.jar.md5 +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-compile.jar.sha1 # Test -$ 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 +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-test.jar +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-test.jar.md5 +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-cached-test.jar.sha1 # Custom artifact -$ 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 +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-custom-artifact.jar +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-custom-artifact.jar.md5 +$ exists r/my-project/my-project_2.12/0.0.0-fixed-id/my-project_2.12-0.0.0-fixed-id-custom-artifact.jar.sha1 > clean