Honor formatEnabledInEnv at the Terminal level

The sbt.log.noformat parameter should be treated very similarly to
sbt.io.virtual. When it is true, we should just use the raw io streams
for the process. This came up because of
https://github.com/sbt/sbt/issues/5784 which reported that intellij
imports were not working and that ansi control characters were being
written to the output.
This commit is contained in:
Ethan Atkins 2020-08-21 11:18:27 -07:00
parent 99e833d11a
commit 02366fdf49
4 changed files with 63 additions and 45 deletions

View File

@ -148,40 +148,9 @@ object ConsoleAppender {
* 3. -Dsbt.colour=always/auto/never/true/false
* 4. -Dsbt.log.format=always/auto/never/true/false
*/
lazy val formatEnabledInEnv: Boolean = {
def useColorDefault: Boolean = {
// This approximates that both stdin and stdio are connected,
// so by default color will be turned off for pipes and redirects.
val hasConsole = Option(java.lang.System.console).isDefined
ansiSupported && hasConsole
}
sys.props.get("sbt.log.noformat") match {
case Some(_) => !java.lang.Boolean.getBoolean("sbt.log.noformat")
case _ =>
sys.props
.get("sbt.color")
.orElse(sys.props.get("sbt.colour"))
.orElse(sys.props.get("sbt.log.format"))
.flatMap({ s =>
parseLogOption(s) match {
case LogOption.Always => Some(true)
case LogOption.Never => Some(false)
case _ => None
}
})
.getOrElse(useColorDefault)
}
}
lazy val formatEnabledInEnv: Boolean = Terminal.formatEnabledInEnv
private[sbt] def parseLogOption(s: String): LogOption =
s.toLowerCase match {
case "always" => LogOption.Always
case "auto" => LogOption.Auto
case "never" => LogOption.Never
case "true" => LogOption.Always
case "false" => LogOption.Never
case _ => LogOption.Auto
}
private[sbt] def parseLogOption(s: String): LogOption = Terminal.parseLogOption(s)
private[this] val generateId: AtomicInteger = new AtomicInteger
@ -399,6 +368,10 @@ trait Appender extends AutoCloseable {
if (ansiCodesSupported && useFormat) scala.Console.RESET
else ""
}
private def clearScreenAfterCursor: String = {
if (ansiCodesSupported && useFormat) ClearScreenAfterCursor
else ""
}
private val SUCCESS_LABEL_COLOR = GREEN
private val SUCCESS_MESSAGE_COLOR = reset
@ -488,7 +461,7 @@ trait Appender extends AutoCloseable {
if (message == null) ()
else {
val len =
labelColor.length + label.length + messageColor.length + reset.length * 3 + ClearScreenAfterCursor.length
labelColor.length + label.length + messageColor.length + reset.length * 3 + clearScreenAfterCursor.length
val builder: StringBuilder = new StringBuilder(len)
message.linesIterator.foreach { line =>
builder.ensureCapacity(len + line.length + 4)
@ -500,7 +473,7 @@ trait Appender extends AutoCloseable {
fmted(labelColor, label)
builder.append("] ")
fmted(messageColor, line)
builder.append(ClearScreenAfterCursor)
builder.append(clearScreenAfterCursor)
write(builder.toString)
}
}

View File

@ -275,17 +275,58 @@ object Terminal {
private[this] val hasProgress: AtomicBoolean = new AtomicBoolean(false)
private[sbt] def parseLogOption(s: String): LogOption =
s.toLowerCase match {
case "always" => LogOption.Always
case "auto" => LogOption.Auto
case "never" => LogOption.Never
case "true" => LogOption.Always
case "false" => LogOption.Never
case _ => LogOption.Auto
}
/**
* Indicates whether formatting has been disabled in environment variables.
* 1. -Dsbt.log.noformat=true means no formatting.
* 2. -Dsbt.color=always/auto/never/true/false
* 3. -Dsbt.colour=always/auto/never/true/false
* 4. -Dsbt.log.format=always/auto/never/true/false
*/
private[sbt] lazy val formatEnabledInEnv: Boolean = {
def useColorDefault: Boolean = {
// This approximates that both stdin and stdio are connected,
// so by default color will be turned off for pipes and redirects.
val hasConsole = Option(java.lang.System.console).isDefined
props.map(_.ansi).getOrElse(true) && hasConsole
}
sys.props.get("sbt.log.noformat") match {
case Some(_) => !java.lang.Boolean.getBoolean("sbt.log.noformat")
case _ =>
sys.props
.get("sbt.color")
.orElse(sys.props.get("sbt.colour"))
.orElse(sys.props.get("sbt.log.format"))
.flatMap({ s =>
parseLogOption(s) match {
case LogOption.Always => Some(true)
case LogOption.Never => Some(false)
case _ => None
}
})
.getOrElse(useColorDefault)
}
}
/**
*
* @param progress toggles whether or not the console terminal has progress
* @param isServer toggles whether or not this is a server of client process
* @param f the thunk to run
* @tparam T the result type of the thunk
* @return the result of the thunk
*/
private[sbt] def withStreams[T](isServer: Boolean)(f: => T): T =
// In ci environments, don't touch the io streams unless run with -Dsbt.io.virtual=true
if (isCI && System.getProperty("sbt.io.virtual", "") != "true") f
else {
if (System.getProperty("sbt.io.virtual", "") == "true" || (formatEnabledInEnv && !isCI)) {
hasProgress.set(isServer)
consoleTerminalHolder.set(wrap(jline.TerminalFactory.get))
activeTerminal.set(consoleTerminalHolder.get)
@ -317,7 +358,7 @@ object Terminal {
console.close()
}
}
}
} else f
private[this] object ProxyTerminal extends Terminal {
private def t: Terminal = activeTerminal.get
@ -693,7 +734,7 @@ object Terminal {
override def isSupported: Boolean = terminal.isSupported
override def getWidth: Int = props.map(_.width).getOrElse(terminal.getWidth)
override def getHeight: Int = props.map(_.height).getOrElse(terminal.getHeight)
override def isAnsiSupported: Boolean = props.map(_.ansi).getOrElse(terminal.isAnsiSupported)
override def isAnsiSupported: Boolean = formatEnabledInEnv
override def wrapOutIfNeeded(out: OutputStream): OutputStream = terminal.wrapOutIfNeeded(out)
override def wrapInIfNeeded(in: InputStream): InputStream = terminal.wrapInIfNeeded(in)
override def hasWeirdWrap: Boolean = terminal.hasWeirdWrap

View File

@ -75,9 +75,11 @@ private[sbt] class UserThread(val channel: CommandChannel) extends AutoCloseable
// synchronize to ensure that the state isn't modified during the call to reset
// at the bottom
synchronized {
channel.terminal.withPrintStream { ps =>
ps.print(ConsoleAppender.ClearScreenAfterCursor)
ps.flush()
if (terminal.isAnsiSupported) {
channel.terminal.withPrintStream { ps =>
ps.print(ConsoleAppender.ClearScreenAfterCursor)
ps.flush()
}
}
val state = consolePromptEvent.state
terminal.prompt match {

View File

@ -104,8 +104,10 @@ private[sbt] object xMain {
} finally {
// Clear any stray progress lines
ShutdownHooks.close()
System.out.print(ConsoleAppender.ClearScreenAfterCursor)
System.out.flush()
if (Terminal.formatEnabledInEnv) {
System.out.print(ConsoleAppender.ClearScreenAfterCursor)
System.out.flush()
}
}
}