Migrate updateTask via tuple syntax

This commit is contained in:
Eugene Yokota 2022-09-20 02:08:28 -04:00
parent 0c6eb093ac
commit 0ee7d11afe
4 changed files with 334 additions and 177 deletions

View File

@ -718,7 +718,7 @@ end Scoped
*
* See https://www.scala-sbt.org/1.x/docs/Migrating-from-sbt-013x.html#Migrating+from+sbt+0.12+style for how to migrate.
*/
trait TupleSyntax {
trait TupleSyntax:
import Scoped._
// format: off
@ -748,7 +748,7 @@ trait TupleSyntax {
implicit def t11ToApp11[A, B, C, D, E, F, G, H, I, J, K](t11: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K])): Apply11[A, B, C, D, E, F, G, H, I, J, K] = new Apply11(t11)
// format: on
}
end TupleSyntax
object TupleSyntax extends TupleSyntax
@ -849,3 +849,12 @@ object SettingKey:
def local[A1: Manifest: OptJsonWriter]: SettingKey[A1] = apply[A1](AttributeKey.local[A1])
end SettingKey
class TupleWrap[Tup <: Tuple](value: Tuple.Map[Tup, Taskable]):
type InitTask[A2] = Initialize[Task[A2]]
lazy val alist = AList.tuple[Tup]
lazy val initTasks =
alist.transform[Taskable, InitTask](value)([a] => (t: Taskable[a]) => t.toTask)
def mapN[A1](f: Tup => A1): Def.Initialize[Task[A1]] =
import std.FullInstance.initializeTaskMonad
alist.mapN[InitTask, A1](initTasks)(f.asInstanceOf[Tuple.Map[Tup, Id] => A1])

View File

@ -9,12 +9,19 @@ package sbt.test
import sbt._
import sbt.Def.Initialize
import sbt.TupleSyntax._
import sbt.internal.util.AList
import sbt.internal.util.Types.Id
object TupleSyntaxTest:
def t1[A](a: SettingKey[A], b: TaskKey[A], c: Def.Initialize[A], d: Def.Initialize[Task[A]]) = {
import sbt.TupleSyntax._
(a, b, c.toTaskable, d.toTaskable).mapN { (x: A, y: A, z: A, w: A) =>
"" + x + y + z + w
}
}
def t2[A](a: SettingKey[A], b: TaskKey[A], c: Def.Initialize[A], d: Def.Initialize[Task[A]]) =
TupleWrap[(A, A, A, A)]((a, b, c.toTaskable, d)).mapN { case (x: A, y: A, z: A, w: A) =>
"" + x + y + z + w
}
end TupleSyntaxTest

View File

@ -3633,92 +3633,173 @@ object Classpaths {
cacheLabel: String,
includeCallers: Boolean,
includeDetails: Boolean
): Initialize[Task[UpdateReport]] = Def.task {
val s = streams.value
val cacheDirectory = crossTarget.value / cacheLabel / updateCacheName.value
): Initialize[Task[UpdateReport]] =
TupleWrap[
(
DependencyResolution,
TaskStreams,
UpdateConfiguration,
Option[Level.Value],
String,
State,
String,
xsbti.AppConfiguration,
Option[ScalaInstance],
File,
File,
Seq[ScopedKey[_]],
ScopedKey[_],
Option[FiniteDuration],
Boolean,
ProjectRef,
IvySbt#Module,
String,
Boolean,
Seq[UpdateReport],
UnresolvedWarningConfiguration,
Level.Value,
Seq[ModuleID],
Level.Value,
String,
String,
Boolean,
CompatibilityWarningOptions,
)
](
dependencyResolution,
streams,
updateConfiguration.toTaskable,
(update / logLevel).?.toTaskable,
updateCacheName.toTaskable,
state,
scalaVersion.toTaskable,
appConfiguration.toTaskable,
Defaults.unmanagedScalaInstanceOnly.toTaskable,
dependencyCacheDirectory.toTaskable,
crossTarget.toTaskable,
executionRoots.toTaskable,
resolvedScoped.toTaskable,
forceUpdatePeriod.toTaskable,
sbtPlugin.toTaskable,
thisProjectRef.toTaskable,
ivyModule.toTaskable,
scalaOrganization.toTaskable,
(update / skip).toTaskable,
transitiveUpdate.toTaskable,
(update / unresolvedWarningConfiguration).toTaskable,
evictionErrorLevel.toTaskable,
libraryDependencySchemes.toTaskable,
assumedEvictionErrorLevel.toTaskable,
assumedVersionScheme.toTaskable,
assumedVersionSchemeJava.toTaskable,
publishMavenStyle.toTaskable,
compatibilityWarningOptions.toTaskable,
).mapN {
case (
lm,
s,
conf,
maybeUpdateLevel,
ucn,
state0,
sv,
ac,
usiOnly,
dcd,
ct,
er,
rs,
fup,
isPlugin,
thisRef,
im,
so,
sk,
tu,
uwConfig,
eel,
lds,
aeel,
avs,
avsj,
mavenStyle,
cwo,
) =>
val cacheDirectory = ct / cacheLabel / ucn
val cacheStoreFactory: CacheStoreFactory = {
val factory =
state0.get(Keys.cacheStoreFactoryFactory).getOrElse(InMemoryCacheStore.factory(0))
factory(cacheDirectory.toPath)
}
val cacheStoreFactory: CacheStoreFactory = {
val factory =
state.value.get(Keys.cacheStoreFactoryFactory).getOrElse(InMemoryCacheStore.factory(0))
factory(cacheDirectory.toPath)
val isRoot = er.contains(rs)
val shouldForce = isRoot || {
fup match
case None => false
case Some(period) =>
val fullUpdateOutput = cacheDirectory / "out"
val now = System.currentTimeMillis
val diff = now - IO.getModifiedTimeOrZero(fullUpdateOutput)
val elapsedDuration = new FiniteDuration(diff, TimeUnit.MILLISECONDS)
fullUpdateOutput.exists() && elapsedDuration > period
}
val providedScalaJars: String => Seq[File] = {
val scalaProvider = ac.provider.scalaProvider
usiOnly match
case Some(instance) =>
unmanagedJarsTask(sv, instance.version, instance.allJars)
case None =>
(subVersion: String) =>
if (scalaProvider.version == subVersion) scalaProvider.jars else Nil
}
val updateConf = {
// Log captures log messages at all levels, except ivy logs.
// Use full level when debug is enabled so that ivy logs are shown.
import UpdateLogging.{ Default, DownloadOnly, Full }
val conf1 = maybeUpdateLevel.orElse(state0.get(logLevel.key)) match {
case Some(Level.Debug) if conf.logging == Default => conf.withLogging(logging = Full)
case Some(_) if conf.logging == Default => conf.withLogging(logging = DownloadOnly)
case _ => conf
}
// logical clock is folded into UpdateConfiguration
conf1
.withLogicalClock(LogicalClock(state0.hashCode))
.withMetadataDirectory(dcd)
}
val extracted = Project.extract(state0)
val label =
if (isPlugin) Reference.display(thisRef)
else Def.displayRelativeReference(extracted.currentRef, thisRef)
LibraryManagement.cachedUpdate(
// LM API
lm = lm,
// Ivy-free ModuleDescriptor
module = im,
cacheStoreFactory = cacheStoreFactory,
label = label,
updateConf,
substituteScalaFiles(so, _)(providedScalaJars),
skip = sk,
force = shouldForce,
depsUpdated = tu.exists(!_.stats.cached),
uwConfig = uwConfig,
evictionLevel = eel,
versionSchemeOverrides = lds,
assumedEvictionErrorLevel = aeel,
assumedVersionScheme = avs,
assumedVersionSchemeJava = avsj,
mavenStyle = mavenStyle,
compatWarning = cwo,
includeCallers = includeCallers,
includeDetails = includeDetails,
log = s.log
)
}
val isRoot = executionRoots.value contains resolvedScoped.value
val shouldForce = isRoot || {
forceUpdatePeriod.value match {
case None => false
case Some(period) =>
val fullUpdateOutput = cacheDirectory / "out"
val now = System.currentTimeMillis
val diff = now - IO.getModifiedTimeOrZero(fullUpdateOutput)
val elapsedDuration = new FiniteDuration(diff, TimeUnit.MILLISECONDS)
fullUpdateOutput.exists() && elapsedDuration > period
}
}
val providedScalaJars: String => Seq[File] = {
val scalaProvider = appConfiguration.value.provider.scalaProvider
Defaults.unmanagedScalaInstanceOnly.value match {
case Some(instance) =>
unmanagedJarsTask(scalaVersion.value, instance.version, instance.allJars)
case None =>
(subVersion: String) =>
if (scalaProvider.version == subVersion) scalaProvider.jars else Nil
}
}
val state0 = state.value
val updateConf = {
// Log captures log messages at all levels, except ivy logs.
// Use full level when debug is enabled so that ivy logs are shown.
import UpdateLogging.{ Default, DownloadOnly, Full }
val conf = updateConfiguration.value
val maybeUpdateLevel = (update / logLevel).?.value
val conf1 = maybeUpdateLevel.orElse(state0.get(logLevel.key)) match {
case Some(Level.Debug) if conf.logging == Default => conf.withLogging(logging = Full)
case Some(_) if conf.logging == Default => conf.withLogging(logging = DownloadOnly)
case _ => conf
}
// logical clock is folded into UpdateConfiguration
conf1
.withLogicalClock(LogicalClock(state0.hashCode))
.withMetadataDirectory(dependencyCacheDirectory.value)
}
val extracted = Project.extract(state0)
val isPlugin = sbtPlugin.value
val thisRef = thisProjectRef.value
val label =
if (isPlugin) Reference.display(thisRef)
else Def.displayRelativeReference(extracted.currentRef, thisRef)
LibraryManagement.cachedUpdate(
// LM API
lm = dependencyResolution.value,
// Ivy-free ModuleDescriptor
module = ivyModule.value,
cacheStoreFactory = cacheStoreFactory,
label = label,
updateConf,
substituteScalaFiles(scalaOrganization.value, _)(providedScalaJars),
skip = (update / skip).value,
force = shouldForce,
depsUpdated = transitiveUpdate.value.exists(!_.stats.cached),
uwConfig = (update / unresolvedWarningConfiguration).value,
evictionLevel = evictionErrorLevel.value,
versionSchemeOverrides = libraryDependencySchemes.value,
assumedEvictionErrorLevel = assumedEvictionErrorLevel.value,
assumedVersionScheme = assumedVersionScheme.value,
assumedVersionSchemeJava = assumedVersionSchemeJava.value,
mavenStyle = publishMavenStyle.value,
compatWarning = compatibilityWarningOptions.value,
includeCallers = includeCallers,
includeDetails = includeDetails,
log = s.log
)
}
private[sbt] def dependencyPositionsTask: Initialize[Task[Map[ModuleID, SourcePosition]]] =
Def.task {
val projRef = thisProjectRef.value

View File

@ -11,6 +11,7 @@ package internal
import java.io.File
import java.util.concurrent.Callable
import sbt.Def.ScopedKey
import sbt.SlashSyntax0._
import sbt.internal.librarymanagement._
import sbt.librarymanagement._
@ -21,6 +22,7 @@ import sbt.io.syntax._
import sbt.Project.richInitializeTask
import sjsonnew.JsonFormat
import scala.compat.Platform.EOL
import scala.concurrent.duration.FiniteDuration
private[sbt] object LibraryManagement {
implicit val linter: sbt.dsl.LinterLevel.Ignore.type = sbt.dsl.LinterLevel.Ignore
@ -242,100 +244,158 @@ private[sbt] object LibraryManagement {
* for dependency definitions, transitively.
*/
def updateClassifiersTask: Def.Initialize[Task[UpdateReport]] =
(Def.task {
import Keys._
val s = streams.value
val cacheDirectory = streams.value.cacheDirectory
val csr = useCoursier.value
val lm = dependencyResolution.value
if (csr) {
// following copied from https://github.com/coursier/sbt-coursier/blob/9173406bb399879508aa481fed16efda72f55820/modules/sbt-lm-coursier/src/main/scala/sbt/hack/Foo.scala
val isRoot = executionRoots.value contains resolvedScoped.value
val shouldForce = isRoot || {
forceUpdatePeriod.value match {
case None => false
case Some(period) =>
val fullUpdateOutput = cacheDirectory / "out"
val now = System.currentTimeMillis
val diff = now - fullUpdateOutput.lastModified()
val elapsedDuration = new scala.concurrent.duration.FiniteDuration(
diff,
java.util.concurrent.TimeUnit.MILLISECONDS
)
fullUpdateOutput.exists() && elapsedDuration > period
}
}
val state0 = state.value
val updateConf = {
import UpdateLogging.{ Full, DownloadOnly, Default }
val conf = updateConfiguration.value
val maybeUpdateLevel = (update / logLevel).?.value
val conf1 = maybeUpdateLevel.orElse(state0.get(logLevel.key)) match {
case Some(Level.Debug) if conf.logging == Default => conf.withLogging(logging = Full)
case Some(_) if conf.logging == Default => conf.withLogging(logging = DownloadOnly)
case _ => conf
}
// logical clock is folded into UpdateConfiguration
conf1.withLogicalClock(LogicalClock(state0.hashCode))
}
cachedUpdate(
// LM API
lm = lm,
// Ivy-free ModuleDescriptor
module = ivyModule.value,
s.cacheStoreFactory.sub(updateCacheName.value),
Reference.display(thisProjectRef.value),
updateConf,
identity,
skip = (update / skip).value,
force = shouldForce,
depsUpdated = transitiveUpdate.value.exists(!_.stats.cached),
uwConfig = (update / unresolvedWarningConfiguration).value,
evictionLevel = Level.Debug,
versionSchemeOverrides = Nil,
assumedEvictionErrorLevel = Level.Debug,
assumedVersionScheme = VersionScheme.Always,
assumedVersionSchemeJava = VersionScheme.Always,
mavenStyle = publishMavenStyle.value,
compatWarning = compatibilityWarningOptions.value,
includeCallers = false,
includeDetails = false,
log = s.log
)
} else {
val is = ivySbt.value
val mod = classifiersModule.value
val updateConfig0 = updateConfiguration.value
lazy val updateConfig = updateConfig0
.withMetadataDirectory(dependencyCacheDirectory.value)
.withArtifactFilter(
updateConfig0.artifactFilter.map(af => af.withInverted(!af.inverted))
)
val app = appConfiguration.value
val srcTypes = sourceArtifactTypes.value
val docTypes = docArtifactTypes.value
val uwConfig = (update / unresolvedWarningConfiguration).value
val out = is.withIvy(s.log)(_.getSettings.getDefaultIvyUserDir)
withExcludes(out, mod.classifiers, lock(app)) { excludes =>
lm.updateClassifiers(
GetClassifiersConfiguration(
mod,
excludes.toVector,
updateConfig,
srcTypes.toVector,
docTypes.toVector
),
TupleWrap[
(
DependencyResolution,
State,
Keys.TaskStreams,
UpdateConfiguration,
Option[Level.Value],
Boolean,
Seq[ScopedKey[_]],
ScopedKey[_],
Option[FiniteDuration],
IvySbt#Module,
String,
ProjectRef,
Boolean,
Seq[UpdateReport],
UnresolvedWarningConfiguration,
Boolean,
CompatibilityWarningOptions,
IvySbt,
GetClassifiersModule,
File,
xsbti.AppConfiguration,
Seq[String],
Seq[String],
)
](
Keys.dependencyResolution,
Keys.state,
Keys.streams,
Keys.updateConfiguration.toTaskable,
(Keys.update / Keys.logLevel).?.toTaskable,
Keys.useCoursier.toTaskable,
Keys.executionRoots,
Keys.resolvedScoped.toTaskable,
Keys.forceUpdatePeriod.toTaskable,
Keys.ivyModule.toTaskable,
Keys.updateCacheName.toTaskable,
Keys.thisProjectRef.toTaskable,
(Keys.update / Keys.skip).toTaskable,
Keys.transitiveUpdate,
(Keys.update / Keys.unresolvedWarningConfiguration).toTaskable,
Keys.publishMavenStyle.toTaskable,
Keys.compatibilityWarningOptions.toTaskable,
Keys.ivySbt,
Keys.classifiersModule,
Keys.dependencyCacheDirectory,
Keys.appConfiguration.toTaskable,
Keys.sourceArtifactTypes.toTaskable,
Keys.docArtifactTypes.toTaskable,
).mapN {
case (
lm,
state0,
s,
conf,
maybeUpdateLevel,
csr,
er,
rs,
fup,
im,
ucn,
thisRef,
sk,
tu,
uwConfig,
Vector.empty,
s.log
) match {
case Left(_) => ???
case Right(ur) => ur
mavenStyle,
cwo,
ivySbt0,
mod,
dcd,
app,
srcTypes,
docTypes,
) =>
import Keys._
val cacheDirectory = s.cacheDirectory
val isRoot = er.contains(rs)
if csr then {
// following copied from https://github.com/coursier/sbt-coursier/blob/9173406bb399879508aa481fed16efda72f55820/modules/sbt-lm-coursier/src/main/scala/sbt/hack/Foo.scala
val shouldForce = isRoot || {
fup match
case None => false
case Some(period) =>
val fullUpdateOutput = cacheDirectory / "out"
val now = System.currentTimeMillis
val diff = now - fullUpdateOutput.lastModified()
val elapsedDuration = new FiniteDuration(
diff,
java.util.concurrent.TimeUnit.MILLISECONDS
)
fullUpdateOutput.exists() && elapsedDuration > period
}
val updateConf = {
import UpdateLogging.{ Full, DownloadOnly, Default }
val conf1 = maybeUpdateLevel.orElse(state0.get(logLevel.key)) match
case Some(Level.Debug) if conf.logging == Default => conf.withLogging(logging = Full)
case Some(_) if conf.logging == Default => conf.withLogging(logging = DownloadOnly)
case _ => conf
// logical clock is folded into UpdateConfiguration
conf1.withLogicalClock(LogicalClock(state0.hashCode))
}
cachedUpdate(
// LM API
lm = lm,
// Ivy-free ModuleDescriptor
module = im,
s.cacheStoreFactory.sub(ucn),
Reference.display(thisRef),
updateConf,
identity,
skip = sk,
force = shouldForce,
depsUpdated = tu.exists(!_.stats.cached),
uwConfig = uwConfig,
evictionLevel = Level.Debug,
versionSchemeOverrides = Nil,
assumedEvictionErrorLevel = Level.Debug,
assumedVersionScheme = VersionScheme.Always,
assumedVersionSchemeJava = VersionScheme.Always,
mavenStyle = mavenStyle,
compatWarning = cwo,
includeCallers = false,
includeDetails = false,
log = s.log
)
} else {
lazy val updateConfig = conf
.withMetadataDirectory(dcd)
.withArtifactFilter(
conf.artifactFilter.map(af => af.withInverted(!af.inverted))
)
val out = ivySbt0.withIvy(s.log)(_.getSettings.getDefaultIvyUserDir)
withExcludes(out, mod.classifiers, lock(app)) { excludes =>
lm.updateClassifiers(
GetClassifiersConfiguration(
mod,
excludes.toVector,
updateConfig,
srcTypes.toVector,
docTypes.toVector
),
uwConfig,
Vector.empty,
s.log
) match
case Left(_) => ???
case Right(ur) => ur
}
}
}
} tag (Tags.Update, Tags.Network))
}.tag(Tags.Update, Tags.Network)
def withExcludes(out: File, classifiers: Seq[String], lock: xsbti.GlobalLock)(
f: Map[ModuleID, Vector[ConfigRef]] => UpdateReport