github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/pkg/platform/runtime/buildscript/json.go (about) 1 package buildscript 2 3 import ( 4 "encoding/json" 5 "strings" 6 7 "github.com/go-openapi/strfmt" 8 9 "github.com/ActiveState/cli/internal/errs" 10 "github.com/ActiveState/cli/internal/logging" 11 "github.com/ActiveState/cli/internal/rtutils/ptr" 12 "github.com/ActiveState/cli/pkg/platform/runtime/buildexpression" 13 ) 14 15 // MarshalJSON marshals the Participle-produced Script into an equivalent buildexpression. 16 // Users of buildscripts do not need to do this manually; the Expr field contains the 17 // equivalent buildexpression. 18 func (s *Script) MarshalJSON() ([]byte, error) { 19 m := make(map[string]interface{}) 20 let := make(map[string]interface{}) 21 for _, assignment := range s.Assignments { 22 key := assignment.Key 23 value := assignment.Value 24 switch key { 25 case buildexpression.AtTimeKey: 26 if value.Str == nil { 27 return nil, errs.New("String timestamp expected for '%s'", key) 28 } 29 atTime, err := strfmt.ParseDateTime(strings.Trim(*value.Str, `"`)) 30 if err != nil { 31 return nil, errs.Wrap(err, "Invalid timestamp: %s", *value.Str) 32 } 33 s.AtTime = &atTime 34 continue // do not include this custom assignment in the let block 35 case "main": 36 key = "in" 37 } 38 let[key] = value 39 } 40 m["let"] = let 41 return json.Marshal(m) 42 } 43 44 func (a *Assignment) MarshalJSON() ([]byte, error) { 45 m := make(map[string]interface{}) 46 m[a.Key] = a.Value 47 return json.Marshal(m) 48 } 49 50 func (v *Value) MarshalJSON() ([]byte, error) { 51 switch { 52 case v.FuncCall != nil: 53 return json.Marshal(v.FuncCall) 54 case v.List != nil: 55 return json.Marshal(v.List) 56 case v.Str != nil: 57 return json.Marshal(strings.Trim(*v.Str, `"`)) 58 case v.Number != nil: 59 return json.Marshal(*v.Number) 60 case v.Null != nil: 61 return json.Marshal(nil) 62 case v.Assignment != nil: 63 return json.Marshal(v.Assignment) 64 case v.Object != nil: 65 m := make(map[string]interface{}) 66 for _, assignment := range *v.Object { 67 m[assignment.Key] = assignment.Value 68 } 69 return json.Marshal(m) 70 case v.Ident != nil: 71 return json.Marshal("$" + *v.Ident) 72 } 73 return json.Marshal([]*Value{}) // participle does not create v.List if it's empty 74 } 75 76 func (f *FuncCall) MarshalJSON() ([]byte, error) { 77 if f.Name == reqFuncName { 78 return marshalReq(f.Arguments) 79 } 80 81 m := make(map[string]interface{}) 82 args := make(map[string]interface{}) 83 for _, argument := range f.Arguments { 84 switch { 85 case argument.Assignment != nil: 86 args[argument.Assignment.Key] = argument.Assignment.Value 87 case argument.FuncCall != nil: 88 args[argument.FuncCall.Name] = argument.FuncCall.Arguments 89 default: 90 return nil, errs.New("Cannot marshal %v (arg %v)", f, argument) 91 } 92 } 93 94 m[f.Name] = args 95 return json.Marshal(m) 96 } 97 98 func marshalReq(args []*Value) ([]byte, error) { 99 requirement := make(map[string]interface{}) 100 101 for _, arg := range args { 102 assignment := arg.Assignment 103 if assignment == nil { 104 return nil, errs.New("Cannot marshal %v", arg) 105 } 106 107 switch { 108 // Marshal the name argument (e.g. name = "<name>") into {"name": "<name>"} 109 case assignment.Key == buildexpression.RequirementNameKey && assignment.Value.Str != nil: 110 requirement[buildexpression.RequirementNameKey] = strings.Trim(*assignment.Value.Str, `"`) 111 112 // Marshal the namespace argument (e.g. namespace = "<namespace>") into 113 // {"namespace": "<namespace>"} 114 case assignment.Key == buildexpression.RequirementNamespaceKey && assignment.Value.Str != nil: 115 requirement[buildexpression.RequirementNamespaceKey] = strings.Trim(*assignment.Value.Str, `"`) 116 117 // Marshal the version argument (e.g. version = <op>(value = "<version>")) into 118 // {"version_requirements": [{"comparator": "<op>", "version": "<version>"}]} 119 case assignment.Key == buildexpression.RequirementVersionKey && assignment.Value.FuncCall != nil: 120 var requirements []*Value 121 var addRequirement func(*FuncCall) error // recursive function for adding to requirements list 122 addRequirement = func(funcCall *FuncCall) error { 123 switch name := funcCall.Name; name { 124 case eqFuncName, neFuncName, gtFuncName, gteFuncName, ltFuncName, lteFuncName: 125 req := make([]*Assignment, 0) 126 req = append(req, &Assignment{buildexpression.RequirementComparatorKey, &Value{Str: ptr.To(strings.ToLower(name))}}) 127 if len(funcCall.Arguments) == 0 || funcCall.Arguments[0].Assignment == nil || 128 funcCall.Arguments[0].Assignment.Value.Str == nil || *funcCall.Arguments[0].Assignment.Value.Str == "value" { 129 return errs.New(`Illegal argument for version comparator '%s': 'value = "<version>"' expected`, name) 130 } 131 req = append(req, &Assignment{buildexpression.RequirementVersionKey, &Value{Str: funcCall.Arguments[0].Assignment.Value.Str}}) 132 requirements = append(requirements, &Value{Object: &req}) 133 case andFuncName: 134 if len(funcCall.Arguments) != 2 { 135 return errs.New("Illegal arguments for version comparator '%s': 2 arguments expected, got %d", name, len(funcCall.Arguments)) 136 } 137 for _, a := range funcCall.Arguments { 138 if a.Assignment == nil || (a.Assignment.Key != "left" && a.Assignment.Key != "right") || a.Assignment.Value.FuncCall == nil { 139 return errs.New("Illegal argument for version comparator '%s': 'left|right = function' expected", name) 140 } 141 err := addRequirement(a.Assignment.Value.FuncCall) 142 if err != nil { 143 return errs.Wrap(err, "Could not marshal additional requirement") 144 } 145 } 146 default: 147 return errs.New("Unknown version comparator: %s", name) 148 } 149 return nil 150 } 151 err := addRequirement(assignment.Value.FuncCall) 152 if err != nil { 153 return nil, errs.Wrap(err, "Could not marshal requirement") 154 } 155 requirement[buildexpression.RequirementVersionRequirementsKey] = &Value{List: &requirements} 156 157 default: 158 logging.Debug("Adding unknown argument: %v", assignment) 159 requirement[assignment.Key] = assignment.Value 160 } 161 } 162 163 return json.Marshal(requirement) 164 }