github.com/SAP/jenkins-library@v1.362.0/pkg/log/url.go (about) 1 package log 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "os" 9 "sync" 10 11 "mvdan.cc/xurls/v2" 12 ) 13 14 type ( 15 step struct { 16 Step map[string]u `json:"step"` 17 } 18 u struct { 19 URLs []string `json:"url"` 20 } 21 ) 22 23 const ( 24 urlLogFileName = "url-log.json" 25 ) 26 27 type URLLogger struct { 28 buf struct { 29 data [][]byte 30 sync.RWMutex 31 } 32 stepName string 33 } 34 35 func NewURLLogger(stepName string) *URLLogger { 36 return &URLLogger{stepName: stepName} 37 } 38 39 func (cl *URLLogger) WriteURLsLogToJSON() error { 40 cl.buf.Lock() 41 defer cl.buf.Unlock() 42 if len(cl.buf.data) == 0 { 43 return nil 44 } 45 file, err := os.OpenFile(urlLogFileName, os.O_CREATE|os.O_RDWR, 0666) 46 if err != nil { 47 return fmt.Errorf("failed to open file: %w", err) 48 } 49 defer func() { 50 dErr := file.Close() 51 if dErr != nil { 52 err = fmt.Errorf("can't close file: %w", dErr) 53 } 54 }() 55 fileBuf, err := io.ReadAll(file) 56 if err != nil { 57 return fmt.Errorf("can't read from gile: %w", err) 58 } 59 urlsLog := step{make(map[string]u)} 60 if len(fileBuf) != 0 { 61 err = json.Unmarshal(fileBuf, &urlsLog) 62 if err != nil { 63 return fmt.Errorf("can't unmarshal log: %w", err) 64 } 65 fileBuf = fileBuf[:0] 66 } 67 var urls []string 68 if stepLogs, ok := urlsLog.Step[cl.stepName]; ok { 69 urls = stepLogs.URLs 70 } 71 for _, url := range cl.buf.data { 72 urls = append(urls, string(url)) 73 } 74 urlsLog.Step[cl.stepName] = u{urls} 75 encoderBuf := bytes.NewBuffer(fileBuf) 76 jsonEncoder := json.NewEncoder(encoderBuf) 77 jsonEncoder.SetEscapeHTML(false) 78 jsonEncoder.SetIndent("", " ") 79 err = jsonEncoder.Encode(urlsLog) 80 if err != nil { 81 return fmt.Errorf("json encode error: %w", err) 82 } 83 _, err = file.WriteAt(encoderBuf.Bytes(), 0) 84 if err != nil { 85 return fmt.Errorf("failed to write log: %w", err) 86 } 87 return err 88 } 89 90 func (cl *URLLogger) Parse(buf bytes.Buffer) { 91 cl.buf.Lock() 92 defer cl.buf.Unlock() 93 classifier := returnURLStrictClassifier(cl.stepName) 94 cl.buf.data = append(cl.buf.data, parseURLs(buf.Bytes(), classifier)...) 95 } 96 97 func parseURLs(src []byte, classifier string) [][]byte { 98 if classifier == "Strict" { 99 return xurls.Strict().FindAll(src, -1) 100 } else { 101 return xurls.Relaxed().FindAll(src, -1) 102 } 103 } 104 105 func returnURLStrictClassifier(stepName string) string { 106 107 switch stepName { 108 // golang cli output urls without the http protocol hence making the search less strict 109 //ToDo: other cases where the url is without protocol 110 case "golangBuild": 111 return "Relaxed" 112 default: 113 return "Strict" 114 } 115 }