github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/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  }