github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/tiltfile/encoding/json.go (about)

     1  package encoding
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  
    10  	"github.com/pkg/errors"
    11  	"go.starlark.net/starlark"
    12  
    13  	tiltfile_io "github.com/tilt-dev/tilt/internal/tiltfile/io"
    14  	"github.com/tilt-dev/tilt/internal/tiltfile/starkit"
    15  	"github.com/tilt-dev/tilt/internal/tiltfile/value"
    16  )
    17  
    18  // reads json from a file
    19  func readJSON(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
    20  	path := value.NewLocalPathUnpacker(thread)
    21  	var defaultValue starlark.Value
    22  	if err := starkit.UnpackArgs(thread, fn.Name(), args, kwargs, "paths", &path, "default?", &defaultValue); err != nil {
    23  		return nil, err
    24  	}
    25  
    26  	localPath := path.Value
    27  	contents, err := tiltfile_io.ReadFile(thread, localPath)
    28  	if err != nil {
    29  		// Return the default value if the file doesn't exist AND a default value was given
    30  		if os.IsNotExist(err) && defaultValue != nil {
    31  			return defaultValue, nil
    32  		}
    33  		return nil, err
    34  	}
    35  
    36  	return jsonStringToStarlark(string(contents), localPath)
    37  }
    38  
    39  // reads json from a string
    40  func decodeJSON(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
    41  	var contents value.Stringable
    42  	if err := starkit.UnpackArgs(thread, fn.Name(), args, kwargs, "json", &contents); err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	return jsonStringToStarlark(contents.Value, "")
    47  }
    48  
    49  func jsonStringToStarlark(s string, source string) (starlark.Value, error) {
    50  	var decodedJSON interface{}
    51  	dec := json.NewDecoder(strings.NewReader(s))
    52  	dec.UseNumber()
    53  	if err := dec.Decode(&decodedJSON); err != nil {
    54  		return nil, wrapError(err, "error parsing JSON", source)
    55  	}
    56  	if dec.More() {
    57  		return nil, wrapError(fmt.Errorf("found multiple JSON values"), "error parsing JSON", source)
    58  	}
    59  
    60  	v, err := ConvertStructuredDataToStarlark(decodedJSON)
    61  	if err != nil {
    62  		return nil, wrapError(err, "error converting JSON to Starlark", source)
    63  	}
    64  	return v, nil
    65  }
    66  
    67  func encodeJSON(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
    68  	var obj starlark.Value
    69  	if err := starkit.UnpackArgs(thread, fn.Name(), args, kwargs, "obj", &obj); err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	ret, err := starlarkToJSONString(obj)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	return starlark.String(ret), nil
    79  }
    80  
    81  func starlarkToJSONString(obj starlark.Value) (string, error) {
    82  	v, err := convertStarlarkToStructuredData(obj)
    83  	if err != nil {
    84  		return "", errors.Wrap(err, "error converting object from starlark")
    85  	}
    86  
    87  	w := bytes.Buffer{}
    88  	e := json.NewEncoder(&w)
    89  	e.SetIndent("", "  ")
    90  	err = e.Encode(v)
    91  	if err != nil {
    92  		return "", errors.Wrap(err, "error serializing object to json")
    93  	}
    94  
    95  	return w.String(), nil
    96  }