1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
package mill.util
import java.io._
import ammonite.ops.Path
import ammonite.util.Colors
/**
* The standard logging interface of the Mill build tool.
*
* Contains four primary logging methods, in order of increasing importance:
*
* - `ticker`: short-lived logging output where consecutive lines over-write
* each other; useful for information which is transient and disposable
*
* - `info`: miscellaneous logging output which isn't part of the main output
* a user is looking for, but useful to provide context on what Mill is doing
*
* - `error`: logging output which represents problems the user should care
* about
*
* Also contains the two forwarded stdout and stderr streams, for code executed
* by Mill to use directly. Typically these correspond to the stdout and stderr,
* but when `--show` is used both are forwarded to stderr and stdout is only
* used to display the final `--show` output for easy piping.
*/
trait Logger {
def colored: Boolean
val errorStream: PrintStream
val outputStream: PrintStream
def info(s: String): Unit
def error(s: String): Unit
def ticker(s: String): Unit
def close(): Unit = ()
}
object DummyLogger extends Logger {
def colored = false
object errorStream extends PrintStream(_ => ())
object outputStream extends PrintStream(_ => ())
def info(s: String) = ()
def error(s: String) = ()
def ticker(s: String) = ()
}
case class PrintLogger(colored: Boolean,
colors: ammonite.util.Colors,
outStream: PrintStream,
infoStream: PrintStream,
errStream: PrintStream) extends Logger {
var lastLineTicker = false
override val errorStream = new PrintStream(
new OutputStream {
override def write(b: Array[Byte]): Unit = {
lastLineTicker = false
errStream.write(b)
}
override def write(b: Array[Byte], off: Int, len: Int): Unit = {
lastLineTicker = false
errStream.write(b, off, len)
}
def write(b: Int) = {
lastLineTicker = false
errStream.write(b)
}
}
)
override val outputStream = new PrintStream(
new OutputStream {
override def write(b: Array[Byte]): Unit = {
lastLineTicker = false
outStream.write(b)
}
override def write(b: Array[Byte], off: Int, len: Int): Unit = {
lastLineTicker = false
outStream.write(b, off, len)
}
def write(b: Int) = {
lastLineTicker = false
outStream.write(b)
}
}
)
def info(s: String) = {
lastLineTicker = false
infoStream.println(colors.info()(s))
}
def error(s: String) = {
lastLineTicker = false
errStream.println(colors.error()(s))
}
def ticker(s: String) = {
if (lastLineTicker){
val p = new PrintWriter(infoStream)
val nav = new ammonite.terminal.AnsiNav(p)
nav.up(1)
nav.clearLine(2)
nav.left(9999)
p.flush()
}
lastLineTicker = true
infoStream.println(colors.info()(s))
}
}
case class FileLogger(colored: Boolean, file: Path) extends Logger {
private[this] var outputStreamUsed: Boolean = false
lazy val outputStream = {
outputStreamUsed = true
new PrintStream(new FileOutputStream(file.toIO.getAbsolutePath))
}
lazy val errorStream = {
outputStreamUsed = true
new PrintStream(new FileOutputStream(file.toIO.getAbsolutePath))
}
def info(s: String) = outputStream.println(s)
def error(s: String) = outputStream.println(s)
def ticker(s: String) = outputStream.println(s)
override def close() = {
if (outputStreamUsed)
outputStream.close()
}
}
case class MultiLogger(colored: Boolean, streams: Logger*) extends Logger {
lazy val outputStream: PrintStream =
new PrintStream(b => streams.foreach(_.outputStream.write(b))) {
override def flush() = streams.foreach(_.outputStream.flush())
override def close() = streams.foreach(_.outputStream.close())
}
lazy val errorStream: PrintStream =
new PrintStream(b => streams.foreach(_.outputStream.write(b))) {
override def flush() = streams.foreach(_.outputStream.flush())
override def close() = streams.foreach(_.outputStream.close())
}
def info(s: String) = streams.foreach(_.info(s))
def error(s: String) = streams.foreach(_.error(s))
def ticker(s: String) = streams.foreach(_.ticker(s))
override def close() = streams.foreach(_.close())
}
|