Skip to content

Commit 596f4e4

Browse files
Massimiliano PippiRoberto Sora
Massimiliano Pippi
authored and
Roberto Sora
committed
Add gRPC interface to CLI settings (#521)
* define proto messages and service * run protoc on settings interface, regenerate code * add service implementation and tests * remove test leftovers
1 parent d474176 commit 596f4e4

17 files changed

+1015
-307
lines changed

Diff for: Taskfile.yml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ tasks:
66
cmds:
77
- '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/commands/*.proto'
88
- '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/monitor/*.proto'
9+
- '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/settings/*.proto'
910

1011
build:
1112
desc: Build the project

Diff for: arduino/builder/sketch_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ func TestLoadSketchFolderSymlink(t *testing.T) {
115115
symlinkSketchPath := filepath.Join("testdata", t.Name())
116116
srcSketchPath := t.Name() + "Src"
117117
os.Symlink(srcSketchPath, symlinkSketchPath)
118+
defer os.Remove(symlinkSketchPath)
118119
mainFilePath := filepath.Join(symlinkSketchPath, t.Name()+".ino")
119120
s, err := builder.SketchLoad(symlinkSketchPath, "")
120121
require.Nil(t, err)

Diff for: cli/daemon/daemon.go

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/arduino/arduino-cli/commands/daemon"
3131
srv_commands "github.com/arduino/arduino-cli/rpc/commands"
3232
srv_monitor "github.com/arduino/arduino-cli/rpc/monitor"
33+
srv_settings "github.com/arduino/arduino-cli/rpc/settings"
3334
"github.com/sirupsen/logrus"
3435
"github.com/spf13/cobra"
3536
"github.com/spf13/viper"
@@ -73,6 +74,9 @@ func runDaemonCommand(cmd *cobra.Command, args []string) {
7374
// register the monitors service
7475
srv_monitor.RegisterMonitorServer(s, &daemon.MonitorService{})
7576

77+
// register the settings service
78+
srv_settings.RegisterSettingsServer(s, &daemon.SettingsService{})
79+
7680
if !daemonize {
7781
// When parent process ends terminate also the daemon
7882
go func() {

Diff for: commands/daemon/settings.go

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2019 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package daemon
17+
18+
import (
19+
"context"
20+
"encoding/json"
21+
"errors"
22+
"fmt"
23+
24+
rpc "github.com/arduino/arduino-cli/rpc/settings"
25+
"github.com/spf13/viper"
26+
)
27+
28+
// SettingsService implements the `Settings` service
29+
type SettingsService struct{}
30+
31+
// GetAll returns a message with a string field containing all the settings
32+
// currently in use, marshalled in JSON format.
33+
func (s *SettingsService) GetAll(ctx context.Context, req *rpc.GetAllRequest) (*rpc.RawData, error) {
34+
b, err := json.Marshal(viper.AllSettings())
35+
if err == nil {
36+
return &rpc.RawData{
37+
JsonData: string(b),
38+
}, nil
39+
}
40+
41+
return nil, err
42+
}
43+
44+
// Merge applies multiple settings values at once.
45+
func (s *SettingsService) Merge(ctx context.Context, req *rpc.RawData) (*rpc.MergeResponse, error) {
46+
var toMerge map[string]interface{}
47+
if err := json.Unmarshal([]byte(req.GetJsonData()), &toMerge); err != nil {
48+
return nil, err
49+
}
50+
51+
if err := viper.MergeConfigMap(toMerge); err != nil {
52+
return nil, err
53+
}
54+
55+
return &rpc.MergeResponse{}, nil
56+
}
57+
58+
// GetValue returns a settings value given its key. If the key is not present
59+
// an error will be returned, so that we distinguish empty settings from missing
60+
// ones.
61+
func (s *SettingsService) GetValue(ctx context.Context, req *rpc.GetValueRequest) (*rpc.Value, error) {
62+
key := req.GetKey()
63+
value := &rpc.Value{}
64+
65+
fmt.Println(viper.AllKeys())
66+
67+
if !viper.InConfig(key) {
68+
return nil, errors.New("key not found in settings")
69+
}
70+
71+
b, err := json.Marshal(viper.Get(key))
72+
if err == nil {
73+
value.Key = key
74+
value.JsonData = string(b)
75+
}
76+
77+
return value, err
78+
}
79+
80+
// SetValue updates or set a value for a certain key.
81+
func (s *SettingsService) SetValue(ctx context.Context, val *rpc.Value) (*rpc.SetValueResponse, error) {
82+
key := val.GetKey()
83+
var value interface{}
84+
85+
err := json.Unmarshal([]byte(val.GetJsonData()), &value)
86+
if err == nil {
87+
viper.Set(key, value)
88+
}
89+
90+
return &rpc.SetValueResponse{}, err
91+
}

Diff for: commands/daemon/settings_test.go

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2019 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package daemon
17+
18+
import (
19+
"context"
20+
"encoding/json"
21+
"fmt"
22+
"testing"
23+
24+
"github.com/spf13/viper"
25+
26+
"github.com/arduino/arduino-cli/configuration"
27+
rpc "github.com/arduino/arduino-cli/rpc/settings"
28+
"github.com/stretchr/testify/require"
29+
)
30+
31+
var svc = SettingsService{}
32+
33+
func init() {
34+
configuration.Init("testdata")
35+
}
36+
37+
func reset() {
38+
viper.Reset()
39+
configuration.Init("testdata")
40+
}
41+
42+
func TestGetAll(t *testing.T) {
43+
resp, err := svc.GetAll(context.Background(), &rpc.GetAllRequest{})
44+
require.Nil(t, err)
45+
46+
content, err := json.Marshal(viper.AllSettings())
47+
require.Nil(t, err)
48+
49+
require.Equal(t, string(content), resp.GetJsonData())
50+
}
51+
52+
func TestMerge(t *testing.T) {
53+
bulkSettings := `{"foo": "bar", "daemon":{"port":"420"}}`
54+
_, err := svc.Merge(context.Background(), &rpc.RawData{JsonData: bulkSettings})
55+
require.Nil(t, err)
56+
57+
fmt.Println(viper.AllSettings())
58+
require.Equal(t, "420", viper.GetString("daemon.port"))
59+
require.Equal(t, "bar", viper.GetString("foo"))
60+
61+
reset()
62+
}
63+
64+
func TestGetValue(t *testing.T) {
65+
key := &rpc.GetValueRequest{Key: "daemon"}
66+
resp, err := svc.GetValue(context.Background(), key)
67+
require.Nil(t, err)
68+
require.Equal(t, `{"port":"50051"}`, resp.GetJsonData())
69+
}
70+
71+
func TestGetValueNotFound(t *testing.T) {
72+
key := &rpc.GetValueRequest{Key: "DOESNTEXIST"}
73+
_, err := svc.GetValue(context.Background(), key)
74+
require.NotNil(t, err)
75+
require.Equal(t, `key not found in settings`, err.Error())
76+
}
77+
78+
func TestSetValue(t *testing.T) {
79+
val := &rpc.Value{
80+
Key: "foo",
81+
JsonData: `"bar"`,
82+
}
83+
_, err := svc.SetValue(context.Background(), val)
84+
require.Nil(t, err)
85+
require.Equal(t, "bar", viper.GetString("foo"))
86+
}

Diff for: commands/daemon/testdata/arduino-cli.yml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
board_manager:
2+
additional_urls:
3+
- http://foobar.com
4+
- http://example.com
5+
6+
daemon:
7+
port: "50051"
8+
9+
directories:
10+
data: /home/massi/.arduino15
11+
downloads: /home/massi/.arduino15/staging
12+
13+
logging:
14+
file: ""
15+
format: text
16+
level: info

Diff for: go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
124124
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
125125
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
126126
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
127+
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
127128
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
128129
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
129130
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=

Diff for: rpc/commands/board.pb.go

+42-42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)