Skip to content

Commit

Permalink
DRAFT 2
Browse files Browse the repository at this point in the history
  • Loading branch information
cmaglie committed Apr 18, 2024
1 parent af4513f commit 2309152
Show file tree
Hide file tree
Showing 19 changed files with 302 additions and 201 deletions.
4 changes: 2 additions & 2 deletions commands/service_platform_search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestPlatformSearch(t *testing.T) {
conf, err := paths.TempDir().Join("test", "arduino-cli.yaml").ReadFile()
require.NoError(t, err)
_, err = srv.ConfigurationOpen(ctx, &rpc.ConfigurationOpenRequest{
Format: "yaml",
SettingsFormat: "yaml",
EncodedSettings: string(conf),
})
require.NoError(t, err)
Expand Down Expand Up @@ -350,7 +350,7 @@ func TestPlatformSearchSorting(t *testing.T) {
conf, err := paths.TempDir().Join("test", "arduino-cli.yaml").ReadFile()
require.NoError(t, err)
_, err = srv.ConfigurationOpen(ctx, &rpc.ConfigurationOpenRequest{
Format: "yaml",
SettingsFormat: "yaml",
EncodedSettings: string(conf),
})
require.NoError(t, err)
Expand Down
53 changes: 39 additions & 14 deletions commands/service_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,31 @@ func (s *arduinoCoreServerImpl) SettingsSetValue(ctx context.Context, req *rpc.S
key := req.GetKey()

// Extract the value from the request
jsonValue := []byte(req.GetValueJson())
if len(jsonValue) == 0 {
encodedValue := []byte(req.GetEncodedValue())
if len(encodedValue) == 0 {
// If the value is empty, unset the key
s.settings.Delete(key)
return &rpc.SettingsSetValueResponse{}, nil
}

var newValue any
if err := json.Unmarshal(jsonValue, &newValue); err != nil {
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("invalid value: %v", err)}
switch req.GetValueFormat() {
case "", "json":
if err := json.Unmarshal(encodedValue, &newValue); err != nil {
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("invalid value: %v", err)}
}
case "yaml":
if err := yaml.Unmarshal(encodedValue, &newValue); err != nil {
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("invalid value: %v", err)}
}
case "cli":
err := s.settings.SetFromCLIArgs(key, req.GetEncodedValue())
if err != nil {
return nil, err
}
return &rpc.SettingsSetValueResponse{}, nil
default:
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("unsupported value format: %s", req.ValueFormat)}
}

// If the value is "null", unset the key
Expand All @@ -130,18 +145,28 @@ func (s *arduinoCoreServerImpl) SettingsGetValue(ctx context.Context, req *rpc.S
if !ok {
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("key %s not found", key)}
}
valueJson, err := json.Marshal(value)
if err != nil {
return nil, fmt.Errorf("error marshalling value: %v", err)

switch req.ValueFormat {
case "json":
valueJson, err := json.Marshal(value)
if err != nil {
return nil, fmt.Errorf("error marshalling value: %v", err)
}
return &rpc.SettingsGetValueResponse{EncodedValue: string(valueJson)}, nil
case "yaml":
valueYaml, err := yaml.Marshal(value)
if err != nil {
return nil, fmt.Errorf("error marshalling value: %v", err)
}
return &rpc.SettingsGetValueResponse{EncodedValue: string(valueYaml)}, nil
default:
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("unsupported value format: %s", req.ValueFormat)}
}
return &rpc.SettingsGetValueResponse{
ValueJson: string(valueJson),
}, nil
}

// ConfigurationSave encodes the current configuration in the specified format
func (s *arduinoCoreServerImpl) ConfigurationSave(ctx context.Context, req *rpc.ConfigurationSaveRequest) (*rpc.ConfigurationSaveResponse, error) {
switch req.GetFormat() {
switch req.GetSettingsFormat() {
case "yaml":
data, err := yaml.Marshal(s.settings)
if err != nil {
Expand All @@ -155,13 +180,13 @@ func (s *arduinoCoreServerImpl) ConfigurationSave(ctx context.Context, req *rpc.
}
return &rpc.ConfigurationSaveResponse{EncodedSettings: string(data)}, nil
default:
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("unsupported format: %s", req.GetFormat())}
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("unsupported format: %s", req.GetSettingsFormat())}
}
}

// SettingsReadFromFile read settings from a YAML file and replace the settings currently stored in memory.
func (s *arduinoCoreServerImpl) ConfigurationOpen(ctx context.Context, req *rpc.ConfigurationOpenRequest) (*rpc.ConfigurationOpenResponse, error) {
switch req.GetFormat() {
switch req.GetSettingsFormat() {
case "yaml":
err := yaml.Unmarshal([]byte(req.GetEncodedSettings()), s.settings)
if err != nil {
Expand All @@ -175,7 +200,7 @@ func (s *arduinoCoreServerImpl) ConfigurationOpen(ctx context.Context, req *rpc.
}
return &rpc.ConfigurationOpenResponse{}, nil
default:
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("unsupported format: %s", req.GetFormat())}
return nil, &cmderrors.InvalidArgumentError{Message: fmt.Sprintf("unsupported format: %s", req.GetSettingsFormat())}
}
}

Expand Down
97 changes: 97 additions & 0 deletions go-configmap/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package configmap

import (
"fmt"
"strconv"
"strings"
)

func (c *Map) SetFromCLIArgs(key string, args ...string) error {
if len(args) == 0 {
c.Delete(key)
return nil
}

// in case of schemaless configuration, we don't know the type of the setting
// we will save it as a string or array of strings
if len(c.schema) == 0 {
switch len(args) {
case 1:
c.Set(key, args[0])
default:
c.Set(key, args)
}
return nil
}
fmt.Println(key, args)

// Find the correct type for the given setting
valueType, ok := c.schema[key]
if !ok {
return fmt.Errorf("key not found: %s", key)
}

var value any
isArray := false
{
var conversionError error
switch valueType.String() {
case "uint":
value, conversionError = strconv.Atoi(args[0])
case "bool":
value, conversionError = strconv.ParseBool(args[0])
case "string":
value = args[0]
case "[]string":
value = args
isArray = true
default:
return fmt.Errorf("unhandled type: %s", valueType)
}
if conversionError != nil {
return fmt.Errorf("error setting value: %v", conversionError)
}
}
if !isArray && len(args) != 1 {
return fmt.Errorf("error setting value: key is not an array, but multiple values were provided")
}

return c.Set(key, value)
}

func (c *Map) InjectEnvVars(env []string, prefix string) []error {
if prefix != "" {
prefix = strings.ToUpper(prefix) + "_"
}

errs := []error{}

envKeyToConfigKey := map[string]string{}
for _, k := range c.AllKeys() {
normalizedKey := prefix + strings.ToUpper(k)
normalizedKey = strings.Replace(normalizedKey, ".", "_", -1)
envKeyToConfigKey[normalizedKey] = k
}

for _, e := range env {
// Extract key and value from env
parts := strings.SplitN(e, "=", 2)
if len(parts) != 2 {
continue
}
envKey := strings.ToUpper(parts[0])
envValue := parts[1]

// Check if the configuration has a matching key
key, ok := envKeyToConfigKey[envKey]
if !ok {
continue
}

// Update the configuration value
if err := c.SetFromCLIArgs(key, envValue); err != nil {
errs = append(errs, err)
}
}
return errs
}
42 changes: 0 additions & 42 deletions go-configmap/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,48 +142,6 @@ func (c Map) delete(keys []string) {
}
}

func (c Map) InjectEnvVars(env []string, prefix string) {
if prefix != "" {
prefix = strings.ToUpper(prefix) + "_"
}

// Try submaps first
for k, v := range c.values {
if subConf, ok := v.(*Map); ok {
subConf.InjectEnvVars(env, prefix+k)
}
}

for _, e := range env {
parts := strings.SplitN(e, "=", 2)
if len(parts) != 2 {
continue
}
key := strings.ToUpper(parts[0])
value := parts[1]
if !strings.HasPrefix(key, prefix) {
continue
}
key = strings.TrimPrefix(key, prefix)

// check if the configuration has a matching key
matchingKey := ""
for k := range c.values {
if k == key {
matchingKey = k
break
}
if strings.EqualFold(k, key) {
matchingKey = k
}
}
if matchingKey == "" {
continue
}
c.Set(matchingKey, value)
}
}

func (c *Map) Merge(x *Map) error {
for xk, xv := range x.values {
if xSubConf, ok := xv.(*Map); ok {
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
set := func(key string, value any) {
if valueJson, err := json.Marshal(value); err != nil {
feedback.Fatal(tr("Error setting value %s: %v", key, err), feedback.ErrGeneric)
} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, ValueJson: string(valueJson)}); err != nil {
} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, EncodedValue: string(valueJson)}); err != nil {
feedback.Fatal(tr("Error setting value %s: %v", key, err), feedback.ErrGeneric)
}
}
Expand Down
4 changes: 2 additions & 2 deletions internal/cli/config/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func runAddCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args [
var currentValues []string
if resp, err := srv.SettingsGetValue(ctx, &rpc.SettingsGetValueRequest{Key: key}); err != nil {
feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
} else if err := json.Unmarshal([]byte(resp.GetValueJson()), &currentValues); err != nil {
} else if err := json.Unmarshal([]byte(resp.GetEncodedValue()), &currentValues); err != nil {
feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
}

Expand All @@ -72,7 +72,7 @@ func runAddCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, args [

if newValuesJSON, err := json.Marshal(currentValues); err != nil {
feedback.Fatal(tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, ValueJson: string(newValuesJSON)}); err != nil {
} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, EncodedValue: string(newValuesJSON)}); err != nil {
feedback.Fatal(tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func getAllArraySettingsKeys(ctx context.Context, srv rpc.ArduinoCoreServiceServ

func saveConfiguration(ctx context.Context, srv rpc.ArduinoCoreServiceServer) {
var outConfig []byte
if res, err := srv.ConfigurationSave(ctx, &rpc.ConfigurationSaveRequest{Format: "yaml"}); err != nil {
if res, err := srv.ConfigurationSave(ctx, &rpc.ConfigurationSaveRequest{SettingsFormat: "yaml"}); err != nil {
feedback.Fatal(tr("Error writing to file: %v", err), feedback.ErrGeneric)
} else {
outConfig = []byte(res.GetEncodedSettings())
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/config/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func runDeleteCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
logrus.Info("Executing `arduino-cli config delete`")

key := args[0]
if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, ValueJson: ""}); err != nil {
if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, EncodedValue: ""}); err != nil {
feedback.Fatal(tr("Cannot delete the key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
}

Expand Down
4 changes: 2 additions & 2 deletions internal/cli/config/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ func initDumpCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
res := &rawResult{}
switch feedback.GetFormat() {
case feedback.JSON, feedback.MinifiedJSON:
resp, err := srv.ConfigurationSave(cmd.Context(), &rpc.ConfigurationSaveRequest{Format: "json"})
resp, err := srv.ConfigurationSave(cmd.Context(), &rpc.ConfigurationSaveRequest{SettingsFormat: "json"})
if err != nil {
logrus.Fatalf("Error creating configuration: %v", err)
}
res.rawJSON = []byte(resp.GetEncodedSettings())
case feedback.YAML, feedback.Text:
resp, err := srv.ConfigurationSave(cmd.Context(), &rpc.ConfigurationSaveRequest{Format: "yaml"})
resp, err := srv.ConfigurationSave(cmd.Context(), &rpc.ConfigurationSaveRequest{SettingsFormat: "yaml"})
if err != nil {
logrus.Fatalf("Error creating configuration: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/config/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func runGetCommand(srv rpc.ArduinoCoreServiceServer, args []string) {
feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", toGet, err), feedback.ErrGeneric)
}
var result getResult
if err := json.Unmarshal([]byte(resp.GetValueJson()), &result.resp); err != nil {
if err := json.Unmarshal([]byte(resp.GetEncodedValue()), &result.resp); err != nil {
// Should never happen...
panic(fmt.Sprintf("Cannot parse JSON for key %[1]s: %[2]v", toGet, err))
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/config/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func runInitCommand(srv rpc.ArduinoCoreServiceServer) {
// }
// }

resp, err := srv.ConfigurationSave(ctx, &rpc.ConfigurationSaveRequest{Format: "yaml"})
resp, err := srv.ConfigurationSave(ctx, &rpc.ConfigurationSaveRequest{SettingsFormat: "yaml"})
if err != nil {
feedback.Fatal(tr("Error creating configuration: %v", err), feedback.ErrGeneric)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/cli/config/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func runRemoveCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg
var currentValues []string
if resp, err := srv.SettingsGetValue(ctx, &rpc.SettingsGetValueRequest{Key: key}); err != nil {
feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
} else if err := json.Unmarshal([]byte(resp.GetValueJson()), &currentValues); err != nil {
} else if err := json.Unmarshal([]byte(resp.GetEncodedValue()), &currentValues); err != nil {
feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
}

Expand All @@ -70,7 +70,7 @@ func runRemoveCommand(ctx context.Context, srv rpc.ArduinoCoreServiceServer, arg

if newValuesJSON, err := json.Marshal(currentValues); err != nil {
feedback.Fatal(tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, ValueJson: string(newValuesJSON)}); err != nil {
} else if _, err := srv.SettingsSetValue(ctx, &rpc.SettingsSetValueRequest{Key: key, EncodedValue: string(newValuesJSON)}); err != nil {
feedback.Fatal(tr("Cannot remove the configuration key %[1]s: %[2]v", key, err), feedback.ErrGeneric)
}

Expand Down
Loading

0 comments on commit 2309152

Please sign in to comment.