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 (#494)

* Avoid unnecessary dependency downloading by providing fetches per cache policy; add ticker logging when they are downloading

* Fix GenIdeaTests by making the Log context Option[]al

* Add some comments

* Rebase and resolve
  • Loading branch information
gehnaphore authored and lefou committed Dec 20, 2018
1 parent 2752dcf commit 056cd88
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 21 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
18 changes: 18 additions & 0 deletions main/core/src/util/Loggers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,21 @@ case class MultiLogger(colored: Boolean, logger1: Logger, logger2: Logger) exten
logger2.close()
}
}

/**
* A Logger that forwards all logging to another Logger. Intended to be
* used as a base class for wrappers that modify logging behavior.
*/
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()
}
79 changes: 74 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,75 @@ 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)
}

/**
* A Coursier Cache.Logger implementation that updates the ticker with the count and
* overall byte size of artifacts being downloaded.
*
* In practice, this ticket output gets prefixed with the current target for which
* dependencies are being resolved, using a ProxyLogger subclass.
*/
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()
}
}

}
3 changes: 2 additions & 1 deletion scalajslib/src/ScalaJSModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer =>
resolveDependencies(
repositories,
Lib.depToDependency(_, "2.12.4", ""),
commonDeps :+ envDep
commonDeps :+ envDep,
ctx = Some(implicitly[mill.util.Ctx.Log])
)
}

Expand Down
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, Some(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: Option[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,
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
3 changes: 2 additions & 1 deletion scalalib/src/ZincWorkerModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ trait ZincWorkerModule extends mill.Module{
resolveDependencies(
repositories,
Lib.depToDependency(_, "2.12.4", ""),
Seq(ivy"org.scala-sbt:compiler-interface:${Versions.zinc}")
Seq(ivy"org.scala-sbt:compiler-interface:${Versions.zinc}"),
ctx = Some(implicitly[mill.util.Ctx.Log])
)
}

Expand Down
2 changes: 1 addition & 1 deletion scalalib/test/src/GenIdeaTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ object GenIdeaTests extends TestSuite {
val layout = GenIdeaImpl.xmlFileLayout(
helloWorldEvaluator.evaluator,
HelloWorld,
("JDK_1_8", "1.8 (1)"), fetchMillModules = false)
("JDK_1_8", "1.8 (1)"), None, fetchMillModules = false)
for((relPath, xml) <- layout){
os.write.over(millSourcePath/ "generated"/ relPath, pp.format(xml), createFolders = true)
}
Expand Down
9 changes: 6 additions & 3 deletions scalanativelib/src/ScalaNativeModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ trait ScalaNativeModule extends ScalaModule { outer =>
Lib.resolveDependencies(
Seq(Cache.ivy2Local, MavenRepository("https://repo1.maven.org/maven2")),
Lib.depToDependency(_, "2.12.4", ""),
Seq(ivy"com.lihaoyi::mill-scalanativelib-worker-${scalaNativeBinaryVersion()}:${sys.props("MILL_VERSION")}")
Seq(ivy"com.lihaoyi::mill-scalanativelib-worker-${scalaNativeBinaryVersion()}:${sys.props("MILL_VERSION")}"),
ctx = Some(implicitly[mill.util.Ctx.Log])
)
}

Expand Down Expand Up @@ -83,7 +84,8 @@ trait ScalaNativeModule extends ScalaModule { outer =>
Lib.resolveDependencies(
Seq(Cache.ivy2Local, MavenRepository("https://repo1.maven.org/maven2")),
Lib.depToDependency(_, scalaVersion(), platformSuffix()),
toolsIvyDeps()
toolsIvyDeps(),
ctx = Some(implicitly[mill.util.Ctx.Log])
).map(t => (scalaNativeWorkerClasspath().toSeq ++ t.toSeq).map(_.path))
}

Expand Down Expand Up @@ -200,7 +202,8 @@ trait TestScalaNativeModule extends ScalaNativeModule with TestModule { testOute
Lib.resolveDependencies(
repositories,
Lib.depToDependency(_, scalaVersion(), ""),
transitiveIvyDeps().filter(d => d.cross.isBinary && supportedTestFrameworks(d.dep.module.name))
transitiveIvyDeps().filter(d => d.cross.isBinary && supportedTestFrameworks(d.dep.module.name)),
ctx = Some(implicitly[mill.util.Ctx.Log])
)
}

Expand Down

0 comments on commit 056cd88

Please sign in to comment.