Fallback output

This commit is contained in:
Alexandre Archambault 2015-12-30 01:34:35 +01:00
parent 6e2905d905
commit ca17da83f1
2 changed files with 103 additions and 45 deletions

View File

@ -10,15 +10,58 @@ import coursier.Files.Logger
import scala.annotation.tailrec import scala.annotation.tailrec
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
class TermDisplay(out: Writer) extends Logger { class TermDisplay(
out: Writer,
var fallbackMode: Boolean = false
) extends Logger {
private val ansi = new Ansi(out) private val ansi = new Ansi(out)
private var width = 80 private var width = 80
private val refreshInterval = 1000 / 60 private val refreshInterval = 1000 / 60
private val fallbackRefreshInterval = 1000
private val lock = new AnyRef private val lock = new AnyRef
private val t = new Thread("TermDisplay") { private val t = new Thread("TermDisplay") {
override def run() = lock.synchronized { override def run() = lock.synchronized {
val baseExtraWidth = width / 5 val baseExtraWidth = width / 5
def reflowed(url: String, info: Info) = {
val pctOpt = info.pct.map(100.0 * _)
val extra =
if (info.length.isEmpty && info.downloaded == 0L)
""
else
s"(${pctOpt.map(pct => f"$pct%.2f %%, ").mkString}${info.downloaded}${info.length.map(" / " + _).mkString})"
val total = url.length + 1 + extra.length
val (url0, extra0) =
if (total >= width) { // or > ? If equal, does it go down 2 lines?
val overflow = total - width + 1
val extra0 =
if (extra.length > baseExtraWidth)
extra.take((baseExtraWidth max (extra.length - overflow)) - 1) + "…"
else
extra
val total0 = url.length + 1 + extra0.length
val overflow0 = total0 - width + 1
val url0 =
if (total0 >= width)
url.take(((width - baseExtraWidth - 1) max (url.length - overflow0)) - 1) + "…"
else
url
(url0, extra0)
} else
(url, extra)
(url0, extra0)
}
@tailrec def helper(lineCount: Int): Unit = @tailrec def helper(lineCount: Int): Unit =
Option(q.poll(100L, TimeUnit.MILLISECONDS)) match { Option(q.poll(100L, TimeUnit.MILLISECONDS)) match {
case None => helper(lineCount) case None => helper(lineCount)
@ -35,36 +78,8 @@ class TermDisplay(out: Writer) extends Logger {
for ((url, info) <- downloads0) { for ((url, info) <- downloads0) {
assert(info != null, s"Incoherent state ($url)") assert(info != null, s"Incoherent state ($url)")
val pctOpt = info.pct.map(100.0 * _)
val extra =
if (info.length.isEmpty && info.downloaded == 0L)
""
else
s"(${pctOpt.map(pct => f"$pct%.2f %%, ").mkString}${info.downloaded}${info.length.map(" / " + _).mkString})"
val total = url.length + 1 + extra.length val (url0, extra0) = reflowed(url, info)
val (url0, extra0) =
if (total >= width) { // or > ? If equal, does it go down 2 lines?
val overflow = total - width + 1
val extra0 =
if (extra.length > baseExtraWidth)
extra.take((baseExtraWidth max (extra.length - overflow)) - 1) + "…"
else
extra
val total0 = url.length + 1 + extra0.length
val overflow0 = total0 - width + 1
val url0 =
if (total0 >= width)
url.take(((width - baseExtraWidth - 1) max (url.length - overflow0)) - 1) + "…"
else
url
(url0, extra0)
} else
(url, extra)
ansi.clearLine(2) ansi.clearLine(2)
out.write(s"$url0 $extra0\n") out.write(s"$url0 $extra0\n")
@ -88,15 +103,54 @@ class TermDisplay(out: Writer) extends Logger {
helper(downloads0.length) helper(downloads0.length)
} }
helper(0)
@tailrec def fallbackHelper(previous: Set[String]): Unit =
Option(q.poll(100L, TimeUnit.MILLISECONDS)) match {
case None => fallbackHelper(previous)
case Some(Left(())) => // poison pill
case Some(Right(())) =>
val downloads0 = downloads.synchronized {
downloads
.toVector
.map { url => url -> infos.get(url) }
.sortBy { case (_, info) => - info.pct.sum }
}
var displayedSomething = false
for ((url, info) <- downloads0 if previous(url)) {
assert(info != null, s"Incoherent state ($url)")
val (url0, extra0) = reflowed(url, info)
displayedSomething = true
out.write(s"$url0 $extra0\n")
}
if (displayedSomething)
out.write("\n")
out.flush()
Thread.sleep(fallbackRefreshInterval)
fallbackHelper(previous ++ downloads0.map { case (url, _) => url })
}
if (fallbackMode)
fallbackHelper(Set.empty)
else
helper(0)
} }
} }
t.setDaemon(true) t.setDaemon(true)
def init(): Unit = { def init(): Unit = {
width = TTY.consoleDim("cols") try {
ansi.clearLine(2) width = TTY.consoleDim("cols")
ansi.clearLine(2)
} catch { case _: Exception =>
fallbackMode = true
}
t.start() t.start()
} }
@ -123,6 +177,12 @@ class TermDisplay(out: Writer) extends Logger {
val prev = infos.putIfAbsent(url, Info(0L, None)) val prev = infos.putIfAbsent(url, Info(0L, None))
assert(prev == null) assert(prev == null)
if (fallbackMode) {
// FIXME What about concurrent accesses to out from the thread above?
out.write(s"Downloading $url\n")
out.flush()
}
downloads.synchronized { downloads.synchronized {
downloads.append(url) downloads.append(url)
} }
@ -150,6 +210,12 @@ class TermDisplay(out: Writer) extends Logger {
downloads -= url downloads -= url
} }
if (fallbackMode) {
// FIXME What about concurrent accesses to out from the thread above?
out.write(s"Downloaded $url\n")
out.flush()
}
val info = infos.remove(url) val info = infos.remove(url)
assert(info != null) assert(info != null)

View File

@ -36,18 +36,10 @@ object CoursierPlugin extends AutoPlugin {
) ++ sys.props ) ++ sys.props
private def createLogger() = Some { private def createLogger() = Some {
if (sys.env.get("COURSIER_NO_TERM").nonEmpty) new TermDisplay(
new coursier.Files.Logger { new OutputStreamWriter(System.err),
override def downloadingArtifact(url: String, file: File): Unit = { fallbackMode = sys.env.get("COURSIER_NO_TERM").nonEmpty
println(s"$url\n -> $file") )
}
override def downloadedArtifact(url: String, success: Boolean): Unit = {
println(s"$url: ${if (success) "Success" else "Failed"}")
}
def init() = {}
}
else
new TermDisplay(new OutputStreamWriter(System.err))
} }