mirror of https://github.com/sbt/sbt.git
Fallback output
This commit is contained in:
parent
6e2905d905
commit
ca17da83f1
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue