get.porter.sh/porter@v1.3.0/pkg/exec/builder/output_jsonpath.go (about) 1 package builder 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 9 "get.porter.sh/porter/pkg/runtime" 10 "get.porter.sh/porter/pkg/tracing" 11 "github.com/PaesslerAG/jsonpath" 12 ) 13 14 type OutputJsonPath interface { 15 Output 16 GetJsonPath() string 17 } 18 19 // ProcessJsonPathOutputs evaluates the specified output buffer as JSON, looks through the outputs for 20 // any that implement the OutputJsonPath and extracts their output. 21 func ProcessJsonPathOutputs(ctx context.Context, cfg runtime.RuntimeConfig, step StepWithOutputs, stdout string) error { 22 _, span := tracing.StartSpan(ctx) 23 defer span.EndSpan() 24 25 outputs := step.GetOutputs() 26 27 if len(outputs) == 0 { 28 return nil 29 } 30 31 var outputJson interface{} 32 33 for _, o := range outputs { 34 output, ok := o.(OutputJsonPath) 35 if !ok { 36 continue 37 } 38 39 outputName := output.GetName() 40 outputPath := output.GetJsonPath() 41 if outputPath == "" { 42 continue 43 } 44 45 if cfg.DebugMode { 46 fmt.Fprintf(cfg.Err, "Processing jsonpath output %s using query %s against document\n%s\n", outputName, outputPath, stdout) 47 } 48 49 var valueB []byte 50 51 if outputJson == nil { 52 if stdout != "" { 53 d := json.NewDecoder(bytes.NewBuffer([]byte(stdout))) 54 d.UseNumber() 55 err := d.Decode(&outputJson) 56 if err != nil { 57 return span.Error(fmt.Errorf("error unmarshaling stdout as json %s: %w", stdout, err)) 58 } 59 } 60 } 61 62 // Always write an output, even when there isn't json output to parse (like when stdout is empty) 63 if outputJson != nil { 64 value, err := jsonpath.Get(outputPath, outputJson) 65 if err != nil { 66 return span.Error(fmt.Errorf("error evaluating jsonpath %q for output %q against %s: %w", outputPath, outputName, stdout, err)) 67 } 68 69 // Only marshal complex types to json, leave strings, numbers and booleans alone 70 switch t := value.(type) { 71 case map[string]interface{}, []interface{}: 72 valueB, err = json.Marshal(value) 73 if err != nil { 74 return span.Error(fmt.Errorf("error marshaling jsonpath result %v for output %q: %w", valueB, outputName, err)) 75 } 76 default: 77 valueB = []byte(fmt.Sprintf("%v", t)) 78 } 79 } 80 81 err := cfg.WriteMixinOutputToFile(outputName, valueB) 82 if err != nil { 83 return span.Error(fmt.Errorf("error writing mixin output for %q: %w", outputName, err)) 84 } 85 } 86 87 return nil 88 }