github.com/kubeshop/testkube@v1.17.23/cmd/tcl/testworkflow-init/data/emit.go (about) 1 // Copyright 2024 Testkube. 2 // 3 // Licensed as a Testkube Pro file under the Testkube Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt 8 9 package data 10 11 import ( 12 "encoding/json" 13 "fmt" 14 "regexp" 15 "strings" 16 ) 17 18 const ( 19 InstructionPrefix = "\u0001\u0005" 20 HintPrefix = "\u0006" 21 InstructionSeparator = "\u0003" 22 InstructionValueSeparator = "\u0004" 23 ) 24 25 var instructionRe = regexp.MustCompile(fmt.Sprintf(`^%s(%s)?([^%s]+)%s([a-zA-Z0-9-_.]+)(?:%s([^\n]+))?%s$`, 26 InstructionPrefix, HintPrefix, InstructionSeparator, InstructionSeparator, InstructionValueSeparator, InstructionSeparator)) 27 28 type Instruction struct { 29 Ref string 30 Name string 31 Value interface{} 32 } 33 34 func SprintOutput(ref string, name string, value interface{}) string { 35 j, err := json.Marshal(value) 36 if err != nil { 37 panic(fmt.Sprintf("error while marshalling reference: %v", err)) 38 } 39 var sb strings.Builder 40 sb.WriteString("\n") 41 sb.WriteString(InstructionPrefix) 42 sb.WriteString(ref) 43 sb.WriteString(InstructionSeparator) 44 sb.WriteString(name) 45 sb.WriteString(InstructionValueSeparator) 46 sb.Write(j) 47 sb.WriteString(InstructionSeparator) 48 sb.WriteString("\n") 49 return sb.String() 50 } 51 52 func SprintHint(ref string, name string) string { 53 var sb strings.Builder 54 sb.WriteString("\n") 55 sb.WriteString(InstructionPrefix) 56 sb.WriteString(HintPrefix) 57 sb.WriteString(ref) 58 sb.WriteString(InstructionSeparator) 59 sb.WriteString(name) 60 sb.WriteString(InstructionSeparator) 61 sb.WriteString("\n") 62 return sb.String() 63 } 64 65 func SprintHintDetails(ref string, name string, value interface{}) string { 66 j, err := json.Marshal(value) 67 if err != nil { 68 panic(fmt.Sprintf("error while marshalling reference: %v", err)) 69 } 70 var sb strings.Builder 71 sb.WriteString("\n") 72 sb.WriteString(InstructionPrefix) 73 sb.WriteString(HintPrefix) 74 sb.WriteString(ref) 75 sb.WriteString(InstructionSeparator) 76 sb.WriteString(name) 77 sb.WriteString(InstructionValueSeparator) 78 sb.Write(j) 79 sb.WriteString(InstructionSeparator) 80 sb.WriteString("\n") 81 return sb.String() 82 } 83 84 func PrintOutput(ref string, name string, value interface{}) { 85 fmt.Print(SprintOutput(ref, name, value)) 86 } 87 88 func PrintHint(ref string, name string) { 89 fmt.Print(SprintHint(ref, name)) 90 } 91 92 func PrintHintDetails(ref string, name string, value interface{}) { 93 fmt.Print(SprintHintDetails(ref, name, value)) 94 } 95 96 func DetectInstruction(line []byte) (*Instruction, bool, error) { 97 // Fast check to avoid regexes 98 if len(line) < 4 || string(line[0:len(InstructionPrefix)]) != InstructionPrefix || string(line[:len(InstructionPrefix)]) != InstructionPrefix { 99 return nil, false, nil 100 } 101 // Parse the line 102 v := instructionRe.FindSubmatch(line) 103 if v == nil { 104 return nil, false, nil 105 } 106 isHint := string(v[1]) == HintPrefix 107 instruction := &Instruction{ 108 Ref: string(v[2]), 109 Name: string(v[3]), 110 } 111 if len(v) > 4 && v[4] != nil { 112 err := json.Unmarshal(v[4], &instruction.Value) 113 if err != nil { 114 return instruction, isHint, err 115 } 116 } 117 return instruction, isHint, nil 118 }