This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / pipelines / logs.go
2.0 kB 89 lines
1package pipelines 2 3import ( 4 "html/template" 5 "path" 6 "regexp" 7 "strings" 8 9 terminal "github.com/buildkite/terminal-to-html/v3" 10 "github.com/gorilla/websocket" 11 "tangled.org/core/appview/pages/markup/sanitizer" 12 "tangled.org/core/hostutil" 13) 14 15// matches any ANSI escape sequence: ESC [ <params> m 16var sequenceRe = regexp.MustCompile(`\x1b\[([\d;]*)m`) 17 18// ansiState tracks the active stack across log lines 19// each non-reset SGR code is pushed onto the stack; a reset clears it. 20// 21// the stack contents are prepended to each new line so colours carry over. 22type ansiState struct { 23 stack []string 24} 25 26func NewAnsiState() *ansiState { 27 return &ansiState{ 28 stack: []string{}, 29 } 30} 31 32func (a *ansiState) Render(line string) template.HTML { 33 // prepend whatever sequences are still open from the previous line 34 prefix := strings.Join(a.stack, "") 35 // render current line with the existing prefix 36 rendered := terminal.Render([]byte(prefix + line)) 37 // sanitize 38 sanitized := sanitizer.SanitizeLogs(rendered) 39 40 // update the stack with sequences from current line 41 for _, m := range sequenceRe.FindAllStringSubmatch(line, -1) { 42 params := m[1] 43 if params == "" || params == "0" || params == "00" { 44 a.stack = a.stack[:0] 45 } else { 46 a.stack = append(a.stack, m[0]) 47 } 48 } 49 50 return template.HTML(sanitized) 51} 52 53type LogEvent struct { 54 Msg []byte 55 Err error 56} 57 58func (ev *LogEvent) IsCloseError() bool { 59 return websocket.IsCloseError( 60 ev.Err, 61 websocket.CloseNormalClosure, 62 websocket.CloseGoingAway, 63 websocket.CloseAbnormalClosure, 64 ) 65} 66 67func ReadLogs(conn *websocket.Conn, ch chan LogEvent) { 68 defer close(ch) 69 for { 70 if conn == nil { 71 return 72 } 73 _, msg, err := conn.ReadMessage() 74 if err != nil { 75 ch <- LogEvent{Err: err} 76 return 77 } 78 ch <- LogEvent{Msg: msg} 79 } 80} 81 82func SpindleURL(spindle, knot, rkey, workflow string) string { 83 url, err := hostutil.EnsureWsScheme(spindle) 84 if err != nil { 85 return "" 86 } 87 88 return url + path.Join("/logs", knot, rkey, workflow) 89}