Skip to content

Commit

Permalink
Restructure VersionFinder, increase speed, added ticker messages (#…
Browse files Browse the repository at this point in the history
…3014)

Searching for updates can take quite some time, especially for larger
projects.

This change adds some progress messages via Mills ticker log messages.

More important, I restructured the implementation such that work is
distributed over more tasks. If the used evaluator is run with parallel
jobs, this will significantly increase the speed.

Pull request: #3014
  • Loading branch information
lefou authored Feb 15, 2024
1 parent 3335d2a commit e3ef411
Showing 1 changed file with 65 additions and 54 deletions.
119 changes: 65 additions & 54 deletions scalalib/src/mill/scalalib/dependency/versions/VersionsFinder.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package mill.scalalib.dependency.versions

import coursier.Dependency
import mill.define.{BaseModule}
import mill.define.{BaseModule, Task}
import mill.eval.Evaluator
import mill.scalalib.dependency.metadata.MetadataLoaderFactory
import mill.scalalib.dependency.metadata.{MetadataLoader, MetadataLoaderFactory}
import mill.scalalib.{JavaModule, Lib}
import mill.api.Ctx.{Home, Log}
import mill.T

import java.util.concurrent.atomic.AtomicInteger

private[dependency] object VersionsFinder {

def findVersions(
Expand All @@ -20,61 +21,71 @@ private[dependency] object VersionsFinder {
case javaModule: JavaModule => javaModule
}

val resolvedDependencies = resolveDependencies(evaluator, javaModules)
resolveVersions(evaluator, resolvedDependencies)
}
val resolvedDependencies = evaluator.evalOrThrow() {
val progress = new Progress(javaModules.size)
javaModules.map(resolveDeps(progress))
}

private def resolveDependencies(
evaluator: Evaluator,
javaModules: Seq[JavaModule]
): Seq[(JavaModule, Seq[Dependency])] = evaluator.evalOrThrow() {
javaModules.map { javaModule =>
T.task {
val bindDependency = javaModule.bindDependency()
val deps = javaModule.ivyDeps()
val compileIvyDeps = javaModule.compileIvyDeps()
val runIvyDeps = javaModule.runIvyDeps()
val repos = javaModule.repositoriesTask()
val mapDeps = javaModule.mapDependencies()
val custom = javaModule.resolutionCustomizer()
val cacheCustom = javaModule.coursierCacheCustomizer()

val (dependencies, _) =
Lib.resolveDependenciesMetadata(
repositories = repos,
deps = (deps ++ compileIvyDeps ++ runIvyDeps).map(bindDependency),
mapDependencies = Some(mapDeps),
customizer = custom,
coursierCacheCustomizer = cacheCustom,
ctx = Some(T.log)
)

(javaModule, dependencies)
}
evaluator.evalOrThrow() {
val progress = new Progress(resolvedDependencies.map(_._3.size).sum)
resolvedDependencies.map(resolveVersions(progress))
}
}

private def resolveVersions(
evaluator: Evaluator,
resolvedDependencies: Seq[ResolvedDependencies]
): Seq[ModuleDependenciesVersions] =
resolvedDependencies.map {
case (javaModule, dependencies) =>
val metadataLoaders =
evaluator.evalOrThrow()(javaModule.repositoriesTask)
.flatMap(MetadataLoaderFactory(_))

val versions = dependencies.map { dependency =>
val currentVersion = Version(dependency.version)
val allVersions =
metadataLoaders
.flatMap(_.getVersions(dependency.module))
.toSet
DependencyVersions(dependency, currentVersion, allVersions)
}

ModuleDependenciesVersions(javaModule.toString, versions)
class Progress(val count: Int) {
private val counter = new AtomicInteger(1)
def next(): Int = counter.getAndIncrement()
}

private def resolveDeps(progress: Progress)(
javaModule: JavaModule
): Task[ResolvedDependencies] =
T.task {
T.log.ticker(s"Resolving dependencies [${progress.next()}/${progress.count}]: ${javaModule}")

val bindDependency = javaModule.bindDependency()
val deps = javaModule.ivyDeps()
val compileIvyDeps = javaModule.compileIvyDeps()
val runIvyDeps = javaModule.runIvyDeps()
val repos = javaModule.repositoriesTask()
val mapDeps = javaModule.mapDependencies()
val custom = javaModule.resolutionCustomizer()
val cacheCustom = javaModule.coursierCacheCustomizer()

val metadataLoaders = repos.flatMap(MetadataLoaderFactory(_))

val (dependencies, _) =
Lib.resolveDependenciesMetadata(
repositories = repos,
deps = (deps ++ compileIvyDeps ++ runIvyDeps).map(bindDependency),
mapDependencies = Some(mapDeps),
customizer = custom,
coursierCacheCustomizer = cacheCustom,
ctx = Some(T.log)
)

(javaModule, metadataLoaders, dependencies)
}

private def resolveVersions(progres: Progress)(
resolvedDependencies: ResolvedDependencies
): Task[ModuleDependenciesVersions] = T.task {
val (javaModule, metadataLoaders, dependencies) = resolvedDependencies

val versions = dependencies.map { dependency =>
T.log.ticker(
s"Analyzing dependencies [${progres.next()}/${progres.count}]: ${javaModule} / ${dependency.module}"
)
val currentVersion = Version(dependency.version)
val allVersions =
metadataLoaders
.flatMap(_.getVersions(dependency.module))
.toSet
DependencyVersions(dependency, currentVersion, allVersions)
}

private type ResolvedDependencies = (JavaModule, Seq[coursier.Dependency])
ModuleDependenciesVersions(javaModule.toString, versions)
}

private type ResolvedDependencies = (JavaModule, Seq[MetadataLoader], Seq[coursier.Dependency])
}

0 comments on commit e3ef411

Please # to comment.