Skip to content

Instantly share code, notes, and snippets.

@danslapman
Created June 23, 2021 07:12
Show Gist options
  • Save danslapman/aa42b1a95895b2f08f8aa47b6589ce55 to your computer and use it in GitHub Desktop.
Save danslapman/aa42b1a95895b2f08f8aa47b6589ce55 to your computer and use it in GitHub Desktop.
ManagedSourcesCachePlugin
package sbt
import sbt.Keys._
import sbt.internal.inc.HashUtil
import sbt.internal.remotecache.CustomRemoteCacheArtifact
import sbt.nio.FileStamp
import sbt.nio.file.FileAttributes
import sbt.plugins.JvmPlugin
import sbt.util.InterfaceUtil.toOption
//Adopted from https://github.com/iRevive/sbt-twirl-remote-cache
object ManagedSourcesCachePlugin extends AutoPlugin {
override def requires: Plugins = JvmPlugin
override def trigger: PluginTrigger = allRequirements
object autoImport {
lazy val ManagedSourcesCache = config("managedSourcesCache")
lazy val sourceGeneratorInputs = settingKey[Seq[File]]("Source generator inputs")
lazy val managedSourcesRemoteCacheArtifactName = settingKey[String]("The artifact name")
lazy val managedSourcesRemoteCacheDir = settingKey[File]("Managed sources remote cache directory")
lazy val pullManagedSourcesRemoteCache = taskKey[Unit]("Pull managed sources from remote cache")
lazy val pushManagedSourcesRemoteCache = taskKey[Unit]("Push managed sources to remote cache")
}
import autoImport._
override lazy val projectConfigurations: Seq[Configuration] = Seq(ManagedSourcesCache)
override lazy val projectSettings: Seq[Setting[_]] =
Seq(
sourceGeneratorInputs := Seq()
) ++
inConfig(ManagedSourcesCache)(
Seq(
packageOptions := {
val n = name.value + "-" + managedSourcesRemoteCacheArtifactName.value
val ver = version.value
val org = organization.value
val orgName = organizationName.value
val hp = homepage.value
List(
Package.addSpecManifestAttributes(n, ver, orgName),
Package.addImplManifestAttributes(n, ver, hp, org, orgName)
)
},
mappings := {
val sourcesDir = sourceManaged.value
val sources = sourcesDir.globRecursive("*.scala").pair(Path.relativeTo(sourcesDir))
sources
},
packageConfiguration := Defaults.packageConfigurationTask.value,
packageCache := Defaults.packageTask.value,
artifact := Artifact(moduleName.value, managedSourcesRemoteCacheArtifactName.value),
packagedArtifact := (artifact.value -> packageCache.value),
artifactPath := Defaults.artifactPathSetting(artifact).value,
artifactName := Artifact.artifactName,
managedSourcesRemoteCacheArtifactName := "managed-sources",
pushRemoteCacheConfiguration / remoteCacheArtifacts += {
val art = (ManagedSourcesCache / artifact).value
val packaged = ManagedSourcesCache / packageCache
val extractDirectory = sourceManaged.value
CustomRemoteCacheArtifact(art, packaged, extractDirectory, preserveLastModified = false)
},
managedSourcesRemoteCacheDir := {
val remote = pushRemoteCacheTo.value
val module = moduleName.value
val scalaBinVersion = scalaBinaryVersion.value
val base = remote match {
case Some(cache: MavenCache) => cache.rootFile
case _ => baseDirectory.value
}
base / module / scalaBinVersion
},
pushManagedSourcesRemoteCache := {
val log = streams.value.log
val cacheDir = managedSourcesRemoteCacheDir.value
val baseDir = sourceManaged.value
val cacheId = {
val inputs = sourceGeneratorInputs.value.flatMap { dir =>
dir
.globRecursive("*")
.get()
.map(_.toPath)
.map(path => path -> FileAttributes(path).toOption.flatMap(FileStamp(path, _)))
.collect { case (path, Some(stamp)) => path -> stamp }
}
combineHash(extractHash(inputs))
}
val templates = baseDir.globRecursive("*.scala").pair(Path.relativeTo(baseDir))
val output = cacheDir / s"$cacheId.zip"
if (sourceGeneratorInputs.value.nonEmpty && templates.nonEmpty) {
IO.zip(templates, output, None)
log.info(s"Published managed sources cache to $output")
}
},
pullManagedSourcesRemoteCache := {
if (sourceGeneratorInputs.value.nonEmpty) {
val log = streams.value.log
val baseDir = sourceManaged.value
val cacheDir = managedSourcesRemoteCacheDir.value
val candidateIds = {
val inputs = sourceGeneratorInputs.value.flatMap { dir =>
dir
.globRecursive("*")
.get()
.map(_.toPath)
.map(path => path -> FileAttributes(path).toOption.flatMap(FileStamp(path, _)))
.collect { case (path, Some(stamp)) => path -> stamp }
}
combineHash(extractHash(inputs))
} :: Nil
candidateIds.map(id => cacheDir / s"$id.zip").find(_.exists) match {
case Some(archive) =>
log.info(s"Found managed sources cache $archive")
IO.unzip(archive, baseDir, preserveLastModified = false)
case None =>
log.info("Managed sources cache does not exist")
}
}
}
)
)
def extractHash(inputs: Seq[(java.nio.file.Path, FileStamp)]): Vector[String] =
inputs.toVector map { case (_, stamp0) =>
toOption(stamp0.stamp.getHash).getOrElse("cafe")
}
def combineHash(vs: Vector[String]): String = {
val hashValue = HashUtil.farmHash(vs.sorted.mkString("").getBytes("UTF-8"))
java.lang.Long.toHexString(hashValue)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment