mirror of
https://github.com/astaxie/beego.git
synced 2024-11-25 17:10:54 +00:00
Removed external dependency
This commit is contained in:
parent
c893b3472c
commit
2b867f8152
@ -31,7 +31,6 @@ install:
|
|||||||
- go get github.com/siddontang/ledisdb/config
|
- go get github.com/siddontang/ledisdb/config
|
||||||
- go get github.com/siddontang/ledisdb/ledis
|
- go get github.com/siddontang/ledisdb/ledis
|
||||||
- go get github.com/ssdb/gossdb/ssdb
|
- go get github.com/ssdb/gossdb/ssdb
|
||||||
- go get github.com/shiena/ansicolor
|
|
||||||
before_script:
|
before_script:
|
||||||
- psql --version
|
- psql --version
|
||||||
- sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
|
- sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
|
||||||
|
461
logs/color_windows.go
Normal file
461
logs/color_windows.go
Normal file
@ -0,0 +1,461 @@
|
|||||||
|
// Copyright 2014 beego Author. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
outputMode int
|
||||||
|
csiState int
|
||||||
|
parseResult int
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
outsideCsiCode csiState = iota
|
||||||
|
firstCsiCode
|
||||||
|
secondCsiCode
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
noConsole parseResult = iota
|
||||||
|
changedColor
|
||||||
|
unknown
|
||||||
|
)
|
||||||
|
|
||||||
|
type ansiColorWriter struct {
|
||||||
|
w io.Writer
|
||||||
|
mode outputMode
|
||||||
|
state csiState
|
||||||
|
paramStartBuf bytes.Buffer
|
||||||
|
paramBuf bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
firstCsiChar byte = '\x1b'
|
||||||
|
secondeCsiChar byte = '['
|
||||||
|
separatorChar byte = ';'
|
||||||
|
sgrCode byte = 'm'
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
foregroundBlue = uint16(0x0001)
|
||||||
|
foregroundGreen = uint16(0x0002)
|
||||||
|
foregroundRed = uint16(0x0004)
|
||||||
|
foregroundIntensity = uint16(0x0008)
|
||||||
|
backgroundBlue = uint16(0x0010)
|
||||||
|
backgroundGreen = uint16(0x0020)
|
||||||
|
backgroundRed = uint16(0x0040)
|
||||||
|
backgroundIntensity = uint16(0x0080)
|
||||||
|
underscore = uint16(0x8000)
|
||||||
|
|
||||||
|
foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity
|
||||||
|
backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ansiReset = "0"
|
||||||
|
ansiIntensityOn = "1"
|
||||||
|
ansiIntensityOff = "21"
|
||||||
|
ansiUnderlineOn = "4"
|
||||||
|
ansiUnderlineOff = "24"
|
||||||
|
ansiBlinkOn = "5"
|
||||||
|
ansiBlinkOff = "25"
|
||||||
|
|
||||||
|
ansiForegroundBlack = "30"
|
||||||
|
ansiForegroundRed = "31"
|
||||||
|
ansiForegroundGreen = "32"
|
||||||
|
ansiForegroundYellow = "33"
|
||||||
|
ansiForegroundBlue = "34"
|
||||||
|
ansiForegroundMagenta = "35"
|
||||||
|
ansiForegroundCyan = "36"
|
||||||
|
ansiForegroundWhite = "37"
|
||||||
|
ansiForegroundDefault = "39"
|
||||||
|
|
||||||
|
ansiBackgroundBlack = "40"
|
||||||
|
ansiBackgroundRed = "41"
|
||||||
|
ansiBackgroundGreen = "42"
|
||||||
|
ansiBackgroundYellow = "43"
|
||||||
|
ansiBackgroundBlue = "44"
|
||||||
|
ansiBackgroundMagenta = "45"
|
||||||
|
ansiBackgroundCyan = "46"
|
||||||
|
ansiBackgroundWhite = "47"
|
||||||
|
ansiBackgroundDefault = "49"
|
||||||
|
|
||||||
|
ansiLightForegroundGray = "90"
|
||||||
|
ansiLightForegroundRed = "91"
|
||||||
|
ansiLightForegroundGreen = "92"
|
||||||
|
ansiLightForegroundYellow = "93"
|
||||||
|
ansiLightForegroundBlue = "94"
|
||||||
|
ansiLightForegroundMagenta = "95"
|
||||||
|
ansiLightForegroundCyan = "96"
|
||||||
|
ansiLightForegroundWhite = "97"
|
||||||
|
|
||||||
|
ansiLightBackgroundGray = "100"
|
||||||
|
ansiLightBackgroundRed = "101"
|
||||||
|
ansiLightBackgroundGreen = "102"
|
||||||
|
ansiLightBackgroundYellow = "103"
|
||||||
|
ansiLightBackgroundBlue = "104"
|
||||||
|
ansiLightBackgroundMagenta = "105"
|
||||||
|
ansiLightBackgroundCyan = "106"
|
||||||
|
ansiLightBackgroundWhite = "107"
|
||||||
|
)
|
||||||
|
|
||||||
|
type drawType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
foreground drawType = iota
|
||||||
|
background
|
||||||
|
)
|
||||||
|
|
||||||
|
type winColor struct {
|
||||||
|
code uint16
|
||||||
|
drawType drawType
|
||||||
|
}
|
||||||
|
|
||||||
|
var colorMap = map[string]winColor{
|
||||||
|
ansiForegroundBlack: {0, foreground},
|
||||||
|
ansiForegroundRed: {foregroundRed, foreground},
|
||||||
|
ansiForegroundGreen: {foregroundGreen, foreground},
|
||||||
|
ansiForegroundYellow: {foregroundRed | foregroundGreen, foreground},
|
||||||
|
ansiForegroundBlue: {foregroundBlue, foreground},
|
||||||
|
ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground},
|
||||||
|
ansiForegroundCyan: {foregroundGreen | foregroundBlue, foreground},
|
||||||
|
ansiForegroundWhite: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
|
||||||
|
ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
|
||||||
|
|
||||||
|
ansiBackgroundBlack: {0, background},
|
||||||
|
ansiBackgroundRed: {backgroundRed, background},
|
||||||
|
ansiBackgroundGreen: {backgroundGreen, background},
|
||||||
|
ansiBackgroundYellow: {backgroundRed | backgroundGreen, background},
|
||||||
|
ansiBackgroundBlue: {backgroundBlue, background},
|
||||||
|
ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background},
|
||||||
|
ansiBackgroundCyan: {backgroundGreen | backgroundBlue, background},
|
||||||
|
ansiBackgroundWhite: {backgroundRed | backgroundGreen | backgroundBlue, background},
|
||||||
|
ansiBackgroundDefault: {0, background},
|
||||||
|
|
||||||
|
ansiLightForegroundGray: {foregroundIntensity, foreground},
|
||||||
|
ansiLightForegroundRed: {foregroundIntensity | foregroundRed, foreground},
|
||||||
|
ansiLightForegroundGreen: {foregroundIntensity | foregroundGreen, foreground},
|
||||||
|
ansiLightForegroundYellow: {foregroundIntensity | foregroundRed | foregroundGreen, foreground},
|
||||||
|
ansiLightForegroundBlue: {foregroundIntensity | foregroundBlue, foreground},
|
||||||
|
ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground},
|
||||||
|
ansiLightForegroundCyan: {foregroundIntensity | foregroundGreen | foregroundBlue, foreground},
|
||||||
|
ansiLightForegroundWhite: {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground},
|
||||||
|
|
||||||
|
ansiLightBackgroundGray: {backgroundIntensity, background},
|
||||||
|
ansiLightBackgroundRed: {backgroundIntensity | backgroundRed, background},
|
||||||
|
ansiLightBackgroundGreen: {backgroundIntensity | backgroundGreen, background},
|
||||||
|
ansiLightBackgroundYellow: {backgroundIntensity | backgroundRed | backgroundGreen, background},
|
||||||
|
ansiLightBackgroundBlue: {backgroundIntensity | backgroundBlue, background},
|
||||||
|
ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background},
|
||||||
|
ansiLightBackgroundCyan: {backgroundIntensity | backgroundGreen | backgroundBlue, background},
|
||||||
|
ansiLightBackgroundWhite: {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background},
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
|
||||||
|
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||||
|
defaultAttr *textAttributes
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
|
||||||
|
if screenInfo != nil {
|
||||||
|
colorMap[ansiForegroundDefault] = winColor{
|
||||||
|
screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue),
|
||||||
|
foreground,
|
||||||
|
}
|
||||||
|
colorMap[ansiBackgroundDefault] = winColor{
|
||||||
|
screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue),
|
||||||
|
background,
|
||||||
|
}
|
||||||
|
defaultAttr = convertTextAttr(screenInfo.WAttributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type coord struct {
|
||||||
|
X, Y int16
|
||||||
|
}
|
||||||
|
|
||||||
|
type smallRect struct {
|
||||||
|
Left, Top, Right, Bottom int16
|
||||||
|
}
|
||||||
|
|
||||||
|
type consoleScreenBufferInfo struct {
|
||||||
|
DwSize coord
|
||||||
|
DwCursorPosition coord
|
||||||
|
WAttributes uint16
|
||||||
|
SrWindow smallRect
|
||||||
|
DwMaximumWindowSize coord
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
|
||||||
|
var csbi consoleScreenBufferInfo
|
||||||
|
ret, _, _ := procGetConsoleScreenBufferInfo.Call(
|
||||||
|
hConsoleOutput,
|
||||||
|
uintptr(unsafe.Pointer(&csbi)))
|
||||||
|
if ret == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &csbi
|
||||||
|
}
|
||||||
|
|
||||||
|
func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
|
||||||
|
ret, _, _ := procSetConsoleTextAttribute.Call(
|
||||||
|
hConsoleOutput,
|
||||||
|
uintptr(wAttributes))
|
||||||
|
return ret != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type textAttributes struct {
|
||||||
|
foregroundColor uint16
|
||||||
|
backgroundColor uint16
|
||||||
|
foregroundIntensity uint16
|
||||||
|
backgroundIntensity uint16
|
||||||
|
underscore uint16
|
||||||
|
otherAttributes uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTextAttr(winAttr uint16) *textAttributes {
|
||||||
|
fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue)
|
||||||
|
bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue)
|
||||||
|
fgIntensity := winAttr & foregroundIntensity
|
||||||
|
bgIntensity := winAttr & backgroundIntensity
|
||||||
|
underline := winAttr & underscore
|
||||||
|
otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore)
|
||||||
|
return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertWinAttr(textAttr *textAttributes) uint16 {
|
||||||
|
var winAttr uint16
|
||||||
|
winAttr |= textAttr.foregroundColor
|
||||||
|
winAttr |= textAttr.backgroundColor
|
||||||
|
winAttr |= textAttr.foregroundIntensity
|
||||||
|
winAttr |= textAttr.backgroundIntensity
|
||||||
|
winAttr |= textAttr.underscore
|
||||||
|
winAttr |= textAttr.otherAttributes
|
||||||
|
return winAttr
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeColor(param []byte) parseResult {
|
||||||
|
screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
|
||||||
|
if screenInfo == nil {
|
||||||
|
return noConsole
|
||||||
|
}
|
||||||
|
|
||||||
|
winAttr := convertTextAttr(screenInfo.WAttributes)
|
||||||
|
strParam := string(param)
|
||||||
|
if len(strParam) <= 0 {
|
||||||
|
strParam = "0"
|
||||||
|
}
|
||||||
|
csiParam := strings.Split(strParam, string(separatorChar))
|
||||||
|
for _, p := range csiParam {
|
||||||
|
c, ok := colorMap[p]
|
||||||
|
switch {
|
||||||
|
case !ok:
|
||||||
|
switch p {
|
||||||
|
case ansiReset:
|
||||||
|
winAttr.foregroundColor = defaultAttr.foregroundColor
|
||||||
|
winAttr.backgroundColor = defaultAttr.backgroundColor
|
||||||
|
winAttr.foregroundIntensity = defaultAttr.foregroundIntensity
|
||||||
|
winAttr.backgroundIntensity = defaultAttr.backgroundIntensity
|
||||||
|
winAttr.underscore = 0
|
||||||
|
winAttr.otherAttributes = 0
|
||||||
|
case ansiIntensityOn:
|
||||||
|
winAttr.foregroundIntensity = foregroundIntensity
|
||||||
|
case ansiIntensityOff:
|
||||||
|
winAttr.foregroundIntensity = 0
|
||||||
|
case ansiUnderlineOn:
|
||||||
|
winAttr.underscore = underscore
|
||||||
|
case ansiUnderlineOff:
|
||||||
|
winAttr.underscore = 0
|
||||||
|
case ansiBlinkOn:
|
||||||
|
winAttr.backgroundIntensity = backgroundIntensity
|
||||||
|
case ansiBlinkOff:
|
||||||
|
winAttr.backgroundIntensity = 0
|
||||||
|
default:
|
||||||
|
// unknown code
|
||||||
|
}
|
||||||
|
case c.drawType == foreground:
|
||||||
|
winAttr.foregroundColor = c.code
|
||||||
|
case c.drawType == background:
|
||||||
|
winAttr.backgroundColor = c.code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
winTextAttribute := convertWinAttr(winAttr)
|
||||||
|
setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute)
|
||||||
|
|
||||||
|
return changedColor
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEscapeSequence(command byte, param []byte) parseResult {
|
||||||
|
if defaultAttr == nil {
|
||||||
|
return noConsole
|
||||||
|
}
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case sgrCode:
|
||||||
|
return changeColor(param)
|
||||||
|
default:
|
||||||
|
return unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ansiColorWriter) flushBuffer() (int, error) {
|
||||||
|
return cw.flushTo(cw.w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ansiColorWriter) resetBuffer() (int, error) {
|
||||||
|
return cw.flushTo(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ansiColorWriter) flushTo(w io.Writer) (int, error) {
|
||||||
|
var n1, n2 int
|
||||||
|
var err error
|
||||||
|
|
||||||
|
startBytes := cw.paramStartBuf.Bytes()
|
||||||
|
cw.paramStartBuf.Reset()
|
||||||
|
if w != nil {
|
||||||
|
n1, err = cw.w.Write(startBytes)
|
||||||
|
if err != nil {
|
||||||
|
return n1, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n1 = len(startBytes)
|
||||||
|
}
|
||||||
|
paramBytes := cw.paramBuf.Bytes()
|
||||||
|
cw.paramBuf.Reset()
|
||||||
|
if w != nil {
|
||||||
|
n2, err = cw.w.Write(paramBytes)
|
||||||
|
if err != nil {
|
||||||
|
return n1 + n2, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n2 = len(paramBytes)
|
||||||
|
}
|
||||||
|
return n1 + n2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isParameterChar(b byte) bool {
|
||||||
|
return ('0' <= b && b <= '9') || b == separatorChar
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ansiColorWriter) Write(p []byte) (int, error) {
|
||||||
|
r, nw, first, last := 0, 0, 0, 0
|
||||||
|
if cw.mode != DiscardNonColorEscSeq {
|
||||||
|
cw.state = outsideCsiCode
|
||||||
|
cw.resetBuffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for i, ch := range p {
|
||||||
|
switch cw.state {
|
||||||
|
case outsideCsiCode:
|
||||||
|
if ch == firstCsiChar {
|
||||||
|
cw.paramStartBuf.WriteByte(ch)
|
||||||
|
cw.state = firstCsiCode
|
||||||
|
}
|
||||||
|
case firstCsiCode:
|
||||||
|
switch ch {
|
||||||
|
case firstCsiChar:
|
||||||
|
cw.paramStartBuf.WriteByte(ch)
|
||||||
|
break
|
||||||
|
case secondeCsiChar:
|
||||||
|
cw.paramStartBuf.WriteByte(ch)
|
||||||
|
cw.state = secondCsiCode
|
||||||
|
last = i - 1
|
||||||
|
default:
|
||||||
|
cw.resetBuffer()
|
||||||
|
cw.state = outsideCsiCode
|
||||||
|
}
|
||||||
|
case secondCsiCode:
|
||||||
|
if isParameterChar(ch) {
|
||||||
|
cw.paramBuf.WriteByte(ch)
|
||||||
|
} else {
|
||||||
|
nw, err = cw.w.Write(p[first:last])
|
||||||
|
r += nw
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
first = i + 1
|
||||||
|
result := parseEscapeSequence(ch, cw.paramBuf.Bytes())
|
||||||
|
if result == noConsole || (cw.mode == OutputNonColorEscSeq && result == unknown) {
|
||||||
|
cw.paramBuf.WriteByte(ch)
|
||||||
|
nw, err := cw.flushBuffer()
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
r += nw
|
||||||
|
} else {
|
||||||
|
n, _ := cw.resetBuffer()
|
||||||
|
// Add one more to the size of the buffer for the last ch
|
||||||
|
r += n + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cw.state = outsideCsiCode
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
cw.state = outsideCsiCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cw.mode != DiscardNonColorEscSeq || cw.state == outsideCsiCode {
|
||||||
|
nw, err = cw.w.Write(p[first:len(p)])
|
||||||
|
r += nw
|
||||||
|
}
|
||||||
|
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscardNonColorEscSeq supports the divided color escape sequence.
|
||||||
|
// But non-color escape sequence is not output.
|
||||||
|
// Please use the OutputNonColorEscSeq If you want to output a non-color
|
||||||
|
// escape sequences such as ncurses. However, it does not support the divided
|
||||||
|
// color escape sequence.
|
||||||
|
const (
|
||||||
|
_ outputMode = iota
|
||||||
|
DiscardNonColorEscSeq
|
||||||
|
OutputNonColorEscSeq
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewAnsiColorWriter creates and initializes a new ansiColorWriter
|
||||||
|
// using io.Writer w as its initial contents.
|
||||||
|
// In the console of Windows, which change the foreground and background
|
||||||
|
// colors of the text by the escape sequence.
|
||||||
|
// In the console of other systems, which writes to w all text.
|
||||||
|
func NewAnsiColorWriter(w io.Writer) io.Writer {
|
||||||
|
return NewModeAnsiColorWriter(w, DiscardNonColorEscSeq)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewModeAnsiColorWriter create and initializes a new ansiColorWriter
|
||||||
|
// by specifying the outputMode.
|
||||||
|
func NewModeAnsiColorWriter(w io.Writer, mode outputMode) io.Writer {
|
||||||
|
if _, ok := w.(*ansiColorWriter); !ok {
|
||||||
|
return &ansiColorWriter{
|
||||||
|
w: w,
|
||||||
|
mode: mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
294
logs/color_windows_test.go
Normal file
294
logs/color_windows_test.go
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
// Copyright 2014 beego Author. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var GetConsoleScreenBufferInfo = getConsoleScreenBufferInfo
|
||||||
|
|
||||||
|
func ChangeColor(color uint16) {
|
||||||
|
setConsoleTextAttribute(uintptr(syscall.Stdout), color)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResetColor() {
|
||||||
|
ChangeColor(uint16(0x0007))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWritePlanText(t *testing.T) {
|
||||||
|
inner := bytes.NewBufferString("")
|
||||||
|
w := NewAnsiColorWriter(inner)
|
||||||
|
expected := "plain text"
|
||||||
|
fmt.Fprintf(w, expected)
|
||||||
|
actual := inner.String()
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("Get %q, want %q", actual, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteParseText(t *testing.T) {
|
||||||
|
inner := bytes.NewBufferString("")
|
||||||
|
w := NewAnsiColorWriter(inner)
|
||||||
|
|
||||||
|
inputTail := "\x1b[0mtail text"
|
||||||
|
expectedTail := "tail text"
|
||||||
|
fmt.Fprintf(w, inputTail)
|
||||||
|
actualTail := inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualTail != expectedTail {
|
||||||
|
t.Errorf("Get %q, want %q", actualTail, expectedTail)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputHead := "head text\x1b[0m"
|
||||||
|
expectedHead := "head text"
|
||||||
|
fmt.Fprintf(w, inputHead)
|
||||||
|
actualHead := inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualHead != expectedHead {
|
||||||
|
t.Errorf("Get %q, want %q", actualHead, expectedHead)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputBothEnds := "both ends \x1b[0m text"
|
||||||
|
expectedBothEnds := "both ends text"
|
||||||
|
fmt.Fprintf(w, inputBothEnds)
|
||||||
|
actualBothEnds := inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualBothEnds != expectedBothEnds {
|
||||||
|
t.Errorf("Get %q, want %q", actualBothEnds, expectedBothEnds)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputManyEsc := "\x1b\x1b\x1b\x1b[0m many esc"
|
||||||
|
expectedManyEsc := "\x1b\x1b\x1b many esc"
|
||||||
|
fmt.Fprintf(w, inputManyEsc)
|
||||||
|
actualManyEsc := inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualManyEsc != expectedManyEsc {
|
||||||
|
t.Errorf("Get %q, want %q", actualManyEsc, expectedManyEsc)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedSplit := "split text"
|
||||||
|
for _, ch := range "split \x1b[0m text" {
|
||||||
|
fmt.Fprintf(w, string(ch))
|
||||||
|
}
|
||||||
|
actualSplit := inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualSplit != expectedSplit {
|
||||||
|
t.Errorf("Get %q, want %q", actualSplit, expectedSplit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type screenNotFoundError struct {
|
||||||
|
error
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeAnsiColor(expectedText, colorCode string) (actualText string, actualAttributes uint16, err error) {
|
||||||
|
inner := bytes.NewBufferString("")
|
||||||
|
w := NewAnsiColorWriter(inner)
|
||||||
|
fmt.Fprintf(w, "\x1b[%sm%s", colorCode, expectedText)
|
||||||
|
|
||||||
|
actualText = inner.String()
|
||||||
|
screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
|
||||||
|
if screenInfo != nil {
|
||||||
|
actualAttributes = screenInfo.WAttributes
|
||||||
|
} else {
|
||||||
|
err = &screenNotFoundError{}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type testParam struct {
|
||||||
|
text string
|
||||||
|
attributes uint16
|
||||||
|
ansiColor string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteAnsiColorText(t *testing.T) {
|
||||||
|
screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
|
||||||
|
if screenInfo == nil {
|
||||||
|
t.Fatal("Could not get ConsoleScreenBufferInfo")
|
||||||
|
}
|
||||||
|
defer ChangeColor(screenInfo.WAttributes)
|
||||||
|
defaultFgColor := screenInfo.WAttributes & uint16(0x0007)
|
||||||
|
defaultBgColor := screenInfo.WAttributes & uint16(0x0070)
|
||||||
|
defaultFgIntensity := screenInfo.WAttributes & uint16(0x0008)
|
||||||
|
defaultBgIntensity := screenInfo.WAttributes & uint16(0x0080)
|
||||||
|
|
||||||
|
fgParam := []testParam{
|
||||||
|
{"foreground black ", uint16(0x0000 | 0x0000), "30"},
|
||||||
|
{"foreground red ", uint16(0x0004 | 0x0000), "31"},
|
||||||
|
{"foreground green ", uint16(0x0002 | 0x0000), "32"},
|
||||||
|
{"foreground yellow ", uint16(0x0006 | 0x0000), "33"},
|
||||||
|
{"foreground blue ", uint16(0x0001 | 0x0000), "34"},
|
||||||
|
{"foreground magenta", uint16(0x0005 | 0x0000), "35"},
|
||||||
|
{"foreground cyan ", uint16(0x0003 | 0x0000), "36"},
|
||||||
|
{"foreground white ", uint16(0x0007 | 0x0000), "37"},
|
||||||
|
{"foreground default", defaultFgColor | 0x0000, "39"},
|
||||||
|
{"foreground light gray ", uint16(0x0000 | 0x0008 | 0x0000), "90"},
|
||||||
|
{"foreground light red ", uint16(0x0004 | 0x0008 | 0x0000), "91"},
|
||||||
|
{"foreground light green ", uint16(0x0002 | 0x0008 | 0x0000), "92"},
|
||||||
|
{"foreground light yellow ", uint16(0x0006 | 0x0008 | 0x0000), "93"},
|
||||||
|
{"foreground light blue ", uint16(0x0001 | 0x0008 | 0x0000), "94"},
|
||||||
|
{"foreground light magenta", uint16(0x0005 | 0x0008 | 0x0000), "95"},
|
||||||
|
{"foreground light cyan ", uint16(0x0003 | 0x0008 | 0x0000), "96"},
|
||||||
|
{"foreground light white ", uint16(0x0007 | 0x0008 | 0x0000), "97"},
|
||||||
|
}
|
||||||
|
|
||||||
|
bgParam := []testParam{
|
||||||
|
{"background black ", uint16(0x0007 | 0x0000), "40"},
|
||||||
|
{"background red ", uint16(0x0007 | 0x0040), "41"},
|
||||||
|
{"background green ", uint16(0x0007 | 0x0020), "42"},
|
||||||
|
{"background yellow ", uint16(0x0007 | 0x0060), "43"},
|
||||||
|
{"background blue ", uint16(0x0007 | 0x0010), "44"},
|
||||||
|
{"background magenta", uint16(0x0007 | 0x0050), "45"},
|
||||||
|
{"background cyan ", uint16(0x0007 | 0x0030), "46"},
|
||||||
|
{"background white ", uint16(0x0007 | 0x0070), "47"},
|
||||||
|
{"background default", uint16(0x0007) | defaultBgColor, "49"},
|
||||||
|
{"background light gray ", uint16(0x0007 | 0x0000 | 0x0080), "100"},
|
||||||
|
{"background light red ", uint16(0x0007 | 0x0040 | 0x0080), "101"},
|
||||||
|
{"background light green ", uint16(0x0007 | 0x0020 | 0x0080), "102"},
|
||||||
|
{"background light yellow ", uint16(0x0007 | 0x0060 | 0x0080), "103"},
|
||||||
|
{"background light blue ", uint16(0x0007 | 0x0010 | 0x0080), "104"},
|
||||||
|
{"background light magenta", uint16(0x0007 | 0x0050 | 0x0080), "105"},
|
||||||
|
{"background light cyan ", uint16(0x0007 | 0x0030 | 0x0080), "106"},
|
||||||
|
{"background light white ", uint16(0x0007 | 0x0070 | 0x0080), "107"},
|
||||||
|
}
|
||||||
|
|
||||||
|
resetParam := []testParam{
|
||||||
|
{"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, "0"},
|
||||||
|
{"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
boldParam := []testParam{
|
||||||
|
{"bold on", uint16(0x0007 | 0x0008), "1"},
|
||||||
|
{"bold off", uint16(0x0007), "21"},
|
||||||
|
}
|
||||||
|
|
||||||
|
underscoreParam := []testParam{
|
||||||
|
{"underscore on", uint16(0x0007 | 0x8000), "4"},
|
||||||
|
{"underscore off", uint16(0x0007), "24"},
|
||||||
|
}
|
||||||
|
|
||||||
|
blinkParam := []testParam{
|
||||||
|
{"blink on", uint16(0x0007 | 0x0080), "5"},
|
||||||
|
{"blink off", uint16(0x0007), "25"},
|
||||||
|
}
|
||||||
|
|
||||||
|
mixedParam := []testParam{
|
||||||
|
{"both black, bold, underline, blink", uint16(0x0000 | 0x0000 | 0x0008 | 0x8000 | 0x0080), "30;40;1;4;5"},
|
||||||
|
{"both red, bold, underline, blink", uint16(0x0004 | 0x0040 | 0x0008 | 0x8000 | 0x0080), "31;41;1;4;5"},
|
||||||
|
{"both green, bold, underline, blink", uint16(0x0002 | 0x0020 | 0x0008 | 0x8000 | 0x0080), "32;42;1;4;5"},
|
||||||
|
{"both yellow, bold, underline, blink", uint16(0x0006 | 0x0060 | 0x0008 | 0x8000 | 0x0080), "33;43;1;4;5"},
|
||||||
|
{"both blue, bold, underline, blink", uint16(0x0001 | 0x0010 | 0x0008 | 0x8000 | 0x0080), "34;44;1;4;5"},
|
||||||
|
{"both magenta, bold, underline, blink", uint16(0x0005 | 0x0050 | 0x0008 | 0x8000 | 0x0080), "35;45;1;4;5"},
|
||||||
|
{"both cyan, bold, underline, blink", uint16(0x0003 | 0x0030 | 0x0008 | 0x8000 | 0x0080), "36;46;1;4;5"},
|
||||||
|
{"both white, bold, underline, blink", uint16(0x0007 | 0x0070 | 0x0008 | 0x8000 | 0x0080), "37;47;1;4;5"},
|
||||||
|
{"both default, bold, underline, blink", uint16(defaultFgColor | defaultBgColor | 0x0008 | 0x8000 | 0x0080), "39;49;1;4;5"},
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTextAttribute := func(expectedText string, expectedAttributes uint16, ansiColor string) {
|
||||||
|
actualText, actualAttributes, err := writeAnsiColor(expectedText, ansiColor)
|
||||||
|
if actualText != expectedText {
|
||||||
|
t.Errorf("Get %q, want %q", actualText, expectedText)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Could not get ConsoleScreenBufferInfo")
|
||||||
|
}
|
||||||
|
if actualAttributes != expectedAttributes {
|
||||||
|
t.Errorf("Text: %q, Get 0x%04x, want 0x%04x", expectedText, actualAttributes, expectedAttributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range fgParam {
|
||||||
|
ResetColor()
|
||||||
|
assertTextAttribute(v.text, v.attributes, v.ansiColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range bgParam {
|
||||||
|
ChangeColor(uint16(0x0070 | 0x0007))
|
||||||
|
assertTextAttribute(v.text, v.attributes, v.ansiColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range resetParam {
|
||||||
|
ChangeColor(uint16(0x0000 | 0x0070 | 0x0008))
|
||||||
|
assertTextAttribute(v.text, v.attributes, v.ansiColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetColor()
|
||||||
|
for _, v := range boldParam {
|
||||||
|
assertTextAttribute(v.text, v.attributes, v.ansiColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetColor()
|
||||||
|
for _, v := range underscoreParam {
|
||||||
|
assertTextAttribute(v.text, v.attributes, v.ansiColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetColor()
|
||||||
|
for _, v := range blinkParam {
|
||||||
|
assertTextAttribute(v.text, v.attributes, v.ansiColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range mixedParam {
|
||||||
|
ResetColor()
|
||||||
|
assertTextAttribute(v.text, v.attributes, v.ansiColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIgnoreUnknownSequences(t *testing.T) {
|
||||||
|
inner := bytes.NewBufferString("")
|
||||||
|
w := NewModeAnsiColorWriter(inner, OutputNonColorEscSeq)
|
||||||
|
|
||||||
|
inputText := "\x1b[=decpath mode"
|
||||||
|
expectedTail := inputText
|
||||||
|
fmt.Fprintf(w, inputText)
|
||||||
|
actualTail := inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualTail != expectedTail {
|
||||||
|
t.Errorf("Get %q, want %q", actualTail, expectedTail)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputText = "\x1b[=tailing esc and bracket\x1b["
|
||||||
|
expectedTail = inputText
|
||||||
|
fmt.Fprintf(w, inputText)
|
||||||
|
actualTail = inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualTail != expectedTail {
|
||||||
|
t.Errorf("Get %q, want %q", actualTail, expectedTail)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputText = "\x1b[?tailing esc\x1b"
|
||||||
|
expectedTail = inputText
|
||||||
|
fmt.Fprintf(w, inputText)
|
||||||
|
actualTail = inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualTail != expectedTail {
|
||||||
|
t.Errorf("Get %q, want %q", actualTail, expectedTail)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputText = "\x1b[1h;3punended color code invalid\x1b3"
|
||||||
|
expectedTail = inputText
|
||||||
|
fmt.Fprintf(w, inputText)
|
||||||
|
actualTail = inner.String()
|
||||||
|
inner.Reset()
|
||||||
|
if actualTail != expectedTail {
|
||||||
|
t.Errorf("Get %q, want %q", actualTail, expectedTail)
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"github.com/shiena/ansicolor"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
@ -138,16 +137,16 @@ func ColorByMethod(cond bool, method string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Guard Mutex to guarantee atomicity of W32Debug(string) function
|
||||||
var mu sync.Mutex
|
var mu sync.Mutex
|
||||||
|
|
||||||
// Helper method to output colored logs in Windows terminals
|
// Helper method to output colored logs in Windows terminals
|
||||||
// using ansicolor (https://github.com/shiena/ansicolor)
|
|
||||||
func W32Debug(msg string) {
|
func W32Debug(msg string) {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
current := time.Now()
|
current := time.Now()
|
||||||
w := ansicolor.NewAnsiColorWriter(os.Stdout)
|
w := NewAnsiColorWriter(os.Stdout)
|
||||||
|
|
||||||
fmt.Fprintf(w, "[beego] %v %s\n", current.Format("2006/01/02 - 15:04:05"), msg)
|
fmt.Fprintf(w, "[beego] %v %s\n", current.Format("2006/01/02 - 15:04:05"), msg)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user