mirror of https://github.com/sbt/sbt.git
Merge pull request #8382 from eed3si9n/wip/remove-old-remote
[2.x] Remove sbt 1.x remote cache impl
This commit is contained in:
commit
476a8fb3a0
27
build.sbt
27
build.sbt
|
|
@ -708,6 +708,33 @@ lazy val mainProj = (project in file("main"))
|
|||
mimaSettings,
|
||||
mimaBinaryIssueFilters ++= Vector(
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.scalaCompilerBridgeBinaryJar"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.packageCache"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pullRemoteCache"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pushRemoteCache"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pushRemoteCacheArtifact"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pushRemoteCacheConfiguration"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pushRemoteCacheTo"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheArtifact"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheArtifacts"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheId"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheIdCandidates"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCachePom"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheProjectId"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheResolvers"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.packageCache"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheId"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheProjectId"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheIdCandidates"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheArtifacts"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheArtifact"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pullRemoteCache"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pushRemoteCache"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pushRemoteCacheArtifact"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pushRemoteCacheConfiguration"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.pushRemoteCacheTo"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCacheResolvers"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.Keys.remoteCachePom"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.internal.RemoteCache.*"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.internal.Compiler.*"),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2781,7 +2781,7 @@ object Classpaths {
|
|||
packagedDefaultArtifacts.value
|
||||
} else Map.empty[Artifact, HashedVirtualFileRef]
|
||||
}
|
||||
) ++ RemoteCache.projectSettings
|
||||
)
|
||||
|
||||
/**
|
||||
* Produces the Maven-compatible artifacts of an sbt plugin.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import sbt.internal.bsp.*
|
|||
import sbt.internal.inc.ScalaInstance
|
||||
import sbt.internal.librarymanagement.{ CompatibilityWarningOptions, IvySbt }
|
||||
import sbt.internal.librarymanagement.ivy.{ IvyConfiguration, UpdateOptions }
|
||||
import sbt.internal.remotecache.RemoteCacheArtifact
|
||||
import sbt.internal.server.BuildServerProtocol.BspFullWorkspace
|
||||
import sbt.internal.server.{ BspCompileTask, BuildServerReporter, ServerHandler }
|
||||
import sbt.internal.util.{ AttributeKey, ProgressState, SourcePosition }
|
||||
|
|
@ -299,7 +298,6 @@ object Keys {
|
|||
val `package` = taskKey[HashedVirtualFileRef]("Produces the main artifact, such as a binary jar. This is typically an alias for the task that actually does the packaging.").withRank(APlusTask)
|
||||
val packageDoc = taskKey[HashedVirtualFileRef]("Produces a documentation artifact, such as a jar containing API documentation.").withRank(AMinusTask)
|
||||
val packageSrc = taskKey[HashedVirtualFileRef]("Produces a source artifact, such as a jar containing sources and resources.").withRank(AMinusTask)
|
||||
val packageCache = taskKey[HashedVirtualFileRef]("Produces the main artifact for caching.")
|
||||
|
||||
val packageOptions = taskKey[Seq[PackageOption]]("Options for packaging.").withRank(BTask)
|
||||
val packageTimestamp = settingKey[Option[Long]]("Overwrites timestamps in JAR file to make the build reproducible; None keeps the existing timestamps (useful for web resources)").withRank(CSetting)
|
||||
|
|
@ -429,19 +427,6 @@ object Keys {
|
|||
val internalDependencyConfigurations = settingKey[Seq[(ProjectRef, Set[String])]]("The project configurations that this configuration depends on")
|
||||
val closeClassLoaders = settingKey[Boolean]("Close classloaders in run and test when the task completes.").withRank(DSetting)
|
||||
val allowZombieClassLoaders = settingKey[Boolean]("Allow a classloader that has previously been closed by `run` or `test` to continue loading classes.")
|
||||
// val useRemoteCache = settingKey[Boolean]("Use remote cache.")
|
||||
val remoteCacheId = taskKey[String]("Unique identifier for the remote cache.")
|
||||
val remoteCacheProjectId = taskKey[ModuleID]("ModuleID used for remote cache JARs.")
|
||||
val remoteCacheIdCandidates = taskKey[Seq[String]]("Remote cache ids to pull.")
|
||||
val remoteCacheArtifacts = taskKey[Seq[RemoteCacheArtifact]]("Remote cache artifact definitions.")
|
||||
val remoteCacheArtifact = taskKey[RemoteCacheArtifact]("The remote cache artifact definition.")
|
||||
val pullRemoteCache = taskKey[Unit]("Retrieve remote cache.")
|
||||
val pushRemoteCache = taskKey[Unit]("Push remote cache to the cache server.")
|
||||
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[HashedVirtualFileRef]("Generates a pom for publishing when publishing Maven-style.")
|
||||
val localCacheDirectory = settingKey[File]("Operating system specific cache directory.")
|
||||
val localDigestCacheByteSize = SettingKey[Long](BasicKeys.localDigestCacheByteSize).withRank(DSetting)
|
||||
val usePipelining = settingKey[Boolean]("Use subproject pipelining for compilation.").withRank(BSetting)
|
||||
|
|
|
|||
|
|
@ -12,47 +12,12 @@ package internal
|
|||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
|
||||
import org.apache.ivy.core.module.descriptor.{ DefaultArtifact, Artifact as IArtifact }
|
||||
import org.apache.ivy.core.report.DownloadStatus
|
||||
import org.apache.ivy.core.resolve.DownloadOptions
|
||||
import org.apache.ivy.plugins.resolver.DependencyResolver
|
||||
import sbt.Defaults.prefix
|
||||
import sbt.Keys.*
|
||||
import sbt.Project.{ inConfig as _, * }
|
||||
import sbt.ProjectExtra.*
|
||||
import sbt.ScopeFilter.Make.*
|
||||
import sbt.ScopeAxis.Select
|
||||
import sbt.SlashSyntax0.*
|
||||
import sbt.coursierint.LMCoursier
|
||||
import sbt.internal.inc.{ HashUtil, JarUtils }
|
||||
import sbt.internal.librarymanagement.*
|
||||
import sbt.internal.remotecache.*
|
||||
import sbt.io.IO
|
||||
import sbt.io.syntax.*
|
||||
import sbt.librarymanagement.*
|
||||
import sbt.internal.librarymanagement.ivy.{ IvyCredentials, UpdateOptions }
|
||||
import sbt.librarymanagement.syntax.*
|
||||
import sbt.nio.FileStamp
|
||||
import sbt.nio.Keys.{ inputFileStamps, outputFileStamps }
|
||||
import sbt.std.TaskExtra.*
|
||||
import sbt.util.InterfaceUtil.toOption
|
||||
import sbt.util.{ CacheImplicits, DiskActionCacheStore, Logger }
|
||||
import sbt.util.CacheImplicits.given
|
||||
import sbt.util.{ CacheImplicits, DiskActionCacheStore }
|
||||
import sjsonnew.JsonFormat
|
||||
import xsbti.{ FileConverter, HashedVirtualFileRef, VirtualFileRef }
|
||||
import xsbti.compile.CompileAnalysis
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
object RemoteCache {
|
||||
final val cachedCompileClassifier = "cached-compile"
|
||||
final val cachedTestClassifier = "cached-test"
|
||||
final val commitLength = 10
|
||||
|
||||
// TODO: cap with caffeine
|
||||
private[sbt] val analysisStore: mutable.Map[HashedVirtualFileRef, CompileAnalysis] =
|
||||
mutable.Map.empty
|
||||
|
||||
object RemoteCache:
|
||||
private[sbt] def artifactToStr(art: Artifact): String = {
|
||||
import LibraryManagementCodec.given
|
||||
import sjsonnew.support.scalajson.unsafe.*
|
||||
|
|
@ -60,31 +25,11 @@ object RemoteCache {
|
|||
CompactPrinter(Converter.toJsonUnsafe(art)(using format))
|
||||
}
|
||||
|
||||
def gitCommitId: String =
|
||||
scala.sys.process.Process("git rev-parse HEAD").!!.trim.take(commitLength)
|
||||
|
||||
def gitCommitIds(n: Int): List[String] =
|
||||
scala.sys.process
|
||||
.Process("git log -n " + n.toString + " --format=%H")
|
||||
.!!
|
||||
.linesIterator
|
||||
.toList
|
||||
.map(_.take(commitLength))
|
||||
|
||||
lazy val defaultCacheLocation: File = SysProp.globalLocalCache
|
||||
|
||||
lazy val globalSettings: Seq[Def.Setting[?]] = Seq(
|
||||
remoteCacheId := "",
|
||||
remoteCacheIdCandidates :== Nil,
|
||||
pushRemoteCacheTo :== None,
|
||||
localCacheDirectory :== defaultCacheLocation,
|
||||
localDigestCacheByteSize :== CacheImplicits.defaultLocalDigestCacheByteSize,
|
||||
pushRemoteCache / ivyPaths := {
|
||||
val app = appConfiguration.value
|
||||
val base = app.baseDirectory.getCanonicalFile
|
||||
// base is used only to resolve relative paths, which should never happen
|
||||
IvyPaths(base.toString, localCacheDirectory.value.toString)
|
||||
},
|
||||
rootOutputDirectory := {
|
||||
appConfiguration.value.baseDirectory
|
||||
.toPath()
|
||||
|
|
@ -103,408 +48,4 @@ object RemoteCache {
|
|||
remoteCacheTlsClientKey := SysProp.remoteCacheTlsClientKey,
|
||||
remoteCacheHeaders := SysProp.remoteCacheHeaders,
|
||||
)
|
||||
|
||||
lazy val projectSettings: Seq[Def.Setting[?]] = (Seq(
|
||||
pushRemoteCache := ((Def
|
||||
.task {
|
||||
val arts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value
|
||||
val configs = arts flatMap { art =>
|
||||
art.packaged.scopedKey.scope match {
|
||||
case Scope(_, Select(c), _, _) => Some(c)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
ScopeFilter(configurations = inConfigurationsByKeys(configs*))
|
||||
})
|
||||
.flatMapTask { case filter =>
|
||||
Def.task {
|
||||
val _ = pushRemoteCache.all(filter).value
|
||||
()
|
||||
}
|
||||
})
|
||||
.value,
|
||||
pullRemoteCache := ((Def
|
||||
.task {
|
||||
val arts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value
|
||||
val configs = arts flatMap { art =>
|
||||
art.packaged.scopedKey.scope match {
|
||||
case Scope(_, Select(c), _, _) => Some(c)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
ScopeFilter(configurations = inConfigurationsByKeys(configs*))
|
||||
})
|
||||
.flatMapTask { case filter =>
|
||||
Def.task {
|
||||
val _ = pullRemoteCache.all(filter).value
|
||||
()
|
||||
}
|
||||
})
|
||||
.value,
|
||||
pushRemoteCacheConfiguration / remoteCacheArtifacts := Def.uncached {
|
||||
enabledOnly(remoteCacheArtifact.toSettingKey, defaultArtifactTasks).apply(_.join).value
|
||||
},
|
||||
pushRemoteCacheConfiguration / publishMavenStyle := true,
|
||||
Compile / packageCache / pushRemoteCacheArtifact := true,
|
||||
Compile / packageCache / artifact := Artifact(moduleName.value, cachedCompileClassifier),
|
||||
remoteCachePom / pushRemoteCacheArtifact := true,
|
||||
remoteCachePom := Def.uncached {
|
||||
val s = streams.value
|
||||
val converter = fileConverter.value
|
||||
val config = (remoteCachePom / makePomConfiguration).value
|
||||
val publisher = Keys.publisher.value
|
||||
publisher.makePomFile((pushRemoteCache / ivyModule).value, config, s.log)
|
||||
converter.toVirtualFile(config.file.get.toPath)
|
||||
},
|
||||
remoteCachePom / artifactPath := {
|
||||
Defaults.prefixArtifactPathSetting(makePom / artifact, "remote-cache").value
|
||||
},
|
||||
remoteCachePom / makePomConfiguration := {
|
||||
val converter = fileConverter.value
|
||||
val config = makePomConfiguration.value
|
||||
val out = converter.toPath((remoteCachePom / artifactPath).value)
|
||||
config.withFile(out.toFile())
|
||||
},
|
||||
remoteCachePom / remoteCacheArtifact := Def.uncached {
|
||||
PomRemoteCacheArtifact((makePom / artifact).value, remoteCachePom)
|
||||
},
|
||||
remoteCacheResolvers := pushRemoteCacheTo.value.toVector,
|
||||
) ++ inTask(pushRemoteCache)(
|
||||
Seq(
|
||||
ivyPaths := (Scope.Global / pushRemoteCache / ivyPaths).value,
|
||||
ivyConfiguration := Def.uncached {
|
||||
val config0 = Classpaths.mkIvyConfiguration.value
|
||||
config0
|
||||
.withResolvers(remoteCacheResolvers.value.toVector)
|
||||
.withOtherResolvers(pushRemoteCacheTo.value.toVector)
|
||||
.withResolutionCacheDir(crossTarget.value / "alt-resolution")
|
||||
.withPaths(ivyPaths.value)
|
||||
.withUpdateOptions(UpdateOptions().withGigahorse(true))
|
||||
},
|
||||
ivySbt := Def.uncached {
|
||||
IvyCredentials.register(credentials.value, streams.value.log)
|
||||
val config0 = ivyConfiguration.value
|
||||
new IvySbt(config0)
|
||||
},
|
||||
)
|
||||
) ++ inTask(pullRemoteCache)(
|
||||
Seq(
|
||||
dependencyResolution := Def.uncached(Defaults.dependencyResolutionTask.value),
|
||||
csrConfiguration := Def.uncached {
|
||||
val rs = pushRemoteCacheTo.value.toVector ++ remoteCacheResolvers.value.toVector
|
||||
LMCoursier.scalaCompilerBridgeConfigurationTask.value
|
||||
.withResolvers(rs)
|
||||
}
|
||||
)
|
||||
) ++ inConfig(Compile)(configCacheSettings(compileArtifact(Compile, cachedCompileClassifier))))
|
||||
|
||||
def getResourceFilePaths() = Def.task {
|
||||
val syncDir = crossTarget.value / (prefix(configuration.value.name) + "sync")
|
||||
val file = syncDir / "copy-resource"
|
||||
file
|
||||
}
|
||||
|
||||
def configCacheSettings[A <: RemoteCacheArtifact](
|
||||
cacheArtifactTask: Def.Initialize[Task[A]]
|
||||
): Seq[Def.Setting[?]] =
|
||||
inTask(packageCache)(
|
||||
Seq(
|
||||
(Defaults.TaskZero / packageCache) := Def.uncached {
|
||||
val converter = fileConverter.value
|
||||
val original = (Defaults.TaskZero / packageBin).value
|
||||
val originalFile = converter.toPath(original)
|
||||
val artp = artifactPath.value
|
||||
val artpFile = converter.toPath(artp)
|
||||
val af = compileAnalysisFile.value
|
||||
IO.copyFile(originalFile.toFile(), artpFile.toFile())
|
||||
// skip zip manipulation if the artp is a blank file
|
||||
if (af.exists && artpFile.toFile().length() > 0) {
|
||||
JarUtils.includeInJar(artpFile.toFile(), Vector(af -> s"META-INF/inc_compile.zip"))
|
||||
}
|
||||
val rf = getResourceFilePaths().value
|
||||
if (rf.exists) {
|
||||
JarUtils.includeInJar(artpFile.toFile(), Vector(rf -> s"META-INF/copy-resources.txt"))
|
||||
}
|
||||
// val testStream = (test / streams).?.value
|
||||
// testStream foreach { s =>
|
||||
// val sf = Defaults.succeededFile(s.cacheDirectory)
|
||||
// if (sf.exists) {
|
||||
// JarUtils.includeInJar(artp, Vector(sf -> s"META-INF/succeeded_tests"))
|
||||
// }
|
||||
// }
|
||||
converter.toVirtualFile(artpFile)
|
||||
},
|
||||
pushRemoteCacheArtifact := true,
|
||||
remoteCacheArtifact := Def.uncached(cacheArtifactTask.value),
|
||||
packagedArtifact := Def.uncached(artifact.value -> packageCache.value),
|
||||
artifactPath := Defaults.artifactPathSetting(artifact).value
|
||||
)
|
||||
) ++ inTask(pushRemoteCache)(
|
||||
Seq(
|
||||
moduleSettings := Def.uncached {
|
||||
val smi = scalaModuleInfo.value
|
||||
ModuleDescriptorConfiguration(remoteCacheProjectId.value, projectInfo.value)
|
||||
.withScalaModuleInfo(smi)
|
||||
},
|
||||
(Defaults.TaskZero / pushRemoteCache) := (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 := Def.uncached {
|
||||
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 := Def.uncached {
|
||||
val inputs = (unmanagedSources / inputFileStamps).value
|
||||
val cp = (externalDependencyClasspath / outputFileStamps).?.value.getOrElse(Nil)
|
||||
val extraInc = (extraIncOptions.value) flatMap { (k, v) =>
|
||||
Vector(k, v)
|
||||
}
|
||||
combineHash(extractHash(inputs) ++ extractHash(cp) ++ extraInc)
|
||||
},
|
||||
pushRemoteCacheConfiguration := Def.uncached {
|
||||
val converter = fileConverter.value
|
||||
val artifacts =
|
||||
(pushRemoteCacheConfiguration / packagedArtifacts).value.toVector.map { (a, vf) =>
|
||||
a -> converter.toPath(vf).toFile
|
||||
}
|
||||
Classpaths.publishConfig(
|
||||
(pushRemoteCacheConfiguration / publishMavenStyle).value,
|
||||
Classpaths.deliverPattern(crossTarget.value),
|
||||
if (isSnapshot.value) "integration" else "release",
|
||||
ivyConfigurations.value.map(c => ConfigRef(c.name)).toVector,
|
||||
artifacts,
|
||||
(pushRemoteCacheConfiguration / checksums).value.toVector,
|
||||
Classpaths.getPublishTo(pushRemoteCacheTo.value).name,
|
||||
ivyLoggingLevel.value,
|
||||
isSnapshot.value
|
||||
)
|
||||
},
|
||||
pushRemoteCacheConfiguration / packagedArtifacts := Def.uncached(
|
||||
(Def
|
||||
.task { (pushRemoteCacheConfiguration / remoteCacheArtifacts).value })
|
||||
.flatMapTask { case artifacts =>
|
||||
artifacts
|
||||
.map(a => a.packaged.map(file => (a.artifact, file)))
|
||||
.join
|
||||
.apply(_.join.map(_.toMap))
|
||||
}
|
||||
.value
|
||||
),
|
||||
pushRemoteCacheConfiguration / remoteCacheArtifacts := Def.uncached {
|
||||
List((packageCache / remoteCacheArtifact).value)
|
||||
},
|
||||
pullRemoteCache := Def.uncached {
|
||||
import scala.jdk.CollectionConverters.*
|
||||
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
|
||||
val copyResources = getResourceFilePaths().value
|
||||
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[String](_))
|
||||
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, copyResources)
|
||||
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 =
|
||||
artifact match {
|
||||
case _: PomRemoteCacheArtifact => true
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def compileArtifact(
|
||||
configuration: Configuration,
|
||||
classifier: String
|
||||
): Def.Initialize[Task[CompileRemoteCacheArtifact]] = Def.task {
|
||||
CompileRemoteCacheArtifact(
|
||||
Artifact(moduleName.value, classifier),
|
||||
configuration / packageCache,
|
||||
(configuration / classDirectory).value,
|
||||
(configuration / compileAnalysisFile).value
|
||||
)
|
||||
}
|
||||
|
||||
private def toVersion(v: String): String = s"0.0.0-$v"
|
||||
|
||||
private lazy val doption = new DownloadOptions
|
||||
private def pullFromMavenRepo0(
|
||||
artifacts: Vector[IArtifact],
|
||||
r: DependencyResolver,
|
||||
log: Logger
|
||||
): 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)
|
||||
}
|
||||
}
|
||||
|
||||
private def findJar(classifier: Option[String], ver: String, jars: Vector[File]): Option[File] = {
|
||||
val suffix = classifier.fold(ver)(c => s"$ver-$c.jar")
|
||||
jars.find(_.toString.endsWith(suffix))
|
||||
}
|
||||
|
||||
private def extractJar(
|
||||
cacheArtifact: RemoteCacheArtifact,
|
||||
jar: File,
|
||||
copyResources: File
|
||||
): Unit =
|
||||
cacheArtifact match {
|
||||
case a: CompileRemoteCacheArtifact =>
|
||||
extractCache(jar, a.extractDirectory, preserveLastModified = true) { output =>
|
||||
extractAnalysis(output, a.analysisFile)
|
||||
extractResourceList(output, copyResources)
|
||||
}
|
||||
|
||||
case a: TestRemoteCacheArtifact =>
|
||||
extractCache(jar, a.extractDirectory, preserveLastModified = true) { output =>
|
||||
extractAnalysis(output, a.analysisFile)
|
||||
extractTestResult(output, a.testResult)
|
||||
}
|
||||
|
||||
case a: CustomRemoteCacheArtifact =>
|
||||
extractCache(jar, a.extractDirectory, a.preserveLastModified)(_ => ())
|
||||
|
||||
case _ =>
|
||||
()
|
||||
}
|
||||
|
||||
private def extractCache(jar: File, output: File, preserveLastModified: Boolean)(
|
||||
processOutput: File => Unit
|
||||
): Unit = {
|
||||
IO.delete(output)
|
||||
IO.unzip(jar, output, preserveLastModified = preserveLastModified)
|
||||
processOutput(output)
|
||||
|
||||
// preserve semanticdb dir
|
||||
// https://github.com/scalameta/scalameta/blob/a7927ee8e012cfff/semanticdb/scalac/library/src/main/scala/scala/meta/internal/semanticdb/scalac/SemanticdbPaths.scala#L9
|
||||
Option((output / "META-INF").listFiles).foreach(
|
||||
_.iterator.filterNot(_.getName == "semanticdb").foreach(IO.delete)
|
||||
)
|
||||
}
|
||||
|
||||
private def extractAnalysis(output: File, analysisFile: File): Unit = {
|
||||
val metaDir = output / "META-INF"
|
||||
val expandedAnalysis = metaDir / "inc_compile.zip"
|
||||
if (expandedAnalysis.exists) {
|
||||
IO.move(expandedAnalysis, analysisFile)
|
||||
}
|
||||
}
|
||||
|
||||
private def extractResourceList(output: File, copyResources: File): Unit = {
|
||||
val metaDir = output / "META-INF"
|
||||
val extractedCopyResources = metaDir / "copy-resources.txt"
|
||||
if (extractedCopyResources.exists) {
|
||||
IO.move(extractedCopyResources, copyResources)
|
||||
}
|
||||
}
|
||||
|
||||
private def extractTestResult(output: File, testResult: File): Unit = {
|
||||
// val expandedTestResult = output / "META-INF" / "succeeded_tests"
|
||||
// if (expandedTestResult.exists) {
|
||||
// IO.move(expandedTestResult, testResult)
|
||||
// }
|
||||
}
|
||||
|
||||
private def defaultArtifactTasks: Seq[TaskKey[HashedVirtualFileRef]] =
|
||||
Seq(Compile / packageCache, Test / packageCache)
|
||||
|
||||
private def enabledOnly[A](
|
||||
key: SettingKey[A],
|
||||
pkgTasks: Seq[TaskKey[HashedVirtualFileRef]]
|
||||
): Def.Initialize[Seq[A]] =
|
||||
Classpaths
|
||||
.forallIn(key, pkgTasks)
|
||||
.zipWith(Classpaths.forallIn(pushRemoteCacheArtifact, pkgTasks))
|
||||
.apply(_.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)
|
||||
}
|
||||
}
|
||||
end RemoteCache
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ object LintUnused {
|
|||
onLoadMessage,
|
||||
onUnload,
|
||||
pollInterval,
|
||||
pushRemoteCacheArtifact,
|
||||
sbt.nio.Keys.outputFileStamper,
|
||||
sbt.nio.Keys.watchTriggers,
|
||||
serverConnectionType,
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
name := "my-project"
|
||||
|
||||
scalaVersion := "2.12.20"
|
||||
|
||||
semanticdbIncludeInJar := true
|
||||
|
||||
semanticdbEnabled := true
|
||||
|
||||
pushRemoteCacheTo := Some(
|
||||
MavenCache("local-cache", (ThisBuild / baseDirectory).value / "remote-cache-semanticdb")
|
||||
)
|
||||
|
||||
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)
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
> pushRemoteCache
|
||||
|
||||
# Generated sources, compiled classes
|
||||
$ exists target/scala-2.12/classes/MyClass.class
|
||||
$ exists target/scala-2.12/classes/MyClass$.class
|
||||
$ exists target/scala-2.12/classes/META-INF/semanticdb/src/main/scala/MyClass.scala.semanticdb
|
||||
$ exists target/scala-2.12/zinc/inc_compile_2.12.zip
|
||||
$ exists target/scala-2.12/test-classes/MyTest.class
|
||||
$ 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
|
||||
|
||||
# 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
|
||||
$ 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.sha1
|
||||
|
||||
# Test
|
||||
$ 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-test.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-test.jar.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-cached-test.jar.sha1
|
||||
|
||||
> clean
|
||||
|
||||
$ absent target/scala-2.12/classes/MyClass.class
|
||||
$ absent target/scala-2.12/classes/MyClass$.class
|
||||
$ absent target/scala-2.12/classes/META-INF
|
||||
$ absent target/scala-2.12/zinc/inc_compile_2.12.zip
|
||||
$ absent target/scala-2.12/test-classes/MyTest.class
|
||||
$ absent target/scala-2.12/test-classes/MyTest$.class
|
||||
$ absent target/scala-2.12/test-classes/META-INF
|
||||
$ absent target/scala-2.12/test-zinc/inc_compile_2.12.zip
|
||||
|
||||
> pullRemoteCache
|
||||
|
||||
# Files extracted from the cache artifacts
|
||||
$ exists target/scala-2.12/classes/MyClass.class
|
||||
$ exists target/scala-2.12/classes/MyClass$.class
|
||||
$ exists target/scala-2.12/classes/META-INF/semanticdb/src/main/scala/MyClass.scala.semanticdb
|
||||
$ exists target/scala-2.12/zinc/inc_compile_2.12.zip
|
||||
$ exists target/scala-2.12/test-classes/MyTest.class
|
||||
$ 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
|
||||
|
||||
# Artifacts can be pushed twice (enabled overriding)
|
||||
> pushRemoteCache
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
object MyClass
|
||||
|
|
@ -1 +0,0 @@
|
|||
object MyTest
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
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.20"
|
||||
ThisBuild / pushRemoteCacheTo := Some(
|
||||
MavenCache("local-cache", (ThisBuild / baseDirectory).value / "r")
|
||||
)
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.configs(CustomArtifact)
|
||||
.settings(
|
||||
name := "my-project",
|
||||
|
||||
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,
|
||||
// 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 := {
|
||||
val log = streams.value.log
|
||||
CompileState.previousIterations = {
|
||||
val previousAnalysis = (Compile / previousCompile).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 / compile).value match { case a: Analysis => a.compilations.allCompilations.size }) - CompileState.previousIterations
|
||||
assert(expected == actual, s"Expected $expected compilations, got $actual")
|
||||
}
|
||||
)
|
||||
|
||||
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
|
||||
val ver = version.value
|
||||
val orgName = organizationName.value
|
||||
|
||||
List(Package.addSpecManifestAttributes(n, ver, orgName))
|
||||
},
|
||||
sourceManaged := (Compile / target).value / "custom-artifact-gen",
|
||||
mappings := {
|
||||
val sourcesDir = sourceManaged.value
|
||||
val sources = sourcesDir.allPaths.pair(Path.relativeTo(sourcesDir))
|
||||
|
||||
sources
|
||||
},
|
||||
packageConfiguration := Defaults.packageConfigurationTask.value,
|
||||
packageCache := Defaults.packageTask.value,
|
||||
artifact := Artifact(moduleName.value, classifier),
|
||||
packagedArtifact := (artifact.value -> packageCache.value),
|
||||
artifactPath := Defaults.artifactPathSetting(artifact).value,
|
||||
artifactName := Artifact.artifactName
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
> recordPreviousIterations
|
||||
> compile
|
||||
> pushRemoteCache
|
||||
|
||||
# Generated sources, compiled classes
|
||||
$ exists target/custom-artifact-gen/HelloWorld.scala
|
||||
$ exists target/scala-2.12/classes/HelloWorld.class
|
||||
$ exists target/scala-2.12/classes/MyClass.class
|
||||
$ exists target/scala-2.12/classes/MyClass$.class
|
||||
$ exists target/scala-2.12/zinc/inc_compile_2.12.zip
|
||||
$ 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
|
||||
|
||||
# Compile
|
||||
$ 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-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-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
|
||||
|
||||
$ absent target/custom-artifact-gen/HelloWorld.scala
|
||||
$ absent target/scala-2.12/classes/HelloWorld.class
|
||||
$ absent target/scala-2.12/classes/MyClass.class
|
||||
$ absent target/scala-2.12/classes/MyClass$.class
|
||||
$ absent target/scala-2.12/zinc/inc_compile_2.12.zip
|
||||
$ absent target/scala-2.12/test-classes/MyTest.class
|
||||
$ absent target/scala-2.12/test-classes/MyTest$.class
|
||||
$ absent target/scala-2.12/test-zinc/inc_compile_2.12.zip
|
||||
|
||||
> pullRemoteCache
|
||||
|
||||
# Files extracted from the cache artifacts
|
||||
$ exists target/custom-artifact-gen/HelloWorld.scala
|
||||
$ exists target/scala-2.12/classes/HelloWorld.class
|
||||
$ exists target/scala-2.12/classes/MyClass.class
|
||||
$ exists target/scala-2.12/classes/MyClass$.class
|
||||
$ exists target/scala-2.12/zinc/inc_compile_2.12.zip
|
||||
$ 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
|
||||
|
||||
> checkIterations 1
|
||||
|
||||
# Artifacts can be pushed twice (enabled overriding)
|
||||
> pushRemoteCache
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
// This is necessary because tests are run in batch mode
|
||||
object CompileState {
|
||||
@volatile var previousIterations: Int = -1
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
object MyClass
|
||||
|
|
@ -1 +0,0 @@
|
|||
object MyTest
|
||||
Loading…
Reference in New Issue