Skip to content

Commit

Permalink
Avoid unnecessary dependency downloading by providing fetches per cac…
Browse files Browse the repository at this point in the history
…he policy; add ticker logging when they are downloading
  • Loading branch information
gehnaphore committed Dec 18, 2018
1 parent ea36ea3 commit bf2fe66
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 16 deletions.
12 changes: 9 additions & 3 deletions main/core/src/eval/Evaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,18 +251,24 @@ case class Evaluator(home: os.Path,

val nonEvaluatedTargets = group.indexed.filterNot(results.contains)

maybeTargetLabel.foreach { targetLabel =>
val tickerPrefix = maybeTargetLabel.map { targetLabel =>
val inputResults = for {
target <- nonEvaluatedTargets
item <- target.inputs.filterNot(group.contains)
} yield results(item).map(_._1)

val logRun = inputResults.forall(_.isInstanceOf[Result.Success[_]])

if(logRun) { log.ticker(s"[$counterMsg] $targetLabel ") }
val prefix = s"[$counterMsg] $targetLabel "
if(logRun) log.ticker(prefix)
prefix + "| "
}

val multiLogger = resolveLogger(paths.map(_.log))
val multiLogger = new ProxyLogger(resolveLogger(paths.map(_.log))) {
override def ticker(s: String): Unit = {
super.ticker(tickerPrefix.getOrElse("")+s)
}
}
var usedDest = Option.empty[(Task[_], Array[StackTraceElement])]
for (task <- nonEvaluatedTargets) {
newEvaluated.append(task)
Expand Down
15 changes: 15 additions & 0 deletions main/core/src/util/Loggers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,18 @@ case class MultiLogger(colored: Boolean, logger1: Logger, logger2: Logger) exten
logger2.close()
}
}


case class ProxyLogger(logger: Logger) extends Logger {
def colored = logger.colored

lazy val outputStream = logger.outputStream
lazy val errorStream = logger.errorStream
lazy val inStream = logger.inStream

def info(s: String) = logger.info(s)
def error(s: String) = logger.error(s)
def ticker(s: String) = logger.ticker(s)
def debug(s: String) = logger.debug(s)
override def close() = logger.close()
}
72 changes: 67 additions & 5 deletions main/src/modules/Jvm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import java.nio.file.attribute.PosixFilePermission
import java.util.Collections
import java.util.jar.{JarEntry, JarFile, JarOutputStream}

import coursier.{Cache, Dependency, Fetch, Repository, Resolution}
import coursier.{Cache, Dependency, Fetch, Repository, Resolution, CachePolicy}
import coursier.util.{Gather, Task}
import geny.Generator
import mill.main.client.InputPumper
Expand Down Expand Up @@ -402,10 +402,11 @@ object Jvm {
deps: TraversableOnce[coursier.Dependency],
force: TraversableOnce[coursier.Dependency],
sources: Boolean = false,
mapDependencies: Option[Dependency => Dependency] = None): Result[Agg[PathRef]] = {
mapDependencies: Option[Dependency => Dependency] = None,
ctx: Option[mill.util.Ctx.Log] = None): Result[Agg[PathRef]] = {

val (_, resolution) = resolveDependenciesMetadata(
repositories, deps, force, mapDependencies
repositories, deps, force, mapDependencies, ctx
)
val errs = resolution.metadataErrors
if(errs.nonEmpty) {
Expand Down Expand Up @@ -459,7 +460,10 @@ object Jvm {
def resolveDependenciesMetadata(repositories: Seq[Repository],
deps: TraversableOnce[coursier.Dependency],
force: TraversableOnce[coursier.Dependency],
mapDependencies: Option[Dependency => Dependency] = None) = {
mapDependencies: Option[Dependency => Dependency] = None,
ctx: Option[mill.util.Ctx.Log] = None) = {

val cachePolicies = CachePolicy.default

val forceVersions = force
.map(mapDependencies.getOrElse(identity[Dependency](_)))
Expand All @@ -472,10 +476,68 @@ object Jvm {
mapDependencies = mapDependencies
)

val fetch = Fetch.from(repositories, Cache.fetch[Task]())
val resolutionLogger = ctx.map(c => new TickerResolutionLogger(c))
val fetches = cachePolicies.map { p =>
Cache.fetch[Task](
logger = resolutionLogger,
cachePolicy = p
)
}

val fetch = Fetch.from(repositories, fetches.head, fetches.tail: _*)

import scala.concurrent.ExecutionContext.Implicits.global
val resolution = start.process.run(fetch).unsafeRun()
(deps.toSeq, resolution)
}

class TickerResolutionLogger(ctx: mill.util.Ctx.Log) extends Cache.Logger {
case class DownloadState(var current: Long, var total: Long)
var downloads = new mutable.TreeMap[String,DownloadState]()
var totalDownloadCount = 0
var finishedCount = 0
var finishedState = DownloadState(0,0)

def updateTicker(): Unit = {
val sums = downloads.values
.fold(DownloadState(0,0)) {
(s1, s2) => DownloadState(
s1.current + s2.current,
Math.max(s1.current,s1.total) + Math.max(s2.current,s2.total)
)
}
sums.current += finishedState.current
sums.total += finishedState.total
ctx.log.ticker(s"Downloading [${downloads.size + finishedCount}/$totalDownloadCount] artifacts (~${sums.current}/${sums.total} bytes)")
}

override def downloadingArtifact(url: String, file: File): Unit = synchronized {
totalDownloadCount += 1
downloads += url -> DownloadState(0,0)
updateTicker()
}

override def downloadLength(url: String, totalLength: Long, alreadyDownloaded: Long, watching: Boolean): Unit = synchronized {
val state = downloads(url)
state.current = alreadyDownloaded
state.total = totalLength
updateTicker()
}

override def downloadProgress(url: String, downloaded: Long): Unit = synchronized {
val state = downloads(url)
state.current = downloaded
updateTicker()
}

override def downloadedArtifact(url: String, success: Boolean): Unit = synchronized {
val state = downloads(url)
finishedState.current += state.current
finishedState.total += Math.max(state.current, state.total)
finishedCount += 1
downloads -= url
updateTicker()
}
}

}
8 changes: 6 additions & 2 deletions scalalib/src/GenIdeaImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ object GenIdeaImpl {

val evaluator = new Evaluator(ctx.home, os.pwd / 'out, os.pwd / 'out, rootModule, ctx.log)

for((relPath, xml) <- xmlFileLayout(evaluator, rootModule, jdkInfo)){
for((relPath, xml) <- xmlFileLayout(evaluator, rootModule, jdkInfo, ctx)){
os.write.over(os.pwd/relPath, pp.format(xml), createFolders = true)
}
}
Expand All @@ -61,6 +61,7 @@ object GenIdeaImpl {
def xmlFileLayout(evaluator: Evaluator,
rootModule: mill.Module,
jdkInfo: (String,String),
ctx: Log,
fetchMillModules: Boolean = true): Seq[(os.RelPath, scala.xml.Node)] = {

val modules = rootModule.millInternal.segmentsToModules.values
Expand All @@ -78,7 +79,10 @@ object GenIdeaImpl {
repos.toList,
Lib.depToDependency(_, "2.12.4", ""),
for(name <- artifactNames)
yield ivy"com.lihaoyi::mill-$name:${sys.props("MILL_VERSION")}"
yield ivy"com.lihaoyi::mill-$name:${sys.props("MILL_VERSION")}",
false,
None,
Some(ctx)
)
res.items.toList.map(_.path)
}
Expand Down
3 changes: 2 additions & 1 deletion scalalib/src/JavaModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
resolveCoursierDependency().apply(_),
deps(),
sources,
mapDependencies = Some(mapDependencies())
mapDependencies = Some(mapDependencies()),
Some(implicitly[mill.util.Ctx.Log])
)
}

Expand Down
12 changes: 8 additions & 4 deletions scalalib/src/Lib.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ object Lib{
def resolveDependenciesMetadata(repositories: Seq[Repository],
depToDependency: Dep => coursier.Dependency,
deps: TraversableOnce[Dep],
mapDependencies: Option[Dependency => Dependency] = None) = {
mapDependencies: Option[Dependency => Dependency] = None,
ctx: Option[mill.util.Ctx.Log] = None) = {
val depSeq = deps.toSeq
mill.modules.Jvm.resolveDependenciesMetadata(
repositories,
depSeq.map(depToDependency),
depSeq.filter(_.force).map(depToDependency),
mapDependencies
mapDependencies,
ctx
)
}
/**
Expand All @@ -55,14 +57,16 @@ object Lib{
depToDependency: Dep => coursier.Dependency,
deps: TraversableOnce[Dep],
sources: Boolean = false,
mapDependencies: Option[Dependency => Dependency] = None): Result[Agg[PathRef]] = {
mapDependencies: Option[Dependency => Dependency] = None,
ctx: Option[mill.util.Ctx.Log] = None): Result[Agg[PathRef]] = {
val depSeq = deps.toSeq
mill.modules.Jvm.resolveDependencies(
repositories,
depSeq.map(depToDependency),
depSeq.filter(_.force).map(depToDependency),
sources,
mapDependencies
mapDependencies,
ctx
)
}
def scalaCompilerIvyDeps(scalaOrganization: String, scalaVersion: String) =
Expand Down
4 changes: 3 additions & 1 deletion scalalib/src/ScalaModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ trait ScalaModule extends JavaModule { outer =>
repositories,
Lib.depToDependency(_, scalaVersion0, platformSuffix()),
Seq(bridgeDep),
sources = true
sources = true,
mapDependencies = None,
Some(implicitly[mill.util.Ctx.Log])
).map(deps =>
mill.scalalib.api.Util.grepJar(deps.map(_.path), bridgeName, bridgeVersion, sources = true)
)
Expand Down

0 comments on commit bf2fe66

Please sign in to comment.