diff --git a/lm-coursier/src/main/scala/lmcoursier/internal/RelocationCycleDetector.scala b/lm-coursier/src/main/scala/lmcoursier/internal/RelocationCycleDetector.scala deleted file mode 100644 index ec3569ff3..000000000 --- a/lm-coursier/src/main/scala/lmcoursier/internal/RelocationCycleDetector.scala +++ /dev/null @@ -1,70 +0,0 @@ -package lmcoursier.internal - -import coursier.core.* -import coursier.core.Resolution as CoreResolution -import coursier.{ Dependency, Resolution } - -import scala.annotation.tailrec - -/** - * Detects cyclic Maven / Gradle relocation chains that make - * `coursier.graph.DependencyTree` loop forever (see sbt#8917, coursier#3578). - * - * Mirrors one step of `coursier.graph.DependencyTree.Node.relocation` so we - * only skip `Conflict` when Coursier would spin on the same graph. - */ -private[internal] object RelocationCycleDetector: - - type Mvc = CoreResolution.ModuleVersionConstraint - - private def oneRelocationStep(resolution: Resolution, dep: Dependency): Option[Mvc] = - resolution.reconciledVersions - .get(dep.module) - .flatMap: recon => - val dep0 = - if dep.versionConstraint == recon then dep - else dep.withVersionConstraint(recon) - resolution.projectCache0 - .get(dep0.moduleVersionConstraint) - .flatMap: - case (_, proj) => - val mavenRelocatedOpt = - if proj.relocated && proj.dependencies0.lengthCompare(1) == 0 then - Some(proj.dependencies0.head._2) - else None - def gradleRelocated: Option[Dependency] = - dep0.variantSelector match - case attr: VariantSelector.AttributesBased => - if proj.variants.isEmpty then None - else - proj.variantFor(attr) match - case Left(_) => None - case Right(variant) => proj.isRelocatedVariant(variant) - case _: VariantSelector.ConfigurationBased => None - mavenRelocatedOpt - .orElse(gradleRelocated) - .map: relocatedTo => - val relocatedTo0 = - if relocatedTo.variantSelector.isEmpty then - relocatedTo.withVariantSelector(dep0.variantSelector) - else relocatedTo - relocatedTo0.moduleVersionConstraint - - /** When true, `coursier.graph.Conflict(resolution)` can run indefinitely. */ - def hasRelocationCycle(resolution: Resolution): Boolean = - resolution.isDone && resolution.conflicts.isEmpty && resolution.errors0.isEmpty && { - val keys = resolution.projectCache0.keySet - keys.exists: start => - @tailrec - def walk(visited: Set[Mvc], cur: Option[Mvc]): Boolean = - cur match - case None => false - case Some(mvc) => - if visited.contains(mvc) then true - else - val dep = Dependency(module = mvc._1, version = mvc._2) - walk(visited + mvc, oneRelocationStep(resolution, dep)) - walk(Set.empty, Some(start)) - } - -end RelocationCycleDetector diff --git a/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala b/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala index a4555b89c..85663875b 100644 --- a/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala +++ b/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala @@ -361,22 +361,6 @@ private[internal] object SbtUpdateReport { classLoaders: Seq[ClassLoader], ): UpdateReport = { - val skipConflictDetail: Map[Configuration, Boolean] = - resolutions.map { case (cfg, subRes) => - cfg -> RelocationCycleDetector.hasRelocationCycle(subRes) - }.toMap - val configsWithRelocationCycle = - skipConflictDetail.collect { case (cfg, true) => cfg.value }.toSeq.sorted - if (configsWithRelocationCycle.nonEmpty) { - log.warn( - "Skipping dependency conflict detail for configuration(s) " + - configsWithRelocationCycle.mkString(", ") + - ": cyclic Maven or Gradle relocations in the resolved graph. " + - "Resolution succeeded; eviction detail may be incomplete. " + - "See https://github.com/sbt/sbt/issues/8917" - ) - } - val configReports = resolutions.map { (config, subRes) => val reports = moduleReports( thisModule, @@ -412,9 +396,7 @@ private[internal] object SbtUpdateReport { } def conflicts: Seq[coursier.graph.Conflict] = - try - if (skipConflictDetail.getOrElse(config, false)) Nil - else coursier.graph.Conflict(subRes) + try coursier.graph.Conflict(subRes) catch case e: Throwable if missingOk => Nil val evicted = for { c <- conflicts diff --git a/lm-coursier/src/test/scala/lmcoursier/internal/RelocationCycleDetectorSpec.scala b/lm-coursier/src/test/scala/lmcoursier/internal/RelocationCycleDetectorSpec.scala deleted file mode 100644 index eb132dd17..000000000 --- a/lm-coursier/src/test/scala/lmcoursier/internal/RelocationCycleDetectorSpec.scala +++ /dev/null @@ -1,10 +0,0 @@ -package lmcoursier.internal - -import coursier.Resolution -import org.scalatest.funsuite.AnyFunSuite -import org.scalatest.matchers.should.Matchers - -class RelocationCycleDetectorSpec extends AnyFunSuite with Matchers: - - test("incomplete resolution is not treated as having a relocation cycle"): - RelocationCycleDetector.hasRelocationCycle(Resolution()) shouldBe false