From 0ee7d11afeae3a55d4256323435ce0c9bae810f2 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 20 Sep 2022 02:08:28 -0400 Subject: [PATCH] Migrate updateTask via tuple syntax --- .../src/main/scala/sbt/Structure.scala | 13 +- .../src/test/scala/sbt/TupleSyntaxTest.scala | 9 +- main/src/main/scala/sbt/Defaults.scala | 247 ++++++++++++------ .../sbt/internal/LibraryManagement.scala | 242 ++++++++++------- 4 files changed, 334 insertions(+), 177 deletions(-) diff --git a/main-settings/src/main/scala/sbt/Structure.scala b/main-settings/src/main/scala/sbt/Structure.scala index ccf5dd400..768c8247b 100644 --- a/main-settings/src/main/scala/sbt/Structure.scala +++ b/main-settings/src/main/scala/sbt/Structure.scala @@ -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]) diff --git a/main-settings/src/test/scala/sbt/TupleSyntaxTest.scala b/main-settings/src/test/scala/sbt/TupleSyntaxTest.scala index 59c267071..bbb1899e2 100644 --- a/main-settings/src/test/scala/sbt/TupleSyntaxTest.scala +++ b/main-settings/src/test/scala/sbt/TupleSyntaxTest.scala @@ -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 diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 83cd0868f..25e39db76 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -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 diff --git a/main/src/main/scala/sbt/internal/LibraryManagement.scala b/main/src/main/scala/sbt/internal/LibraryManagement.scala index 2a9b431d5..45f22c97e 100644 --- a/main/src/main/scala/sbt/internal/LibraryManagement.scala +++ b/main/src/main/scala/sbt/internal/LibraryManagement.scala @@ -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