Skip to content

Commit

Permalink
Parse param values
Browse files Browse the repository at this point in the history
  • Loading branch information
akclace committed Oct 12, 2024
1 parent d7638ac commit 357fd73
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 80 deletions.
46 changes: 24 additions & 22 deletions internal/app/action/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,21 @@ var embedHtml embed.FS
// provide a way to trigger app operations, with an auto-generated form UI
// and an API interface
type Action struct {
name string
description string
path string
run starlark.Callable
suggest starlark.Callable
params []apptype.AppParam
paramValues map[string]string
template *template.Template
pagePath string
name string
description string
path string
run starlark.Callable
suggest starlark.Callable
params []apptype.AppParam
paramValuesStr map[string]string
paramDict starlark.StringDict
template *template.Template
pagePath string
}

// NewAction creates a new action
func NewAction(name, description, apath string, run, suggest starlark.Callable,
params []apptype.AppParam, paramValues map[string]string, appPath string) (*Action, error) {
params []apptype.AppParam, paramValuesStr map[string]string, paramDict starlark.StringDict, appPath string) (*Action, error) {
tmpl, err := template.New("form").ParseFS(embedHtml, "*.go.html")
if err != nil {
return nil, err
Expand All @@ -52,15 +53,16 @@ func NewAction(name, description, apath string, run, suggest starlark.Callable,
})

return &Action{
name: name,
description: description,
path: apath,
run: run,
suggest: suggest,
params: params,
paramValues: paramValues,
template: tmpl,
pagePath: path.Join(appPath, apath),
name: name,
description: description,
path: apath,
run: run,
suggest: suggest,
params: params,
paramValuesStr: paramValuesStr,
paramDict: paramDict,
template: tmpl,
pagePath: path.Join(appPath, apath),
}, nil
}

Expand Down Expand Up @@ -105,9 +107,9 @@ func (a *Action) getForm(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(p.Name, OPTIONS_PREFIX) {
name := p.Name[len(OPTIONS_PREFIX):]
var vals []string
err := json.Unmarshal([]byte(a.paramValues[p.Name]), &vals)
err := json.Unmarshal([]byte(a.paramValuesStr[p.Name]), &vals)
if err != nil {
http.Error(w, fmt.Sprintf("invalid value for %s: %s", p.Name, a.paramValues[p.Name]), http.StatusBadRequest)
http.Error(w, fmt.Sprintf("invalid value for %s: %s", p.Name, a.paramValuesStr[p.Name]), http.StatusBadRequest)
return
}
options[name] = vals
Expand All @@ -124,7 +126,7 @@ func (a *Action) getForm(w http.ResponseWriter, r *http.Request) {
Description: p.Description,
}

value, ok := a.paramValues[p.Name]
value, ok := a.paramValuesStr[p.Name]
if !ok {
http.Error(w, fmt.Sprintf("missing param value for %s", p.Name), http.StatusInternalServerError)
return
Expand Down
5 changes: 3 additions & 2 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ type App struct {
systemConfig *types.SystemConfig
storeInfo *starlark_type.StoreInfo
paramInfo map[string]apptype.AppParam
paramMap map[string]string // the param values for the app, from metadata and defaults
paramValuesStr map[string]string // the param values for the app, from metadata and defaults
paramDict starlark.StringDict // the Starlark param values for the app
plugins *AppPlugins
containerManager *ContainerManager

Expand Down Expand Up @@ -463,7 +464,7 @@ func (a *App) loadContainerManager(stripAppPath bool) error {

a.containerManager, err = NewContainerManager(a.Logger, a,
fileName, a.systemConfig, port, lifetime, scheme, health, buildDir,
a.sourceFS, a.paramMap, a.appConfig.Container, stripAppPath, a.Metadata.ContainerVolumes)
a.sourceFS, a.paramValuesStr, a.appConfig.Container, stripAppPath, a.Metadata.ContainerVolumes)
if err != nil {
return fmt.Errorf("error creating container manager: %w", err)
}
Expand Down
45 changes: 45 additions & 0 deletions internal/app/apptype/param_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
package apptype

import (
"encoding/json"
"fmt"
"regexp"
"strconv"

"github.com/claceio/clace/internal/app/starlark_type"
"go.starlark.net/starlark"
Expand Down Expand Up @@ -169,3 +171,46 @@ func LoadParamInfo(fileName string, data []byte) (map[string]AppParam, error) {

return definedParams, nil
}

func ParamStringToType(name string, typeName starlark_type.TypeName, valueStr string) (starlark.Value, error) {
switch typeName {
case starlark_type.STRING:
return starlark.String(valueStr), nil
case starlark_type.INT:
intValue, err := strconv.Atoi(valueStr)
if err != nil {
return nil, fmt.Errorf("param %s is not an int", name)
}

return starlark.MakeInt(intValue), nil
case starlark_type.BOOLEAN:
boolValue, err := strconv.ParseBool(valueStr)
if err != nil {
return nil, fmt.Errorf("param %s is not a boolean", name)
}
return starlark.Bool(boolValue), nil
case starlark_type.DICT:
var dictValue map[string]any
if err := json.Unmarshal([]byte(valueStr), &dictValue); err != nil {
return nil, fmt.Errorf("param %s is not a json dict", name)
}

dictVal, err := starlark_type.MarshalStarlark(dictValue)
if err != nil {
return nil, fmt.Errorf("param %s is not a starlark dict", name)
}
return dictVal, nil
case starlark_type.LIST:
var listValue []any
if err := json.Unmarshal([]byte(valueStr), &listValue); err != nil {
return nil, fmt.Errorf("param %s is not a json list", name)
}
listVal, err := starlark_type.MarshalStarlark(listValue)
if err != nil {
return nil, fmt.Errorf("param %s is not a starlark list", name)
}
return listVal, nil
default:
return nil, fmt.Errorf("unknown type %s for param %s", typeName, name)
}
}
76 changes: 20 additions & 56 deletions internal/app/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,7 @@ func (a *App) addSchemaTypes(builtin starlark.StringDict) (starlark.StringDict,
}

func (a *App) addParams(builtin starlark.StringDict) (starlark.StringDict, error) {
if a.paramInfo == nil || len(a.paramInfo) == 0 {
return builtin, nil
}
a.paramMap = make(map[string]string)
a.paramValuesStr = make(map[string]string)

// Create a copy of the builtins, don't modify the original
newBuiltins := starlark.StringDict{}
Expand All @@ -221,23 +218,23 @@ func (a *App) addParams(builtin starlark.StringDict) (starlark.StringDict, error
}

// Add param module for referencing param values
paramDict := starlark.StringDict{}
a.paramDict = starlark.StringDict{}
for _, p := range a.paramInfo {
paramDict[p.Name] = p.DefaultValue
a.paramDict[p.Name] = p.DefaultValue

if p.DefaultValue != starlark.None {
switch p.Type {
// Set the default value in the paramMap (in the string format)
case starlark_type.STRING:
a.paramMap[p.Name] = string(p.DefaultValue.(starlark.String))
a.paramValuesStr[p.Name] = string(p.DefaultValue.(starlark.String))
case starlark_type.INT:
intVal, ok := p.DefaultValue.(starlark.Int).Int64()
if !ok {
return nil, fmt.Errorf("param %s is not an int", p.Name)
}
a.paramMap[p.Name] = fmt.Sprintf("%d", intVal)
a.paramValuesStr[p.Name] = fmt.Sprintf("%d", intVal)
case starlark_type.BOOLEAN:
a.paramMap[p.Name] = strconv.FormatBool(bool(p.DefaultValue.(starlark.Bool)))
a.paramValuesStr[p.Name] = strconv.FormatBool(bool(p.DefaultValue.(starlark.Bool)))
case starlark_type.DICT:
case starlark_type.LIST:
val, err := starlark_type.UnmarshalStarlark(p.DefaultValue)
Expand All @@ -248,7 +245,7 @@ func (a *App) addParams(builtin starlark.StringDict) (starlark.StringDict, error
if err != nil {
return nil, err
}
a.paramMap[p.Name] = string(jsonVal)
a.paramValuesStr[p.Name] = string(jsonVal)
}
}

Expand All @@ -260,63 +257,29 @@ func (a *App) addParams(builtin starlark.StringDict) (starlark.StringDict, error
}
continue
}
a.paramMap[p.Name] = valueStr // Update the paramMap with the custom value

switch p.Type {
case starlark_type.STRING:
paramDict[p.Name] = starlark.String(valueStr)
if p.Required && valueStr == "" {
return nil, fmt.Errorf("param %s is a required param, value cannot be empty", p.Name)
}
case starlark_type.INT:
intValue, err := strconv.Atoi(valueStr)
if err != nil {
return nil, fmt.Errorf("param %s is not an int", p.Name)
}

paramDict[p.Name] = starlark.MakeInt(intValue)
case starlark_type.BOOLEAN:
boolValue, err := strconv.ParseBool(valueStr)
if err != nil {
return nil, fmt.Errorf("param %s is not a boolean", p.Name)
}
paramDict[p.Name] = starlark.Bool(boolValue)
case starlark_type.DICT:
var dictValue map[string]any
if err := json.Unmarshal([]byte(valueStr), &dictValue); err != nil {
return nil, fmt.Errorf("param %s is not a json dict", p.Name)
}
a.paramValuesStr[p.Name] = valueStr
value, err := apptype.ParamStringToType(p.Name, p.Type, valueStr)
if err != nil {
return nil, fmt.Errorf("error parsing param %s: %w", p.Name, err)
}
a.paramDict[p.Name] = value

dictVal, err := starlark_type.MarshalStarlark(dictValue)
if err != nil {
return nil, fmt.Errorf("param %s is not a starlark dict", p.Name)
}
paramDict[p.Name] = dictVal
case starlark_type.LIST:
var listValue []any
if err := json.Unmarshal([]byte(valueStr), &listValue); err != nil {
return nil, fmt.Errorf("param %s is not a json list", p.Name)
}
listVal, err := starlark_type.MarshalStarlark(listValue)
if err != nil {
return nil, fmt.Errorf("param %s is not a starlark list", p.Name)
}
paramDict[p.Name] = listVal
default:
return nil, fmt.Errorf("unknown type %s for param %s", p.Type, p.Name)
if p.Type == starlark_type.STRING && p.Required && valueStr == "" {
return nil, fmt.Errorf("param %s is a required param, value cannot be empty", p.Name)
}
}

paramModule := starlarkstruct.Module{
Name: apptype.PARAM_MODULE,
Members: paramDict,
Members: a.paramDict,
}

newBuiltins[apptype.PARAM_MODULE] = &paramModule

for k, v := range a.Metadata.ParamValues {
if _, ok := paramDict[k]; !ok {
a.paramMap[k] = v // add additional param values to paramMap
if _, ok := a.paramDict[k]; !ok {
a.paramValuesStr[k] = v // add additional param values to paramMap
}
}
return newBuiltins, nil
Expand Down Expand Up @@ -523,7 +486,8 @@ func (a *App) addAction(count int, val starlark.Value) error {
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
action, err := action.NewAction(name, description, path, run, suggest, slices.Collect(maps.Values(a.paramInfo)), a.paramMap, a.Path)
action, err := action.NewAction(name, description, path, run, suggest,
slices.Collect(maps.Values(a.paramInfo)), a.paramValuesStr, a.paramDict, a.Path)
if err != nil {
return fmt.Errorf("error creating action %s: %w", name, err)
}
Expand Down

0 comments on commit 357fd73

Please sign in to comment.