From 3e861b7f41686535524ec6ad8a5b12db227554e5 Mon Sep 17 00:00:00 2001 From: rsora Date: Fri, 14 Feb 2020 09:45:07 +0100 Subject: [PATCH 01/29] Implement first draft of debugger gRPC service --- Taskfile.yml | 1 + cli/daemon/daemon.go | 4 + client_example/go.mod | 7 +- client_example/go.sum | 36 +- client_example/main.go | 1475 ++++++++++++++++++----------------- commands/daemon/debug.go | 141 ++++ commands/debug/debug.go | 181 +++++ go.sum | 1 + rpc/commands/commands.pb.go | 90 +-- rpc/debug/debug.pb.go | 364 +++++++++ rpc/debug/debug.proto | 65 ++ rpc/monitor/monitor.pb.go | 18 +- rpc/settings/settings.pb.go | 27 +- 13 files changed, 1564 insertions(+), 846 deletions(-) create mode 100644 commands/daemon/debug.go create mode 100644 commands/debug/debug.go create mode 100644 rpc/debug/debug.pb.go create mode 100644 rpc/debug/debug.proto diff --git a/Taskfile.yml b/Taskfile.yml index 780f80f0b9b..5dc842fb9b9 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,6 +7,7 @@ tasks: - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/commands/*.proto' - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/monitor/*.proto' - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/settings/*.proto' + - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/debug/*.proto' build: desc: Build the project diff --git a/cli/daemon/daemon.go b/cli/daemon/daemon.go index e3ea2811d9a..dae9453707e 100644 --- a/cli/daemon/daemon.go +++ b/cli/daemon/daemon.go @@ -31,6 +31,7 @@ import ( "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/commands/daemon" srv_commands "github.com/arduino/arduino-cli/rpc/commands" + srv_debug "github.com/arduino/arduino-cli/rpc/debug" srv_monitor "github.com/arduino/arduino-cli/rpc/monitor" srv_settings "github.com/arduino/arduino-cli/rpc/settings" "github.com/sirupsen/logrus" @@ -79,6 +80,9 @@ func runDaemonCommand(cmd *cobra.Command, args []string) { // register the settings service srv_settings.RegisterSettingsServer(s, &daemon.SettingsService{}) + // register the debug session service + srv_debug.RegisterDebugServer(s, &daemon.DebugService{}) + if !daemonize { // When parent process ends terminate also the daemon go func() { diff --git a/client_example/go.mod b/client_example/go.mod index 91cc576487c..7bce3c37a40 100644 --- a/client_example/go.mod +++ b/client_example/go.mod @@ -2,8 +2,9 @@ module github.com/arduino/arduino-cli/client_example go 1.13 +replace github.com/arduino/arduino-cli => ../ + require ( github.com/arduino/arduino-cli v0.0.0-20200109150215-ffa84fdaab21 - github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282 // indirect - google.golang.org/grpc v1.23.0 -) \ No newline at end of file + google.golang.org/grpc v1.27.0 +) diff --git a/client_example/go.sum b/client_example/go.sum index 8e07356509d..b101220d43c 100644 --- a/client_example/go.sum +++ b/client_example/go.sum @@ -1,18 +1,13 @@ bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/arduino/arduino-cli v0.0.0-20190826141027-35722fda467d h1:1Rwlmz0+4ofl3wKC29IlgAwb/66f2afOTUWsGgh5NLk= -github.com/arduino/arduino-cli v0.0.0-20190826141027-35722fda467d/go.mod h1:XFDg7LwMgVGiJAkVLQ0AM3Gei5LjfuDIKwOcrU9rnsI= -github.com/arduino/arduino-cli v0.0.0-20200109150215-ffa84fdaab21 h1:KEQLrEwD+3UG3wS5vPFcudrMFzvjJHq5xOoIgvjFPaQ= -github.com/arduino/arduino-cli v0.0.0-20200109150215-ffa84fdaab21/go.mod h1:Jtn7ZeNH70MG8bW0MZRVeGGxmAf1FQ3BgnFgLZmBOTc= github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c/go.mod h1:HK7SpkEax/3P+0w78iRQx1sz1vCDYYw9RXwHjQTB5i8= -github.com/arduino/go-paths-helper v0.0.0-20190214132331-c3c98d1bf2e1/go.mod h1:OGL+FS3aTrS01YsBAJJhkGuxtEGsFRSgZYo8b3vefdc= github.com/arduino/go-paths-helper v1.0.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck= -github.com/arduino/go-properties-orderedmap v0.0.0-20181003091528-89278049acd3/go.mod h1:kiSuHm7yz3chiy8rb2MphC7ECn3MlkQFAIe4SXmQg6o= github.com/arduino/go-properties-orderedmap v0.0.0-20190828172252-05018b28ff6c/go.mod h1:kiSuHm7yz3chiy8rb2MphC7ECn3MlkQFAIe4SXmQg6o= github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b/go.mod h1:uwGy5PpN4lqW97FiLnbcx+xx8jly5YuPMJWfVwwjJiQ= github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b/go.mod h1:iIPnclBMYm1g32Q5kXoqng4jLhMStReIP7ZxaoUC2y8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cmaglie/pb v1.0.27 h1:ynGj8vBXR+dtj4B7Q/W/qGt31771Ux5iFfRQBnwdQiA= github.com/cmaglie/pb v1.0.27/go.mod h1:GilkKZMXYjBA4NxItWFfO+lwkp59PLHQ+IOW/b/kmZI= @@ -22,23 +17,27 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/creack/goselect v0.0.0-20180328191401-176c667f75aa/go.mod h1:gHrIcH/9UZDn2qgeTUeW5K9eZsVYCH6/60J/FHysWyE= github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fluxio/iohelpers v0.0.0-20160419043813-3a4dd67a94d2/go.mod h1:c7sGIpDbBo0JZZ1tKyC1p5smWf8QcUjK4bFtZjHAecg= github.com/fluxio/multierror v0.0.0-20160419044231-9c68d39025e5/go.mod h1:BEUDl7FG1cc76sM0J0x8dqr6RhiL4uqvk6oFkwuNyuM= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/h2non/filetype v1.0.8/go.mod h1:isekKqOuhMj+s/7r3rIeTErIRy4Rub5uBWHfvMusLMU= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -63,10 +62,10 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmylund/sortutil v0.0.0-20120526081524-abeda66eb583/go.mod h1:sFPiU/UgDcsQVu3vkqpZLCXWFwUoQRpHGu9ATihPAl0= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -79,7 +78,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -88,7 +86,6 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader v1.1.0 h1:LipC9rqRCe8kwa+ah3ZDfCqneVaf34cB/TKjXZiZt54= go.bug.st/downloader v1.1.0/go.mod h1:l+RPbNbrTB+MoAIp8nrZsP22nRPDy26XJZQqmm4gNT4= -go.bug.st/relaxed-semver v0.0.0-20181022103824-0265409c5852/go.mod h1:WWVH9tve4kargu9fsX18qW/UHxE37QcgPXRtE/xSvxY= go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= go.bug.st/serial v1.0.0/go.mod h1:rpXPISGjuNjPTRTcMlxi9lN6LoIPxd1ixVjBd8aSk/Q= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw= @@ -103,10 +100,11 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -114,9 +112,15 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -125,12 +129,14 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8= -google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90 h1:7THRSvPuzF1bql5kyFzX0JM0vpGhwuhskgJrJsbZ80Y= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= diff --git a/client_example/main.go b/client_example/main.go index b67e3f5de55..7a4ef534d17 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -17,16 +17,19 @@ package main import ( "context" + "fmt" + rpc "github.com/arduino/arduino-cli/rpc/commands" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "io" "io/ioutil" "log" "os" - "path" + // "path" "path/filepath" "time" - rpc "github.com/arduino/arduino-cli/rpc/commands" - "github.com/arduino/arduino-cli/rpc/settings" + //"github.com/arduino/arduino-cli/rpc/settings" "google.golang.org/grpc" ) @@ -58,747 +61,809 @@ func main() { // Create an instance of the gRPC client. client := rpc.NewArduinoCoreClient(conn) - settingsClient := settings.NewSettingsClient(conn) - - // Now we can call various methods of the API... + //settingsClient := settings.NewSettingsClient(conn) + ///////////////////////////////////////////////////////////////////////// + debugClient := dbg.NewDebugClient(conn) // `Version` can be called without any setup or init procedure. log.Println("calling Version") callVersion(client) - // Use SetValue to configure the arduino-cli directories. - log.Println("calling SetValue") - callSetValue(settingsClient) - - // List all the settings. - log.Println("calling GetAll()") - callGetAll(settingsClient) - - // Merge applies multiple settings values at once. - log.Println("calling Merge(`{\"foo\": \"bar\", \"daemon\":{\"port\":\"422\"}}`)") - callMerge(settingsClient) - - // Get the value of the foo key. - log.Println("calling GetValue(foo)") - callGetValue(settingsClient) - - // Before we can do anything with the CLI, an "instance" must be created. - // We keep a reference to the created instance because we will need it to - // run subsequent commands. - log.Println("calling Init") - instance := initInstance(client) - - // With a brand new instance, the first operation should always be updatating - // the index. - log.Println("calling UpdateIndex") - callUpdateIndex(client, instance) - - // Let's search for a platform (also known as 'core') called 'samd'. - log.Println("calling PlatformSearch(samd)") - callPlatformSearch(client, instance) - - // Install arduino:samd@1.6.19 - log.Println("calling PlatformInstall(arduino:samd@1.6.19)") - callPlatformInstall(client, instance) - - // Now list the installed platforms to double check previous installation - // went right. - log.Println("calling PlatformList()") - callPlatformList(client, instance) - - // Upgrade the installed platform to the latest version. - log.Println("calling PlatformUpgrade(arduino:samd)") - callPlatformUpgrade(client, instance) - - // Query board details for a mkr1000 - log.Println("calling BoardDetails(arduino:samd:mkr1000)") - callBoardsDetails(client, instance) - - // Attach a board to a sketch. - // Uncomment if you do have an actual board connected. - // log.Println("calling BoardAttach(serial:///dev/ttyACM0)") - // callBoardAttach(client, instance) - - // Compile a sketch - log.Println("calling Compile(arduino:samd:mkr1000, VERBOSE, hello.ino)") - callCompile(client, instance) - - // Upload a sketch - // Uncomment if you do have an actual board connected. - // log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") - // callUpload(client, instance) - - // List all boards - log.Println("calling BoardListAll(mkr)") - callListAll(client, instance) - - // List connected boards - log.Println("calling BoardList()") - callBoardList(client, instance) - - // Uninstall a platform - log.Println("calling PlatformUninstall(arduino:samd)") - callPlatformUnInstall(client, instance) - - // Update the Library index - log.Println("calling UpdateLibrariesIndex()") - callUpdateLibraryIndex(client, instance) - - // Download a library - log.Println("calling LibraryDownload(WiFi101@0.15.2)") - callLibDownload(client, instance) - - // Install a library - log.Println("calling LibraryInstall(WiFi101@0.15.1)") - callLibInstall(client, instance, "0.15.1") - - // Replace the previous version - log.Println("calling LibraryInstall(WiFi101@0.15.2)") - callLibInstall(client, instance, "0.15.2") - - // Upgrade all libs to latest - log.Println("calling LibraryUpgradeAll()") - callLibUpgradeAll(client, instance) - - // Search for a lib using the 'audio' keyword - log.Println("calling LibrarySearch(audio)") - callLibSearch(client, instance) - - // List the dependencies of the ArduinoIoTCloud library - log.Println("calling LibraryResolveDependencies(ArduinoIoTCloud)") - callLibraryResolveDependencies(client, instance) - - // List installed libraries - log.Println("calling LibraryList") - callLibList(client, instance) - - // Uninstall a library - log.Println("calling LibraryUninstall(WiFi101)") - callLibUninstall(client, instance) -} - -func callVersion(client rpc.ArduinoCoreClient) { - versionResp, err := client.Version(context.Background(), &rpc.VersionReq{}) - if err != nil { - log.Fatalf("Error getting version: %s", err) - } - - log.Printf("arduino-cli version: %v", versionResp.GetVersion()) -} - -func callSetValue(client settings.SettingsClient) { - _, err := client.SetValue(context.Background(), - &settings.Value{ - Key: "directories", - JsonData: `{"data": "` + dataDir + `", "downloads": "` + path.Join(dataDir, "staging") + `", "user": "` + path.Join(dataDir, "sketchbook") + `"}`, - }) - - if err != nil { - log.Fatalf("Error setting settings value: %s", err) - } -} - -func callMerge(client settings.SettingsClient) { - bulkSettings := `{"foo": "bar", "daemon":{"port":"422"}}` - _, err := client.Merge(context.Background(), - &settings.RawData{ - JsonData: bulkSettings, - }) - - if err != nil { - log.Fatalf("Error merging settings: %s", err) - } -} - -func callGetValue(client settings.SettingsClient) { - getValueResp, err := client.GetValue(context.Background(), - &settings.GetValueRequest{ - Key: "foo", - }) - - if err != nil { - log.Fatalf("Error getting settings value: %s", err) - } - - log.Printf("Value: %s: %s", getValueResp.GetKey(), getValueResp.GetJsonData()) -} - -func callGetAll(client settings.SettingsClient) { - getAllResp, err := client.GetAll(context.Background(), &settings.GetAllRequest{}) - + // debug calls + debugStreamingOpenClient, err := debugClient.StreamingOpen(context.Background()) if err != nil { - log.Fatalf("Error getting settings: %s", err) + log.Fatalf("steraming open error: %s\n", err) } - log.Printf("Settings: %s", getAllResp.GetJsonData()) -} - -func initInstance(client rpc.ArduinoCoreClient) *rpc.Instance { - // The configuration for this example client only contains the path to - // the data folder. - initRespStream, err := client.Init(context.Background(), &rpc.InitReq{}) + err = debugStreamingOpenClient.Send(&dbg.StreamingOpenReq{Content: &dbg.StreamingOpenReq_DebugReq{DebugReq: &dbg.DebugReq{Instance: &dbg.Instance{Id: 1}}}}) if err != nil { - log.Fatalf("Error creating server instance: %s", err) - - } - - var instance *rpc.Instance - // Loop and consume the server stream until all the setup procedures are done. - for { - initResp, err := initRespStream.Recv() - // The server is done. - if err == io.EOF { - break - } - - // There was an error. - if err != nil { - log.Fatalf("Init error: %s", err) - } - - // The server sent us a valid instance, let's print its ID. - if initResp.GetInstance() != nil { - instance = initResp.GetInstance() - log.Printf("Got a new instance with ID: %v", instance.GetId()) - } - - // When a download is ongoing, log the progress - if initResp.GetDownloadProgress() != nil { - log.Printf("DOWNLOAD: %s", initResp.GetDownloadProgress()) - } - - // When an overall task is ongoing, log the progress - if initResp.GetTaskProgress() != nil { - log.Printf("TASK: %s", initResp.GetTaskProgress()) - } + log.Fatalf("Send error: %s\n", err) } + log.Println("calling StreamingOpenReq_DebugReq") - return instance -} - -func callUpdateIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - uiRespStream, err := client.UpdateIndex(context.Background(), &rpc.UpdateIndexReq{ - Instance: instance, - }) + err = debugStreamingOpenClient.Send(&dbg.StreamingOpenReq{Content: &dbg.StreamingOpenReq_Data{Data: []byte("\n")}}) if err != nil { - log.Fatalf("Error updating index: %s", err) + log.Fatalf("Send error: %s\n", err) } + log.Println("calling StreamingOpenReq_Data") // Loop and consume the server stream until all the operations are done. for { - uiResp, err := uiRespStream.Recv() - - // the server is done - if err == io.EOF { - log.Print("Update index done") - break - } - - // there was an error - if err != nil { - log.Fatalf("Update error: %s", err) - } - - // operations in progress - if uiResp.GetDownloadProgress() != nil { - log.Printf("DOWNLOAD: %s", uiResp.GetDownloadProgress()) - } - } -} - -func callPlatformSearch(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - searchResp, err := client.PlatformSearch(context.Background(), &rpc.PlatformSearchReq{ - Instance: instance, - SearchArgs: "samd", - }) - - if err != nil { - log.Fatalf("Search error: %s", err) - } - - platforms := searchResp.GetSearchOutput() - for _, plat := range platforms { - // We only print ID and version of the platforms found but you can look - // at the definition for the rpc.Platform struct for more fields. - log.Printf("Search result: %+v - %+v", plat.GetID(), plat.GetLatest()) - } -} - -func callPlatformInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - installRespStream, err := client.PlatformInstall(context.Background(), - &rpc.PlatformInstallReq{ - Instance: instance, - PlatformPackage: "arduino", - Architecture: "samd", - Version: "1.6.19", - }) - - if err != nil { - log.Fatalf("Error installing platform: %s", err) - } - - // Loop and consume the server stream until all the operations are done. - for { - installResp, err := installRespStream.Recv() + compResp, err := debugStreamingOpenClient.Recv() // The server is done. if err == io.EOF { - log.Printf("Install done") + log.Print("debug done") break } // There was an error. if err != nil { - log.Fatalf("Install error: %s", err) - } - - // When a download is ongoing, log the progress - if installResp.GetProgress() != nil { - log.Printf("DOWNLOAD: %s", installResp.GetProgress()) - } - - // When an overall task is ongoing, log the progress - if installResp.GetTaskProgress() != nil { - log.Printf("TASK: %s", installResp.GetTaskProgress()) - } - } -} - -func callPlatformList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - listResp, err := client.PlatformList(context.Background(), - &rpc.PlatformListReq{Instance: instance}) - - if err != nil { - log.Fatalf("List error: %s", err) - } - - for _, plat := range listResp.GetInstalledPlatform() { - // We only print ID and version of the installed platforms but you can look - // at the definition for the rpc.Platform struct for more fields. - log.Printf("Installed platform: %s - %s", plat.GetID(), plat.GetInstalled()) - } -} - -func callPlatformUpgrade(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - upgradeRespStream, err := client.PlatformUpgrade(context.Background(), - &rpc.PlatformUpgradeReq{ - Instance: instance, - PlatformPackage: "arduino", - Architecture: "samd", - }) - - if err != nil { - log.Fatalf("Error upgrading platform: %s", err) - } - - // Loop and consume the server stream until all the operations are done. - for { - upgradeResp, err := upgradeRespStream.Recv() - - // The server is done. - if err == io.EOF { - log.Printf("Upgrade done") - break - } - - // There was an error. - if err != nil { - log.Fatalf("Upgrade error: %s", err) - } - - // When a download is ongoing, log the progress - if upgradeResp.GetProgress() != nil { - log.Printf("DOWNLOAD: %s", upgradeResp.GetProgress()) - } - - // When an overall task is ongoing, log the progress - if upgradeResp.GetTaskProgress() != nil { - log.Printf("TASK: %s", upgradeResp.GetTaskProgress()) - } - } -} - -func callBoardsDetails(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - details, err := client.BoardDetails(context.Background(), - &rpc.BoardDetailsReq{ - Instance: instance, - Fqbn: "arduino:samd:mkr1000", - }) - - if err != nil { - log.Fatalf("Error getting board data: %s\n", err) - } - - log.Printf("Board details for %s", details.GetName()) - log.Printf("Required tools: %s", details.GetRequiredTools()) - log.Printf("Config options: %s", details.GetConfigOptions()) -} - -func callBoardAttach(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - currDir, _ := os.Getwd() - boardattachresp, err := client.BoardAttach(context.Background(), - &rpc.BoardAttachReq{ - Instance: instance, - BoardUri: "/dev/ttyACM0", - SketchPath: filepath.Join(currDir, "hello.ino"), - }) - - if err != nil { - log.Fatalf("Attach error: %s", err) - } - - // Loop and consume the server stream until all the operations are done. - for { - attachResp, err := boardattachresp.Recv() - - // The server is done. - if err == io.EOF { - log.Print("Attach done") - break - } - - // There was an error. - if err != nil { - log.Fatalf("Attach error: %s\n", err) - } - - // When an overall task is ongoing, log the progress - if attachResp.GetTaskProgress() != nil { - log.Printf("TASK: %s", attachResp.GetTaskProgress()) - } - } -} - -func callCompile(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - currDir, _ := os.Getwd() - compRespStream, err := client.Compile(context.Background(), - &rpc.CompileReq{ - Instance: instance, - Fqbn: "arduino:samd:mkr1000", - SketchPath: filepath.Join(currDir, "hello.ino"), - Verbose: true, - }) - - if err != nil { - log.Fatalf("Compile error: %s\n", err) - } - - // Loop and consume the server stream until all the operations are done. - for { - compResp, err := compRespStream.Recv() - - // The server is done. - if err == io.EOF { - log.Print("Compilation done") - break - } - - // There was an error. - if err != nil { - log.Fatalf("Compile error: %s\n", err) - } - - // When an operation is ongoing you can get its output - if resp := compResp.GetOutStream(); resp != nil { - log.Printf("STDOUT: %s", resp) - } - if resperr := compResp.GetErrStream(); resperr != nil { - log.Printf("STDERR: %s", resperr) - } - } -} - -func callUpload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - currDir, _ := os.Getwd() - uplRespStream, err := client.Upload(context.Background(), - &rpc.UploadReq{ - Instance: instance, - Fqbn: "arduino:samd:mkr1000", - SketchPath: filepath.Join(currDir, "hello.ino"), - Port: "/dev/ttyACM0", - Verbose: true, - }) - - if err != nil { - log.Fatalf("Upload error: %s\n", err) - } - - for { - uplResp, err := uplRespStream.Recv() - if err == io.EOF { - log.Printf("Upload done") - break - } - - if err != nil { - log.Fatalf("Upload error: %s", err) - break + log.Fatalf("debug error: %s\n", err) } // When an operation is ongoing you can get its output - if resp := uplResp.GetOutStream(); resp != nil { - log.Printf("STDOUT: %s", resp) - } - if resperr := uplResp.GetErrStream(); resperr != nil { - log.Printf("STDERR: %s", resperr) - } - } -} - -func callListAll(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - boardListAllResp, err := client.BoardListAll(context.Background(), - &rpc.BoardListAllReq{ - Instance: instance, - SearchArgs: []string{"mkr"}, - }) - - if err != nil { - log.Fatalf("Board list-all error: %s", err) - } - - for _, board := range boardListAllResp.GetBoards() { - log.Printf("%s: %s", board.GetName(), board.GetFQBN()) - } -} - -func callBoardList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - boardListResp, err := client.BoardList(context.Background(), - &rpc.BoardListReq{Instance: instance}) - - if err != nil { - log.Fatalf("Board list error: %s\n", err) - } - - for _, port := range boardListResp.GetPorts() { - log.Printf("port: %s, boards: %+v\n", port.GetAddress(), port.GetBoards()) - } -} - -func callPlatformUnInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - uninstallRespStream, err := client.PlatformUninstall(context.Background(), - &rpc.PlatformUninstallReq{ - Instance: instance, - PlatformPackage: "arduino", - Architecture: "samd", - }) - - if err != nil { - log.Fatalf("Uninstall error: %s", err) - } - - // Loop and consume the server stream until all the operations are done. - for { - uninstallResp, err := uninstallRespStream.Recv() - if err == io.EOF { - log.Print("Uninstall done") - break - } - - if err != nil { - log.Fatalf("Uninstall error: %s\n", err) - } - - if uninstallResp.GetTaskProgress() != nil { - log.Printf("TASK: %s\n", uninstallResp.GetTaskProgress()) - } - } -} - -func callUpdateLibraryIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - libIdxUpdateStream, err := client.UpdateLibrariesIndex(context.Background(), - &rpc.UpdateLibrariesIndexReq{Instance: instance}) - - if err != nil { - log.Fatalf("Error updating libraries index: %s\n", err) - } - - // Loop and consume the server stream until all the operations are done. - for { - resp, err := libIdxUpdateStream.Recv() - if err == io.EOF { - log.Print("Library index update done") - break - } - - if err != nil { - log.Fatalf("Error updating libraries index: %s", err) - } - - if resp.GetDownloadProgress() != nil { - log.Printf("DOWNLOAD: %s", resp.GetDownloadProgress()) - } - } -} - -func callLibDownload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - downloadRespStream, err := client.LibraryDownload(context.Background(), - &rpc.LibraryDownloadReq{ - Instance: instance, - Name: "WiFi101", - Version: "0.15.2", - }) - - if err != nil { - log.Fatalf("Error downloading library: %s", err) - } - - // Loop and consume the server stream until all the operations are done. - for { - downloadResp, err := downloadRespStream.Recv() - if err == io.EOF { - log.Print("Lib download done") - break - } - - if err != nil { - log.Fatalf("Download error: %s", err) - } - - if downloadResp.GetProgress() != nil { - log.Printf("DOWNLOAD: %s", downloadResp.GetProgress()) - } - } -} - -func callLibInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance, version string) { - installRespStream, err := client.LibraryInstall(context.Background(), - &rpc.LibraryInstallReq{ - Instance: instance, - Name: "WiFi101", - Version: version, - }) - - if err != nil { - log.Fatalf("Error installing library: %s", err) - } - - for { - installResp, err := installRespStream.Recv() - if err == io.EOF { - log.Print("Lib install done") - break + if resp := compResp.GetData(); resp != nil { + fmt.Printf("%s", resp) + if string(resp) == " (gdb) " { + break + } } - if err != nil { - log.Fatalf("Install error: %s", err) - } - - if installResp.GetProgress() != nil { - log.Printf("DOWNLOAD: %s\n", installResp.GetProgress()) - } - if installResp.GetTaskProgress() != nil { - log.Printf("TASK: %s\n", installResp.GetTaskProgress()) - } } -} - -func callLibUpgradeAll(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - libUpgradeAllRespStream, err := client.LibraryUpgradeAll(context.Background(), - &rpc.LibraryUpgradeAllReq{ - Instance: instance, - }) + err = debugStreamingOpenClient.Send(&dbg.StreamingOpenReq{Content: &dbg.StreamingOpenReq_Data{Data: []byte("quit\n")}}) if err != nil { - log.Fatalf("Error upgrading all: %s\n", err) - } - - for { - resp, err := libUpgradeAllRespStream.Recv() - if err == io.EOF { - log.Printf("Lib upgrade all done") - break - } - - if err != nil { - log.Fatalf("Upgrading error: %s", err) - } - - if resp.GetProgress() != nil { - log.Printf("DOWNLOAD: %s\n", resp.GetProgress()) - } - if resp.GetTaskProgress() != nil { - log.Printf("TASK: %s\n", resp.GetTaskProgress()) - } + log.Fatalf("Send error: %s\n", err) } -} - -func callLibSearch(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - libSearchResp, err := client.LibrarySearch(context.Background(), - &rpc.LibrarySearchReq{ - Instance: instance, - Query: "audio", - }) + err = debugStreamingOpenClient.CloseSend() if err != nil { - log.Fatalf("Error searching for library: %s", err) - } - - for _, res := range libSearchResp.GetLibraries() { - log.Printf("Result: %s - %s", res.GetName(), res.GetLatest().GetVersion()) - } + log.Fatalf("Send error: %s\n", err) + } + + //////////////////////////////////////////////////////////////////////////////////////////// + + //// Now we can call various methods of the API... + // + //// `Version` can be called without any setup or init procedure. + //log.Println("calling Version") + //callVersion(client) + // + //// Use SetValue to configure the arduino-cli directories. + //log.Println("calling SetValue") + //callSetValue(settingsClient) + // + //// List all the settings. + //log.Println("calling GetAll()") + //callGetAll(settingsClient) + // + //// Merge applies multiple settings values at once. + //log.Println("calling Merge(`{\"foo\": \"bar\", \"daemon\":{\"port\":\"422\"}}`)") + //callMerge(settingsClient) + // + //// Get the value of the foo key. + //log.Println("calling GetValue(foo)") + //callGetValue(settingsClient) + // + //// Before we can do anything with the CLI, an "instance" must be created. + //// We keep a reference to the created instance because we will need it to + //// run subsequent commands. + //log.Println("calling Init") + //instance := initInstance(client) + // + //// With a brand new instance, the first operation should always be updatating + //// the index. + //log.Println("calling UpdateIndex") + //callUpdateIndex(client, instance) + // + //// Let's search for a platform (also known as 'core') called 'samd'. + //log.Println("calling PlatformSearch(samd)") + //callPlatformSearch(client, instance) + // + //// Install arduino:samd@1.6.19 + //log.Println("calling PlatformInstall(arduino:samd@1.6.19)") + //callPlatformInstall(client, instance) + // + //// Now list the installed platforms to double check previous installation + //// went right. + //log.Println("calling PlatformList()") + //callPlatformList(client, instance) + // + //// Upgrade the installed platform to the latest version. + //log.Println("calling PlatformUpgrade(arduino:samd)") + //callPlatformUpgrade(client, instance) + // + //// Query board details for a mkr1000 + //log.Println("calling BoardDetails(arduino:samd:mkr1000)") + //callBoardsDetails(client, instance) + // + //// Attach a board to a sketch. + //// Uncomment if you do have an actual board connected. + //// log.Println("calling BoardAttach(serial:///dev/ttyACM0)") + //// callBoardAttach(client, instance) + // + //// Compile a sketch + //log.Println("calling Compile(arduino:samd:mkr1000, VERBOSE, hello.ino)") + //callCompile(client, instance) + // + //// Upload a sketch + //// Uncomment if you do have an actual board connected. + //// log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") + //// callUpload(client, instance) + // + //// List all boards + //log.Println("calling BoardListAll(mkr)") + //callListAll(client, instance) + // + //// List connected boards + //log.Println("calling BoardList()") + //callBoardList(client, instance) + // + //// Uninstall a platform + //log.Println("calling PlatformUninstall(arduino:samd)") + //callPlatformUnInstall(client, instance) + // + //// Update the Library index + //log.Println("calling UpdateLibrariesIndex()") + //callUpdateLibraryIndex(client, instance) + // + //// Download a library + //log.Println("calling LibraryDownload(WiFi101@0.15.2)") + //callLibDownload(client, instance) + // + //// Install a library + //log.Println("calling LibraryInstall(WiFi101@0.15.1)") + //callLibInstall(client, instance, "0.15.1") + // + //// Replace the previous version + //log.Println("calling LibraryInstall(WiFi101@0.15.2)") + //callLibInstall(client, instance, "0.15.2") + // + //// Upgrade all libs to latest + //log.Println("calling LibraryUpgradeAll()") + //callLibUpgradeAll(client, instance) + // + //// Search for a lib using the 'audio' keyword + //log.Println("calling LibrarySearch(audio)") + //callLibSearch(client, instance) + // + //// List the dependencies of the ArduinoIoTCloud library + //log.Println("calling LibraryResolveDependencies(ArduinoIoTCloud)") + //callLibraryResolveDependencies(client, instance) + // + //// List installed libraries + //log.Println("calling LibraryList") + //callLibList(client, instance) + // + //// Uninstall a library + //log.Println("calling LibraryUninstall(WiFi101)") + //callLibUninstall(client, instance) } -func callLibraryResolveDependencies(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - libraryResolveDependenciesResp, err := client.LibraryResolveDependencies(context.Background(), - &rpc.LibraryResolveDependenciesReq{ - Instance: instance, - Name: "ArduinoIoTCloud", - }) - - if err != nil { - log.Fatalf("Error listing library dependencies: %s", err) - } - - for _, resp := range libraryResolveDependenciesResp.GetDependencies() { - log.Printf("Dependency Name: %s", resp.GetName()) - log.Printf("Version Required: %s", resp.GetVersionRequired()) - if resp.GetVersionInstalled() != "" { - log.Printf("Version Installed: %s\n", resp.GetVersionInstalled()) - } - } -} - -func callLibList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - libLstResp, err := client.LibraryList(context.Background(), - &rpc.LibraryListReq{ - Instance: instance, - All: false, - Updatable: false, - }) - +func callVersion(client rpc.ArduinoCoreClient) { + versionResp, err := client.Version(context.Background(), &rpc.VersionReq{}) if err != nil { - log.Fatalf("Error List Library: %s", err) + log.Fatalf("Error getting version: %s", err) } - for _, res := range libLstResp.GetInstalledLibrary() { - log.Printf("%s - %s", res.GetLibrary().GetName(), res.GetLibrary().GetVersion()) - } + log.Printf("arduino-cli version: %v", versionResp.GetVersion()) } -func callLibUninstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { - libUninstallRespStream, err := client.LibraryUninstall(context.Background(), - &rpc.LibraryUninstallReq{ - Instance: instance, - Name: "WiFi101", - }) - - if err != nil { - log.Fatalf("Error uninstalling: %s", err) - } - - for { - uninstallResp, err := libUninstallRespStream.Recv() - if err == io.EOF { - log.Printf("Lib uninstall done") - break - } - - if err != nil { - log.Fatalf("Uninstall error: %s", err) - } - - if uninstallResp.GetTaskProgress() != nil { - log.Printf("TASK: %s", uninstallResp.GetTaskProgress()) - } - } -} +// +//func callSetValue(client settings.SettingsClient) { +// _, err := client.SetValue(context.Background(), +// &settings.Value{ +// Key: "directories", +// JsonData: `{"data": "` + dataDir + `", "downloads": "` + path.Join(dataDir, "staging") + `", "user": "` + path.Join(dataDir, "sketchbook") + `"}`, +// }) +// +// if err != nil { +// log.Fatalf("Error setting settings value: %s", err) +// } +//} +// +//func callMerge(client settings.SettingsClient) { +// bulkSettings := `{"foo": "bar", "daemon":{"port":"422"}}` +// _, err := client.Merge(context.Background(), +// &settings.RawData{ +// JsonData: bulkSettings, +// }) +// +// if err != nil { +// log.Fatalf("Error merging settings: %s", err) +// } +//} +// +//func callGetValue(client settings.SettingsClient) { +// getValueResp, err := client.GetValue(context.Background(), +// &settings.GetValueRequest{ +// Key: "foo", +// }) +// +// if err != nil { +// log.Fatalf("Error getting settings value: %s", err) +// } +// +// log.Printf("Value: %s: %s", getValueResp.GetKey(), getValueResp.GetJsonData()) +//} +// +//func callGetAll(client settings.SettingsClient) { +// getAllResp, err := client.GetAll(context.Background(), &settings.GetAllRequest{}) +// +// if err != nil { +// log.Fatalf("Error getting settings: %s", err) +// } +// +// log.Printf("Settings: %s", getAllResp.GetJsonData()) +//} +// +//func initInstance(client rpc.ArduinoCoreClient) *rpc.Instance { +// // The configuration for this example client only contains the path to +// // the data folder. +// initRespStream, err := client.Init(context.Background(), &rpc.InitReq{}) +// if err != nil { +// log.Fatalf("Error creating server instance: %s", err) +// +// } +// +// var instance *rpc.Instance +// // Loop and consume the server stream until all the setup procedures are done. +// for { +// initResp, err := initRespStream.Recv() +// // The server is done. +// if err == io.EOF { +// break +// } +// +// // There was an error. +// if err != nil { +// log.Fatalf("Init error: %s", err) +// } +// +// // The server sent us a valid instance, let's print its ID. +// if initResp.GetInstance() != nil { +// instance = initResp.GetInstance() +// log.Printf("Got a new instance with ID: %v", instance.GetId()) +// } +// +// // When a download is ongoing, log the progress +// if initResp.GetDownloadProgress() != nil { +// log.Printf("DOWNLOAD: %s", initResp.GetDownloadProgress()) +// } +// +// // When an overall task is ongoing, log the progress +// if initResp.GetTaskProgress() != nil { +// log.Printf("TASK: %s", initResp.GetTaskProgress()) +// } +// } +// +// return instance +//} +// +//func callUpdateIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// uiRespStream, err := client.UpdateIndex(context.Background(), &rpc.UpdateIndexReq{ +// Instance: instance, +// }) +// if err != nil { +// log.Fatalf("Error updating index: %s", err) +// } +// +// // Loop and consume the server stream until all the operations are done. +// for { +// uiResp, err := uiRespStream.Recv() +// +// // the server is done +// if err == io.EOF { +// log.Print("Update index done") +// break +// } +// +// // there was an error +// if err != nil { +// log.Fatalf("Update error: %s", err) +// } +// +// // operations in progress +// if uiResp.GetDownloadProgress() != nil { +// log.Printf("DOWNLOAD: %s", uiResp.GetDownloadProgress()) +// } +// } +//} +// +//func callPlatformSearch(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// searchResp, err := client.PlatformSearch(context.Background(), &rpc.PlatformSearchReq{ +// Instance: instance, +// SearchArgs: "samd", +// }) +// +// if err != nil { +// log.Fatalf("Search error: %s", err) +// } +// +// platforms := searchResp.GetSearchOutput() +// for _, plat := range platforms { +// // We only print ID and version of the platforms found but you can look +// // at the definition for the rpc.Platform struct for more fields. +// log.Printf("Search result: %+v - %+v", plat.GetID(), plat.GetLatest()) +// } +//} +// +//func callPlatformInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// installRespStream, err := client.PlatformInstall(context.Background(), +// &rpc.PlatformInstallReq{ +// Instance: instance, +// PlatformPackage: "arduino", +// Architecture: "samd", +// Version: "1.6.19", +// }) +// +// if err != nil { +// log.Fatalf("Error installing platform: %s", err) +// } +// +// // Loop and consume the server stream until all the operations are done. +// for { +// installResp, err := installRespStream.Recv() +// +// // The server is done. +// if err == io.EOF { +// log.Printf("Install done") +// break +// } +// +// // There was an error. +// if err != nil { +// log.Fatalf("Install error: %s", err) +// } +// +// // When a download is ongoing, log the progress +// if installResp.GetProgress() != nil { +// log.Printf("DOWNLOAD: %s", installResp.GetProgress()) +// } +// +// // When an overall task is ongoing, log the progress +// if installResp.GetTaskProgress() != nil { +// log.Printf("TASK: %s", installResp.GetTaskProgress()) +// } +// } +//} +// +//func callPlatformList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// listResp, err := client.PlatformList(context.Background(), +// &rpc.PlatformListReq{Instance: instance}) +// +// if err != nil { +// log.Fatalf("List error: %s", err) +// } +// +// for _, plat := range listResp.GetInstalledPlatform() { +// // We only print ID and version of the installed platforms but you can look +// // at the definition for the rpc.Platform struct for more fields. +// log.Printf("Installed platform: %s - %s", plat.GetID(), plat.GetInstalled()) +// } +//} +// +//func callPlatformUpgrade(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// upgradeRespStream, err := client.PlatformUpgrade(context.Background(), +// &rpc.PlatformUpgradeReq{ +// Instance: instance, +// PlatformPackage: "arduino", +// Architecture: "samd", +// }) +// +// if err != nil { +// log.Fatalf("Error upgrading platform: %s", err) +// } +// +// // Loop and consume the server stream until all the operations are done. +// for { +// upgradeResp, err := upgradeRespStream.Recv() +// +// // The server is done. +// if err == io.EOF { +// log.Printf("Upgrade done") +// break +// } +// +// // There was an error. +// if err != nil { +// log.Fatalf("Upgrade error: %s", err) +// } +// +// // When a download is ongoing, log the progress +// if upgradeResp.GetProgress() != nil { +// log.Printf("DOWNLOAD: %s", upgradeResp.GetProgress()) +// } +// +// // When an overall task is ongoing, log the progress +// if upgradeResp.GetTaskProgress() != nil { +// log.Printf("TASK: %s", upgradeResp.GetTaskProgress()) +// } +// } +//} +// +//func callBoardsDetails(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// details, err := client.BoardDetails(context.Background(), +// &rpc.BoardDetailsReq{ +// Instance: instance, +// Fqbn: "arduino:samd:mkr1000", +// }) +// +// if err != nil { +// log.Fatalf("Error getting board data: %s\n", err) +// } +// +// log.Printf("Board details for %s", details.GetName()) +// log.Printf("Required tools: %s", details.GetRequiredTools()) +// log.Printf("Config options: %s", details.GetConfigOptions()) +//} +// +//func callBoardAttach(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// currDir, _ := os.Getwd() +// boardattachresp, err := client.BoardAttach(context.Background(), +// &rpc.BoardAttachReq{ +// Instance: instance, +// BoardUri: "/dev/ttyACM0", +// SketchPath: filepath.Join(currDir, "hello.ino"), +// }) +// +// if err != nil { +// log.Fatalf("Attach error: %s", err) +// } +// +// // Loop and consume the server stream until all the operations are done. +// for { +// attachResp, err := boardattachresp.Recv() +// +// // The server is done. +// if err == io.EOF { +// log.Print("Attach done") +// break +// } +// +// // There was an error. +// if err != nil { +// log.Fatalf("Attach error: %s\n", err) +// } +// +// // When an overall task is ongoing, log the progress +// if attachResp.GetTaskProgress() != nil { +// log.Printf("TASK: %s", attachResp.GetTaskProgress()) +// } +// } +//} +// +//func callCompile(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// currDir, _ := os.Getwd() +// compRespStream, err := client.Compile(context.Background(), +// &rpc.CompileReq{ +// Instance: instance, +// Fqbn: "arduino:samd:mkr1000", +// SketchPath: filepath.Join(currDir, "hello.ino"), +// Verbose: true, +// }) +// +// if err != nil { +// log.Fatalf("Compile error: %s\n", err) +// } +// +// // Loop and consume the server stream until all the operations are done. +// for { +// compResp, err := compRespStream.Recv() +// +// // The server is done. +// if err == io.EOF { +// log.Print("Compilation done") +// break +// } +// +// // There was an error. +// if err != nil { +// log.Fatalf("Compile error: %s\n", err) +// } +// +// // When an operation is ongoing you can get its output +// if resp := compResp.GetOutStream(); resp != nil { +// log.Printf("STDOUT: %s", resp) +// } +// if resperr := compResp.GetErrStream(); resperr != nil { +// log.Printf("STDERR: %s", resperr) +// } +// } +//} +// +//func callUpload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// currDir, _ := os.Getwd() +// uplRespStream, err := client.Upload(context.Background(), +// &rpc.UploadReq{ +// Instance: instance, +// Fqbn: "arduino:samd:mkr1000", +// SketchPath: filepath.Join(currDir, "hello.ino"), +// Port: "/dev/ttyACM0", +// Verbose: true, +// }) +// +// if err != nil { +// log.Fatalf("Upload error: %s\n", err) +// } +// +// for { +// uplResp, err := uplRespStream.Recv() +// if err == io.EOF { +// log.Printf("Upload done") +// break +// } +// +// if err != nil { +// log.Fatalf("Upload error: %s", err) +// break +// } +// +// // When an operation is ongoing you can get its output +// if resp := uplResp.GetOutStream(); resp != nil { +// log.Printf("STDOUT: %s", resp) +// } +// if resperr := uplResp.GetErrStream(); resperr != nil { +// log.Printf("STDERR: %s", resperr) +// } +// } +//} +// +//func callListAll(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// boardListAllResp, err := client.BoardListAll(context.Background(), +// &rpc.BoardListAllReq{ +// Instance: instance, +// SearchArgs: []string{"mkr"}, +// }) +// +// if err != nil { +// log.Fatalf("Board list-all error: %s", err) +// } +// +// for _, board := range boardListAllResp.GetBoards() { +// log.Printf("%s: %s", board.GetName(), board.GetFQBN()) +// } +//} +// +//func callBoardList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// boardListResp, err := client.BoardList(context.Background(), +// &rpc.BoardListReq{Instance: instance}) +// +// if err != nil { +// log.Fatalf("Board list error: %s\n", err) +// } +// +// for _, port := range boardListResp.GetPorts() { +// log.Printf("port: %s, boards: %+v\n", port.GetAddress(), port.GetBoards()) +// } +//} +// +//func callPlatformUnInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// uninstallRespStream, err := client.PlatformUninstall(context.Background(), +// &rpc.PlatformUninstallReq{ +// Instance: instance, +// PlatformPackage: "arduino", +// Architecture: "samd", +// }) +// +// if err != nil { +// log.Fatalf("Uninstall error: %s", err) +// } +// +// // Loop and consume the server stream until all the operations are done. +// for { +// uninstallResp, err := uninstallRespStream.Recv() +// if err == io.EOF { +// log.Print("Uninstall done") +// break +// } +// +// if err != nil { +// log.Fatalf("Uninstall error: %s\n", err) +// } +// +// if uninstallResp.GetTaskProgress() != nil { +// log.Printf("TASK: %s\n", uninstallResp.GetTaskProgress()) +// } +// } +//} +// +//func callUpdateLibraryIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// libIdxUpdateStream, err := client.UpdateLibrariesIndex(context.Background(), +// &rpc.UpdateLibrariesIndexReq{Instance: instance}) +// +// if err != nil { +// log.Fatalf("Error updating libraries index: %s\n", err) +// } +// +// // Loop and consume the server stream until all the operations are done. +// for { +// resp, err := libIdxUpdateStream.Recv() +// if err == io.EOF { +// log.Print("Library index update done") +// break +// } +// +// if err != nil { +// log.Fatalf("Error updating libraries index: %s", err) +// } +// +// if resp.GetDownloadProgress() != nil { +// log.Printf("DOWNLOAD: %s", resp.GetDownloadProgress()) +// } +// } +//} +// +//func callLibDownload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// downloadRespStream, err := client.LibraryDownload(context.Background(), +// &rpc.LibraryDownloadReq{ +// Instance: instance, +// Name: "WiFi101", +// Version: "0.15.2", +// }) +// +// if err != nil { +// log.Fatalf("Error downloading library: %s", err) +// } +// +// // Loop and consume the server stream until all the operations are done. +// for { +// downloadResp, err := downloadRespStream.Recv() +// if err == io.EOF { +// log.Print("Lib download done") +// break +// } +// +// if err != nil { +// log.Fatalf("Download error: %s", err) +// } +// +// if downloadResp.GetProgress() != nil { +// log.Printf("DOWNLOAD: %s", downloadResp.GetProgress()) +// } +// } +//} +// +//func callLibInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance, version string) { +// installRespStream, err := client.LibraryInstall(context.Background(), +// &rpc.LibraryInstallReq{ +// Instance: instance, +// Name: "WiFi101", +// Version: version, +// }) +// +// if err != nil { +// log.Fatalf("Error installing library: %s", err) +// } +// +// for { +// installResp, err := installRespStream.Recv() +// if err == io.EOF { +// log.Print("Lib install done") +// break +// } +// +// if err != nil { +// log.Fatalf("Install error: %s", err) +// } +// +// if installResp.GetProgress() != nil { +// log.Printf("DOWNLOAD: %s\n", installResp.GetProgress()) +// } +// if installResp.GetTaskProgress() != nil { +// log.Printf("TASK: %s\n", installResp.GetTaskProgress()) +// } +// } +//} +// +//func callLibUpgradeAll(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// libUpgradeAllRespStream, err := client.LibraryUpgradeAll(context.Background(), +// &rpc.LibraryUpgradeAllReq{ +// Instance: instance, +// }) +// +// if err != nil { +// log.Fatalf("Error upgrading all: %s\n", err) +// } +// +// for { +// resp, err := libUpgradeAllRespStream.Recv() +// if err == io.EOF { +// log.Printf("Lib upgrade all done") +// break +// } +// +// if err != nil { +// log.Fatalf("Upgrading error: %s", err) +// } +// +// if resp.GetProgress() != nil { +// log.Printf("DOWNLOAD: %s\n", resp.GetProgress()) +// } +// if resp.GetTaskProgress() != nil { +// log.Printf("TASK: %s\n", resp.GetTaskProgress()) +// } +// } +//} +// +//func callLibSearch(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// libSearchResp, err := client.LibrarySearch(context.Background(), +// &rpc.LibrarySearchReq{ +// Instance: instance, +// Query: "audio", +// }) +// +// if err != nil { +// log.Fatalf("Error searching for library: %s", err) +// } +// +// for _, res := range libSearchResp.GetLibraries() { +// log.Printf("Result: %s - %s", res.GetName(), res.GetLatest().GetVersion()) +// } +//} +// +//func callLibraryResolveDependencies(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// libraryResolveDependenciesResp, err := client.LibraryResolveDependencies(context.Background(), +// &rpc.LibraryResolveDependenciesReq{ +// Instance: instance, +// Name: "ArduinoIoTCloud", +// }) +// +// if err != nil { +// log.Fatalf("Error listing library dependencies: %s", err) +// } +// +// for _, resp := range libraryResolveDependenciesResp.GetDependencies() { +// log.Printf("Dependency Name: %s", resp.GetName()) +// log.Printf("Version Required: %s", resp.GetVersionRequired()) +// if resp.GetVersionInstalled() != "" { +// log.Printf("Version Installed: %s\n", resp.GetVersionInstalled()) +// } +// } +//} +// +//func callLibList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// libLstResp, err := client.LibraryList(context.Background(), +// &rpc.LibraryListReq{ +// Instance: instance, +// All: false, +// Updatable: false, +// }) +// +// if err != nil { +// log.Fatalf("Error List Library: %s", err) +// } +// +// for _, res := range libLstResp.GetInstalledLibrary() { +// log.Printf("%s - %s", res.GetLibrary().GetName(), res.GetLibrary().GetVersion()) +// } +//} +// +//func callLibUninstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { +// libUninstallRespStream, err := client.LibraryUninstall(context.Background(), +// &rpc.LibraryUninstallReq{ +// Instance: instance, +// Name: "WiFi101", +// }) +// +// if err != nil { +// log.Fatalf("Error uninstalling: %s", err) +// } +// +// for { +// uninstallResp, err := libUninstallRespStream.Recv() +// if err == io.EOF { +// log.Printf("Lib uninstall done") +// break +// } +// +// if err != nil { +// log.Fatalf("Uninstall error: %s", err) +// } +// +// if uninstallResp.GetTaskProgress() != nil { +// log.Printf("TASK: %s", uninstallResp.GetTaskProgress()) +// } +// } +//} diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go new file mode 100644 index 00000000000..5fad678c05c --- /dev/null +++ b/commands/daemon/debug.go @@ -0,0 +1,141 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package daemon + +import ( + "context" + "fmt" + cmd "github.com/arduino/arduino-cli/commands/debug" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "io" +) + +// DebugService implements the `Debug` service +type DebugService struct{} + +// StreamingOpen returns a stream response that can be used to fetch data from the +// Debug target. The first message passed through the `StreamingOpenReq` must +// contain Debug configuration params, not data. +func (s *DebugService) StreamingOpen(stream dbg.Debug_StreamingOpenServer) error { + + // grab the first message + msg, err := stream.Recv() + if err != nil { + return err + } + + // ensure it's a config message and not data + req := msg.GetDebugReq() + if req == nil { + return fmt.Errorf("first message must contain debug request, not data") + } + + // launch debug recipe attaching stdin and out to grpc streaming + cmd, err := cmd.Debug(context.Background(), req) + if err != nil { + return (err) + } + in, err := cmd.StdinPipe() + if err != nil { + return (err) + } + defer in.Close() + + out, err := cmd.StdoutPipe() + if err != nil { + return (err) + } + defer out.Close() + + err = cmd.Start() + if err != nil { + fmt.Println("%v\n", err) + return err + } + + // we'll use these channels to communicate with the goroutines + // handling the stream and the target respectively + streamClosed := make(chan error) + targetClosed := make(chan error) + + // now we can read the other commands and re-route to the Debug Client... + go func() { + for { + command, err := stream.Recv() + if err == io.EOF { + // stream was closed + streamClosed <- nil + break + } + + if err != nil { + // error reading from stream + streamClosed <- err + break + } + + if _, err := in.Write(command.GetData()); err != nil { + // error writing to target + targetClosed <- err + break + } + } + }() + + // ...and read from the Debug and forward to the output stream + go func() { + buf := make([]byte, 8) + for { + n, err := out.Read(buf) + if err != nil { + // error reading from target + targetClosed <- err + break + } + + if n == 0 { + // target was closed + targetClosed <- nil + break + } + + err = stream.Send(&dbg.StreamingOpenResp{ + Data: buf[:n], + }) + if err != nil { + // error sending to stream + streamClosed <- err + break + } + } + }() + + // let goroutines route messages from/to the Debug + // until either the client closes the stream or the + // Debug target is closed + for { + select { + case err := <-streamClosed: + fmt.Println("streamClosed") + cmd.Process.Kill() + cmd.Wait() + return err + case err := <-targetClosed: + fmt.Println("targetClosed") + return err + } + } +} diff --git a/commands/debug/debug.go b/commands/debug/debug.go new file mode 100644 index 00000000000..b6acbeb906c --- /dev/null +++ b/commands/debug/debug.go @@ -0,0 +1,181 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package debug + +import ( + "context" + "fmt" + "github.com/arduino/arduino-cli/arduino/cores" + "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/commands" + "github.com/arduino/arduino-cli/executils" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" + "github.com/sirupsen/logrus" + "os" + "os/exec" + "path/filepath" + "strings" +) + +// Debug FIXMEDOC +func Debug(ctx context.Context, req *dbg.DebugReq, in func(data []bytes), out func(data []bytes)) (*exec.Cmd, error) { + //logrus.Tracef("Debug %s on %s started", req.GetSketchPath(), req.GetFqbn()) + + //// TODO: make a generic function to extract sketch from request + // and remove duplication in commands/compile.go + if req.GetSketchPath() == "" { + return fmt.Errorf("missing sketchPath") + } + sketchPath := paths.New(req.GetSketchPath()) + sketch, err := sketches.NewSketchFromPath(sketchPath) + if err != nil { + return fmt.Errorf("opening sketch: %s", err) + } + + // FIXME: make a specification on how a port is specified via command line + port := req.GetPort() + if port == "" { + return fmt.Errorf("no upload port provided") + } + + fqbnIn := req.GetFqbn() + if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { + fqbnIn = sketch.Metadata.CPU.Fqbn + } + if fqbnIn == "" { + return fmt.Errorf("no Fully Qualified Board Name provided") + } + fqbn, err := cores.ParseFQBN(fqbnIn) + if err != nil { + return fmt.Errorf("incorrect FQBN: %s", err) + } + + pm := commands.GetPackageManager(req.GetInstance().GetId()) + + // Find target board and board properties + _, _, board, boardProperties, _, err := pm.ResolveFQBN(fqbn) + if err != nil { + return fmt.Errorf("incorrect FQBN: %s", err) + } + + // Load programmer tool + uploadToolPattern, have := boardProperties.GetOk("upload.tool") + if !have || uploadToolPattern == "" { + return fmt.Errorf("cannot get programmer tool: undefined 'upload.tool' property") + } + + var referencedPlatformRelease *cores.PlatformRelease + if split := strings.Split(uploadToolPattern, ":"); len(split) > 2 { + return fmt.Errorf("invalid 'upload.tool' property: %s", uploadToolPattern) + } else if len(split) == 2 { + referencedPackageName := split[0] + uploadToolPattern = split[1] + architecture := board.PlatformRelease.Platform.Architecture + + if referencedPackage := pm.Packages[referencedPackageName]; referencedPackage == nil { + return fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) + } else if referencedPlatform := referencedPackage.Platforms[architecture]; referencedPlatform == nil { + return fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) + } else { + referencedPlatformRelease = pm.GetInstalledPlatformRelease(referencedPlatform) + } + } + + // Build configuration for upload + uploadProperties := properties.NewMap() + if referencedPlatformRelease != nil { + uploadProperties.Merge(referencedPlatformRelease.Properties) + } + uploadProperties.Merge(board.PlatformRelease.Properties) + uploadProperties.Merge(board.PlatformRelease.RuntimeProperties()) + uploadProperties.Merge(boardProperties) + + uploadToolProperties := uploadProperties.SubTree("tools." + uploadToolPattern) + uploadProperties.Merge(uploadToolProperties) + + if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil { + for _, requiredTool := range requiredTools { + logrus.WithField("tool", requiredTool).Info("Tool required for upload") + uploadProperties.Merge(requiredTool.RuntimeProperties()) + } + } + + // Set properties for verbose upload + Verbose := req.GetVerbose() + if Verbose { + if v, ok := uploadProperties.GetOk("upload.params.verbose"); ok { + uploadProperties.Set("upload.verbose", v) + } + } else { + if v, ok := uploadProperties.GetOk("upload.params.quiet"); ok { + uploadProperties.Set("upload.verbose", v) + } + } + + // Set path to compiled binary + // Make the filename without the FQBN configs part + fqbn.Configs = properties.NewMap() + fqbnSuffix := strings.Replace(fqbn.String(), ":", ".", -1) + + var importPath *paths.Path + var importFile string + if req.GetImportFile() == "" { + importPath = sketch.FullPath + importFile = sketch.Name + "." + fqbnSuffix + } else { + importPath = paths.New(req.GetImportFile()).Parent() + importFile = paths.New(req.GetImportFile()).Base() + } + + outputTmpFile, ok := uploadProperties.GetOk("recipe.output.tmp_file") + outputTmpFile = uploadProperties.ExpandPropsInString(outputTmpFile) + if !ok { + return fmt.Errorf("property 'recipe.output.tmp_file' not defined") + } + ext := filepath.Ext(outputTmpFile) + if strings.HasSuffix(importFile, ext) { + importFile = importFile[:len(importFile)-len(ext)] + } + + uploadProperties.SetPath("build.path", importPath) + uploadProperties.Set("build.project_name", importFile) + uploadFile := importPath.Join(importFile + ext) + if _, err := uploadFile.Stat(); err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("compiled sketch %s not found", uploadFile.String()) + } + return fmt.Errorf("cannot open sketch: %s", err) + } + + // Build recipe for upload + recipe := uploadProperties.Get("upload.pattern") + cmdLine := uploadProperties.ExpandPropsInString(recipe) + cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false) + if err != nil { + return fmt.Errorf("invalid recipe '%s': %s", recipe, err) + } + + cmdArgs := []string{"gdb"} + // Run Tool + cmd, err := executils.Command(cmdArgs) + if err != nil { + return nil, fmt.Errorf("cannot execute upload tool: %s", err) + } + + return cmd, nil +} diff --git a/go.sum b/go.sum index db46a426af6..a07a80b85a8 100644 --- a/go.sum +++ b/go.sum @@ -184,6 +184,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/rpc/commands/commands.pb.go b/rpc/commands/commands.pb.go index 780bbed2f1e..59fe7937ed8 100644 --- a/rpc/commands/commands.pb.go +++ b/rpc/commands/commands.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -599,11 +597,11 @@ var fileDescriptor_3690061a1131852d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // ArduinoCoreClient is the client API for ArduinoCore service. // @@ -643,10 +641,10 @@ type ArduinoCoreClient interface { } type arduinoCoreClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewArduinoCoreClient(cc grpc.ClientConnInterface) ArduinoCoreClient { +func NewArduinoCoreClient(cc *grpc.ClientConn) ArduinoCoreClient { return &arduinoCoreClient{cc} } @@ -1232,86 +1230,6 @@ type ArduinoCoreServer interface { LibraryList(context.Context, *LibraryListReq) (*LibraryListResp, error) } -// UnimplementedArduinoCoreServer can be embedded to have forward compatible implementations. -type UnimplementedArduinoCoreServer struct { -} - -func (*UnimplementedArduinoCoreServer) Init(req *InitReq, srv ArduinoCore_InitServer) error { - return status.Errorf(codes.Unimplemented, "method Init not implemented") -} -func (*UnimplementedArduinoCoreServer) Destroy(ctx context.Context, req *DestroyReq) (*DestroyResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Destroy not implemented") -} -func (*UnimplementedArduinoCoreServer) Rescan(ctx context.Context, req *RescanReq) (*RescanResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Rescan not implemented") -} -func (*UnimplementedArduinoCoreServer) UpdateIndex(req *UpdateIndexReq, srv ArduinoCore_UpdateIndexServer) error { - return status.Errorf(codes.Unimplemented, "method UpdateIndex not implemented") -} -func (*UnimplementedArduinoCoreServer) UpdateLibrariesIndex(req *UpdateLibrariesIndexReq, srv ArduinoCore_UpdateLibrariesIndexServer) error { - return status.Errorf(codes.Unimplemented, "method UpdateLibrariesIndex not implemented") -} -func (*UnimplementedArduinoCoreServer) Version(ctx context.Context, req *VersionReq) (*VersionResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardDetails(ctx context.Context, req *BoardDetailsReq) (*BoardDetailsResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardDetails not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardAttach(req *BoardAttachReq, srv ArduinoCore_BoardAttachServer) error { - return status.Errorf(codes.Unimplemented, "method BoardAttach not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardList(ctx context.Context, req *BoardListReq) (*BoardListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardList not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardListAll(ctx context.Context, req *BoardListAllReq) (*BoardListAllResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardListAll not implemented") -} -func (*UnimplementedArduinoCoreServer) Compile(req *CompileReq, srv ArduinoCore_CompileServer) error { - return status.Errorf(codes.Unimplemented, "method Compile not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformInstall(req *PlatformInstallReq, srv ArduinoCore_PlatformInstallServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformInstall not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformDownload(req *PlatformDownloadReq, srv ArduinoCore_PlatformDownloadServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformDownload not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformUninstall(req *PlatformUninstallReq, srv ArduinoCore_PlatformUninstallServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformUninstall not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformUpgrade(req *PlatformUpgradeReq, srv ArduinoCore_PlatformUpgradeServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformUpgrade not implemented") -} -func (*UnimplementedArduinoCoreServer) Upload(req *UploadReq, srv ArduinoCore_UploadServer) error { - return status.Errorf(codes.Unimplemented, "method Upload not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformSearch(ctx context.Context, req *PlatformSearchReq) (*PlatformSearchResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlatformSearch not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformList(ctx context.Context, req *PlatformListReq) (*PlatformListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlatformList not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryDownload(req *LibraryDownloadReq, srv ArduinoCore_LibraryDownloadServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryDownload not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryInstall(req *LibraryInstallReq, srv ArduinoCore_LibraryInstallServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryInstall not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryUninstall(req *LibraryUninstallReq, srv ArduinoCore_LibraryUninstallServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryUninstall not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryUpgradeAll(req *LibraryUpgradeAllReq, srv ArduinoCore_LibraryUpgradeAllServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryUpgradeAll not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryResolveDependencies(ctx context.Context, req *LibraryResolveDependenciesReq) (*LibraryResolveDependenciesResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibraryResolveDependencies not implemented") -} -func (*UnimplementedArduinoCoreServer) LibrarySearch(ctx context.Context, req *LibrarySearchReq) (*LibrarySearchResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibrarySearch not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryList(ctx context.Context, req *LibraryListReq) (*LibraryListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibraryList not implemented") -} - func RegisterArduinoCoreServer(s *grpc.Server, srv ArduinoCoreServer) { s.RegisterService(&_ArduinoCore_serviceDesc, srv) } diff --git a/rpc/debug/debug.pb.go b/rpc/debug/debug.pb.go new file mode 100644 index 00000000000..176c7a7e6c7 --- /dev/null +++ b/rpc/debug/debug.pb.go @@ -0,0 +1,364 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: debug/debug.proto + +package commands + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// The top-level message sent by the client for the `StreamingOpen` method. +// Multiple `StreamingOpenReq` messages can be sent but the first message +// must contain a `DebugReq` message to initialize the debug session. +// All subsequent messages must contain bytes to be sent to the debug session +// and must not contain a `DebugReq` message. +type StreamingOpenReq struct { + // Content must be either a debug session config or data to be sent. + // + // Types that are valid to be assigned to Content: + // *StreamingOpenReq_DebugReq + // *StreamingOpenReq_Data + Content isStreamingOpenReq_Content `protobuf_oneof:"content"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StreamingOpenReq) Reset() { *m = StreamingOpenReq{} } +func (m *StreamingOpenReq) String() string { return proto.CompactTextString(m) } +func (*StreamingOpenReq) ProtoMessage() {} +func (*StreamingOpenReq) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{0} +} + +func (m *StreamingOpenReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StreamingOpenReq.Unmarshal(m, b) +} +func (m *StreamingOpenReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StreamingOpenReq.Marshal(b, m, deterministic) +} +func (m *StreamingOpenReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_StreamingOpenReq.Merge(m, src) +} +func (m *StreamingOpenReq) XXX_Size() int { + return xxx_messageInfo_StreamingOpenReq.Size(m) +} +func (m *StreamingOpenReq) XXX_DiscardUnknown() { + xxx_messageInfo_StreamingOpenReq.DiscardUnknown(m) +} + +var xxx_messageInfo_StreamingOpenReq proto.InternalMessageInfo + +type isStreamingOpenReq_Content interface { + isStreamingOpenReq_Content() +} + +type StreamingOpenReq_DebugReq struct { + DebugReq *DebugReq `protobuf:"bytes,1,opt,name=debugReq,proto3,oneof"` +} + +type StreamingOpenReq_Data struct { + Data []byte `protobuf:"bytes,2,opt,name=data,proto3,oneof"` +} + +func (*StreamingOpenReq_DebugReq) isStreamingOpenReq_Content() {} + +func (*StreamingOpenReq_Data) isStreamingOpenReq_Content() {} + +func (m *StreamingOpenReq) GetContent() isStreamingOpenReq_Content { + if m != nil { + return m.Content + } + return nil +} + +func (m *StreamingOpenReq) GetDebugReq() *DebugReq { + if x, ok := m.GetContent().(*StreamingOpenReq_DebugReq); ok { + return x.DebugReq + } + return nil +} + +func (m *StreamingOpenReq) GetData() []byte { + if x, ok := m.GetContent().(*StreamingOpenReq_Data); ok { + return x.Data + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*StreamingOpenReq) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*StreamingOpenReq_DebugReq)(nil), + (*StreamingOpenReq_Data)(nil), + } +} + +type DebugReq struct { + Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DebugReq) Reset() { *m = DebugReq{} } +func (m *DebugReq) String() string { return proto.CompactTextString(m) } +func (*DebugReq) ProtoMessage() {} +func (*DebugReq) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{1} +} + +func (m *DebugReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugReq.Unmarshal(m, b) +} +func (m *DebugReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugReq.Marshal(b, m, deterministic) +} +func (m *DebugReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugReq.Merge(m, src) +} +func (m *DebugReq) XXX_Size() int { + return xxx_messageInfo_DebugReq.Size(m) +} +func (m *DebugReq) XXX_DiscardUnknown() { + xxx_messageInfo_DebugReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DebugReq proto.InternalMessageInfo + +func (m *DebugReq) GetInstance() *Instance { + if m != nil { + return m.Instance + } + return nil +} + +// +type StreamingOpenResp struct { + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StreamingOpenResp) Reset() { *m = StreamingOpenResp{} } +func (m *StreamingOpenResp) String() string { return proto.CompactTextString(m) } +func (*StreamingOpenResp) ProtoMessage() {} +func (*StreamingOpenResp) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{2} +} + +func (m *StreamingOpenResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StreamingOpenResp.Unmarshal(m, b) +} +func (m *StreamingOpenResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StreamingOpenResp.Marshal(b, m, deterministic) +} +func (m *StreamingOpenResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_StreamingOpenResp.Merge(m, src) +} +func (m *StreamingOpenResp) XXX_Size() int { + return xxx_messageInfo_StreamingOpenResp.Size(m) +} +func (m *StreamingOpenResp) XXX_DiscardUnknown() { + xxx_messageInfo_StreamingOpenResp.DiscardUnknown(m) +} + +var xxx_messageInfo_StreamingOpenResp proto.InternalMessageInfo + +func (m *StreamingOpenResp) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +// duplicate from commands/common.proto +// as module imports seems not to work +type Instance struct { + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Instance) Reset() { *m = Instance{} } +func (m *Instance) String() string { return proto.CompactTextString(m) } +func (*Instance) ProtoMessage() {} +func (*Instance) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{3} +} + +func (m *Instance) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Instance.Unmarshal(m, b) +} +func (m *Instance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Instance.Marshal(b, m, deterministic) +} +func (m *Instance) XXX_Merge(src proto.Message) { + xxx_messageInfo_Instance.Merge(m, src) +} +func (m *Instance) XXX_Size() int { + return xxx_messageInfo_Instance.Size(m) +} +func (m *Instance) XXX_DiscardUnknown() { + xxx_messageInfo_Instance.DiscardUnknown(m) +} + +var xxx_messageInfo_Instance proto.InternalMessageInfo + +func (m *Instance) GetId() int32 { + if m != nil { + return m.Id + } + return 0 +} + +func init() { + proto.RegisterType((*StreamingOpenReq)(nil), "cc.arduino.cli.commands.StreamingOpenReq") + proto.RegisterType((*DebugReq)(nil), "cc.arduino.cli.commands.DebugReq") + proto.RegisterType((*StreamingOpenResp)(nil), "cc.arduino.cli.commands.StreamingOpenResp") + proto.RegisterType((*Instance)(nil), "cc.arduino.cli.commands.Instance") +} + +func init() { proto.RegisterFile("debug/debug.proto", fileDescriptor_5ae24eab94cb53d5) } + +var fileDescriptor_5ae24eab94cb53d5 = []byte{ + // 264 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xc1, 0x4b, 0xc3, 0x30, + 0x18, 0xc5, 0x9b, 0xe2, 0xb4, 0x7e, 0x4e, 0x71, 0x41, 0x70, 0xec, 0x34, 0x73, 0xb1, 0x2a, 0x4b, + 0x65, 0x9e, 0x45, 0x18, 0x1e, 0xb6, 0x93, 0x10, 0x6f, 0xde, 0xd2, 0x24, 0xd4, 0x40, 0x9b, 0x64, + 0x6d, 0xfa, 0xff, 0xcb, 0x62, 0x3b, 0x70, 0x50, 0xdc, 0x25, 0x21, 0xe4, 0xfd, 0xde, 0x7b, 0xc9, + 0x07, 0x13, 0xa9, 0xf2, 0xb6, 0xc8, 0xc2, 0x4a, 0x5d, 0x6d, 0xbd, 0xc5, 0xb7, 0x42, 0x50, 0x5e, + 0xcb, 0x56, 0x1b, 0x4b, 0x45, 0xa9, 0xa9, 0xb0, 0x55, 0xc5, 0x8d, 0x6c, 0x88, 0x87, 0xeb, 0x4f, + 0x5f, 0x2b, 0x5e, 0x69, 0x53, 0x7c, 0x38, 0x65, 0x98, 0xda, 0xe2, 0x37, 0x48, 0x02, 0xcb, 0xd4, + 0x76, 0x8a, 0xe6, 0x28, 0xbd, 0x58, 0xde, 0xd1, 0x01, 0x9e, 0xbe, 0x77, 0xc2, 0x75, 0xc4, 0xf6, + 0x10, 0xbe, 0x81, 0x13, 0xc9, 0x3d, 0x9f, 0xc6, 0x73, 0x94, 0x8e, 0xd7, 0x11, 0x0b, 0xa7, 0xd5, + 0x39, 0x9c, 0x09, 0x6b, 0xbc, 0x32, 0x9e, 0x6c, 0x20, 0xe9, 0x41, 0xfc, 0x0a, 0x89, 0x36, 0x8d, + 0xe7, 0x46, 0xa8, 0x7f, 0xd3, 0x36, 0x9d, 0x90, 0xed, 0x11, 0x72, 0x0f, 0x93, 0x83, 0x07, 0x34, + 0x0e, 0xe3, 0xae, 0xc0, 0xce, 0x6f, 0xfc, 0x1b, 0x4f, 0x66, 0x90, 0xf4, 0x38, 0xbe, 0x82, 0x58, + 0xcb, 0x70, 0x3b, 0x62, 0xb1, 0x96, 0xcb, 0x16, 0x46, 0xa1, 0x0f, 0x2e, 0xe1, 0xf2, 0x8f, 0x1b, + 0x7e, 0x18, 0xec, 0x72, 0xf8, 0x6d, 0xb3, 0xc7, 0x63, 0xa5, 0x8d, 0x23, 0x51, 0x8a, 0x9e, 0xd1, + 0x6a, 0xf1, 0xf5, 0x54, 0x68, 0xff, 0xdd, 0xe6, 0x3b, 0x69, 0xd6, 0xa1, 0xfd, 0xbe, 0x10, 0xa5, + 0xce, 0x6a, 0x27, 0xb2, 0xde, 0x26, 0x3f, 0x0d, 0xb3, 0x7c, 0xf9, 0x09, 0x00, 0x00, 0xff, 0xff, + 0xad, 0x8b, 0xed, 0xc4, 0xe0, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// DebugClient is the client API for Debug service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DebugClient interface { + StreamingOpen(ctx context.Context, opts ...grpc.CallOption) (Debug_StreamingOpenClient, error) +} + +type debugClient struct { + cc *grpc.ClientConn +} + +func NewDebugClient(cc *grpc.ClientConn) DebugClient { + return &debugClient{cc} +} + +func (c *debugClient) StreamingOpen(ctx context.Context, opts ...grpc.CallOption) (Debug_StreamingOpenClient, error) { + stream, err := c.cc.NewStream(ctx, &_Debug_serviceDesc.Streams[0], "/cc.arduino.cli.commands.Debug/StreamingOpen", opts...) + if err != nil { + return nil, err + } + x := &debugStreamingOpenClient{stream} + return x, nil +} + +type Debug_StreamingOpenClient interface { + Send(*StreamingOpenReq) error + Recv() (*StreamingOpenResp, error) + grpc.ClientStream +} + +type debugStreamingOpenClient struct { + grpc.ClientStream +} + +func (x *debugStreamingOpenClient) Send(m *StreamingOpenReq) error { + return x.ClientStream.SendMsg(m) +} + +func (x *debugStreamingOpenClient) Recv() (*StreamingOpenResp, error) { + m := new(StreamingOpenResp) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// DebugServer is the server API for Debug service. +type DebugServer interface { + StreamingOpen(Debug_StreamingOpenServer) error +} + +func RegisterDebugServer(s *grpc.Server, srv DebugServer) { + s.RegisterService(&_Debug_serviceDesc, srv) +} + +func _Debug_StreamingOpen_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(DebugServer).StreamingOpen(&debugStreamingOpenServer{stream}) +} + +type Debug_StreamingOpenServer interface { + Send(*StreamingOpenResp) error + Recv() (*StreamingOpenReq, error) + grpc.ServerStream +} + +type debugStreamingOpenServer struct { + grpc.ServerStream +} + +func (x *debugStreamingOpenServer) Send(m *StreamingOpenResp) error { + return x.ServerStream.SendMsg(m) +} + +func (x *debugStreamingOpenServer) Recv() (*StreamingOpenReq, error) { + m := new(StreamingOpenReq) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _Debug_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cc.arduino.cli.commands.Debug", + HandlerType: (*DebugServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "StreamingOpen", + Handler: _Debug_StreamingOpen_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "debug/debug.proto", +} diff --git a/rpc/debug/debug.proto b/rpc/debug/debug.proto new file mode 100644 index 00000000000..f3c5045cb6b --- /dev/null +++ b/rpc/debug/debug.proto @@ -0,0 +1,65 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +syntax = "proto3"; + +package cc.arduino.cli.commands; + +option go_package = "github.com/arduino/arduino-cli/rpc/commands"; + + +// Service that abstract a debug Session usage +service Debug { + rpc StreamingOpen (stream StreamingOpenReq) returns (stream StreamingOpenResp) { + } +} + +// The top-level message sent by the client for the `StreamingOpen` method. +// Multiple `StreamingOpenReq` messages can be sent but the first message +// must contain a `DebugReq` message to initialize the debug session. +// All subsequent messages must contain bytes to be sent to the debug session +// and must not contain a `DebugReq` message. +message StreamingOpenReq { + // Content must be either a debug session config or data to be sent. + oneof content { + // Provides information to the debug that specifies which is the target. + // The first `StreamingOpenReq` message must contain a `DebugReq` + // message. + DebugReq debugReq = 1; + + // The data to be sent to the target being monitored. + bytes data = 2; + } +} + +message DebugReq { + Instance instance = 1; +// string fqbn = 2; +// string sketch_path = 3; +// string port = 4; +// bool verbose = 5; +// bool verify = 6; +// string import_file = 7; +} + + +// +message StreamingOpenResp { + bytes data = 1; +} + +// duplicate from commands/common.proto +// as module imports seems not to work +message Instance { int32 id = 1; } diff --git a/rpc/monitor/monitor.pb.go b/rpc/monitor/monitor.pb.go index 1a06ba48521..78238c1565a 100644 --- a/rpc/monitor/monitor.pb.go +++ b/rpc/monitor/monitor.pb.go @@ -9,8 +9,6 @@ import ( proto "github.com/golang/protobuf/proto" _struct "github.com/golang/protobuf/ptypes/struct" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -268,11 +266,11 @@ var fileDescriptor_94d5950496a7550d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // MonitorClient is the client API for Monitor service. // @@ -282,10 +280,10 @@ type MonitorClient interface { } type monitorClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewMonitorClient(cc grpc.ClientConnInterface) MonitorClient { +func NewMonitorClient(cc *grpc.ClientConn) MonitorClient { return &monitorClient{cc} } @@ -325,14 +323,6 @@ type MonitorServer interface { StreamingOpen(Monitor_StreamingOpenServer) error } -// UnimplementedMonitorServer can be embedded to have forward compatible implementations. -type UnimplementedMonitorServer struct { -} - -func (*UnimplementedMonitorServer) StreamingOpen(srv Monitor_StreamingOpenServer) error { - return status.Errorf(codes.Unimplemented, "method StreamingOpen not implemented") -} - func RegisterMonitorServer(s *grpc.Server, srv MonitorServer) { s.RegisterService(&_Monitor_serviceDesc, srv) } diff --git a/rpc/settings/settings.pb.go b/rpc/settings/settings.pb.go index 0537c7d9e3a..1bbc54f255d 100644 --- a/rpc/settings/settings.pb.go +++ b/rpc/settings/settings.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -277,11 +275,11 @@ var fileDescriptor_a4bfd59e429426d0 = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // SettingsClient is the client API for Settings service. // @@ -294,10 +292,10 @@ type SettingsClient interface { } type settingsClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewSettingsClient(cc grpc.ClientConnInterface) SettingsClient { +func NewSettingsClient(cc *grpc.ClientConn) SettingsClient { return &settingsClient{cc} } @@ -345,23 +343,6 @@ type SettingsServer interface { SetValue(context.Context, *Value) (*SetValueResponse, error) } -// UnimplementedSettingsServer can be embedded to have forward compatible implementations. -type UnimplementedSettingsServer struct { -} - -func (*UnimplementedSettingsServer) GetAll(ctx context.Context, req *GetAllRequest) (*RawData, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetAll not implemented") -} -func (*UnimplementedSettingsServer) Merge(ctx context.Context, req *RawData) (*MergeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Merge not implemented") -} -func (*UnimplementedSettingsServer) GetValue(ctx context.Context, req *GetValueRequest) (*Value, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetValue not implemented") -} -func (*UnimplementedSettingsServer) SetValue(ctx context.Context, req *Value) (*SetValueResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method SetValue not implemented") -} - func RegisterSettingsServer(s *grpc.Server, srv SettingsServer) { s.RegisterService(&_Settings_serviceDesc, srv) } From 0119a907322cce05fbf243d2e072544017577ade Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 17 Feb 2020 15:43:17 +0100 Subject: [PATCH 02/29] Working stdio streaming --- client_example/main.go | 6 +- commands/daemon/debug.go | 98 +----------------- commands/debug/debug.go | 209 +++++++++++++-------------------------- 3 files changed, 75 insertions(+), 238 deletions(-) diff --git a/client_example/main.go b/client_example/main.go index 7a4ef534d17..06a5736c3ce 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -18,6 +18,7 @@ package main import ( "context" "fmt" + rpc "github.com/arduino/arduino-cli/rpc/commands" dbg "github.com/arduino/arduino-cli/rpc/debug" @@ -25,6 +26,7 @@ import ( "io/ioutil" "log" "os" + // "path" "path/filepath" "time" @@ -104,8 +106,8 @@ func main() { // When an operation is ongoing you can get its output if resp := compResp.GetData(); resp != nil { - fmt.Printf("%s", resp) - if string(resp) == " (gdb) " { + fmt.Printf(">>%s<<", resp) + if string(resp) == "(gdb) " { break } } diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go index 5fad678c05c..c1ff37dff5e 100644 --- a/commands/daemon/debug.go +++ b/commands/daemon/debug.go @@ -16,11 +16,10 @@ package daemon import ( - "context" "fmt" + cmd "github.com/arduino/arduino-cli/commands/debug" dbg "github.com/arduino/arduino-cli/rpc/debug" - "io" ) // DebugService implements the `Debug` service @@ -44,98 +43,11 @@ func (s *DebugService) StreamingOpen(stream dbg.Debug_StreamingOpenServer) error } // launch debug recipe attaching stdin and out to grpc streaming - cmd, err := cmd.Debug(context.Background(), req) - if err != nil { - return (err) - } - in, err := cmd.StdinPipe() + resp, err := cmd.Debug(stream.Context(), req, stream, feedStream(func(data []byte) { + stream.Send(&dbg.StreamingOpenResp{Data: data}) + })) if err != nil { return (err) } - defer in.Close() - - out, err := cmd.StdoutPipe() - if err != nil { - return (err) - } - defer out.Close() - - err = cmd.Start() - if err != nil { - fmt.Println("%v\n", err) - return err - } - - // we'll use these channels to communicate with the goroutines - // handling the stream and the target respectively - streamClosed := make(chan error) - targetClosed := make(chan error) - - // now we can read the other commands and re-route to the Debug Client... - go func() { - for { - command, err := stream.Recv() - if err == io.EOF { - // stream was closed - streamClosed <- nil - break - } - - if err != nil { - // error reading from stream - streamClosed <- err - break - } - - if _, err := in.Write(command.GetData()); err != nil { - // error writing to target - targetClosed <- err - break - } - } - }() - - // ...and read from the Debug and forward to the output stream - go func() { - buf := make([]byte, 8) - for { - n, err := out.Read(buf) - if err != nil { - // error reading from target - targetClosed <- err - break - } - - if n == 0 { - // target was closed - targetClosed <- nil - break - } - - err = stream.Send(&dbg.StreamingOpenResp{ - Data: buf[:n], - }) - if err != nil { - // error sending to stream - streamClosed <- err - break - } - } - }() - - // let goroutines route messages from/to the Debug - // until either the client closes the stream or the - // Debug target is closed - for { - select { - case err := <-streamClosed: - fmt.Println("streamClosed") - cmd.Process.Kill() - cmd.Wait() - return err - case err := <-targetClosed: - fmt.Println("targetClosed") - return err - } - } + return stream.Send(resp) } diff --git a/commands/debug/debug.go b/commands/debug/debug.go index b6acbeb906c..abd137a24ac 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -18,164 +18,87 @@ package debug import ( "context" "fmt" - "github.com/arduino/arduino-cli/arduino/cores" - "github.com/arduino/arduino-cli/arduino/sketches" - "github.com/arduino/arduino-cli/commands" + "io" + "github.com/arduino/arduino-cli/executils" dbg "github.com/arduino/arduino-cli/rpc/debug" - "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" - "github.com/sirupsen/logrus" - "os" - "os/exec" - "path/filepath" - "strings" ) // Debug FIXMEDOC -func Debug(ctx context.Context, req *dbg.DebugReq, in func(data []bytes), out func(data []bytes)) (*exec.Cmd, error) { - //logrus.Tracef("Debug %s on %s started", req.GetSketchPath(), req.GetFqbn()) - - //// TODO: make a generic function to extract sketch from request - // and remove duplication in commands/compile.go - if req.GetSketchPath() == "" { - return fmt.Errorf("missing sketchPath") - } - sketchPath := paths.New(req.GetSketchPath()) - sketch, err := sketches.NewSketchFromPath(sketchPath) +func Debug(ctx context.Context, req *dbg.DebugReq, inStream dbg.Debug_StreamingOpenServer, out io.Writer) (*dbg.StreamingOpenResp, error) { + cmdArgs := []string{"gdb"} + // Run Tool + cmd, err := executils.Command(cmdArgs) if err != nil { - return fmt.Errorf("opening sketch: %s", err) - } - - // FIXME: make a specification on how a port is specified via command line - port := req.GetPort() - if port == "" { - return fmt.Errorf("no upload port provided") + return nil, fmt.Errorf("cannot execute upload tool: %s", err) } - fqbnIn := req.GetFqbn() - if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { - fqbnIn = sketch.Metadata.CPU.Fqbn - } - if fqbnIn == "" { - return fmt.Errorf("no Fully Qualified Board Name provided") - } - fqbn, err := cores.ParseFQBN(fqbnIn) + in, err := cmd.StdinPipe() if err != nil { - return fmt.Errorf("incorrect FQBN: %s", err) + fmt.Println("%v\n", err) + return &dbg.StreamingOpenResp{}, nil // TODO: send error in response } + defer in.Close() - pm := commands.GetPackageManager(req.GetInstance().GetId()) + cmd.Stdout = out - // Find target board and board properties - _, _, board, boardProperties, _, err := pm.ResolveFQBN(fqbn) + err = cmd.Start() if err != nil { - return fmt.Errorf("incorrect FQBN: %s", err) - } - - // Load programmer tool - uploadToolPattern, have := boardProperties.GetOk("upload.tool") - if !have || uploadToolPattern == "" { - return fmt.Errorf("cannot get programmer tool: undefined 'upload.tool' property") - } - - var referencedPlatformRelease *cores.PlatformRelease - if split := strings.Split(uploadToolPattern, ":"); len(split) > 2 { - return fmt.Errorf("invalid 'upload.tool' property: %s", uploadToolPattern) - } else if len(split) == 2 { - referencedPackageName := split[0] - uploadToolPattern = split[1] - architecture := board.PlatformRelease.Platform.Architecture - - if referencedPackage := pm.Packages[referencedPackageName]; referencedPackage == nil { - return fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) - } else if referencedPlatform := referencedPackage.Platforms[architecture]; referencedPlatform == nil { - return fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) - } else { - referencedPlatformRelease = pm.GetInstalledPlatformRelease(referencedPlatform) - } - } - - // Build configuration for upload - uploadProperties := properties.NewMap() - if referencedPlatformRelease != nil { - uploadProperties.Merge(referencedPlatformRelease.Properties) - } - uploadProperties.Merge(board.PlatformRelease.Properties) - uploadProperties.Merge(board.PlatformRelease.RuntimeProperties()) - uploadProperties.Merge(boardProperties) - - uploadToolProperties := uploadProperties.SubTree("tools." + uploadToolPattern) - uploadProperties.Merge(uploadToolProperties) - - if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil { - for _, requiredTool := range requiredTools { - logrus.WithField("tool", requiredTool).Info("Tool required for upload") - uploadProperties.Merge(requiredTool.RuntimeProperties()) + fmt.Println("%v\n", err) + return &dbg.StreamingOpenResp{}, nil // TODO: send error in response + } + + // we'll use these channels to communicate with the goroutines + // handling the stream and the target respectively + streamClosed := make(chan error) + targetClosed := make(chan error) + defer close(streamClosed) + defer close(targetClosed) + + // now we can read the other commands and re-route to the Debug Client... + go func() { + for { + command, err := inStream.Recv() + if err == io.EOF { + // stream was closed + streamClosed <- nil + break + } + + if err != nil { + // error reading from stream + streamClosed <- err + break + } + + if _, err := in.Write(command.GetData()); err != nil { + // error writing to target + targetClosed <- err + break + } } - } - - // Set properties for verbose upload - Verbose := req.GetVerbose() - if Verbose { - if v, ok := uploadProperties.GetOk("upload.params.verbose"); ok { - uploadProperties.Set("upload.verbose", v) - } - } else { - if v, ok := uploadProperties.GetOk("upload.params.quiet"); ok { - uploadProperties.Set("upload.verbose", v) - } - } - - // Set path to compiled binary - // Make the filename without the FQBN configs part - fqbn.Configs = properties.NewMap() - fqbnSuffix := strings.Replace(fqbn.String(), ":", ".", -1) - - var importPath *paths.Path - var importFile string - if req.GetImportFile() == "" { - importPath = sketch.FullPath - importFile = sketch.Name + "." + fqbnSuffix - } else { - importPath = paths.New(req.GetImportFile()).Parent() - importFile = paths.New(req.GetImportFile()).Base() - } - - outputTmpFile, ok := uploadProperties.GetOk("recipe.output.tmp_file") - outputTmpFile = uploadProperties.ExpandPropsInString(outputTmpFile) - if !ok { - return fmt.Errorf("property 'recipe.output.tmp_file' not defined") - } - ext := filepath.Ext(outputTmpFile) - if strings.HasSuffix(importFile, ext) { - importFile = importFile[:len(importFile)-len(ext)] - } - - uploadProperties.SetPath("build.path", importPath) - uploadProperties.Set("build.project_name", importFile) - uploadFile := importPath.Join(importFile + ext) - if _, err := uploadFile.Stat(); err != nil { - if os.IsNotExist(err) { - return fmt.Errorf("compiled sketch %s not found", uploadFile.String()) + }() + + // let goroutines route messages from/to the Debug + // until either the client closes the stream or the + // Debug target is closed + for { + select { + case <-ctx.Done(): + cmd.Process.Kill() + cmd.Wait() + case err := <-streamClosed: + fmt.Println("streamClosed") + cmd.Process.Kill() + cmd.Wait() + return &dbg.StreamingOpenResp{}, err // TODO: send error in response + case err := <-targetClosed: + fmt.Println("targetClosed") + cmd.Process.Kill() + cmd.Wait() + return &dbg.StreamingOpenResp{}, err // TODO: send error in response } - return fmt.Errorf("cannot open sketch: %s", err) - } - - // Build recipe for upload - recipe := uploadProperties.Get("upload.pattern") - cmdLine := uploadProperties.ExpandPropsInString(recipe) - cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false) - if err != nil { - return fmt.Errorf("invalid recipe '%s': %s", recipe, err) - } - - cmdArgs := []string{"gdb"} - // Run Tool - cmd, err := executils.Command(cmdArgs) - if err != nil { - return nil, fmt.Errorf("cannot execute upload tool: %s", err) } - return cmd, nil + return &dbg.StreamingOpenResp{}, nil } From a106a4f1c95c7265dee8e84ac4647c61a0403d4e Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 17 Feb 2020 16:02:57 +0100 Subject: [PATCH 03/29] Improved stdio passing via GRPC --- commands/debug/debug.go | 53 +++++++---------------------------------- 1 file changed, 8 insertions(+), 45 deletions(-) diff --git a/commands/debug/debug.go b/commands/debug/debug.go index abd137a24ac..ee4cc15bc13 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -19,6 +19,7 @@ import ( "context" "fmt" "io" + "time" "github.com/arduino/arduino-cli/executils" dbg "github.com/arduino/arduino-cli/rpc/debug" @@ -35,7 +36,7 @@ func Debug(ctx context.Context, req *dbg.DebugReq, inStream dbg.Debug_StreamingO in, err := cmd.StdinPipe() if err != nil { - fmt.Println("%v\n", err) + fmt.Printf("%v\n", err) return &dbg.StreamingOpenResp{}, nil // TODO: send error in response } defer in.Close() @@ -44,61 +45,23 @@ func Debug(ctx context.Context, req *dbg.DebugReq, inStream dbg.Debug_StreamingO err = cmd.Start() if err != nil { - fmt.Println("%v\n", err) + fmt.Printf("%v\n", err) return &dbg.StreamingOpenResp{}, nil // TODO: send error in response } - // we'll use these channels to communicate with the goroutines - // handling the stream and the target respectively - streamClosed := make(chan error) - targetClosed := make(chan error) - defer close(streamClosed) - defer close(targetClosed) - // now we can read the other commands and re-route to the Debug Client... go func() { for { - command, err := inStream.Recv() - if err == io.EOF { - // stream was closed - streamClosed <- nil + if command, err := inStream.Recv(); err != nil { break - } - - if err != nil { - // error reading from stream - streamClosed <- err - break - } - - if _, err := in.Write(command.GetData()); err != nil { - // error writing to target - targetClosed <- err + } else if _, err := in.Write(command.GetData()); err != nil { break } } + time.Sleep(time.Second) + cmd.Process.Kill() }() - // let goroutines route messages from/to the Debug - // until either the client closes the stream or the - // Debug target is closed - for { - select { - case <-ctx.Done(): - cmd.Process.Kill() - cmd.Wait() - case err := <-streamClosed: - fmt.Println("streamClosed") - cmd.Process.Kill() - cmd.Wait() - return &dbg.StreamingOpenResp{}, err // TODO: send error in response - case err := <-targetClosed: - fmt.Println("targetClosed") - cmd.Process.Kill() - cmd.Wait() - return &dbg.StreamingOpenResp{}, err // TODO: send error in response - } - } - + err = cmd.Wait() // TODO: handle err return &dbg.StreamingOpenResp{}, nil } From b16874d449ebc6c94621fe996bd56b83efd745aa Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 17 Feb 2020 16:10:57 +0100 Subject: [PATCH 04/29] Adjusted protoc definitions --- commands/daemon/debug.go | 10 +- commands/debug/debug.go | 8 +- rpc/commands/commands.pb.go | 90 ++++++++++++- rpc/debug/debug.pb.go | 262 +++++++++++++++++++----------------- rpc/debug/debug.proto | 16 +-- rpc/monitor/monitor.pb.go | 18 ++- rpc/settings/settings.pb.go | 27 +++- 7 files changed, 280 insertions(+), 151 deletions(-) diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go index c1ff37dff5e..0955ff300a9 100644 --- a/commands/daemon/debug.go +++ b/commands/daemon/debug.go @@ -25,10 +25,10 @@ import ( // DebugService implements the `Debug` service type DebugService struct{} -// StreamingOpen returns a stream response that can be used to fetch data from the -// Debug target. The first message passed through the `StreamingOpenReq` must -// contain Debug configuration params, not data. -func (s *DebugService) StreamingOpen(stream dbg.Debug_StreamingOpenServer) error { +// Debug returns a stream response that can be used to fetch data from the +// target. The first message passed through the `Debug` request must +// contain DebugConfigReq configuration params, not data. +func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { // grab the first message msg, err := stream.Recv() @@ -44,7 +44,7 @@ func (s *DebugService) StreamingOpen(stream dbg.Debug_StreamingOpenServer) error // launch debug recipe attaching stdin and out to grpc streaming resp, err := cmd.Debug(stream.Context(), req, stream, feedStream(func(data []byte) { - stream.Send(&dbg.StreamingOpenResp{Data: data}) + stream.Send(&dbg.DebugResp{Data: data}) })) if err != nil { return (err) diff --git a/commands/debug/debug.go b/commands/debug/debug.go index ee4cc15bc13..6a33b44afcf 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -26,7 +26,7 @@ import ( ) // Debug FIXMEDOC -func Debug(ctx context.Context, req *dbg.DebugReq, inStream dbg.Debug_StreamingOpenServer, out io.Writer) (*dbg.StreamingOpenResp, error) { +func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_DebugServer, out io.Writer) (*dbg.DebugResp, error) { cmdArgs := []string{"gdb"} // Run Tool cmd, err := executils.Command(cmdArgs) @@ -37,7 +37,7 @@ func Debug(ctx context.Context, req *dbg.DebugReq, inStream dbg.Debug_StreamingO in, err := cmd.StdinPipe() if err != nil { fmt.Printf("%v\n", err) - return &dbg.StreamingOpenResp{}, nil // TODO: send error in response + return &dbg.DebugResp{}, nil // TODO: send error in response } defer in.Close() @@ -46,7 +46,7 @@ func Debug(ctx context.Context, req *dbg.DebugReq, inStream dbg.Debug_StreamingO err = cmd.Start() if err != nil { fmt.Printf("%v\n", err) - return &dbg.StreamingOpenResp{}, nil // TODO: send error in response + return &dbg.DebugResp{}, nil // TODO: send error in response } // now we can read the other commands and re-route to the Debug Client... @@ -63,5 +63,5 @@ func Debug(ctx context.Context, req *dbg.DebugReq, inStream dbg.Debug_StreamingO }() err = cmd.Wait() // TODO: handle err - return &dbg.StreamingOpenResp{}, nil + return &dbg.DebugResp{}, nil } diff --git a/rpc/commands/commands.pb.go b/rpc/commands/commands.pb.go index 59fe7937ed8..780bbed2f1e 100644 --- a/rpc/commands/commands.pb.go +++ b/rpc/commands/commands.pb.go @@ -8,6 +8,8 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" math "math" ) @@ -597,11 +599,11 @@ var fileDescriptor_3690061a1131852d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // ArduinoCoreClient is the client API for ArduinoCore service. // @@ -641,10 +643,10 @@ type ArduinoCoreClient interface { } type arduinoCoreClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewArduinoCoreClient(cc *grpc.ClientConn) ArduinoCoreClient { +func NewArduinoCoreClient(cc grpc.ClientConnInterface) ArduinoCoreClient { return &arduinoCoreClient{cc} } @@ -1230,6 +1232,86 @@ type ArduinoCoreServer interface { LibraryList(context.Context, *LibraryListReq) (*LibraryListResp, error) } +// UnimplementedArduinoCoreServer can be embedded to have forward compatible implementations. +type UnimplementedArduinoCoreServer struct { +} + +func (*UnimplementedArduinoCoreServer) Init(req *InitReq, srv ArduinoCore_InitServer) error { + return status.Errorf(codes.Unimplemented, "method Init not implemented") +} +func (*UnimplementedArduinoCoreServer) Destroy(ctx context.Context, req *DestroyReq) (*DestroyResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Destroy not implemented") +} +func (*UnimplementedArduinoCoreServer) Rescan(ctx context.Context, req *RescanReq) (*RescanResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Rescan not implemented") +} +func (*UnimplementedArduinoCoreServer) UpdateIndex(req *UpdateIndexReq, srv ArduinoCore_UpdateIndexServer) error { + return status.Errorf(codes.Unimplemented, "method UpdateIndex not implemented") +} +func (*UnimplementedArduinoCoreServer) UpdateLibrariesIndex(req *UpdateLibrariesIndexReq, srv ArduinoCore_UpdateLibrariesIndexServer) error { + return status.Errorf(codes.Unimplemented, "method UpdateLibrariesIndex not implemented") +} +func (*UnimplementedArduinoCoreServer) Version(ctx context.Context, req *VersionReq) (*VersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") +} +func (*UnimplementedArduinoCoreServer) BoardDetails(ctx context.Context, req *BoardDetailsReq) (*BoardDetailsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BoardDetails not implemented") +} +func (*UnimplementedArduinoCoreServer) BoardAttach(req *BoardAttachReq, srv ArduinoCore_BoardAttachServer) error { + return status.Errorf(codes.Unimplemented, "method BoardAttach not implemented") +} +func (*UnimplementedArduinoCoreServer) BoardList(ctx context.Context, req *BoardListReq) (*BoardListResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BoardList not implemented") +} +func (*UnimplementedArduinoCoreServer) BoardListAll(ctx context.Context, req *BoardListAllReq) (*BoardListAllResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BoardListAll not implemented") +} +func (*UnimplementedArduinoCoreServer) Compile(req *CompileReq, srv ArduinoCore_CompileServer) error { + return status.Errorf(codes.Unimplemented, "method Compile not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformInstall(req *PlatformInstallReq, srv ArduinoCore_PlatformInstallServer) error { + return status.Errorf(codes.Unimplemented, "method PlatformInstall not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformDownload(req *PlatformDownloadReq, srv ArduinoCore_PlatformDownloadServer) error { + return status.Errorf(codes.Unimplemented, "method PlatformDownload not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformUninstall(req *PlatformUninstallReq, srv ArduinoCore_PlatformUninstallServer) error { + return status.Errorf(codes.Unimplemented, "method PlatformUninstall not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformUpgrade(req *PlatformUpgradeReq, srv ArduinoCore_PlatformUpgradeServer) error { + return status.Errorf(codes.Unimplemented, "method PlatformUpgrade not implemented") +} +func (*UnimplementedArduinoCoreServer) Upload(req *UploadReq, srv ArduinoCore_UploadServer) error { + return status.Errorf(codes.Unimplemented, "method Upload not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformSearch(ctx context.Context, req *PlatformSearchReq) (*PlatformSearchResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PlatformSearch not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformList(ctx context.Context, req *PlatformListReq) (*PlatformListResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PlatformList not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryDownload(req *LibraryDownloadReq, srv ArduinoCore_LibraryDownloadServer) error { + return status.Errorf(codes.Unimplemented, "method LibraryDownload not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryInstall(req *LibraryInstallReq, srv ArduinoCore_LibraryInstallServer) error { + return status.Errorf(codes.Unimplemented, "method LibraryInstall not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryUninstall(req *LibraryUninstallReq, srv ArduinoCore_LibraryUninstallServer) error { + return status.Errorf(codes.Unimplemented, "method LibraryUninstall not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryUpgradeAll(req *LibraryUpgradeAllReq, srv ArduinoCore_LibraryUpgradeAllServer) error { + return status.Errorf(codes.Unimplemented, "method LibraryUpgradeAll not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryResolveDependencies(ctx context.Context, req *LibraryResolveDependenciesReq) (*LibraryResolveDependenciesResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method LibraryResolveDependencies not implemented") +} +func (*UnimplementedArduinoCoreServer) LibrarySearch(ctx context.Context, req *LibrarySearchReq) (*LibrarySearchResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method LibrarySearch not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryList(ctx context.Context, req *LibraryListReq) (*LibraryListResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method LibraryList not implemented") +} + func RegisterArduinoCoreServer(s *grpc.Server, srv ArduinoCoreServer) { s.RegisterService(&_ArduinoCore_serviceDesc, srv) } diff --git a/rpc/debug/debug.pb.go b/rpc/debug/debug.pb.go index 176c7a7e6c7..c7057afe8d1 100644 --- a/rpc/debug/debug.pb.go +++ b/rpc/debug/debug.pb.go @@ -8,6 +8,8 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" math "math" ) @@ -22,126 +24,126 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package -// The top-level message sent by the client for the `StreamingOpen` method. -// Multiple `StreamingOpenReq` messages can be sent but the first message +// The top-level message sent by the client for the `Debug` method. +// Multiple `DebugReq` messages can be sent but the first message // must contain a `DebugReq` message to initialize the debug session. // All subsequent messages must contain bytes to be sent to the debug session // and must not contain a `DebugReq` message. -type StreamingOpenReq struct { +type DebugReq struct { // Content must be either a debug session config or data to be sent. // // Types that are valid to be assigned to Content: - // *StreamingOpenReq_DebugReq - // *StreamingOpenReq_Data - Content isStreamingOpenReq_Content `protobuf_oneof:"content"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *StreamingOpenReq) Reset() { *m = StreamingOpenReq{} } -func (m *StreamingOpenReq) String() string { return proto.CompactTextString(m) } -func (*StreamingOpenReq) ProtoMessage() {} -func (*StreamingOpenReq) Descriptor() ([]byte, []int) { + // *DebugReq_DebugReq + // *DebugReq_Data + Content isDebugReq_Content `protobuf_oneof:"content"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DebugReq) Reset() { *m = DebugReq{} } +func (m *DebugReq) String() string { return proto.CompactTextString(m) } +func (*DebugReq) ProtoMessage() {} +func (*DebugReq) Descriptor() ([]byte, []int) { return fileDescriptor_5ae24eab94cb53d5, []int{0} } -func (m *StreamingOpenReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StreamingOpenReq.Unmarshal(m, b) +func (m *DebugReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugReq.Unmarshal(m, b) } -func (m *StreamingOpenReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StreamingOpenReq.Marshal(b, m, deterministic) +func (m *DebugReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugReq.Marshal(b, m, deterministic) } -func (m *StreamingOpenReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_StreamingOpenReq.Merge(m, src) +func (m *DebugReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugReq.Merge(m, src) } -func (m *StreamingOpenReq) XXX_Size() int { - return xxx_messageInfo_StreamingOpenReq.Size(m) +func (m *DebugReq) XXX_Size() int { + return xxx_messageInfo_DebugReq.Size(m) } -func (m *StreamingOpenReq) XXX_DiscardUnknown() { - xxx_messageInfo_StreamingOpenReq.DiscardUnknown(m) +func (m *DebugReq) XXX_DiscardUnknown() { + xxx_messageInfo_DebugReq.DiscardUnknown(m) } -var xxx_messageInfo_StreamingOpenReq proto.InternalMessageInfo +var xxx_messageInfo_DebugReq proto.InternalMessageInfo -type isStreamingOpenReq_Content interface { - isStreamingOpenReq_Content() +type isDebugReq_Content interface { + isDebugReq_Content() } -type StreamingOpenReq_DebugReq struct { - DebugReq *DebugReq `protobuf:"bytes,1,opt,name=debugReq,proto3,oneof"` +type DebugReq_DebugReq struct { + DebugReq *DebugConfigReq `protobuf:"bytes,1,opt,name=debugReq,proto3,oneof"` } -type StreamingOpenReq_Data struct { +type DebugReq_Data struct { Data []byte `protobuf:"bytes,2,opt,name=data,proto3,oneof"` } -func (*StreamingOpenReq_DebugReq) isStreamingOpenReq_Content() {} +func (*DebugReq_DebugReq) isDebugReq_Content() {} -func (*StreamingOpenReq_Data) isStreamingOpenReq_Content() {} +func (*DebugReq_Data) isDebugReq_Content() {} -func (m *StreamingOpenReq) GetContent() isStreamingOpenReq_Content { +func (m *DebugReq) GetContent() isDebugReq_Content { if m != nil { return m.Content } return nil } -func (m *StreamingOpenReq) GetDebugReq() *DebugReq { - if x, ok := m.GetContent().(*StreamingOpenReq_DebugReq); ok { +func (m *DebugReq) GetDebugReq() *DebugConfigReq { + if x, ok := m.GetContent().(*DebugReq_DebugReq); ok { return x.DebugReq } return nil } -func (m *StreamingOpenReq) GetData() []byte { - if x, ok := m.GetContent().(*StreamingOpenReq_Data); ok { +func (m *DebugReq) GetData() []byte { + if x, ok := m.GetContent().(*DebugReq_Data); ok { return x.Data } return nil } // XXX_OneofWrappers is for the internal use of the proto package. -func (*StreamingOpenReq) XXX_OneofWrappers() []interface{} { +func (*DebugReq) XXX_OneofWrappers() []interface{} { return []interface{}{ - (*StreamingOpenReq_DebugReq)(nil), - (*StreamingOpenReq_Data)(nil), + (*DebugReq_DebugReq)(nil), + (*DebugReq_Data)(nil), } } -type DebugReq struct { +type DebugConfigReq struct { Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *DebugReq) Reset() { *m = DebugReq{} } -func (m *DebugReq) String() string { return proto.CompactTextString(m) } -func (*DebugReq) ProtoMessage() {} -func (*DebugReq) Descriptor() ([]byte, []int) { +func (m *DebugConfigReq) Reset() { *m = DebugConfigReq{} } +func (m *DebugConfigReq) String() string { return proto.CompactTextString(m) } +func (*DebugConfigReq) ProtoMessage() {} +func (*DebugConfigReq) Descriptor() ([]byte, []int) { return fileDescriptor_5ae24eab94cb53d5, []int{1} } -func (m *DebugReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DebugReq.Unmarshal(m, b) +func (m *DebugConfigReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugConfigReq.Unmarshal(m, b) } -func (m *DebugReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DebugReq.Marshal(b, m, deterministic) +func (m *DebugConfigReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugConfigReq.Marshal(b, m, deterministic) } -func (m *DebugReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_DebugReq.Merge(m, src) +func (m *DebugConfigReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugConfigReq.Merge(m, src) } -func (m *DebugReq) XXX_Size() int { - return xxx_messageInfo_DebugReq.Size(m) +func (m *DebugConfigReq) XXX_Size() int { + return xxx_messageInfo_DebugConfigReq.Size(m) } -func (m *DebugReq) XXX_DiscardUnknown() { - xxx_messageInfo_DebugReq.DiscardUnknown(m) +func (m *DebugConfigReq) XXX_DiscardUnknown() { + xxx_messageInfo_DebugConfigReq.DiscardUnknown(m) } -var xxx_messageInfo_DebugReq proto.InternalMessageInfo +var xxx_messageInfo_DebugConfigReq proto.InternalMessageInfo -func (m *DebugReq) GetInstance() *Instance { +func (m *DebugConfigReq) GetInstance() *Instance { if m != nil { return m.Instance } @@ -149,45 +151,53 @@ func (m *DebugReq) GetInstance() *Instance { } // -type StreamingOpenResp struct { +type DebugResp struct { Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *StreamingOpenResp) Reset() { *m = StreamingOpenResp{} } -func (m *StreamingOpenResp) String() string { return proto.CompactTextString(m) } -func (*StreamingOpenResp) ProtoMessage() {} -func (*StreamingOpenResp) Descriptor() ([]byte, []int) { +func (m *DebugResp) Reset() { *m = DebugResp{} } +func (m *DebugResp) String() string { return proto.CompactTextString(m) } +func (*DebugResp) ProtoMessage() {} +func (*DebugResp) Descriptor() ([]byte, []int) { return fileDescriptor_5ae24eab94cb53d5, []int{2} } -func (m *StreamingOpenResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StreamingOpenResp.Unmarshal(m, b) +func (m *DebugResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugResp.Unmarshal(m, b) } -func (m *StreamingOpenResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StreamingOpenResp.Marshal(b, m, deterministic) +func (m *DebugResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugResp.Marshal(b, m, deterministic) } -func (m *StreamingOpenResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_StreamingOpenResp.Merge(m, src) +func (m *DebugResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugResp.Merge(m, src) } -func (m *StreamingOpenResp) XXX_Size() int { - return xxx_messageInfo_StreamingOpenResp.Size(m) +func (m *DebugResp) XXX_Size() int { + return xxx_messageInfo_DebugResp.Size(m) } -func (m *StreamingOpenResp) XXX_DiscardUnknown() { - xxx_messageInfo_StreamingOpenResp.DiscardUnknown(m) +func (m *DebugResp) XXX_DiscardUnknown() { + xxx_messageInfo_DebugResp.DiscardUnknown(m) } -var xxx_messageInfo_StreamingOpenResp proto.InternalMessageInfo +var xxx_messageInfo_DebugResp proto.InternalMessageInfo -func (m *StreamingOpenResp) GetData() []byte { +func (m *DebugResp) GetData() []byte { if m != nil { return m.Data } return nil } +func (m *DebugResp) GetError() string { + if m != nil { + return m.Error + } + return "" +} + // duplicate from commands/common.proto // as module imports seems not to work type Instance struct { @@ -230,83 +240,83 @@ func (m *Instance) GetId() int32 { } func init() { - proto.RegisterType((*StreamingOpenReq)(nil), "cc.arduino.cli.commands.StreamingOpenReq") proto.RegisterType((*DebugReq)(nil), "cc.arduino.cli.commands.DebugReq") - proto.RegisterType((*StreamingOpenResp)(nil), "cc.arduino.cli.commands.StreamingOpenResp") + proto.RegisterType((*DebugConfigReq)(nil), "cc.arduino.cli.commands.DebugConfigReq") + proto.RegisterType((*DebugResp)(nil), "cc.arduino.cli.commands.DebugResp") proto.RegisterType((*Instance)(nil), "cc.arduino.cli.commands.Instance") } func init() { proto.RegisterFile("debug/debug.proto", fileDescriptor_5ae24eab94cb53d5) } var fileDescriptor_5ae24eab94cb53d5 = []byte{ - // 264 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xc1, 0x4b, 0xc3, 0x30, - 0x18, 0xc5, 0x9b, 0xe2, 0xb4, 0x7e, 0x4e, 0x71, 0x41, 0x70, 0xec, 0x34, 0x73, 0xb1, 0x2a, 0x4b, - 0x65, 0x9e, 0x45, 0x18, 0x1e, 0xb6, 0x93, 0x10, 0x6f, 0xde, 0xd2, 0x24, 0xd4, 0x40, 0x9b, 0x64, - 0x6d, 0xfa, 0xff, 0xcb, 0x62, 0x3b, 0x70, 0x50, 0xdc, 0x25, 0x21, 0xe4, 0xfd, 0xde, 0x7b, 0xc9, - 0x07, 0x13, 0xa9, 0xf2, 0xb6, 0xc8, 0xc2, 0x4a, 0x5d, 0x6d, 0xbd, 0xc5, 0xb7, 0x42, 0x50, 0x5e, - 0xcb, 0x56, 0x1b, 0x4b, 0x45, 0xa9, 0xa9, 0xb0, 0x55, 0xc5, 0x8d, 0x6c, 0x88, 0x87, 0xeb, 0x4f, - 0x5f, 0x2b, 0x5e, 0x69, 0x53, 0x7c, 0x38, 0x65, 0x98, 0xda, 0xe2, 0x37, 0x48, 0x02, 0xcb, 0xd4, - 0x76, 0x8a, 0xe6, 0x28, 0xbd, 0x58, 0xde, 0xd1, 0x01, 0x9e, 0xbe, 0x77, 0xc2, 0x75, 0xc4, 0xf6, - 0x10, 0xbe, 0x81, 0x13, 0xc9, 0x3d, 0x9f, 0xc6, 0x73, 0x94, 0x8e, 0xd7, 0x11, 0x0b, 0xa7, 0xd5, - 0x39, 0x9c, 0x09, 0x6b, 0xbc, 0x32, 0x9e, 0x6c, 0x20, 0xe9, 0x41, 0xfc, 0x0a, 0x89, 0x36, 0x8d, - 0xe7, 0x46, 0xa8, 0x7f, 0xd3, 0x36, 0x9d, 0x90, 0xed, 0x11, 0x72, 0x0f, 0x93, 0x83, 0x07, 0x34, - 0x0e, 0xe3, 0xae, 0xc0, 0xce, 0x6f, 0xfc, 0x1b, 0x4f, 0x66, 0x90, 0xf4, 0x38, 0xbe, 0x82, 0x58, - 0xcb, 0x70, 0x3b, 0x62, 0xb1, 0x96, 0xcb, 0x16, 0x46, 0xa1, 0x0f, 0x2e, 0xe1, 0xf2, 0x8f, 0x1b, - 0x7e, 0x18, 0xec, 0x72, 0xf8, 0x6d, 0xb3, 0xc7, 0x63, 0xa5, 0x8d, 0x23, 0x51, 0x8a, 0x9e, 0xd1, - 0x6a, 0xf1, 0xf5, 0x54, 0x68, 0xff, 0xdd, 0xe6, 0x3b, 0x69, 0xd6, 0xa1, 0xfd, 0xbe, 0x10, 0xa5, - 0xce, 0x6a, 0x27, 0xb2, 0xde, 0x26, 0x3f, 0x0d, 0xb3, 0x7c, 0xf9, 0x09, 0x00, 0x00, 0xff, 0xff, - 0xad, 0x8b, 0xed, 0xc4, 0xe0, 0x01, 0x00, 0x00, + // 272 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0xcf, 0x4b, 0xc3, 0x30, + 0x14, 0xc7, 0x97, 0x62, 0xb5, 0x7d, 0x8e, 0x81, 0x61, 0xe0, 0xd8, 0x69, 0xcb, 0xc5, 0x82, 0x2c, + 0x95, 0x89, 0x47, 0x2f, 0x53, 0x61, 0x9e, 0x84, 0xe0, 0x49, 0xf0, 0x90, 0x26, 0x71, 0x06, 0xb6, + 0xa4, 0x4b, 0xd3, 0xff, 0x5f, 0x9a, 0xa5, 0x03, 0x0f, 0xd3, 0x4b, 0xf2, 0x1e, 0x7c, 0x3e, 0xef, + 0x9b, 0x1f, 0x70, 0x25, 0x55, 0xd5, 0x6e, 0xca, 0xb0, 0xd2, 0xda, 0x59, 0x6f, 0xf1, 0xb5, 0x10, + 0x94, 0x3b, 0xd9, 0x6a, 0x63, 0xa9, 0xd8, 0x6a, 0x2a, 0xec, 0x6e, 0xc7, 0x8d, 0x6c, 0x88, 0x83, + 0xec, 0xb9, 0xe3, 0x98, 0xda, 0xe3, 0x17, 0xc8, 0x64, 0xac, 0x27, 0x68, 0x86, 0x8a, 0xcb, 0xe5, + 0x0d, 0x3d, 0xe1, 0xd1, 0x20, 0x3d, 0x59, 0xf3, 0xa5, 0x3b, 0x7c, 0x3d, 0x60, 0x47, 0x15, 0x8f, + 0xe1, 0x4c, 0x72, 0xcf, 0x27, 0xc9, 0x0c, 0x15, 0xc3, 0xf5, 0x80, 0x85, 0x6e, 0x95, 0xc3, 0x85, + 0xb0, 0xc6, 0x2b, 0xe3, 0xc9, 0x1b, 0x8c, 0x7e, 0xeb, 0xf8, 0x11, 0x32, 0x6d, 0x1a, 0xcf, 0x8d, + 0x50, 0x31, 0x79, 0x7e, 0x32, 0xf9, 0x35, 0x82, 0xec, 0xa8, 0x90, 0x07, 0xc8, 0xe3, 0x25, 0x9a, + 0x1a, 0xe3, 0x18, 0xdf, 0xcd, 0x19, 0x1e, 0xc2, 0xf1, 0x18, 0x52, 0xe5, 0x9c, 0x75, 0xe1, 0x4c, + 0x39, 0x3b, 0x34, 0x64, 0x0a, 0x59, 0x3f, 0x0c, 0x8f, 0x20, 0xd1, 0x32, 0x38, 0x29, 0x4b, 0xb4, + 0x5c, 0x7e, 0x42, 0x1a, 0x46, 0xe2, 0xf7, 0xbe, 0x98, 0xff, 0xfd, 0x16, 0x4c, 0xed, 0xa7, 0xe4, + 0x3f, 0xa4, 0xa9, 0xc9, 0xa0, 0x40, 0x77, 0x68, 0xb5, 0xf8, 0xb8, 0xdd, 0x68, 0xff, 0xdd, 0x56, + 0x1d, 0x52, 0x46, 0xa5, 0xdf, 0x17, 0x62, 0xab, 0x4b, 0x57, 0x8b, 0xb2, 0xd7, 0xab, 0xf3, 0xf0, + 0x8b, 0xf7, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x92, 0xfc, 0xa8, 0xda, 0x01, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // DebugClient is the client API for Debug service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type DebugClient interface { - StreamingOpen(ctx context.Context, opts ...grpc.CallOption) (Debug_StreamingOpenClient, error) + Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) } type debugClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewDebugClient(cc *grpc.ClientConn) DebugClient { +func NewDebugClient(cc grpc.ClientConnInterface) DebugClient { return &debugClient{cc} } -func (c *debugClient) StreamingOpen(ctx context.Context, opts ...grpc.CallOption) (Debug_StreamingOpenClient, error) { - stream, err := c.cc.NewStream(ctx, &_Debug_serviceDesc.Streams[0], "/cc.arduino.cli.commands.Debug/StreamingOpen", opts...) +func (c *debugClient) Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) { + stream, err := c.cc.NewStream(ctx, &_Debug_serviceDesc.Streams[0], "/cc.arduino.cli.commands.Debug/Debug", opts...) if err != nil { return nil, err } - x := &debugStreamingOpenClient{stream} + x := &debugDebugClient{stream} return x, nil } -type Debug_StreamingOpenClient interface { - Send(*StreamingOpenReq) error - Recv() (*StreamingOpenResp, error) +type Debug_DebugClient interface { + Send(*DebugReq) error + Recv() (*DebugResp, error) grpc.ClientStream } -type debugStreamingOpenClient struct { +type debugDebugClient struct { grpc.ClientStream } -func (x *debugStreamingOpenClient) Send(m *StreamingOpenReq) error { +func (x *debugDebugClient) Send(m *DebugReq) error { return x.ClientStream.SendMsg(m) } -func (x *debugStreamingOpenClient) Recv() (*StreamingOpenResp, error) { - m := new(StreamingOpenResp) +func (x *debugDebugClient) Recv() (*DebugResp, error) { + m := new(DebugResp) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } @@ -315,33 +325,41 @@ func (x *debugStreamingOpenClient) Recv() (*StreamingOpenResp, error) { // DebugServer is the server API for Debug service. type DebugServer interface { - StreamingOpen(Debug_StreamingOpenServer) error + Debug(Debug_DebugServer) error +} + +// UnimplementedDebugServer can be embedded to have forward compatible implementations. +type UnimplementedDebugServer struct { +} + +func (*UnimplementedDebugServer) Debug(srv Debug_DebugServer) error { + return status.Errorf(codes.Unimplemented, "method Debug not implemented") } func RegisterDebugServer(s *grpc.Server, srv DebugServer) { s.RegisterService(&_Debug_serviceDesc, srv) } -func _Debug_StreamingOpen_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(DebugServer).StreamingOpen(&debugStreamingOpenServer{stream}) +func _Debug_Debug_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(DebugServer).Debug(&debugDebugServer{stream}) } -type Debug_StreamingOpenServer interface { - Send(*StreamingOpenResp) error - Recv() (*StreamingOpenReq, error) +type Debug_DebugServer interface { + Send(*DebugResp) error + Recv() (*DebugReq, error) grpc.ServerStream } -type debugStreamingOpenServer struct { +type debugDebugServer struct { grpc.ServerStream } -func (x *debugStreamingOpenServer) Send(m *StreamingOpenResp) error { +func (x *debugDebugServer) Send(m *DebugResp) error { return x.ServerStream.SendMsg(m) } -func (x *debugStreamingOpenServer) Recv() (*StreamingOpenReq, error) { - m := new(StreamingOpenReq) +func (x *debugDebugServer) Recv() (*DebugReq, error) { + m := new(DebugReq) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } @@ -354,8 +372,8 @@ var _Debug_serviceDesc = grpc.ServiceDesc{ Methods: []grpc.MethodDesc{}, Streams: []grpc.StreamDesc{ { - StreamName: "StreamingOpen", - Handler: _Debug_StreamingOpen_Handler, + StreamName: "Debug", + Handler: _Debug_Debug_Handler, ServerStreams: true, ClientStreams: true, }, diff --git a/rpc/debug/debug.proto b/rpc/debug/debug.proto index f3c5045cb6b..11a6b797e90 100644 --- a/rpc/debug/debug.proto +++ b/rpc/debug/debug.proto @@ -22,29 +22,28 @@ option go_package = "github.com/arduino/arduino-cli/rpc/commands"; // Service that abstract a debug Session usage service Debug { - rpc StreamingOpen (stream StreamingOpenReq) returns (stream StreamingOpenResp) { - } + rpc Debug(stream DebugReq) returns (stream DebugResp) { } } -// The top-level message sent by the client for the `StreamingOpen` method. -// Multiple `StreamingOpenReq` messages can be sent but the first message +// The top-level message sent by the client for the `Debug` method. +// Multiple `DebugReq` messages can be sent but the first message // must contain a `DebugReq` message to initialize the debug session. // All subsequent messages must contain bytes to be sent to the debug session // and must not contain a `DebugReq` message. -message StreamingOpenReq { +message DebugReq { // Content must be either a debug session config or data to be sent. oneof content { // Provides information to the debug that specifies which is the target. // The first `StreamingOpenReq` message must contain a `DebugReq` // message. - DebugReq debugReq = 1; + DebugConfigReq debugReq = 1; // The data to be sent to the target being monitored. bytes data = 2; } } -message DebugReq { +message DebugConfigReq { Instance instance = 1; // string fqbn = 2; // string sketch_path = 3; @@ -56,8 +55,9 @@ message DebugReq { // -message StreamingOpenResp { +message DebugResp { bytes data = 1; + string error = 2; } // duplicate from commands/common.proto diff --git a/rpc/monitor/monitor.pb.go b/rpc/monitor/monitor.pb.go index 78238c1565a..1a06ba48521 100644 --- a/rpc/monitor/monitor.pb.go +++ b/rpc/monitor/monitor.pb.go @@ -9,6 +9,8 @@ import ( proto "github.com/golang/protobuf/proto" _struct "github.com/golang/protobuf/ptypes/struct" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" math "math" ) @@ -266,11 +268,11 @@ var fileDescriptor_94d5950496a7550d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // MonitorClient is the client API for Monitor service. // @@ -280,10 +282,10 @@ type MonitorClient interface { } type monitorClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewMonitorClient(cc *grpc.ClientConn) MonitorClient { +func NewMonitorClient(cc grpc.ClientConnInterface) MonitorClient { return &monitorClient{cc} } @@ -323,6 +325,14 @@ type MonitorServer interface { StreamingOpen(Monitor_StreamingOpenServer) error } +// UnimplementedMonitorServer can be embedded to have forward compatible implementations. +type UnimplementedMonitorServer struct { +} + +func (*UnimplementedMonitorServer) StreamingOpen(srv Monitor_StreamingOpenServer) error { + return status.Errorf(codes.Unimplemented, "method StreamingOpen not implemented") +} + func RegisterMonitorServer(s *grpc.Server, srv MonitorServer) { s.RegisterService(&_Monitor_serviceDesc, srv) } diff --git a/rpc/settings/settings.pb.go b/rpc/settings/settings.pb.go index 1bbc54f255d..0537c7d9e3a 100644 --- a/rpc/settings/settings.pb.go +++ b/rpc/settings/settings.pb.go @@ -8,6 +8,8 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" math "math" ) @@ -275,11 +277,11 @@ var fileDescriptor_a4bfd59e429426d0 = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // SettingsClient is the client API for Settings service. // @@ -292,10 +294,10 @@ type SettingsClient interface { } type settingsClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewSettingsClient(cc *grpc.ClientConn) SettingsClient { +func NewSettingsClient(cc grpc.ClientConnInterface) SettingsClient { return &settingsClient{cc} } @@ -343,6 +345,23 @@ type SettingsServer interface { SetValue(context.Context, *Value) (*SetValueResponse, error) } +// UnimplementedSettingsServer can be embedded to have forward compatible implementations. +type UnimplementedSettingsServer struct { +} + +func (*UnimplementedSettingsServer) GetAll(ctx context.Context, req *GetAllRequest) (*RawData, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAll not implemented") +} +func (*UnimplementedSettingsServer) Merge(ctx context.Context, req *RawData) (*MergeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Merge not implemented") +} +func (*UnimplementedSettingsServer) GetValue(ctx context.Context, req *GetValueRequest) (*Value, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetValue not implemented") +} +func (*UnimplementedSettingsServer) SetValue(ctx context.Context, req *Value) (*SetValueResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetValue not implemented") +} + func RegisterSettingsServer(s *grpc.Server, srv SettingsServer) { s.RegisterService(&_Settings_serviceDesc, srv) } From d9077eb9cb905fed2087bf19982fdeaba03339ad Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 17 Feb 2020 16:13:35 +0100 Subject: [PATCH 05/29] Handle errors gracefully --- commands/debug/debug.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/commands/debug/debug.go b/commands/debug/debug.go index 6a33b44afcf..1533a8ae2e5 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -37,16 +37,15 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu in, err := cmd.StdinPipe() if err != nil { fmt.Printf("%v\n", err) - return &dbg.DebugResp{}, nil // TODO: send error in response + return &dbg.DebugResp{Error: err.Error()}, nil } defer in.Close() cmd.Stdout = out - err = cmd.Start() - if err != nil { + if err := cmd.Start(); err != nil { fmt.Printf("%v\n", err) - return &dbg.DebugResp{}, nil // TODO: send error in response + return &dbg.DebugResp{Error: err.Error()}, nil } // now we can read the other commands and re-route to the Debug Client... @@ -58,10 +57,15 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu break } } + + // In any case, try process termination after a second to avoid leaving + // zombie process. time.Sleep(time.Second) cmd.Process.Kill() }() - err = cmd.Wait() // TODO: handle err + if err := cmd.Wait(); err != nil { + return &dbg.DebugResp{Error: err.Error()}, nil + } return &dbg.DebugResp{}, nil } From e86ae800aabb2cb3bc75ee89328f0ae9bd72f508 Mon Sep 17 00:00:00 2001 From: rsora Date: Mon, 17 Feb 2020 16:54:32 +0100 Subject: [PATCH 06/29] Add recipe calculation to debug command --- commands/debug/debug.go | 153 +++++++++++++++++++++++++++++++++++- rpc/commands/commands.pb.go | 90 +-------------------- rpc/debug/debug.pb.go | 99 +++++++++++++++-------- rpc/debug/debug.proto | 11 ++- rpc/monitor/monitor.pb.go | 18 +---- rpc/settings/settings.pb.go | 27 +------ 6 files changed, 236 insertions(+), 162 deletions(-) diff --git a/commands/debug/debug.go b/commands/debug/debug.go index 1533a8ae2e5..e8c52c268d0 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -18,7 +18,16 @@ package debug import ( "context" "fmt" + "github.com/arduino/arduino-cli/arduino/cores" + "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/commands" + "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" + "github.com/sirupsen/logrus" "io" + "os" + "path/filepath" + "strings" "time" "github.com/arduino/arduino-cli/executils" @@ -27,7 +36,149 @@ import ( // Debug FIXMEDOC func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_DebugServer, out io.Writer) (*dbg.DebugResp, error) { - cmdArgs := []string{"gdb"} + + // TODO: make a generic function to extract sketch from request + // and remove duplication in commands/compile.go + if req.GetSketchPath() == "" { + return nil, fmt.Errorf("missing sketchPath") + } + sketchPath := paths.New(req.GetSketchPath()) + sketch, err := sketches.NewSketchFromPath(sketchPath) + if err != nil { + return nil, fmt.Errorf("opening sketch: %s", err) + } + + // FIXME: make a specification on how a port is specified via command line + port := req.GetPort() + if port == "" { + return nil, fmt.Errorf("no upload port provided") + } + + fqbnIn := req.GetFqbn() + if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { + fqbnIn = sketch.Metadata.CPU.Fqbn + } + if fqbnIn == "" { + return nil, fmt.Errorf("no Fully Qualified Board Name provided") + } + fqbn, err := cores.ParseFQBN(fqbnIn) + if err != nil { + return nil, fmt.Errorf("incorrect FQBN: %s", err) + } + + pm := commands.GetPackageManager(req.GetInstance().GetId()) + + // Find target board and board properties + _, _, board, boardProperties, _, err := pm.ResolveFQBN(fqbn) + if err != nil { + return nil, fmt.Errorf("incorrect FQBN: %s", err) + } + + // Load programmer tool + uploadToolPattern, have := boardProperties.GetOk("debug.tool") + if !have || uploadToolPattern == "" { + return nil, fmt.Errorf("cannot get programmer tool: undefined 'debug.tool' property") + } + + var referencedPlatformRelease *cores.PlatformRelease + if split := strings.Split(uploadToolPattern, ":"); len(split) > 2 { + return nil, fmt.Errorf("invalid 'debug.tool' property: %s", uploadToolPattern) + } else if len(split) == 2 { + referencedPackageName := split[0] + uploadToolPattern = split[1] + architecture := board.PlatformRelease.Platform.Architecture + + if referencedPackage := pm.Packages[referencedPackageName]; referencedPackage == nil { + return nil, fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) + } else if referencedPlatform := referencedPackage.Platforms[architecture]; referencedPlatform == nil { + return nil, fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) + } else { + referencedPlatformRelease = pm.GetInstalledPlatformRelease(referencedPlatform) + } + } + + // Build configuration for upload + debugProperties := properties.NewMap() + if referencedPlatformRelease != nil { + debugProperties.Merge(referencedPlatformRelease.Properties) + } + debugProperties.Merge(board.PlatformRelease.Properties) + debugProperties.Merge(board.PlatformRelease.RuntimeProperties()) + debugProperties.Merge(boardProperties) + + uploadToolProperties := debugProperties.SubTree("tools." + uploadToolPattern) + debugProperties.Merge(uploadToolProperties) + + if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil { + for _, requiredTool := range requiredTools { + logrus.WithField("tool", requiredTool).Info("Tool required for upload") + debugProperties.Merge(requiredTool.RuntimeProperties()) + } + } + + // Set properties for verbose upload + Verbose := req.GetVerbose() + if Verbose { + if v, ok := debugProperties.GetOk("debug.params.verbose"); ok { + debugProperties.Set("debug.verbose", v) + } + } else { + if v, ok := debugProperties.GetOk("debug.params.quiet"); ok { + debugProperties.Set("debug.verbose", v) + } + } + + // Set path to compiled binary + // Make the filename without the FQBN configs part + fqbn.Configs = properties.NewMap() + fqbnSuffix := strings.Replace(fqbn.String(), ":", ".", -1) + + var importPath *paths.Path + var importFile string + if req.GetImportFile() == "" { + importPath = sketch.FullPath + importFile = sketch.Name + "." + fqbnSuffix + } else { + importPath = paths.New(req.GetImportFile()).Parent() + importFile = paths.New(req.GetImportFile()).Base() + } + + outputTmpFile, ok := debugProperties.GetOk("recipe.output.tmp_file") + outputTmpFile = debugProperties.ExpandPropsInString(outputTmpFile) + if !ok { + return nil, fmt.Errorf("property 'recipe.output.tmp_file' not defined") + } + ext := filepath.Ext(outputTmpFile) + if strings.HasSuffix(importFile, ext) { + importFile = importFile[:len(importFile)-len(ext)] + } + + debugProperties.SetPath("build.path", importPath) + debugProperties.Set("build.project_name", importFile) + uploadFile := importPath.Join(importFile + ext) + if _, err := uploadFile.Stat(); err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("compiled sketch %s not found", uploadFile.String()) + } + return nil, fmt.Errorf("cannot open sketch: %s", err) + } + + // Set serial port property + debugProperties.Set("serial.port", port) + if strings.HasPrefix(port, "/dev/") { + debugProperties.Set("serial.port.file", port[5:]) + } else { + debugProperties.Set("serial.port.file", port) + } + + // Build recipe for upload + recipe := debugProperties.Get("debug.pattern") + cmdLine := debugProperties.ExpandPropsInString(recipe) + cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false) + if err != nil { + return nil, fmt.Errorf("invalid recipe '%s': %s", recipe, err) + } + // Run Tool cmd, err := executils.Command(cmdArgs) if err != nil { diff --git a/rpc/commands/commands.pb.go b/rpc/commands/commands.pb.go index 780bbed2f1e..59fe7937ed8 100644 --- a/rpc/commands/commands.pb.go +++ b/rpc/commands/commands.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -599,11 +597,11 @@ var fileDescriptor_3690061a1131852d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // ArduinoCoreClient is the client API for ArduinoCore service. // @@ -643,10 +641,10 @@ type ArduinoCoreClient interface { } type arduinoCoreClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewArduinoCoreClient(cc grpc.ClientConnInterface) ArduinoCoreClient { +func NewArduinoCoreClient(cc *grpc.ClientConn) ArduinoCoreClient { return &arduinoCoreClient{cc} } @@ -1232,86 +1230,6 @@ type ArduinoCoreServer interface { LibraryList(context.Context, *LibraryListReq) (*LibraryListResp, error) } -// UnimplementedArduinoCoreServer can be embedded to have forward compatible implementations. -type UnimplementedArduinoCoreServer struct { -} - -func (*UnimplementedArduinoCoreServer) Init(req *InitReq, srv ArduinoCore_InitServer) error { - return status.Errorf(codes.Unimplemented, "method Init not implemented") -} -func (*UnimplementedArduinoCoreServer) Destroy(ctx context.Context, req *DestroyReq) (*DestroyResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Destroy not implemented") -} -func (*UnimplementedArduinoCoreServer) Rescan(ctx context.Context, req *RescanReq) (*RescanResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Rescan not implemented") -} -func (*UnimplementedArduinoCoreServer) UpdateIndex(req *UpdateIndexReq, srv ArduinoCore_UpdateIndexServer) error { - return status.Errorf(codes.Unimplemented, "method UpdateIndex not implemented") -} -func (*UnimplementedArduinoCoreServer) UpdateLibrariesIndex(req *UpdateLibrariesIndexReq, srv ArduinoCore_UpdateLibrariesIndexServer) error { - return status.Errorf(codes.Unimplemented, "method UpdateLibrariesIndex not implemented") -} -func (*UnimplementedArduinoCoreServer) Version(ctx context.Context, req *VersionReq) (*VersionResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardDetails(ctx context.Context, req *BoardDetailsReq) (*BoardDetailsResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardDetails not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardAttach(req *BoardAttachReq, srv ArduinoCore_BoardAttachServer) error { - return status.Errorf(codes.Unimplemented, "method BoardAttach not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardList(ctx context.Context, req *BoardListReq) (*BoardListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardList not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardListAll(ctx context.Context, req *BoardListAllReq) (*BoardListAllResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardListAll not implemented") -} -func (*UnimplementedArduinoCoreServer) Compile(req *CompileReq, srv ArduinoCore_CompileServer) error { - return status.Errorf(codes.Unimplemented, "method Compile not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformInstall(req *PlatformInstallReq, srv ArduinoCore_PlatformInstallServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformInstall not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformDownload(req *PlatformDownloadReq, srv ArduinoCore_PlatformDownloadServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformDownload not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformUninstall(req *PlatformUninstallReq, srv ArduinoCore_PlatformUninstallServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformUninstall not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformUpgrade(req *PlatformUpgradeReq, srv ArduinoCore_PlatformUpgradeServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformUpgrade not implemented") -} -func (*UnimplementedArduinoCoreServer) Upload(req *UploadReq, srv ArduinoCore_UploadServer) error { - return status.Errorf(codes.Unimplemented, "method Upload not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformSearch(ctx context.Context, req *PlatformSearchReq) (*PlatformSearchResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlatformSearch not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformList(ctx context.Context, req *PlatformListReq) (*PlatformListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlatformList not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryDownload(req *LibraryDownloadReq, srv ArduinoCore_LibraryDownloadServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryDownload not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryInstall(req *LibraryInstallReq, srv ArduinoCore_LibraryInstallServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryInstall not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryUninstall(req *LibraryUninstallReq, srv ArduinoCore_LibraryUninstallServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryUninstall not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryUpgradeAll(req *LibraryUpgradeAllReq, srv ArduinoCore_LibraryUpgradeAllServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryUpgradeAll not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryResolveDependencies(ctx context.Context, req *LibraryResolveDependenciesReq) (*LibraryResolveDependenciesResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibraryResolveDependencies not implemented") -} -func (*UnimplementedArduinoCoreServer) LibrarySearch(ctx context.Context, req *LibrarySearchReq) (*LibrarySearchResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibrarySearch not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryList(ctx context.Context, req *LibraryListReq) (*LibraryListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibraryList not implemented") -} - func RegisterArduinoCoreServer(s *grpc.Server, srv ArduinoCoreServer) { s.RegisterService(&_ArduinoCore_serviceDesc, srv) } diff --git a/rpc/debug/debug.pb.go b/rpc/debug/debug.pb.go index c7057afe8d1..4cec8aad7f8 100644 --- a/rpc/debug/debug.pb.go +++ b/rpc/debug/debug.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -113,6 +111,11 @@ func (*DebugReq) XXX_OneofWrappers() []interface{} { type DebugConfigReq struct { Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` + Fqbn string `protobuf:"bytes,2,opt,name=fqbn,proto3" json:"fqbn,omitempty"` + SketchPath string `protobuf:"bytes,3,opt,name=sketch_path,json=sketchPath,proto3" json:"sketch_path,omitempty"` + Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"` + Verbose bool `protobuf:"varint,5,opt,name=verbose,proto3" json:"verbose,omitempty"` + ImportFile string `protobuf:"bytes,7,opt,name=import_file,json=importFile,proto3" json:"import_file,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -150,6 +153,41 @@ func (m *DebugConfigReq) GetInstance() *Instance { return nil } +func (m *DebugConfigReq) GetFqbn() string { + if m != nil { + return m.Fqbn + } + return "" +} + +func (m *DebugConfigReq) GetSketchPath() string { + if m != nil { + return m.SketchPath + } + return "" +} + +func (m *DebugConfigReq) GetPort() string { + if m != nil { + return m.Port + } + return "" +} + +func (m *DebugConfigReq) GetVerbose() bool { + if m != nil { + return m.Verbose + } + return false +} + +func (m *DebugConfigReq) GetImportFile() string { + if m != nil { + return m.ImportFile + } + return "" +} + // type DebugResp struct { Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` @@ -249,33 +287,38 @@ func init() { func init() { proto.RegisterFile("debug/debug.proto", fileDescriptor_5ae24eab94cb53d5) } var fileDescriptor_5ae24eab94cb53d5 = []byte{ - // 272 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0xcf, 0x4b, 0xc3, 0x30, - 0x14, 0xc7, 0x97, 0x62, 0xb5, 0x7d, 0x8e, 0x81, 0x61, 0xe0, 0xd8, 0x69, 0xcb, 0xc5, 0x82, 0x2c, - 0x95, 0x89, 0x47, 0x2f, 0x53, 0x61, 0x9e, 0x84, 0xe0, 0x49, 0xf0, 0x90, 0x26, 0x71, 0x06, 0xb6, - 0xa4, 0x4b, 0xd3, 0xff, 0x5f, 0x9a, 0xa5, 0x03, 0x0f, 0xd3, 0x4b, 0xf2, 0x1e, 0x7c, 0x3e, 0xef, - 0x9b, 0x1f, 0x70, 0x25, 0x55, 0xd5, 0x6e, 0xca, 0xb0, 0xd2, 0xda, 0x59, 0x6f, 0xf1, 0xb5, 0x10, - 0x94, 0x3b, 0xd9, 0x6a, 0x63, 0xa9, 0xd8, 0x6a, 0x2a, 0xec, 0x6e, 0xc7, 0x8d, 0x6c, 0x88, 0x83, - 0xec, 0xb9, 0xe3, 0x98, 0xda, 0xe3, 0x17, 0xc8, 0x64, 0xac, 0x27, 0x68, 0x86, 0x8a, 0xcb, 0xe5, - 0x0d, 0x3d, 0xe1, 0xd1, 0x20, 0x3d, 0x59, 0xf3, 0xa5, 0x3b, 0x7c, 0x3d, 0x60, 0x47, 0x15, 0x8f, - 0xe1, 0x4c, 0x72, 0xcf, 0x27, 0xc9, 0x0c, 0x15, 0xc3, 0xf5, 0x80, 0x85, 0x6e, 0x95, 0xc3, 0x85, - 0xb0, 0xc6, 0x2b, 0xe3, 0xc9, 0x1b, 0x8c, 0x7e, 0xeb, 0xf8, 0x11, 0x32, 0x6d, 0x1a, 0xcf, 0x8d, - 0x50, 0x31, 0x79, 0x7e, 0x32, 0xf9, 0x35, 0x82, 0xec, 0xa8, 0x90, 0x07, 0xc8, 0xe3, 0x25, 0x9a, - 0x1a, 0xe3, 0x18, 0xdf, 0xcd, 0x19, 0x1e, 0xc2, 0xf1, 0x18, 0x52, 0xe5, 0x9c, 0x75, 0xe1, 0x4c, - 0x39, 0x3b, 0x34, 0x64, 0x0a, 0x59, 0x3f, 0x0c, 0x8f, 0x20, 0xd1, 0x32, 0x38, 0x29, 0x4b, 0xb4, - 0x5c, 0x7e, 0x42, 0x1a, 0x46, 0xe2, 0xf7, 0xbe, 0x98, 0xff, 0xfd, 0x16, 0x4c, 0xed, 0xa7, 0xe4, - 0x3f, 0xa4, 0xa9, 0xc9, 0xa0, 0x40, 0x77, 0x68, 0xb5, 0xf8, 0xb8, 0xdd, 0x68, 0xff, 0xdd, 0x56, - 0x1d, 0x52, 0x46, 0xa5, 0xdf, 0x17, 0x62, 0xab, 0x4b, 0x57, 0x8b, 0xb2, 0xd7, 0xab, 0xf3, 0xf0, - 0x8b, 0xf7, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x92, 0xfc, 0xa8, 0xda, 0x01, 0x00, 0x00, + // 352 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0x4f, 0x6f, 0xe2, 0x30, + 0x10, 0xc5, 0x09, 0x4b, 0x96, 0x30, 0x20, 0xa4, 0xb5, 0x90, 0x36, 0xe2, 0xb2, 0x90, 0xcb, 0x46, + 0xaa, 0x48, 0x2a, 0xaa, 0x1e, 0x7b, 0xa1, 0x7f, 0x44, 0x6f, 0x95, 0xd5, 0x53, 0xa5, 0x0a, 0x39, + 0xb6, 0x21, 0x56, 0x83, 0x1d, 0x1c, 0xd3, 0x2f, 0xda, 0x2f, 0x54, 0xd9, 0x49, 0x90, 0x7a, 0xa0, + 0xbd, 0x24, 0x6f, 0x9c, 0xf7, 0x7b, 0x93, 0x99, 0x04, 0xfe, 0x30, 0x9e, 0x1d, 0x77, 0xa9, 0xbb, + 0x26, 0xa5, 0x56, 0x46, 0xa1, 0xbf, 0x94, 0x26, 0x44, 0xb3, 0xa3, 0x90, 0x2a, 0xa1, 0x85, 0x48, + 0xa8, 0xda, 0xef, 0x89, 0x64, 0x55, 0xa4, 0x21, 0xb8, 0xb3, 0x3e, 0xcc, 0x0f, 0xe8, 0x1e, 0x02, + 0xd6, 0xe8, 0xd0, 0x9b, 0x79, 0xf1, 0x70, 0xf9, 0x3f, 0x39, 0xc3, 0x25, 0x0e, 0xba, 0x55, 0x72, + 0x2b, 0xac, 0x7d, 0xdd, 0xc1, 0x27, 0x14, 0x4d, 0xa0, 0xc7, 0x88, 0x21, 0x61, 0x77, 0xe6, 0xc5, + 0xa3, 0x75, 0x07, 0xbb, 0x6a, 0x35, 0x80, 0x3e, 0x55, 0xd2, 0x70, 0x69, 0xa2, 0x0f, 0x0f, 0xc6, + 0x5f, 0x79, 0x74, 0x03, 0x81, 0x90, 0x95, 0x21, 0x92, 0xf2, 0xa6, 0xf5, 0xfc, 0x6c, 0xeb, 0xc7, + 0xc6, 0x88, 0x4f, 0x08, 0x42, 0xd0, 0xdb, 0x1e, 0x32, 0xe9, 0x5a, 0x0e, 0xb0, 0xd3, 0xe8, 0x1f, + 0x0c, 0xab, 0x37, 0x6e, 0x68, 0xbe, 0x29, 0x89, 0xc9, 0xc3, 0x5f, 0xee, 0x11, 0xd4, 0x47, 0x4f, + 0xc4, 0xe4, 0x16, 0x2a, 0x95, 0x36, 0x61, 0xaf, 0x86, 0xac, 0x46, 0x21, 0xf4, 0xdf, 0xb9, 0xce, + 0x54, 0xc5, 0x43, 0x7f, 0xe6, 0xc5, 0x01, 0x6e, 0x4b, 0x1b, 0x27, 0xf6, 0xd6, 0xb3, 0xd9, 0x8a, + 0x82, 0x87, 0xfd, 0x3a, 0xae, 0x3e, 0x7a, 0x10, 0x05, 0x8f, 0xae, 0x61, 0xd0, 0x6c, 0xb2, 0x2a, + 0x6d, 0xb6, 0xdb, 0x81, 0x9d, 0x65, 0x54, 0x6f, 0x00, 0x4d, 0xc0, 0xe7, 0x5a, 0x2b, 0xdd, 0xbc, + 0x65, 0x5d, 0x44, 0x53, 0x08, 0xda, 0x81, 0xd0, 0x18, 0xba, 0x82, 0x39, 0xc6, 0xc7, 0x5d, 0xc1, + 0x96, 0xaf, 0xe0, 0xbb, 0x48, 0xf4, 0xdc, 0x8a, 0xf9, 0xf7, 0x1f, 0x04, 0xf3, 0xc3, 0x34, 0xfa, + 0xc9, 0x52, 0x95, 0x51, 0x27, 0xf6, 0x2e, 0xbd, 0xd5, 0xe2, 0xe5, 0x62, 0x27, 0x4c, 0x7e, 0xcc, + 0xac, 0x25, 0x6d, 0x90, 0xf6, 0xbe, 0xa0, 0x85, 0x48, 0x75, 0x49, 0xd3, 0x16, 0xcf, 0x7e, 0xbb, + 0x5f, 0xe9, 0xea, 0x33, 0x00, 0x00, 0xff, 0xff, 0x2b, 0xc0, 0xf0, 0xc3, 0x5f, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // DebugClient is the client API for Debug service. // @@ -285,10 +328,10 @@ type DebugClient interface { } type debugClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewDebugClient(cc grpc.ClientConnInterface) DebugClient { +func NewDebugClient(cc *grpc.ClientConn) DebugClient { return &debugClient{cc} } @@ -328,14 +371,6 @@ type DebugServer interface { Debug(Debug_DebugServer) error } -// UnimplementedDebugServer can be embedded to have forward compatible implementations. -type UnimplementedDebugServer struct { -} - -func (*UnimplementedDebugServer) Debug(srv Debug_DebugServer) error { - return status.Errorf(codes.Unimplemented, "method Debug not implemented") -} - func RegisterDebugServer(s *grpc.Server, srv DebugServer) { s.RegisterService(&_Debug_serviceDesc, srv) } diff --git a/rpc/debug/debug.proto b/rpc/debug/debug.proto index 11a6b797e90..9477f699e16 100644 --- a/rpc/debug/debug.proto +++ b/rpc/debug/debug.proto @@ -45,12 +45,11 @@ message DebugReq { message DebugConfigReq { Instance instance = 1; -// string fqbn = 2; -// string sketch_path = 3; -// string port = 4; -// bool verbose = 5; -// bool verify = 6; -// string import_file = 7; + string fqbn = 2; + string sketch_path = 3; + string port = 4; + bool verbose = 5; + string import_file = 7; } diff --git a/rpc/monitor/monitor.pb.go b/rpc/monitor/monitor.pb.go index 1a06ba48521..78238c1565a 100644 --- a/rpc/monitor/monitor.pb.go +++ b/rpc/monitor/monitor.pb.go @@ -9,8 +9,6 @@ import ( proto "github.com/golang/protobuf/proto" _struct "github.com/golang/protobuf/ptypes/struct" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -268,11 +266,11 @@ var fileDescriptor_94d5950496a7550d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // MonitorClient is the client API for Monitor service. // @@ -282,10 +280,10 @@ type MonitorClient interface { } type monitorClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewMonitorClient(cc grpc.ClientConnInterface) MonitorClient { +func NewMonitorClient(cc *grpc.ClientConn) MonitorClient { return &monitorClient{cc} } @@ -325,14 +323,6 @@ type MonitorServer interface { StreamingOpen(Monitor_StreamingOpenServer) error } -// UnimplementedMonitorServer can be embedded to have forward compatible implementations. -type UnimplementedMonitorServer struct { -} - -func (*UnimplementedMonitorServer) StreamingOpen(srv Monitor_StreamingOpenServer) error { - return status.Errorf(codes.Unimplemented, "method StreamingOpen not implemented") -} - func RegisterMonitorServer(s *grpc.Server, srv MonitorServer) { s.RegisterService(&_Monitor_serviceDesc, srv) } diff --git a/rpc/settings/settings.pb.go b/rpc/settings/settings.pb.go index 0537c7d9e3a..1bbc54f255d 100644 --- a/rpc/settings/settings.pb.go +++ b/rpc/settings/settings.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -277,11 +275,11 @@ var fileDescriptor_a4bfd59e429426d0 = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // SettingsClient is the client API for Settings service. // @@ -294,10 +292,10 @@ type SettingsClient interface { } type settingsClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewSettingsClient(cc grpc.ClientConnInterface) SettingsClient { +func NewSettingsClient(cc *grpc.ClientConn) SettingsClient { return &settingsClient{cc} } @@ -345,23 +343,6 @@ type SettingsServer interface { SetValue(context.Context, *Value) (*SetValueResponse, error) } -// UnimplementedSettingsServer can be embedded to have forward compatible implementations. -type UnimplementedSettingsServer struct { -} - -func (*UnimplementedSettingsServer) GetAll(ctx context.Context, req *GetAllRequest) (*RawData, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetAll not implemented") -} -func (*UnimplementedSettingsServer) Merge(ctx context.Context, req *RawData) (*MergeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Merge not implemented") -} -func (*UnimplementedSettingsServer) GetValue(ctx context.Context, req *GetValueRequest) (*Value, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetValue not implemented") -} -func (*UnimplementedSettingsServer) SetValue(ctx context.Context, req *Value) (*SetValueResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method SetValue not implemented") -} - func RegisterSettingsServer(s *grpc.Server, srv SettingsServer) { s.RegisterService(&_Settings_serviceDesc, srv) } From 879367b8e4c83fa578e35432e0a884d0feebd206 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 17 Feb 2020 18:09:42 +0100 Subject: [PATCH 07/29] First implementation of debug --- client_example/main.go | 101 ++++++++++++++++-------------- commands/debug/debug.go | 77 ++++++++++++----------- rpc/commands/commands.pb.go | 90 +++++++++++++++++++++++++-- rpc/debug/debug.pb.go | 120 +++++++++++++++--------------------- rpc/debug/debug.proto | 15 +++-- rpc/monitor/monitor.pb.go | 18 ++++-- rpc/settings/settings.pb.go | 27 ++++++-- 7 files changed, 275 insertions(+), 173 deletions(-) diff --git a/client_example/main.go b/client_example/main.go index 06a5736c3ce..ce03ece43a9 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -63,7 +63,7 @@ func main() { // Create an instance of the gRPC client. client := rpc.NewArduinoCoreClient(conn) - //settingsClient := settings.NewSettingsClient(conn) + instance := initInstance(client) ///////////////////////////////////////////////////////////////////////// debugClient := dbg.NewDebugClient(conn) @@ -72,18 +72,24 @@ func main() { callVersion(client) // debug calls - debugStreamingOpenClient, err := debugClient.StreamingOpen(context.Background()) + debugStreamingOpenClient, err := debugClient.Debug(context.Background()) if err != nil { log.Fatalf("steraming open error: %s\n", err) } - err = debugStreamingOpenClient.Send(&dbg.StreamingOpenReq{Content: &dbg.StreamingOpenReq_DebugReq{DebugReq: &dbg.DebugReq{Instance: &dbg.Instance{Id: 1}}}}) + err = debugStreamingOpenClient.Send(&dbg.DebugReq{ + DebugReq: &dbg.DebugConfigReq{ + Instance: &dbg.Instance{Id: instance.GetId()}, + Fqbn: "arduino-sadsadasd:samd:arduino_zero_edbg", + SketchPath: os.Args[1], + Port: "none", + }}) if err != nil { log.Fatalf("Send error: %s\n", err) } log.Println("calling StreamingOpenReq_DebugReq") - err = debugStreamingOpenClient.Send(&dbg.StreamingOpenReq{Content: &dbg.StreamingOpenReq_Data{Data: []byte("\n")}}) + err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("\n")}) if err != nil { log.Fatalf("Send error: %s\n", err) } @@ -114,7 +120,7 @@ func main() { } - err = debugStreamingOpenClient.Send(&dbg.StreamingOpenReq{Content: &dbg.StreamingOpenReq_Data{Data: []byte("quit\n")}}) + err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("quit\n")}) if err != nil { log.Fatalf("Send error: %s\n", err) } @@ -300,48 +306,49 @@ func callVersion(client rpc.ArduinoCoreClient) { // log.Printf("Settings: %s", getAllResp.GetJsonData()) //} // -//func initInstance(client rpc.ArduinoCoreClient) *rpc.Instance { -// // The configuration for this example client only contains the path to -// // the data folder. -// initRespStream, err := client.Init(context.Background(), &rpc.InitReq{}) -// if err != nil { -// log.Fatalf("Error creating server instance: %s", err) -// -// } -// -// var instance *rpc.Instance -// // Loop and consume the server stream until all the setup procedures are done. -// for { -// initResp, err := initRespStream.Recv() -// // The server is done. -// if err == io.EOF { -// break -// } -// -// // There was an error. -// if err != nil { -// log.Fatalf("Init error: %s", err) -// } -// -// // The server sent us a valid instance, let's print its ID. -// if initResp.GetInstance() != nil { -// instance = initResp.GetInstance() -// log.Printf("Got a new instance with ID: %v", instance.GetId()) -// } -// -// // When a download is ongoing, log the progress -// if initResp.GetDownloadProgress() != nil { -// log.Printf("DOWNLOAD: %s", initResp.GetDownloadProgress()) -// } -// -// // When an overall task is ongoing, log the progress -// if initResp.GetTaskProgress() != nil { -// log.Printf("TASK: %s", initResp.GetTaskProgress()) -// } -// } -// -// return instance -//} +func initInstance(client rpc.ArduinoCoreClient) *rpc.Instance { + // The configuration for this example client only contains the path to + // the data folder. + initRespStream, err := client.Init(context.Background(), &rpc.InitReq{}) + if err != nil { + log.Fatalf("Error creating server instance: %s", err) + + } + + var instance *rpc.Instance + // Loop and consume the server stream until all the setup procedures are done. + for { + initResp, err := initRespStream.Recv() + // The server is done. + if err == io.EOF { + break + } + + // There was an error. + if err != nil { + log.Fatalf("Init error: %s", err) + } + + // The server sent us a valid instance, let's print its ID. + if initResp.GetInstance() != nil { + instance = initResp.GetInstance() + log.Printf("Got a new instance with ID: %v", instance.GetId()) + } + + // When a download is ongoing, log the progress + if initResp.GetDownloadProgress() != nil { + log.Printf("DOWNLOAD: %s", initResp.GetDownloadProgress()) + } + + // When an overall task is ongoing, log the progress + if initResp.GetTaskProgress() != nil { + log.Printf("TASK: %s", initResp.GetTaskProgress()) + } + } + + return instance +} + // //func callUpdateIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { // uiRespStream, err := client.UpdateIndex(context.Background(), &rpc.UpdateIndexReq{ diff --git a/commands/debug/debug.go b/commands/debug/debug.go index e8c52c268d0..8ebc0cb5a22 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -18,17 +18,18 @@ package debug import ( "context" "fmt" + "io" + "os" + "path/filepath" + "strings" + "time" + "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/sketches" "github.com/arduino/arduino-cli/commands" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/sirupsen/logrus" - "io" - "os" - "path/filepath" - "strings" - "time" "github.com/arduino/arduino-cli/executils" dbg "github.com/arduino/arduino-cli/rpc/debug" @@ -75,17 +76,17 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu } // Load programmer tool - uploadToolPattern, have := boardProperties.GetOk("debug.tool") - if !have || uploadToolPattern == "" { + toolName, have := boardProperties.GetOk("debug.tool") + if !have || toolName == "" { return nil, fmt.Errorf("cannot get programmer tool: undefined 'debug.tool' property") } var referencedPlatformRelease *cores.PlatformRelease - if split := strings.Split(uploadToolPattern, ":"); len(split) > 2 { - return nil, fmt.Errorf("invalid 'debug.tool' property: %s", uploadToolPattern) + if split := strings.Split(toolName, ":"); len(split) > 2 { + return nil, fmt.Errorf("invalid 'debug.tool' property: %s", toolName) } else if len(split) == 2 { referencedPackageName := split[0] - uploadToolPattern = split[1] + toolName = split[1] architecture := board.PlatformRelease.Platform.Architecture if referencedPackage := pm.Packages[referencedPackageName]; referencedPackage == nil { @@ -98,33 +99,33 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu } // Build configuration for upload - debugProperties := properties.NewMap() + toolProperties := properties.NewMap() if referencedPlatformRelease != nil { - debugProperties.Merge(referencedPlatformRelease.Properties) + toolProperties.Merge(referencedPlatformRelease.Properties) } - debugProperties.Merge(board.PlatformRelease.Properties) - debugProperties.Merge(board.PlatformRelease.RuntimeProperties()) - debugProperties.Merge(boardProperties) + toolProperties.Merge(board.PlatformRelease.Properties) + toolProperties.Merge(board.PlatformRelease.RuntimeProperties()) + toolProperties.Merge(boardProperties) - uploadToolProperties := debugProperties.SubTree("tools." + uploadToolPattern) - debugProperties.Merge(uploadToolProperties) + requestedToolProperties := toolProperties.SubTree("tools." + toolName) + toolProperties.Merge(requestedToolProperties) if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil { for _, requiredTool := range requiredTools { logrus.WithField("tool", requiredTool).Info("Tool required for upload") - debugProperties.Merge(requiredTool.RuntimeProperties()) + toolProperties.Merge(requiredTool.RuntimeProperties()) } } // Set properties for verbose upload - Verbose := req.GetVerbose() - if Verbose { - if v, ok := debugProperties.GetOk("debug.params.verbose"); ok { - debugProperties.Set("debug.verbose", v) + verbose := req.GetVerbose() + if verbose { + if v, ok := toolProperties.GetOk("debug.params.verbose"); ok { + toolProperties.Set("debug.verbose", v) } } else { - if v, ok := debugProperties.GetOk("debug.params.quiet"); ok { - debugProperties.Set("debug.verbose", v) + if v, ok := toolProperties.GetOk("debug.params.quiet"); ok { + toolProperties.Set("debug.verbose", v) } } @@ -143,8 +144,8 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu importFile = paths.New(req.GetImportFile()).Base() } - outputTmpFile, ok := debugProperties.GetOk("recipe.output.tmp_file") - outputTmpFile = debugProperties.ExpandPropsInString(outputTmpFile) + outputTmpFile, ok := toolProperties.GetOk("recipe.output.tmp_file") + outputTmpFile = toolProperties.ExpandPropsInString(outputTmpFile) if !ok { return nil, fmt.Errorf("property 'recipe.output.tmp_file' not defined") } @@ -153,8 +154,8 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu importFile = importFile[:len(importFile)-len(ext)] } - debugProperties.SetPath("build.path", importPath) - debugProperties.Set("build.project_name", importFile) + toolProperties.SetPath("build.path", importPath) + toolProperties.Set("build.project_name", importFile) uploadFile := importPath.Join(importFile + ext) if _, err := uploadFile.Stat(); err != nil { if os.IsNotExist(err) { @@ -163,22 +164,27 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu return nil, fmt.Errorf("cannot open sketch: %s", err) } - // Set serial port property - debugProperties.Set("serial.port", port) + // Set debug port property + toolProperties.Set("debug.port", port) if strings.HasPrefix(port, "/dev/") { - debugProperties.Set("serial.port.file", port[5:]) + toolProperties.Set("debug.port.file", port[5:]) } else { - debugProperties.Set("serial.port.file", port) + toolProperties.Set("debug.port.file", port) } - // Build recipe for upload - recipe := debugProperties.Get("debug.pattern") - cmdLine := debugProperties.ExpandPropsInString(recipe) + // Build recipe for tool + recipe := toolProperties.Get("debug.pattern") + cmdLine := toolProperties.ExpandPropsInString(recipe) cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false) if err != nil { return nil, fmt.Errorf("invalid recipe '%s': %s", recipe, err) } + // for _, arg := range cmdArgs { + // fmt.Println(">>", arg) + // } + // time.Sleep(time.Hour) + // Run Tool cmd, err := executils.Command(cmdArgs) if err != nil { @@ -193,6 +199,7 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu defer in.Close() cmd.Stdout = out + cmd.Stderr = out if err := cmd.Start(); err != nil { fmt.Printf("%v\n", err) diff --git a/rpc/commands/commands.pb.go b/rpc/commands/commands.pb.go index 59fe7937ed8..780bbed2f1e 100644 --- a/rpc/commands/commands.pb.go +++ b/rpc/commands/commands.pb.go @@ -8,6 +8,8 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" math "math" ) @@ -597,11 +599,11 @@ var fileDescriptor_3690061a1131852d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // ArduinoCoreClient is the client API for ArduinoCore service. // @@ -641,10 +643,10 @@ type ArduinoCoreClient interface { } type arduinoCoreClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewArduinoCoreClient(cc *grpc.ClientConn) ArduinoCoreClient { +func NewArduinoCoreClient(cc grpc.ClientConnInterface) ArduinoCoreClient { return &arduinoCoreClient{cc} } @@ -1230,6 +1232,86 @@ type ArduinoCoreServer interface { LibraryList(context.Context, *LibraryListReq) (*LibraryListResp, error) } +// UnimplementedArduinoCoreServer can be embedded to have forward compatible implementations. +type UnimplementedArduinoCoreServer struct { +} + +func (*UnimplementedArduinoCoreServer) Init(req *InitReq, srv ArduinoCore_InitServer) error { + return status.Errorf(codes.Unimplemented, "method Init not implemented") +} +func (*UnimplementedArduinoCoreServer) Destroy(ctx context.Context, req *DestroyReq) (*DestroyResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Destroy not implemented") +} +func (*UnimplementedArduinoCoreServer) Rescan(ctx context.Context, req *RescanReq) (*RescanResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Rescan not implemented") +} +func (*UnimplementedArduinoCoreServer) UpdateIndex(req *UpdateIndexReq, srv ArduinoCore_UpdateIndexServer) error { + return status.Errorf(codes.Unimplemented, "method UpdateIndex not implemented") +} +func (*UnimplementedArduinoCoreServer) UpdateLibrariesIndex(req *UpdateLibrariesIndexReq, srv ArduinoCore_UpdateLibrariesIndexServer) error { + return status.Errorf(codes.Unimplemented, "method UpdateLibrariesIndex not implemented") +} +func (*UnimplementedArduinoCoreServer) Version(ctx context.Context, req *VersionReq) (*VersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") +} +func (*UnimplementedArduinoCoreServer) BoardDetails(ctx context.Context, req *BoardDetailsReq) (*BoardDetailsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BoardDetails not implemented") +} +func (*UnimplementedArduinoCoreServer) BoardAttach(req *BoardAttachReq, srv ArduinoCore_BoardAttachServer) error { + return status.Errorf(codes.Unimplemented, "method BoardAttach not implemented") +} +func (*UnimplementedArduinoCoreServer) BoardList(ctx context.Context, req *BoardListReq) (*BoardListResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BoardList not implemented") +} +func (*UnimplementedArduinoCoreServer) BoardListAll(ctx context.Context, req *BoardListAllReq) (*BoardListAllResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BoardListAll not implemented") +} +func (*UnimplementedArduinoCoreServer) Compile(req *CompileReq, srv ArduinoCore_CompileServer) error { + return status.Errorf(codes.Unimplemented, "method Compile not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformInstall(req *PlatformInstallReq, srv ArduinoCore_PlatformInstallServer) error { + return status.Errorf(codes.Unimplemented, "method PlatformInstall not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformDownload(req *PlatformDownloadReq, srv ArduinoCore_PlatformDownloadServer) error { + return status.Errorf(codes.Unimplemented, "method PlatformDownload not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformUninstall(req *PlatformUninstallReq, srv ArduinoCore_PlatformUninstallServer) error { + return status.Errorf(codes.Unimplemented, "method PlatformUninstall not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformUpgrade(req *PlatformUpgradeReq, srv ArduinoCore_PlatformUpgradeServer) error { + return status.Errorf(codes.Unimplemented, "method PlatformUpgrade not implemented") +} +func (*UnimplementedArduinoCoreServer) Upload(req *UploadReq, srv ArduinoCore_UploadServer) error { + return status.Errorf(codes.Unimplemented, "method Upload not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformSearch(ctx context.Context, req *PlatformSearchReq) (*PlatformSearchResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PlatformSearch not implemented") +} +func (*UnimplementedArduinoCoreServer) PlatformList(ctx context.Context, req *PlatformListReq) (*PlatformListResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PlatformList not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryDownload(req *LibraryDownloadReq, srv ArduinoCore_LibraryDownloadServer) error { + return status.Errorf(codes.Unimplemented, "method LibraryDownload not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryInstall(req *LibraryInstallReq, srv ArduinoCore_LibraryInstallServer) error { + return status.Errorf(codes.Unimplemented, "method LibraryInstall not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryUninstall(req *LibraryUninstallReq, srv ArduinoCore_LibraryUninstallServer) error { + return status.Errorf(codes.Unimplemented, "method LibraryUninstall not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryUpgradeAll(req *LibraryUpgradeAllReq, srv ArduinoCore_LibraryUpgradeAllServer) error { + return status.Errorf(codes.Unimplemented, "method LibraryUpgradeAll not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryResolveDependencies(ctx context.Context, req *LibraryResolveDependenciesReq) (*LibraryResolveDependenciesResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method LibraryResolveDependencies not implemented") +} +func (*UnimplementedArduinoCoreServer) LibrarySearch(ctx context.Context, req *LibrarySearchReq) (*LibrarySearchResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method LibrarySearch not implemented") +} +func (*UnimplementedArduinoCoreServer) LibraryList(ctx context.Context, req *LibraryListReq) (*LibraryListResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method LibraryList not implemented") +} + func RegisterArduinoCoreServer(s *grpc.Server, srv ArduinoCoreServer) { s.RegisterService(&_ArduinoCore_serviceDesc, srv) } diff --git a/rpc/debug/debug.pb.go b/rpc/debug/debug.pb.go index 4cec8aad7f8..2090e87850f 100644 --- a/rpc/debug/debug.pb.go +++ b/rpc/debug/debug.pb.go @@ -8,6 +8,8 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" math "math" ) @@ -28,15 +30,15 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // All subsequent messages must contain bytes to be sent to the debug session // and must not contain a `DebugReq` message. type DebugReq struct { - // Content must be either a debug session config or data to be sent. - // - // Types that are valid to be assigned to Content: - // *DebugReq_DebugReq - // *DebugReq_Data - Content isDebugReq_Content `protobuf_oneof:"content"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + // Provides information to the debug that specifies which is the target. + // The first `StreamingOpenReq` message must contain a `DebugReq` + // message. + DebugReq *DebugConfigReq `protobuf:"bytes,1,opt,name=debugReq,proto3" json:"debugReq,omitempty"` + // The data to be sent to the target being monitored. + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *DebugReq) Reset() { *m = DebugReq{} } @@ -64,51 +66,20 @@ func (m *DebugReq) XXX_DiscardUnknown() { var xxx_messageInfo_DebugReq proto.InternalMessageInfo -type isDebugReq_Content interface { - isDebugReq_Content() -} - -type DebugReq_DebugReq struct { - DebugReq *DebugConfigReq `protobuf:"bytes,1,opt,name=debugReq,proto3,oneof"` -} - -type DebugReq_Data struct { - Data []byte `protobuf:"bytes,2,opt,name=data,proto3,oneof"` -} - -func (*DebugReq_DebugReq) isDebugReq_Content() {} - -func (*DebugReq_Data) isDebugReq_Content() {} - -func (m *DebugReq) GetContent() isDebugReq_Content { - if m != nil { - return m.Content - } - return nil -} - func (m *DebugReq) GetDebugReq() *DebugConfigReq { - if x, ok := m.GetContent().(*DebugReq_DebugReq); ok { - return x.DebugReq + if m != nil { + return m.DebugReq } return nil } func (m *DebugReq) GetData() []byte { - if x, ok := m.GetContent().(*DebugReq_Data); ok { - return x.Data + if m != nil { + return m.Data } return nil } -// XXX_OneofWrappers is for the internal use of the proto package. -func (*DebugReq) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*DebugReq_DebugReq)(nil), - (*DebugReq_Data)(nil), - } -} - type DebugConfigReq struct { Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` Fqbn string `protobuf:"bytes,2,opt,name=fqbn,proto3" json:"fqbn,omitempty"` @@ -287,38 +258,37 @@ func init() { func init() { proto.RegisterFile("debug/debug.proto", fileDescriptor_5ae24eab94cb53d5) } var fileDescriptor_5ae24eab94cb53d5 = []byte{ - // 352 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0x4f, 0x6f, 0xe2, 0x30, - 0x10, 0xc5, 0x09, 0x4b, 0x96, 0x30, 0x20, 0xa4, 0xb5, 0x90, 0x36, 0xe2, 0xb2, 0x90, 0xcb, 0x46, - 0xaa, 0x48, 0x2a, 0xaa, 0x1e, 0x7b, 0xa1, 0x7f, 0x44, 0x6f, 0x95, 0xd5, 0x53, 0xa5, 0x0a, 0x39, - 0xb6, 0x21, 0x56, 0x83, 0x1d, 0x1c, 0xd3, 0x2f, 0xda, 0x2f, 0x54, 0xd9, 0x49, 0x90, 0x7a, 0xa0, - 0xbd, 0x24, 0x6f, 0x9c, 0xf7, 0x7b, 0x93, 0x99, 0x04, 0xfe, 0x30, 0x9e, 0x1d, 0x77, 0xa9, 0xbb, - 0x26, 0xa5, 0x56, 0x46, 0xa1, 0xbf, 0x94, 0x26, 0x44, 0xb3, 0xa3, 0x90, 0x2a, 0xa1, 0x85, 0x48, - 0xa8, 0xda, 0xef, 0x89, 0x64, 0x55, 0xa4, 0x21, 0xb8, 0xb3, 0x3e, 0xcc, 0x0f, 0xe8, 0x1e, 0x02, - 0xd6, 0xe8, 0xd0, 0x9b, 0x79, 0xf1, 0x70, 0xf9, 0x3f, 0x39, 0xc3, 0x25, 0x0e, 0xba, 0x55, 0x72, - 0x2b, 0xac, 0x7d, 0xdd, 0xc1, 0x27, 0x14, 0x4d, 0xa0, 0xc7, 0x88, 0x21, 0x61, 0x77, 0xe6, 0xc5, - 0xa3, 0x75, 0x07, 0xbb, 0x6a, 0x35, 0x80, 0x3e, 0x55, 0xd2, 0x70, 0x69, 0xa2, 0x0f, 0x0f, 0xc6, - 0x5f, 0x79, 0x74, 0x03, 0x81, 0x90, 0x95, 0x21, 0x92, 0xf2, 0xa6, 0xf5, 0xfc, 0x6c, 0xeb, 0xc7, - 0xc6, 0x88, 0x4f, 0x08, 0x42, 0xd0, 0xdb, 0x1e, 0x32, 0xe9, 0x5a, 0x0e, 0xb0, 0xd3, 0xe8, 0x1f, - 0x0c, 0xab, 0x37, 0x6e, 0x68, 0xbe, 0x29, 0x89, 0xc9, 0xc3, 0x5f, 0xee, 0x11, 0xd4, 0x47, 0x4f, - 0xc4, 0xe4, 0x16, 0x2a, 0x95, 0x36, 0x61, 0xaf, 0x86, 0xac, 0x46, 0x21, 0xf4, 0xdf, 0xb9, 0xce, - 0x54, 0xc5, 0x43, 0x7f, 0xe6, 0xc5, 0x01, 0x6e, 0x4b, 0x1b, 0x27, 0xf6, 0xd6, 0xb3, 0xd9, 0x8a, - 0x82, 0x87, 0xfd, 0x3a, 0xae, 0x3e, 0x7a, 0x10, 0x05, 0x8f, 0xae, 0x61, 0xd0, 0x6c, 0xb2, 0x2a, - 0x6d, 0xb6, 0xdb, 0x81, 0x9d, 0x65, 0x54, 0x6f, 0x00, 0x4d, 0xc0, 0xe7, 0x5a, 0x2b, 0xdd, 0xbc, - 0x65, 0x5d, 0x44, 0x53, 0x08, 0xda, 0x81, 0xd0, 0x18, 0xba, 0x82, 0x39, 0xc6, 0xc7, 0x5d, 0xc1, - 0x96, 0xaf, 0xe0, 0xbb, 0x48, 0xf4, 0xdc, 0x8a, 0xf9, 0xf7, 0x1f, 0x04, 0xf3, 0xc3, 0x34, 0xfa, - 0xc9, 0x52, 0x95, 0x51, 0x27, 0xf6, 0x2e, 0xbd, 0xd5, 0xe2, 0xe5, 0x62, 0x27, 0x4c, 0x7e, 0xcc, - 0xac, 0x25, 0x6d, 0x90, 0xf6, 0xbe, 0xa0, 0x85, 0x48, 0x75, 0x49, 0xd3, 0x16, 0xcf, 0x7e, 0xbb, - 0x5f, 0xe9, 0xea, 0x33, 0x00, 0x00, 0xff, 0xff, 0x2b, 0xc0, 0xf0, 0xc3, 0x5f, 0x02, 0x00, 0x00, + // 335 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xd1, 0x4b, 0xeb, 0x30, + 0x14, 0xc6, 0x6f, 0x76, 0xd7, 0xbb, 0xee, 0xec, 0x32, 0x30, 0x08, 0x86, 0xbd, 0xb8, 0xf5, 0xc5, + 0x82, 0xac, 0x95, 0x89, 0x8f, 0xbe, 0x38, 0x11, 0x7c, 0x93, 0xe0, 0x93, 0x20, 0x23, 0x4d, 0xb2, + 0x35, 0xd8, 0x35, 0x5d, 0x9a, 0xf9, 0x8f, 0xfa, 0x0f, 0x49, 0xd2, 0x76, 0xe2, 0xc3, 0xf4, 0xa5, + 0xfd, 0xce, 0xe9, 0xf7, 0x3b, 0x5f, 0x4f, 0x1b, 0x38, 0x11, 0x32, 0xdb, 0x6f, 0x52, 0x7f, 0x4d, + 0x2a, 0xa3, 0xad, 0xc6, 0x67, 0x9c, 0x27, 0xcc, 0x88, 0xbd, 0x2a, 0x75, 0xc2, 0x0b, 0x95, 0x70, + 0xbd, 0xdd, 0xb2, 0x52, 0xd4, 0x11, 0x87, 0xf0, 0xde, 0xf9, 0xa8, 0xdc, 0xe1, 0x25, 0x84, 0xa2, + 0xd5, 0x04, 0x4d, 0x51, 0x3c, 0x5a, 0x5c, 0x24, 0x47, 0xb8, 0xc4, 0x43, 0x4b, 0x5d, 0xae, 0x95, + 0xb3, 0xd3, 0x03, 0x88, 0x31, 0xf4, 0x05, 0xb3, 0x8c, 0xf4, 0xa6, 0x28, 0xfe, 0x4f, 0xbd, 0x8e, + 0x3e, 0x10, 0x8c, 0xbf, 0x03, 0xf8, 0x16, 0x42, 0x55, 0xd6, 0x96, 0x95, 0x5c, 0xb6, 0x59, 0xb3, + 0xa3, 0x59, 0x8f, 0xad, 0x91, 0x1e, 0x10, 0x97, 0xb2, 0xde, 0x65, 0xa5, 0x4f, 0x19, 0x52, 0xaf, + 0xf1, 0x39, 0x8c, 0xea, 0x37, 0x69, 0x79, 0xbe, 0xaa, 0x98, 0xcd, 0xc9, 0x5f, 0xff, 0x08, 0x9a, + 0xd6, 0x13, 0xb3, 0xb9, 0x83, 0x2a, 0x6d, 0x2c, 0xe9, 0x37, 0x90, 0xd3, 0x98, 0xc0, 0xe0, 0x5d, + 0x9a, 0x4c, 0xd7, 0x92, 0x04, 0x53, 0x14, 0x87, 0xb4, 0x2b, 0xdd, 0x38, 0xb5, 0x75, 0x9e, 0xd5, + 0x5a, 0x15, 0x92, 0x0c, 0x9a, 0x71, 0x4d, 0xeb, 0x41, 0x15, 0x32, 0xba, 0x81, 0x61, 0xfb, 0xe9, + 0xea, 0xea, 0xb0, 0x36, 0xfa, 0x5a, 0x1b, 0x9f, 0x42, 0x20, 0x8d, 0xd1, 0xa6, 0x7d, 0xcb, 0xa6, + 0x88, 0x26, 0x10, 0x76, 0x0b, 0xe1, 0x31, 0xf4, 0x94, 0xf0, 0x4c, 0x40, 0x7b, 0x4a, 0x2c, 0x5e, + 0x21, 0xf0, 0x23, 0xf1, 0x73, 0x27, 0x66, 0x3f, 0xff, 0x01, 0x2a, 0x77, 0x93, 0xe8, 0x37, 0x4b, + 0x5d, 0x45, 0x7f, 0x62, 0x74, 0x85, 0xee, 0xe6, 0x2f, 0x97, 0x1b, 0x65, 0xf3, 0x7d, 0xe6, 0x2c, + 0x69, 0x8b, 0x74, 0xf7, 0x39, 0x2f, 0x54, 0x6a, 0x2a, 0x9e, 0x76, 0x78, 0xf6, 0xcf, 0x9f, 0x9d, + 0xeb, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x86, 0x6c, 0xb4, 0xc7, 0x50, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // DebugClient is the client API for Debug service. // @@ -328,10 +298,10 @@ type DebugClient interface { } type debugClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewDebugClient(cc *grpc.ClientConn) DebugClient { +func NewDebugClient(cc grpc.ClientConnInterface) DebugClient { return &debugClient{cc} } @@ -371,6 +341,14 @@ type DebugServer interface { Debug(Debug_DebugServer) error } +// UnimplementedDebugServer can be embedded to have forward compatible implementations. +type UnimplementedDebugServer struct { +} + +func (*UnimplementedDebugServer) Debug(srv Debug_DebugServer) error { + return status.Errorf(codes.Unimplemented, "method Debug not implemented") +} + func RegisterDebugServer(s *grpc.Server, srv DebugServer) { s.RegisterService(&_Debug_serviceDesc, srv) } diff --git a/rpc/debug/debug.proto b/rpc/debug/debug.proto index 9477f699e16..ce520fa9bda 100644 --- a/rpc/debug/debug.proto +++ b/rpc/debug/debug.proto @@ -32,15 +32,14 @@ service Debug { // and must not contain a `DebugReq` message. message DebugReq { // Content must be either a debug session config or data to be sent. - oneof content { - // Provides information to the debug that specifies which is the target. - // The first `StreamingOpenReq` message must contain a `DebugReq` - // message. - DebugConfigReq debugReq = 1; - // The data to be sent to the target being monitored. - bytes data = 2; - } + // Provides information to the debug that specifies which is the target. + // The first `StreamingOpenReq` message must contain a `DebugReq` + // message. + DebugConfigReq debugReq = 1; + + // The data to be sent to the target being monitored. + bytes data = 2; } message DebugConfigReq { diff --git a/rpc/monitor/monitor.pb.go b/rpc/monitor/monitor.pb.go index 78238c1565a..1a06ba48521 100644 --- a/rpc/monitor/monitor.pb.go +++ b/rpc/monitor/monitor.pb.go @@ -9,6 +9,8 @@ import ( proto "github.com/golang/protobuf/proto" _struct "github.com/golang/protobuf/ptypes/struct" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" math "math" ) @@ -266,11 +268,11 @@ var fileDescriptor_94d5950496a7550d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // MonitorClient is the client API for Monitor service. // @@ -280,10 +282,10 @@ type MonitorClient interface { } type monitorClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewMonitorClient(cc *grpc.ClientConn) MonitorClient { +func NewMonitorClient(cc grpc.ClientConnInterface) MonitorClient { return &monitorClient{cc} } @@ -323,6 +325,14 @@ type MonitorServer interface { StreamingOpen(Monitor_StreamingOpenServer) error } +// UnimplementedMonitorServer can be embedded to have forward compatible implementations. +type UnimplementedMonitorServer struct { +} + +func (*UnimplementedMonitorServer) StreamingOpen(srv Monitor_StreamingOpenServer) error { + return status.Errorf(codes.Unimplemented, "method StreamingOpen not implemented") +} + func RegisterMonitorServer(s *grpc.Server, srv MonitorServer) { s.RegisterService(&_Monitor_serviceDesc, srv) } diff --git a/rpc/settings/settings.pb.go b/rpc/settings/settings.pb.go index 1bbc54f255d..0537c7d9e3a 100644 --- a/rpc/settings/settings.pb.go +++ b/rpc/settings/settings.pb.go @@ -8,6 +8,8 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" math "math" ) @@ -275,11 +277,11 @@ var fileDescriptor_a4bfd59e429426d0 = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // SettingsClient is the client API for Settings service. // @@ -292,10 +294,10 @@ type SettingsClient interface { } type settingsClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewSettingsClient(cc *grpc.ClientConn) SettingsClient { +func NewSettingsClient(cc grpc.ClientConnInterface) SettingsClient { return &settingsClient{cc} } @@ -343,6 +345,23 @@ type SettingsServer interface { SetValue(context.Context, *Value) (*SetValueResponse, error) } +// UnimplementedSettingsServer can be embedded to have forward compatible implementations. +type UnimplementedSettingsServer struct { +} + +func (*UnimplementedSettingsServer) GetAll(ctx context.Context, req *GetAllRequest) (*RawData, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAll not implemented") +} +func (*UnimplementedSettingsServer) Merge(ctx context.Context, req *RawData) (*MergeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Merge not implemented") +} +func (*UnimplementedSettingsServer) GetValue(ctx context.Context, req *GetValueRequest) (*Value, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetValue not implemented") +} +func (*UnimplementedSettingsServer) SetValue(ctx context.Context, req *Value) (*SetValueResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetValue not implemented") +} + func RegisterSettingsServer(s *grpc.Server, srv SettingsServer) { s.RegisterService(&_Settings_serviceDesc, srv) } From 7648814244dcb2c1ec7873a9cc3dcdc5e5ad82eb Mon Sep 17 00:00:00 2001 From: rsora Date: Mon, 17 Feb 2020 18:34:55 +0100 Subject: [PATCH 08/29] updated client example for testing --- client_example/main.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client_example/main.go b/client_example/main.go index ce03ece43a9..997639d33ed 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -80,7 +80,7 @@ func main() { err = debugStreamingOpenClient.Send(&dbg.DebugReq{ DebugReq: &dbg.DebugConfigReq{ Instance: &dbg.Instance{Id: instance.GetId()}, - Fqbn: "arduino-sadsadasd:samd:arduino_zero_edbg", + Fqbn: "arduino-pippo:samd:arduino_zero_edbg", SketchPath: os.Args[1], Port: "none", }}) @@ -88,8 +88,8 @@ func main() { log.Fatalf("Send error: %s\n", err) } log.Println("calling StreamingOpenReq_DebugReq") - - err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("\n")}) + time.Sleep(time.Second * 3) + err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("info registers\n")}) if err != nil { log.Fatalf("Send error: %s\n", err) } @@ -112,10 +112,10 @@ func main() { // When an operation is ongoing you can get its output if resp := compResp.GetData(); resp != nil { - fmt.Printf(">>%s<<", resp) - if string(resp) == "(gdb) " { - break - } + fmt.Printf("%s", resp) + //if string(resp) == "(gdb) " { + // break + //} } } From 3960fea1592df757ce3395cd42af0accd4b4cc21 Mon Sep 17 00:00:00 2001 From: rsora Date: Wed, 19 Feb 2020 15:53:39 +0100 Subject: [PATCH 09/29] Implement debug command --- cli/cli.go | 2 + cli/debug/debug.go | 98 ++++++++++++++++++++++++++++++++++++++++ commands/daemon/debug.go | 16 ++++++- commands/debug/debug.go | 11 +---- 4 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 cli/debug/debug.go diff --git a/cli/cli.go b/cli/cli.go index f1c81d7a697..8c8b0a87871 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -17,6 +17,7 @@ package cli import ( "fmt" + "github.com/arduino/arduino-cli/cli/debug" "io/ioutil" "os" "path/filepath" @@ -77,6 +78,7 @@ func createCliCommandTree(cmd *cobra.Command) { cmd.AddCommand(lib.NewCommand()) cmd.AddCommand(sketch.NewCommand()) cmd.AddCommand(upload.NewCommand()) + cmd.AddCommand(debug.NewCommand()) cmd.AddCommand(version.NewCommand()) cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the logs on the standard output.") diff --git a/cli/debug/debug.go b/cli/debug/debug.go new file mode 100644 index 00000000000..d47533e563b --- /dev/null +++ b/cli/debug/debug.go @@ -0,0 +1,98 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package debug + +import ( + "context" + "os" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" + "github.com/arduino/arduino-cli/cli/instance" + "github.com/arduino/arduino-cli/commands/debug" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/go-paths-helper" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var ( + fqbn string + port string + verbose bool + verify bool + importFile string +) + +// NewCommand created a new `upload` command +func NewCommand() *cobra.Command { + debugCommand := &cobra.Command{ + Use: "debug", + Short: "Debug Arduino sketches.", + Long: "Debug Arduino sketches.", + Example: " " + os.Args[0] + " debug /home/user/Arduino/MySketch", + Args: cobra.MaximumNArgs(1), + Run: run, + } + + debugCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno") + debugCommand.Flags().StringVarP(&port, "port", "p", "", "Upload port, e.g.: COM10 or /dev/ttyACM0") + debugCommand.Flags().StringVarP(&importFile, "input", "i", "", "Input file to be uploaded.") + + debugCommand.MarkFlagRequired("port") + + return debugCommand +} + +func run(command *cobra.Command, args []string) { + instance, err := instance.CreateInstance() + if err != nil { + feedback.Errorf("Error during Debug: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + + var path *paths.Path + if len(args) > 0 { + path = paths.New(args[0]) + } + sketchPath := initSketchPath(path) + + if _, err := debug.Debug(context.Background(), &dbg.DebugConfigReq{ + Instance: &dbg.Instance{Id: instance.GetId()}, + Fqbn: fqbn, + SketchPath: sketchPath.String(), + Port: port, + ImportFile: importFile, + }, os.Stdin, os.Stdout); err != nil { + feedback.Errorf("Error during Upload: %v", err) + os.Exit(errorcodes.ErrGeneric) + } +} + +// initSketchPath returns the current working directory +func initSketchPath(sketchPath *paths.Path) *paths.Path { + if sketchPath != nil { + return sketchPath + } + + wd, err := paths.Getwd() + if err != nil { + feedback.Errorf("Couldn't get current working directory: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + logrus.Infof("Reading sketch from dir: %s", wd) + return wd +} diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go index 0955ff300a9..b6dadad8bfc 100644 --- a/commands/daemon/debug.go +++ b/commands/daemon/debug.go @@ -17,8 +17,9 @@ package daemon import ( "fmt" - cmd "github.com/arduino/arduino-cli/commands/debug" + "io" + dbg "github.com/arduino/arduino-cli/rpc/debug" ) @@ -42,8 +43,19 @@ func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { return fmt.Errorf("first message must contain debug request, not data") } + r, w := io.Pipe() + go func() { + for { + if command, err := stream.Recv(); err != nil { + return + } else if _, err := w.Write(command.GetData()); err != nil { + return + } + } + }() + // launch debug recipe attaching stdin and out to grpc streaming - resp, err := cmd.Debug(stream.Context(), req, stream, feedStream(func(data []byte) { + resp, err := cmd.Debug(stream.Context(), req, r, feedStream(func(data []byte) { stream.Send(&dbg.DebugResp{Data: data}) })) if err != nil { diff --git a/commands/debug/debug.go b/commands/debug/debug.go index 8ebc0cb5a22..dd1703ea6af 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -36,7 +36,7 @@ import ( ) // Debug FIXMEDOC -func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_DebugServer, out io.Writer) (*dbg.DebugResp, error) { +func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out io.Writer) (*dbg.DebugResp, error) { // TODO: make a generic function to extract sketch from request // and remove duplication in commands/compile.go @@ -208,14 +208,7 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream dbg.Debug_Debu // now we can read the other commands and re-route to the Debug Client... go func() { - for { - if command, err := inStream.Recv(); err != nil { - break - } else if _, err := in.Write(command.GetData()); err != nil { - break - } - } - + io.Copy(in, inStream) // In any case, try process termination after a second to avoid leaving // zombie process. time.Sleep(time.Second) From 52287095bb6ab55d6399160048e61621e7298e3f Mon Sep 17 00:00:00 2001 From: rsora Date: Wed, 19 Feb 2020 16:17:05 +0100 Subject: [PATCH 10/29] Implement copyStream --- commands/daemon/debug.go | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go index b6dadad8bfc..7015e81924a 100644 --- a/commands/daemon/debug.go +++ b/commands/daemon/debug.go @@ -43,23 +43,32 @@ func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { return fmt.Errorf("first message must contain debug request, not data") } + // launch debug recipe attaching stdin and out to grpc streaming + resp, err := cmd.Debug(stream.Context(), req, + copyStream(func() ([]byte, error) { + command, err := stream.Recv() + return command.GetData(), err + }), + feedStream(func(data []byte) { + stream.Send(&dbg.DebugResp{Data: data}) + })) + if err != nil { + return (err) + } + return stream.Send(resp) +} + +func copyStream(streamIn func() ([]byte, error)) io.Reader { + r, w := io.Pipe() go func() { for { - if command, err := stream.Recv(); err != nil { + if data, err := streamIn(); err != nil { return - } else if _, err := w.Write(command.GetData()); err != nil { + } else if _, err := w.Write(data); err != nil { return } } }() - - // launch debug recipe attaching stdin and out to grpc streaming - resp, err := cmd.Debug(stream.Context(), req, r, feedStream(func(data []byte) { - stream.Send(&dbg.DebugResp{Data: data}) - })) - if err != nil { - return (err) - } - return stream.Send(resp) + return r } From 9d314abf77537b026524db35e8ba0ae75fcd6097 Mon Sep 17 00:00:00 2001 From: rsora Date: Wed, 19 Feb 2020 17:18:30 +0100 Subject: [PATCH 11/29] Refactor stream helpers --- arduino/utils/stream.go | 52 +++++++++++++++++++++++++++++++++++++++ commands/daemon/daemon.go | 21 +++------------- commands/daemon/debug.go | 22 +++-------------- 3 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 arduino/utils/stream.go diff --git a/arduino/utils/stream.go b/arduino/utils/stream.go new file mode 100644 index 00000000000..2cce6043097 --- /dev/null +++ b/arduino/utils/stream.go @@ -0,0 +1,52 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package utils + +import "io" + +// FeedStreamTo creates a pipe to pass data to the writer function. +// FeedStreamTo returns the io.Writer side of the pipe, on which the user can write data +func FeedStreamTo(writer func(data []byte)) io.Writer { + r, w := io.Pipe() + go func() { + data := make([]byte, 1024) + for { + if n, err := r.Read(data); err == nil { + writer(data[:n]) + } else { + return + } + } + }() + return w +} + +// ConsumeStreamFrom creates a pipe to consume data from the reader function. +// ConsumeStreamFrom returns the io.Reader side of the pipe, which the user can use to consume the data +func ConsumeStreamFrom(reader func() ([]byte, error)) io.Reader { + + r, w := io.Pipe() + go func() { + for { + if data, err := reader(); err != nil { + return + } else if _, err := w.Write(data); err != nil { + return + } + } + }() + return r +} diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index 38e195a3495..d11ba0c06a2 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -19,9 +19,9 @@ package daemon import ( "context" - "io" "net/http" + "github.com/arduino/arduino-cli/arduino/utils" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/commands/board" "github.com/arduino/arduino-cli/commands/compile" @@ -125,8 +125,8 @@ func (s *ArduinoCoreServerImpl) Version(ctx context.Context, req *rpc.VersionReq func (s *ArduinoCoreServerImpl) Compile(req *rpc.CompileReq, stream rpc.ArduinoCore_CompileServer) error { resp, err := compile.Compile( stream.Context(), req, - feedStream(func(data []byte) { stream.Send(&rpc.CompileResp{OutStream: data}) }), - feedStream(func(data []byte) { stream.Send(&rpc.CompileResp{ErrStream: data}) }), + utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.CompileResp{OutStream: data}) }), + utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.CompileResp{ErrStream: data}) }), false) // set debug to false if err != nil { return err @@ -222,21 +222,6 @@ func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadReq, stream rpc.ArduinoCor return stream.Send(resp) } -func feedStream(streamer func(data []byte)) io.Writer { - r, w := io.Pipe() - go func() { - data := make([]byte, 1024) - for { - if n, err := r.Read(data); err == nil { - streamer(data[:n]) - } else { - return - } - } - }() - return w -} - // LibraryDownload FIXMEDOC func (s *ArduinoCoreServerImpl) LibraryDownload(req *rpc.LibraryDownloadReq, stream rpc.ArduinoCore_LibraryDownloadServer) error { resp, err := lib.LibraryDownload( diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go index 7015e81924a..6107fac57df 100644 --- a/commands/daemon/debug.go +++ b/commands/daemon/debug.go @@ -17,9 +17,8 @@ package daemon import ( "fmt" + "github.com/arduino/arduino-cli/arduino/utils" cmd "github.com/arduino/arduino-cli/commands/debug" - "io" - dbg "github.com/arduino/arduino-cli/rpc/debug" ) @@ -45,11 +44,11 @@ func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { // launch debug recipe attaching stdin and out to grpc streaming resp, err := cmd.Debug(stream.Context(), req, - copyStream(func() ([]byte, error) { + utils.ConsumeStreamFrom(func() ([]byte, error) { command, err := stream.Recv() return command.GetData(), err }), - feedStream(func(data []byte) { + utils.FeedStreamTo(func(data []byte) { stream.Send(&dbg.DebugResp{Data: data}) })) if err != nil { @@ -57,18 +56,3 @@ func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { } return stream.Send(resp) } - -func copyStream(streamIn func() ([]byte, error)) io.Reader { - - r, w := io.Pipe() - go func() { - for { - if data, err := streamIn(); err != nil { - return - } else if _, err := w.Write(data); err != nil { - return - } - } - }() - return r -} From 8d44e6fdf7816bbd2c0e599c8953bc0a6423be13 Mon Sep 17 00:00:00 2001 From: rsora Date: Wed, 19 Feb 2020 17:46:08 +0100 Subject: [PATCH 12/29] Extract recipe creation from debug command --- commands/debug/debug.go | 115 ++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/commands/debug/debug.go b/commands/debug/debug.go index dd1703ea6af..89ea60849eb 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -35,9 +35,62 @@ import ( dbg "github.com/arduino/arduino-cli/rpc/debug" ) -// Debug FIXMEDOC +// Debug command launches a debug tool for a sketch. +// It also implements streams routing: +// gRPC In -> tool stdIn +// grpc Out <- tool stdOut +// grpc Out <- tool stdErr +// It also implements tool process lifecycle management func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out io.Writer) (*dbg.DebugResp, error) { + // get tool commandLine from core recipe + commandLine, err := getCommandLine(req) + if err != nil { + return nil, fmt.Errorf("cannot get command line for tool: %s", err) + } + + // Run Tool + cmd, err := executils.Command(commandLine) + if err != nil { + return nil, fmt.Errorf("cannot execute debug tool: %s", err) + } + + // Get stdIn pipe from tool + in, err := cmd.StdinPipe() + if err != nil { + fmt.Printf("%v\n", err) + return &dbg.DebugResp{Error: err.Error()}, nil + } + defer in.Close() + + // Merge tool StdOut and StdErr to stream them in the io.Writer passed stream + cmd.Stdout = out + cmd.Stderr = out + + // Start the debug command + if err := cmd.Start(); err != nil { + fmt.Printf("%v\n", err) + return &dbg.DebugResp{Error: err.Error()}, nil + } + + go func() { + // copy data from passed inStream into command stdIn + io.Copy(in, inStream) + // In any case, try process termination after a second to avoid leaving + // zombie process. + time.Sleep(time.Second) + cmd.Process.Kill() + }() + + // Wait for process to finish + if err := cmd.Wait(); err != nil { + return &dbg.DebugResp{Error: err.Error()}, nil + } + return &dbg.DebugResp{}, nil +} + +// getCommandLine compose a debug command represented by a core recipe +func getCommandLine(req *dbg.DebugConfigReq) ([]string, error) { // TODO: make a generic function to extract sketch from request // and remove duplication in commands/compile.go if req.GetSketchPath() == "" { @@ -52,7 +105,7 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out // FIXME: make a specification on how a port is specified via command line port := req.GetPort() if port == "" { - return nil, fmt.Errorf("no upload port provided") + return nil, fmt.Errorf("no debug port provided") } fqbnIn := req.GetFqbn() @@ -98,7 +151,7 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out } } - // Build configuration for upload + // Build configuration for debug toolProperties := properties.NewMap() if referencedPlatformRelease != nil { toolProperties.Merge(referencedPlatformRelease.Properties) @@ -109,26 +162,13 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out requestedToolProperties := toolProperties.SubTree("tools." + toolName) toolProperties.Merge(requestedToolProperties) - if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil { for _, requiredTool := range requiredTools { - logrus.WithField("tool", requiredTool).Info("Tool required for upload") + logrus.WithField("tool", requiredTool).Info("Tool required for debug") toolProperties.Merge(requiredTool.RuntimeProperties()) } } - // Set properties for verbose upload - verbose := req.GetVerbose() - if verbose { - if v, ok := toolProperties.GetOk("debug.params.verbose"); ok { - toolProperties.Set("debug.verbose", v) - } - } else { - if v, ok := toolProperties.GetOk("debug.params.quiet"); ok { - toolProperties.Set("debug.verbose", v) - } - } - // Set path to compiled binary // Make the filename without the FQBN configs part fqbn.Configs = properties.NewMap() @@ -179,44 +219,5 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out if err != nil { return nil, fmt.Errorf("invalid recipe '%s': %s", recipe, err) } - - // for _, arg := range cmdArgs { - // fmt.Println(">>", arg) - // } - // time.Sleep(time.Hour) - - // Run Tool - cmd, err := executils.Command(cmdArgs) - if err != nil { - return nil, fmt.Errorf("cannot execute upload tool: %s", err) - } - - in, err := cmd.StdinPipe() - if err != nil { - fmt.Printf("%v\n", err) - return &dbg.DebugResp{Error: err.Error()}, nil - } - defer in.Close() - - cmd.Stdout = out - cmd.Stderr = out - - if err := cmd.Start(); err != nil { - fmt.Printf("%v\n", err) - return &dbg.DebugResp{Error: err.Error()}, nil - } - - // now we can read the other commands and re-route to the Debug Client... - go func() { - io.Copy(in, inStream) - // In any case, try process termination after a second to avoid leaving - // zombie process. - time.Sleep(time.Second) - cmd.Process.Kill() - }() - - if err := cmd.Wait(); err != nil { - return &dbg.DebugResp{Error: err.Error()}, nil - } - return &dbg.DebugResp{}, nil + return cmdArgs, nil } From 9923f628f5cfb240868d391319ae8c7a807107fc Mon Sep 17 00:00:00 2001 From: rsora Date: Wed, 19 Feb 2020 13:07:35 +0100 Subject: [PATCH 13/29] Add test for debug recipe generation --- commands/debug/debug.go | 8 +- commands/debug/debug_test.go | 86 +++++++ commands/debug/testdata/.gitignore | 1 + .../arduino-test/samd/boards.txt | 114 +++++++++ .../arduino-test/samd/platform.txt | 231 ++++++++++++++++++ .../7-2017q4/bin/arm-none-eabi-gdb | 0 .../tools/openocd/0.10.0-arduino7/bin/openocd | 0 7 files changed, 436 insertions(+), 4 deletions(-) create mode 100644 commands/debug/debug_test.go create mode 100644 commands/debug/testdata/.gitignore create mode 100644 commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt create mode 100644 commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt create mode 100644 commands/debug/testdata/data_dir/packages/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-gdb create mode 100644 commands/debug/testdata/data_dir/packages/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd diff --git a/commands/debug/debug.go b/commands/debug/debug.go index 89ea60849eb..fff62760418 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -25,6 +25,7 @@ import ( "time" "github.com/arduino/arduino-cli/arduino/cores" + "github.com/arduino/arduino-cli/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/arduino/sketches" "github.com/arduino/arduino-cli/commands" "github.com/arduino/go-paths-helper" @@ -44,7 +45,8 @@ import ( func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out io.Writer) (*dbg.DebugResp, error) { // get tool commandLine from core recipe - commandLine, err := getCommandLine(req) + pm := commands.GetPackageManager(req.GetInstance().GetId()) + commandLine, err := getCommandLine(req, pm) if err != nil { return nil, fmt.Errorf("cannot get command line for tool: %s", err) } @@ -90,7 +92,7 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out } // getCommandLine compose a debug command represented by a core recipe -func getCommandLine(req *dbg.DebugConfigReq) ([]string, error) { +func getCommandLine(req *dbg.DebugConfigReq, pm *packagemanager.PackageManager) ([]string, error) { // TODO: make a generic function to extract sketch from request // and remove duplication in commands/compile.go if req.GetSketchPath() == "" { @@ -120,8 +122,6 @@ func getCommandLine(req *dbg.DebugConfigReq) ([]string, error) { return nil, fmt.Errorf("incorrect FQBN: %s", err) } - pm := commands.GetPackageManager(req.GetInstance().GetId()) - // Find target board and board properties _, _, board, boardProperties, _, err := pm.ResolveFQBN(fqbn) if err != nil { diff --git a/commands/debug/debug_test.go b/commands/debug/debug_test.go new file mode 100644 index 00000000000..81236f68f10 --- /dev/null +++ b/commands/debug/debug_test.go @@ -0,0 +1,86 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package debug + +import ( + "fmt" + "github.com/arduino/arduino-cli/arduino/cores/packagemanager" + rpc "github.com/arduino/arduino-cli/rpc/common" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/go-paths-helper" + "github.com/stretchr/testify/assert" + "strings" + "testing" +) + +var customHardware = paths.New("testdata", "custom_hardware") +var dataDir = paths.New("testdata", "data_dir", "packages") +var sketch = "hello" +var sketchPath = paths.New("testdata", sketch).String() + +func TestGetCommandLine(t *testing.T) { + pm := packagemanager.NewPackageManager(nil, nil, nil, nil) + pm.LoadHardwareFromDirectory(customHardware) + pm.LoadHardwareFromDirectory(dataDir) + + req := &dbg.DebugConfigReq{ + Instance: &rpc.Instance{Id: 1}, + Fqbn: "arduino-test:samd:arduino_zero_edbg", + SketchPath: sketchPath, + Port: "none", + } + packageName := strings.Split(req.Fqbn, ":")[0] + processor := strings.Split(req.Fqbn, ":")[1] + boardFamily := "arduino_zero" + + goldCommand := []string{ + fmt.Sprintf("%s/%s/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb", dataDir, packageName), + fmt.Sprintf("-ex"), + fmt.Sprintf("target extended-remote | %s/%s/tools/openocd/0.10.0-arduino7/bin/openocd", dataDir, packageName) + " " + + fmt.Sprintf("-s \"%s/%s/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir, packageName) + " " + + fmt.Sprintf("--file \"%s/%s/%s/variants/%s/openocd_scripts/arduino_zero.cfg\" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt", customHardware, packageName, processor, boardFamily), + fmt.Sprintf("%s/%s.%s.elf", sketchPath, sketch, strings.ReplaceAll(req.Fqbn, ":", ".")), + } + + command, err := getCommandLine(req, pm) + assert.Nil(t, err) + assert.Equal(t, goldCommand, command) + + // for other samd boards + req2 := &dbg.DebugConfigReq{ + Instance: &rpc.Instance{Id: 1}, + Fqbn: "arduino-test:samd:mkr1000", + SketchPath: sketchPath, + Port: "none", + } + packageName2 := strings.Split(req2.Fqbn, ":")[0] + processor2 := strings.Split(req2.Fqbn, ":")[1] + name2 := strings.Split(req2.Fqbn, ":")[2] + + goldCommand2 := []string{ + fmt.Sprintf("%s/%s/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb", dataDir, packageName2), + fmt.Sprintf("-ex"), + fmt.Sprintf("target extended-remote | %s/%s/tools/openocd/0.10.0-arduino7/bin/openocd", dataDir, packageName2) + " " + + fmt.Sprintf("-s \"%s/%s/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir, packageName2) + " " + + fmt.Sprintf("--file \"%s/%s/%s/variants/%s/openocd_scripts/arduino_zero.cfg\" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt", customHardware, packageName2, processor2, name2), + fmt.Sprintf("%s/%s.%s.elf", sketchPath, sketch, strings.ReplaceAll(req2.Fqbn, ":", ".")), + } + + command2, err := getCommandLine(req2, pm) + assert.Nil(t, err) + assert.Equal(t, goldCommand2, command2) + +} diff --git a/commands/debug/testdata/.gitignore b/commands/debug/testdata/.gitignore new file mode 100644 index 00000000000..a4337a420ca --- /dev/null +++ b/commands/debug/testdata/.gitignore @@ -0,0 +1 @@ +!arduino \ No newline at end of file diff --git a/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt b/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt new file mode 100644 index 00000000000..ce473db2ef9 --- /dev/null +++ b/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt @@ -0,0 +1,114 @@ +# Copyright (c) 2014-2017 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Arduino Zero (Prorgamming Port) +# --------------------------------------- +arduino_zero_edbg.name=Arduino Zero (Programming Port) +arduino_zero_edbg.vid.0=0x03eb +arduino_zero_edbg.pid.0=0x2157 + +arduino_zero_edbg.debug.tool=gdb +arduino_zero_edbg.upload.tool=openocd +arduino_zero_edbg.upload.protocol=sam-ba +arduino_zero_edbg.upload.maximum_size=262144 +arduino_zero_edbg.upload.use_1200bps_touch=false +arduino_zero_edbg.upload.wait_for_upload_port=false +arduino_zero_edbg.upload.native_usb=false +arduino_zero_edbg.build.mcu=cortex-m0plus +arduino_zero_edbg.build.f_cpu=48000000L +arduino_zero_edbg.build.usb_product="Arduino Zero" +arduino_zero_edbg.build.usb_manufacturer="Arduino LLC" +arduino_zero_edbg.build.board=SAMD_ZERO +arduino_zero_edbg.build.core=arduino +arduino_zero_edbg.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} +arduino_zero_edbg.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +arduino_zero_edbg.build.openocdscript=openocd_scripts/arduino_zero.cfg +arduino_zero_edbg.build.variant=arduino_zero +arduino_zero_edbg.build.variant_system_lib= +arduino_zero_edbg.build.vid=0x2341 +arduino_zero_edbg.build.pid=0x804d +arduino_zero_edbg.bootloader.tool=openocd +arduino_zero_edbg.bootloader.file=zero/samd21_sam_ba.bin + +# Arduino MKR1000 +# ----------------------- +mkr1000.name=Arduino MKR1000 +mkr1000.vid.0=0x2341 +mkr1000.pid.0=0x804e +mkr1000.vid.1=0x2341 +mkr1000.pid.1=0x004e +mkr1000.vid.2=0x2341 +mkr1000.pid.2=0x824e +mkr1000.vid.3=0x2341 +mkr1000.pid.3=0x024e + +mkr1000.debug.tool=gdb +mkr1000.upload.tool=bossac +mkr1000.upload.protocol=sam-ba +mkr1000.upload.maximum_size=262144 +mkr1000.upload.use_1200bps_touch=true +mkr1000.upload.wait_for_upload_port=true +mkr1000.upload.native_usb=true +mkr1000.build.mcu=cortex-m0plus +mkr1000.build.f_cpu=48000000L +mkr1000.build.usb_product="Arduino MKR1000" +mkr1000.build.usb_manufacturer="Arduino LLC" +mkr1000.build.board=SAMD_MKR1000 +mkr1000.build.core=arduino +mkr1000.build.extra_flags=-DUSE_ARDUINO_MKR_PIN_LAYOUT -D__SAMD21G18A__ {build.usb_flags} +mkr1000.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +mkr1000.build.openocdscript=openocd_scripts/arduino_zero.cfg +mkr1000.build.variant=mkr1000 +mkr1000.build.vid=0x2341 +mkr1000.build.pid=0x804e +mkr1000.bootloader.tool=openocd +mkr1000.bootloader.file=mkr1000/samd21_sam_ba_arduino_mkr1000.bin + +# Arduino Tian (with) Bootloader +# ------------------------------ +tian.name=Arduino Tian +tian.upload.via_ssh=true +tian.vid.0=0x10C4 +tian.pid.0=0xEA70 +tian.descriptor.0=Enhanced Com Port + +tian.upload.tool=avrdude +#tian.upload.protocol=stk500v2 +tian.upload.protocol=wiring +tian.upload.maximum_size=262144 +tian.upload.use_1200bps_touch=true +tian.upload.wait_for_upload_port=true +tian.upload.native_usb=true +tian.upload.speed=57600 +tian.build.mcu=cortex-m0plus +tian.build.f_cpu=48000000L +tian.build.usb_product="Arduino Tian" +tian.build.board=SAMD_TIAN +tian.build.core=arduino +tian.build.extra_flags=-D__SAMD21G18A__ -mthumb {build.usb_flags} +tian.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +tian.build.openocdscript=openocd_scripts/arduino_zero.cfg +tian.build.variant=arduino_mzero +tian.build.variant_system_lib= +tian.build.vid=0x2a03 +tian.build.pid=0x8052 +tian.build.preferred_out_format=hex +tian.bootloader.size=0x4000 +tian.build.emu.mcu=atmega2560 +tian.bootloader.tool=openocd-withbootsize +tian.bootloader.low_fuses=0xff +tian.bootloader.file=sofia/Sofia_Tian_151118.hex +tian.drivers=SiliconLabs-CP2105/Silicon Labs VCP Driver.pkg diff --git a/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt b/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt new file mode 100644 index 00000000000..ded30da7c9e --- /dev/null +++ b/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt @@ -0,0 +1,231 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Arduino SAMD Core and platform. +# +# For more info: +# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification + +name=Arduino SAMD (32-bits ARM Cortex-M0+) Boards +version=1.8.5 + +# Compile variables +# ----------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall -Wno-expansion-to-defined +compiler.warning_flags.all=-Wall -Wextra -Wno-expansion-to-defined + +compiler.path={runtime.tools.arm-none-eabi-gcc-7-2017q4.path}/bin/ +compiler.c.cmd=arm-none-eabi-gcc +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD +compiler.c.elf.cmd=arm-none-eabi-g++ +compiler.c.elf.flags=-Os -Wl,--gc-sections -save-temps +compiler.S.cmd=arm-none-eabi-gcc +compiler.S.flags=-c -g -x assembler-with-cpp -MMD +compiler.cpp.cmd=arm-none-eabi-g++ +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.ar.cmd=arm-none-eabi-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=arm-none-eabi-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2hex.bin.flags=-O binary +compiler.elf2hex.hex.flags=-O ihex -R .eeprom +compiler.elf2hex.cmd=arm-none-eabi-objcopy +compiler.ldflags=-mcpu={build.mcu} -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align +compiler.size.cmd=arm-none-eabi-size +compiler.define=-DARDUINO= +compiler.readelf.cmd=arm-none-eabi-readelf + +# this can be overriden in boards.txt +build.extra_flags= + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +#compiler.c.elf.extra_flags=-v +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.ar.extra_flags= +compiler.elf2hex.extra_flags= + +compiler.arm.cmsis.c.flags="-I{runtime.tools.CMSIS-4.5.0.path}/CMSIS/Include/" "-I{runtime.tools.CMSIS-Atmel-1.2.0.path}/CMSIS/Device/ATMEL/" +compiler.arm.cmsis.ldflags="-L{runtime.tools.CMSIS-4.5.0.path}/CMSIS/Lib/GCC/" -larm_cortexM0l_math + +compiler.libraries.ldflags= + +# USB Flags +# --------- +build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSBCON '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + +# Default usb manufacturer will be replaced at compile time using +# numeric vendor ID if available or by board's specific value. +build.usb_manufacturer="Unknown" + +# Compile patterns +# ---------------- + +## Compile c files +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" + +## Create archives +# archive_file_path is needed for backwards compatibility with IDE 1.6.5 or older, IDE 1.6.6 or newer overrides this value +archive_file_path={build.path}/{archive_file} +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" --specs=nano.specs --specs=nosys.specs {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} {compiler.libraries.ldflags} -Wl,--start-group {compiler.arm.cmsis.ldflags} -lm "{build.path}/{archive_file}" -Wl,--end-group + +## Create output (bin file) +recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.bin.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" + +## Create output (hex file) +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +build.preferred_out_format=bin + +## Save hex +recipe.output.tmp_file={build.project_name}.{build.preferred_out_format} +recipe.output.save_file={build.project_name}.{build.variant}.{build.preferred_out_format} + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=\.text\s+([0-9]+).* + +# Upload/Debug tools +# ------------------ + +# +# AVRDUDE +# +tools.avrdude.path={runtime.tools.avrdude.path} +tools.avrdude.cmd={path}/bin/avrdude +tools.avrdude.config.path={path}/etc/avrdude.conf + +tools.avrdude.upload.params.verbose=-v -v +tools.avrdude.upload.params.quiet=-q -q +tools.avrdude.upload.params.noverify=-V +tools.avrdude.upload.pattern="{cmd}" "-C{config.path}" {upload.verbose} -p{build.emu.mcu} -c{upload.protocol} -P{serial.port} -b{upload.speed} "-Uflash:w:{build.path}/{build.project_name}.hex:i" + +tools.avrdude_remote.upload.pattern="openocd --version 2>&1 | grep 2016 && if opkg update; then opkg upgrade openocd; exit 1; else echo 'Please connect your board to the Internet in order to upgrade tools' >&2; exit 1; fi || /usr/bin/run-avrdude /tmp/sketch.hex" + +tools.avrdude.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA +tools.avrdude.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b + +# +# BOSSA +# +tools.bossac.path={runtime.tools.bossac-1.7.0-arduino3.path} +tools.bossac.cmd=bossac +tools.bossac.cmd.windows=bossac.exe + +tools.bossac.upload.params.verbose=-i -d +tools.bossac.upload.params.quiet= +tools.bossac.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -U {upload.native_usb} -i -e -w -v "{build.path}/{build.project_name}.bin" -R + +tools.bossac_remote.upload.pattern=/usr/bin/run-bossac {upload.verbose} --port=ttyATH0 -U {upload.native_usb} -e -w -v /tmp/sketch.bin -R + +tools.bossac.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA +tools.bossac.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b + +# +# BOSSA (ignore binary size) +# +tools.bossacI.path={runtime.tools.bossac-1.7.0-arduino3.path} +tools.bossacI.cmd=bossac +tools.bossacI.cmd.windows=bossac.exe + +tools.bossacI.upload.params.verbose=-i -d +tools.bossacI.upload.params.quiet= +tools.bossacI.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -I -U {upload.native_usb} -i -e -w "{build.path}/{build.project_name}.bin" -R + +tools.bossacI_remote.upload.pattern=/usr/bin/run-bossac {upload.verbose} --port=ttyATH0 -U {upload.native_usb} -e -w -v /tmp/sketch.bin -R + +tools.bossacI.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA +tools.bossacI.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b + + +# +# OpenOCD sketch upload +# + +tools.openocd.path={runtime.tools.openocd.path} +tools.openocd.cmd=bin/openocd +tools.openocd.cmd.windows=bin/openocd.exe + +tools.openocd.upload.params.verbose=-d2 +tools.openocd.upload.params.quiet=-d0 +tools.openocd.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.bin} verify reset 0x2000; shutdown" + +tools.openocd.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA +tools.openocd.upload.network_pattern={network_cmd} -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b + +# Program flashes the binary at 0x0000, so use the linker script without_bootloader +tools.openocd.program.params.verbose=-d2 +tools.openocd.program.params.quiet=-d0 +tools.openocd.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.elf} verify reset; shutdown" + +tools.openocd.erase.params.verbose=-d3 +tools.openocd.erase.params.quiet=-d0 +tools.openocd.erase.pattern= + +tools.openocd.bootloader.params.verbose=-d2 +tools.openocd.bootloader.params.quiet=-d0 +tools.openocd.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{runtime.platform.path}/bootloaders/{bootloader.file}} verify reset; shutdown" + +# +# OpenOCD sketch upload - version with configurable bootloader size +# FIXME: this programmer is a workaround for default options being overwritten by uploadUsingPreferences +# + +tools.openocd-withbootsize.path={runtime.tools.openocd-0.10.0-arduino7.path} +tools.openocd-withbootsize.cmd=bin/openocd +tools.openocd-withbootsize.cmd.windows=bin/openocd.exe + +tools.openocd-withbootsize.upload.params.verbose=-d2 +tools.openocd-withbootsize.upload.params.quiet=-d0 +tools.openocd-withbootsize.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.bin} verify reset {bootloader.size}; shutdown" + +# Program flashes the binary at 0x0000, so use the linker script without_bootloader +tools.openocd-withbootsize.program.params.verbose=-d2 +tools.openocd-withbootsize.program.params.quiet=-d0 +tools.openocd-withbootsize.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.elf} verify reset; shutdown" + +tools.openocd-withbootsize.erase.params.verbose=-d3 +tools.openocd-withbootsize.erase.params.quiet=-d0 +tools.openocd-withbootsize.erase.pattern= + +tools.openocd-withbootsize.bootloader.params.verbose=-d2 +tools.openocd-withbootsize.bootloader.params.quiet=-d0 +tools.openocd-withbootsize.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{runtime.platform.path}/bootloaders/{bootloader.file}} verify reset; shutdown" + +# +# GDB (Debugger) +# + +tools.gdb.path={runtime.tools.arm-none-eabi-gcc-7-2017q4.path}/bin/ +tools.gdb.cmd=arm-none-eabi-gdb +tools.gdb.cmd.windows=arm-none-eabi-gdb.exe + +tools.gdb.debug.pattern="{path}/{cmd}" -ex 'target extended-remote | {tools.openocd.path}/{tools.openocd.cmd} -s "{tools.openocd.path}/share/openocd/scripts/" --file "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "gdb_port pipe" -c "telnet_port 0" -c init -c halt' {build.path}/{build.project_name}.elf \ No newline at end of file diff --git a/commands/debug/testdata/data_dir/packages/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-gdb b/commands/debug/testdata/data_dir/packages/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-gdb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/commands/debug/testdata/data_dir/packages/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd b/commands/debug/testdata/data_dir/packages/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd new file mode 100644 index 00000000000..e69de29bb2d From 378b8bfda7c8752ec89621c35f78f90c6fdaa4d0 Mon Sep 17 00:00:00 2001 From: rsora Date: Wed, 19 Feb 2020 18:35:50 +0100 Subject: [PATCH 14/29] Cosmetics here and there --- arduino/utils/stream.go | 1 - cli/cli.go | 2 +- cli/debug/debug.go | 10 ++++------ commands/debug/debug.go | 7 +++---- commands/debug/debug_test.go | 17 +++++++++++------ 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/arduino/utils/stream.go b/arduino/utils/stream.go index 2cce6043097..019934cdb41 100644 --- a/arduino/utils/stream.go +++ b/arduino/utils/stream.go @@ -37,7 +37,6 @@ func FeedStreamTo(writer func(data []byte)) io.Writer { // ConsumeStreamFrom creates a pipe to consume data from the reader function. // ConsumeStreamFrom returns the io.Reader side of the pipe, which the user can use to consume the data func ConsumeStreamFrom(reader func() ([]byte, error)) io.Reader { - r, w := io.Pipe() go func() { for { diff --git a/cli/cli.go b/cli/cli.go index 8c8b0a87871..c5a061d085b 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -17,7 +17,6 @@ package cli import ( "fmt" - "github.com/arduino/arduino-cli/cli/debug" "io/ioutil" "os" "path/filepath" @@ -29,6 +28,7 @@ import ( "github.com/arduino/arduino-cli/cli/config" "github.com/arduino/arduino-cli/cli/core" "github.com/arduino/arduino-cli/cli/daemon" + "github.com/arduino/arduino-cli/cli/debug" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/generatedocs" diff --git a/cli/debug/debug.go b/cli/debug/debug.go index d47533e563b..64e8e7150a9 100644 --- a/cli/debug/debug.go +++ b/cli/debug/debug.go @@ -42,17 +42,15 @@ func NewCommand() *cobra.Command { debugCommand := &cobra.Command{ Use: "debug", Short: "Debug Arduino sketches.", - Long: "Debug Arduino sketches.", - Example: " " + os.Args[0] + " debug /home/user/Arduino/MySketch", + Long: "Debug Arduino sketches. (this command opens an interactive gdb session)", + Example: " " + os.Args[0] + " debug -b arduino:samd:mkr1000 /home/user/Arduino/MySketch", Args: cobra.MaximumNArgs(1), Run: run, } debugCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno") debugCommand.Flags().StringVarP(&port, "port", "p", "", "Upload port, e.g.: COM10 or /dev/ttyACM0") - debugCommand.Flags().StringVarP(&importFile, "input", "i", "", "Input file to be uploaded.") - - debugCommand.MarkFlagRequired("port") + debugCommand.Flags().StringVarP(&importFile, "input", "i", "", "Input file to be uploaded for debug.") return debugCommand } @@ -77,7 +75,7 @@ func run(command *cobra.Command, args []string) { Port: port, ImportFile: importFile, }, os.Stdin, os.Stdout); err != nil { - feedback.Errorf("Error during Upload: %v", err) + feedback.Errorf("Error during Debug: %v", err) os.Exit(errorcodes.ErrGeneric) } } diff --git a/commands/debug/debug.go b/commands/debug/debug.go index fff62760418..8a888a41c95 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -28,12 +28,11 @@ import ( "github.com/arduino/arduino-cli/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/arduino/sketches" "github.com/arduino/arduino-cli/commands" + "github.com/arduino/arduino-cli/executils" + dbg "github.com/arduino/arduino-cli/rpc/debug" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/sirupsen/logrus" - - "github.com/arduino/arduino-cli/executils" - dbg "github.com/arduino/arduino-cli/rpc/debug" ) // Debug command launches a debug tool for a sketch. @@ -44,7 +43,7 @@ import ( // It also implements tool process lifecycle management func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out io.Writer) (*dbg.DebugResp, error) { - // get tool commandLine from core recipe + // Get tool commandLine from core recipe pm := commands.GetPackageManager(req.GetInstance().GetId()) commandLine, err := getCommandLine(req, pm) if err != nil { diff --git a/commands/debug/debug_test.go b/commands/debug/debug_test.go index 81236f68f10..f6975f67c4b 100644 --- a/commands/debug/debug_test.go +++ b/commands/debug/debug_test.go @@ -17,13 +17,13 @@ package debug import ( "fmt" + "strings" + "testing" + "github.com/arduino/arduino-cli/arduino/cores/packagemanager" - rpc "github.com/arduino/arduino-cli/rpc/common" dbg "github.com/arduino/arduino-cli/rpc/debug" "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/assert" - "strings" - "testing" ) var customHardware = paths.New("testdata", "custom_hardware") @@ -36,14 +36,18 @@ func TestGetCommandLine(t *testing.T) { pm.LoadHardwareFromDirectory(customHardware) pm.LoadHardwareFromDirectory(dataDir) + // Arduino Zero has an integrated debugger port, anc it could be debugged directly using USB req := &dbg.DebugConfigReq{ - Instance: &rpc.Instance{Id: 1}, + Instance: &dbg.Instance{Id: 1}, Fqbn: "arduino-test:samd:arduino_zero_edbg", SketchPath: sketchPath, Port: "none", } packageName := strings.Split(req.Fqbn, ":")[0] processor := strings.Split(req.Fqbn, ":")[1] + // This boardFamily variable is necessary for this particular board as it is represented in the core as 2 separated + // boards, to expose the programming port and the debug (edbg) port. So we point at the same openocd configuration + // variant for upload in both cases boardFamily := "arduino_zero" goldCommand := []string{ @@ -59,9 +63,10 @@ func TestGetCommandLine(t *testing.T) { assert.Nil(t, err) assert.Equal(t, goldCommand, command) - // for other samd boards + // Other samd boards such as mkr1000 can be debugged using an external tool such as Atmel ICE connected to + // the board debug port req2 := &dbg.DebugConfigReq{ - Instance: &rpc.Instance{Id: 1}, + Instance: &dbg.Instance{Id: 1}, Fqbn: "arduino-test:samd:mkr1000", SketchPath: sketchPath, Port: "none", From 74fa6df9d99e16109d43e4fd5da58931f6e1fabd Mon Sep 17 00:00:00 2001 From: rsora Date: Wed, 19 Feb 2020 18:52:24 +0100 Subject: [PATCH 15/29] Refreshed client example --- client_example/main.go | 1508 ++++++++++++++++++++-------------------- 1 file changed, 755 insertions(+), 753 deletions(-) diff --git a/client_example/main.go b/client_example/main.go index 997639d33ed..71b06d0cff1 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -16,22 +16,20 @@ package main import ( + "bytes" "context" "fmt" - - rpc "github.com/arduino/arduino-cli/rpc/commands" - dbg "github.com/arduino/arduino-cli/rpc/debug" - "io" "io/ioutil" "log" "os" - - // "path" + "path" "path/filepath" - "time" + "strings" - //"github.com/arduino/arduino-cli/rpc/settings" + rpc "github.com/arduino/arduino-cli/rpc/commands" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/arduino-cli/rpc/settings" "google.golang.org/grpc" ) @@ -45,7 +43,7 @@ func main() { // Establish a connection with the gRPC server, started with the command: // arduino-cli daemon - conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(100*time.Millisecond)) + conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock()) if err != nil { log.Fatal("error connecting to arduino-cli rpc server, you can start it by running `arduino-cli daemon`") } @@ -61,251 +59,195 @@ func main() { dataDir = filepath.ToSlash(dataDir) defer os.RemoveAll(dataDir) - // Create an instance of the gRPC client. + // Create an instance of the gRPC clients. client := rpc.NewArduinoCoreClient(conn) - instance := initInstance(client) - ///////////////////////////////////////////////////////////////////////// - debugClient := dbg.NewDebugClient(conn) + + settingsClient := settings.NewSettingsClient(conn) + + // Now we can call various methods of the API... // `Version` can be called without any setup or init procedure. log.Println("calling Version") callVersion(client) - // debug calls - debugStreamingOpenClient, err := debugClient.Debug(context.Background()) - if err != nil { - log.Fatalf("steraming open error: %s\n", err) - } + // Use SetValue to configure the arduino-cli directories. + log.Println("calling SetValue") + callSetValue(settingsClient) - err = debugStreamingOpenClient.Send(&dbg.DebugReq{ - DebugReq: &dbg.DebugConfigReq{ - Instance: &dbg.Instance{Id: instance.GetId()}, - Fqbn: "arduino-pippo:samd:arduino_zero_edbg", - SketchPath: os.Args[1], - Port: "none", - }}) - if err != nil { - log.Fatalf("Send error: %s\n", err) - } - log.Println("calling StreamingOpenReq_DebugReq") - time.Sleep(time.Second * 3) - err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("info registers\n")}) - if err != nil { - log.Fatalf("Send error: %s\n", err) - } - log.Println("calling StreamingOpenReq_Data") + // List all the settings. + log.Println("calling GetAll()") + callGetAll(settingsClient) - // Loop and consume the server stream until all the operations are done. - for { - compResp, err := debugStreamingOpenClient.Recv() + // Merge applies multiple settings values at once. + log.Println("calling Merge(`{\"foo\": \"bar\", \"daemon\":{\"port\":\"422\"}}`)") + callMerge(settingsClient) - // The server is done. - if err == io.EOF { - log.Print("debug done") - break - } + // Get the value of the foo key. + log.Println("calling GetValue(foo)") + callGetValue(settingsClient) - // There was an error. - if err != nil { - log.Fatalf("debug error: %s\n", err) - } + // Before we can do anything with the CLI, an "instance" must be created. + // We keep a reference to the created instance because we will need it to + // run subsequent commands. + log.Println("calling Init") + instance := initInstance(client) - // When an operation is ongoing you can get its output - if resp := compResp.GetData(); resp != nil { - fmt.Printf("%s", resp) - //if string(resp) == "(gdb) " { - // break - //} - } + // With a brand new instance, the first operation should always be updatating + // the index. + //log.Println("calling UpdateIndex") + //callUpdateIndex(client, instance) + // + // Let's search for a platform (also known as 'core') called 'samd'. + log.Println("calling PlatformSearch(samd)") + callPlatformSearch(client, instance) + + // Install arduino:samd@1.6.19 + log.Println("calling PlatformInstall(arduino:samd@1.6.19)") + callPlatformInstall(client, instance) + + // Now list the installed platforms to double check previous installation + // went right. + log.Println("calling PlatformList()") + callPlatformList(client, instance) + + // Upgrade the installed platform to the latest version. + log.Println("calling PlatformUpgrade(arduino:samd)") + callPlatformUpgrade(client, instance) + + // Query board details for a mkr1000 + log.Println("calling BoardDetails(arduino:samd:mkr1000)") + callBoardsDetails(client, instance) + + // Attach a board to a sketch. + // Uncomment if you do have an actual board connected. + // log.Println("calling BoardAttach(serial:///dev/ttyACM0)") + // callBoardAttach(client, instance) + + // Compile a sketch + log.Println("calling Compile(arduino-pippo:samd:mkr1000, VERBOSE, hello.ino)") + callCompile(client, instance) + + // Upload a sketch + // Uncomment if you do have an actual board connected. + // log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") + // callUpload(client, instance) + + // Debug a sketch on a board + // Uncomment if you do have an actual board connected via debug port, + // or a board connected to a debugger. + //debugClient := dbg.NewDebugClient(conn) + //debugStreamingClient, err := debugClient.Debug(context.Background()) + //if err != nil { + // log.Fatalf("debug steraming open error: %s\n", err) + //} + // log.Println("calling Debug(arduino:samd:mkr1000, hello.ino)") + // callDebugger(debugStreamingClient, instance) + + // List all boards + log.Println("calling BoardListAll(mkr)") + callListAll(client, instance) + + // List connected boards + log.Println("calling BoardList()") + callBoardList(client, instance) + + // Uninstall a platform + log.Println("calling PlatformUninstall(arduino:samd)") + callPlatformUnInstall(client, instance) + + // Update the Library index + log.Println("calling UpdateLibrariesIndex()") + callUpdateLibraryIndex(client, instance) + + // Download a library + log.Println("calling LibraryDownload(WiFi101@0.15.2)") + callLibDownload(client, instance) + + // Install a library + log.Println("calling LibraryInstall(WiFi101@0.15.1)") + callLibInstall(client, instance, "0.15.1") + + // Replace the previous version + log.Println("calling LibraryInstall(WiFi101@0.15.2)") + callLibInstall(client, instance, "0.15.2") + + // Upgrade all libs to latest + log.Println("calling LibraryUpgradeAll()") + callLibUpgradeAll(client, instance) + + // Search for a lib using the 'audio' keyword + log.Println("calling LibrarySearch(audio)") + callLibSearch(client, instance) + + // List the dependencies of the ArduinoIoTCloud library + log.Println("calling LibraryResolveDependencies(ArduinoIoTCloud)") + callLibraryResolveDependencies(client, instance) + + // List installed libraries + log.Println("calling LibraryList") + callLibList(client, instance) + + // Uninstall a library + log.Println("calling LibraryUninstall(WiFi101)") + callLibUninstall(client, instance) +} +func callVersion(client rpc.ArduinoCoreClient) { + versionResp, err := client.Version(context.Background(), &rpc.VersionReq{}) + if err != nil { + log.Fatalf("Error getting version: %s", err) } - err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("quit\n")}) + log.Printf("arduino-cli version: %v", versionResp.GetVersion()) +} + +func callSetValue(client settings.SettingsClient) { + _, err := client.SetValue(context.Background(), + &settings.Value{ + Key: "directories", + JsonData: `{"data": "` + dataDir + `", "downloads": "` + path.Join(dataDir, "staging") + `", "user": "` + path.Join(dataDir, "sketchbook") + `"}`, + }) + if err != nil { - log.Fatalf("Send error: %s\n", err) + log.Fatalf("Error setting settings value: %s", err) } +} + +func callMerge(client settings.SettingsClient) { + bulkSettings := `{"foo": "bar", "daemon":{"port":"422"}}` + _, err := client.Merge(context.Background(), + &settings.RawData{ + JsonData: bulkSettings, + }) - err = debugStreamingOpenClient.CloseSend() if err != nil { - log.Fatalf("Send error: %s\n", err) + log.Fatalf("Error merging settings: %s", err) } +} - //////////////////////////////////////////////////////////////////////////////////////////// +func callGetValue(client settings.SettingsClient) { + getValueResp, err := client.GetValue(context.Background(), + &settings.GetValueRequest{ + Key: "foo", + }) - //// Now we can call various methods of the API... - // - //// `Version` can be called without any setup or init procedure. - //log.Println("calling Version") - //callVersion(client) - // - //// Use SetValue to configure the arduino-cli directories. - //log.Println("calling SetValue") - //callSetValue(settingsClient) - // - //// List all the settings. - //log.Println("calling GetAll()") - //callGetAll(settingsClient) - // - //// Merge applies multiple settings values at once. - //log.Println("calling Merge(`{\"foo\": \"bar\", \"daemon\":{\"port\":\"422\"}}`)") - //callMerge(settingsClient) - // - //// Get the value of the foo key. - //log.Println("calling GetValue(foo)") - //callGetValue(settingsClient) - // - //// Before we can do anything with the CLI, an "instance" must be created. - //// We keep a reference to the created instance because we will need it to - //// run subsequent commands. - //log.Println("calling Init") - //instance := initInstance(client) - // - //// With a brand new instance, the first operation should always be updatating - //// the index. - //log.Println("calling UpdateIndex") - //callUpdateIndex(client, instance) - // - //// Let's search for a platform (also known as 'core') called 'samd'. - //log.Println("calling PlatformSearch(samd)") - //callPlatformSearch(client, instance) - // - //// Install arduino:samd@1.6.19 - //log.Println("calling PlatformInstall(arduino:samd@1.6.19)") - //callPlatformInstall(client, instance) - // - //// Now list the installed platforms to double check previous installation - //// went right. - //log.Println("calling PlatformList()") - //callPlatformList(client, instance) - // - //// Upgrade the installed platform to the latest version. - //log.Println("calling PlatformUpgrade(arduino:samd)") - //callPlatformUpgrade(client, instance) - // - //// Query board details for a mkr1000 - //log.Println("calling BoardDetails(arduino:samd:mkr1000)") - //callBoardsDetails(client, instance) - // - //// Attach a board to a sketch. - //// Uncomment if you do have an actual board connected. - //// log.Println("calling BoardAttach(serial:///dev/ttyACM0)") - //// callBoardAttach(client, instance) - // - //// Compile a sketch - //log.Println("calling Compile(arduino:samd:mkr1000, VERBOSE, hello.ino)") - //callCompile(client, instance) - // - //// Upload a sketch - //// Uncomment if you do have an actual board connected. - //// log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") - //// callUpload(client, instance) - // - //// List all boards - //log.Println("calling BoardListAll(mkr)") - //callListAll(client, instance) - // - //// List connected boards - //log.Println("calling BoardList()") - //callBoardList(client, instance) - // - //// Uninstall a platform - //log.Println("calling PlatformUninstall(arduino:samd)") - //callPlatformUnInstall(client, instance) - // - //// Update the Library index - //log.Println("calling UpdateLibrariesIndex()") - //callUpdateLibraryIndex(client, instance) - // - //// Download a library - //log.Println("calling LibraryDownload(WiFi101@0.15.2)") - //callLibDownload(client, instance) - // - //// Install a library - //log.Println("calling LibraryInstall(WiFi101@0.15.1)") - //callLibInstall(client, instance, "0.15.1") - // - //// Replace the previous version - //log.Println("calling LibraryInstall(WiFi101@0.15.2)") - //callLibInstall(client, instance, "0.15.2") - // - //// Upgrade all libs to latest - //log.Println("calling LibraryUpgradeAll()") - //callLibUpgradeAll(client, instance) - // - //// Search for a lib using the 'audio' keyword - //log.Println("calling LibrarySearch(audio)") - //callLibSearch(client, instance) - // - //// List the dependencies of the ArduinoIoTCloud library - //log.Println("calling LibraryResolveDependencies(ArduinoIoTCloud)") - //callLibraryResolveDependencies(client, instance) - // - //// List installed libraries - //log.Println("calling LibraryList") - //callLibList(client, instance) - // - //// Uninstall a library - //log.Println("calling LibraryUninstall(WiFi101)") - //callLibUninstall(client, instance) + if err != nil { + log.Fatalf("Error getting settings value: %s", err) + } + + log.Printf("Value: %s: %s", getValueResp.GetKey(), getValueResp.GetJsonData()) } -func callVersion(client rpc.ArduinoCoreClient) { - versionResp, err := client.Version(context.Background(), &rpc.VersionReq{}) +func callGetAll(client settings.SettingsClient) { + getAllResp, err := client.GetAll(context.Background(), &settings.GetAllRequest{}) + if err != nil { - log.Fatalf("Error getting version: %s", err) + log.Fatalf("Error getting settings: %s", err) } - log.Printf("arduino-cli version: %v", versionResp.GetVersion()) + log.Printf("Settings: %s", getAllResp.GetJsonData()) } -// -//func callSetValue(client settings.SettingsClient) { -// _, err := client.SetValue(context.Background(), -// &settings.Value{ -// Key: "directories", -// JsonData: `{"data": "` + dataDir + `", "downloads": "` + path.Join(dataDir, "staging") + `", "user": "` + path.Join(dataDir, "sketchbook") + `"}`, -// }) -// -// if err != nil { -// log.Fatalf("Error setting settings value: %s", err) -// } -//} -// -//func callMerge(client settings.SettingsClient) { -// bulkSettings := `{"foo": "bar", "daemon":{"port":"422"}}` -// _, err := client.Merge(context.Background(), -// &settings.RawData{ -// JsonData: bulkSettings, -// }) -// -// if err != nil { -// log.Fatalf("Error merging settings: %s", err) -// } -//} -// -//func callGetValue(client settings.SettingsClient) { -// getValueResp, err := client.GetValue(context.Background(), -// &settings.GetValueRequest{ -// Key: "foo", -// }) -// -// if err != nil { -// log.Fatalf("Error getting settings value: %s", err) -// } -// -// log.Printf("Value: %s: %s", getValueResp.GetKey(), getValueResp.GetJsonData()) -//} -// -//func callGetAll(client settings.SettingsClient) { -// getAllResp, err := client.GetAll(context.Background(), &settings.GetAllRequest{}) -// -// if err != nil { -// log.Fatalf("Error getting settings: %s", err) -// } -// -// log.Printf("Settings: %s", getAllResp.GetJsonData()) -//} -// func initInstance(client rpc.ArduinoCoreClient) *rpc.Instance { // The configuration for this example client only contains the path to // the data folder. @@ -349,530 +291,590 @@ func initInstance(client rpc.ArduinoCoreClient) *rpc.Instance { return instance } -// -//func callUpdateIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// uiRespStream, err := client.UpdateIndex(context.Background(), &rpc.UpdateIndexReq{ -// Instance: instance, -// }) -// if err != nil { -// log.Fatalf("Error updating index: %s", err) -// } -// -// // Loop and consume the server stream until all the operations are done. -// for { -// uiResp, err := uiRespStream.Recv() -// -// // the server is done -// if err == io.EOF { -// log.Print("Update index done") -// break -// } -// -// // there was an error -// if err != nil { -// log.Fatalf("Update error: %s", err) -// } -// -// // operations in progress -// if uiResp.GetDownloadProgress() != nil { -// log.Printf("DOWNLOAD: %s", uiResp.GetDownloadProgress()) -// } -// } -//} -// -//func callPlatformSearch(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// searchResp, err := client.PlatformSearch(context.Background(), &rpc.PlatformSearchReq{ -// Instance: instance, -// SearchArgs: "samd", -// }) -// -// if err != nil { -// log.Fatalf("Search error: %s", err) -// } -// -// platforms := searchResp.GetSearchOutput() -// for _, plat := range platforms { -// // We only print ID and version of the platforms found but you can look -// // at the definition for the rpc.Platform struct for more fields. -// log.Printf("Search result: %+v - %+v", plat.GetID(), plat.GetLatest()) -// } -//} -// -//func callPlatformInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// installRespStream, err := client.PlatformInstall(context.Background(), -// &rpc.PlatformInstallReq{ -// Instance: instance, -// PlatformPackage: "arduino", -// Architecture: "samd", -// Version: "1.6.19", -// }) -// -// if err != nil { -// log.Fatalf("Error installing platform: %s", err) -// } -// -// // Loop and consume the server stream until all the operations are done. -// for { -// installResp, err := installRespStream.Recv() -// -// // The server is done. -// if err == io.EOF { -// log.Printf("Install done") -// break -// } -// -// // There was an error. -// if err != nil { -// log.Fatalf("Install error: %s", err) -// } -// -// // When a download is ongoing, log the progress -// if installResp.GetProgress() != nil { -// log.Printf("DOWNLOAD: %s", installResp.GetProgress()) -// } -// -// // When an overall task is ongoing, log the progress -// if installResp.GetTaskProgress() != nil { -// log.Printf("TASK: %s", installResp.GetTaskProgress()) -// } -// } -//} -// -//func callPlatformList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// listResp, err := client.PlatformList(context.Background(), -// &rpc.PlatformListReq{Instance: instance}) -// -// if err != nil { -// log.Fatalf("List error: %s", err) -// } -// -// for _, plat := range listResp.GetInstalledPlatform() { -// // We only print ID and version of the installed platforms but you can look -// // at the definition for the rpc.Platform struct for more fields. -// log.Printf("Installed platform: %s - %s", plat.GetID(), plat.GetInstalled()) -// } -//} -// -//func callPlatformUpgrade(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// upgradeRespStream, err := client.PlatformUpgrade(context.Background(), -// &rpc.PlatformUpgradeReq{ -// Instance: instance, -// PlatformPackage: "arduino", -// Architecture: "samd", -// }) -// -// if err != nil { -// log.Fatalf("Error upgrading platform: %s", err) -// } -// -// // Loop and consume the server stream until all the operations are done. -// for { -// upgradeResp, err := upgradeRespStream.Recv() -// -// // The server is done. -// if err == io.EOF { -// log.Printf("Upgrade done") -// break -// } -// -// // There was an error. -// if err != nil { -// log.Fatalf("Upgrade error: %s", err) -// } -// -// // When a download is ongoing, log the progress -// if upgradeResp.GetProgress() != nil { -// log.Printf("DOWNLOAD: %s", upgradeResp.GetProgress()) -// } -// -// // When an overall task is ongoing, log the progress -// if upgradeResp.GetTaskProgress() != nil { -// log.Printf("TASK: %s", upgradeResp.GetTaskProgress()) -// } -// } -//} -// -//func callBoardsDetails(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// details, err := client.BoardDetails(context.Background(), -// &rpc.BoardDetailsReq{ -// Instance: instance, -// Fqbn: "arduino:samd:mkr1000", -// }) -// -// if err != nil { -// log.Fatalf("Error getting board data: %s\n", err) -// } -// -// log.Printf("Board details for %s", details.GetName()) -// log.Printf("Required tools: %s", details.GetRequiredTools()) -// log.Printf("Config options: %s", details.GetConfigOptions()) -//} -// -//func callBoardAttach(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// currDir, _ := os.Getwd() -// boardattachresp, err := client.BoardAttach(context.Background(), -// &rpc.BoardAttachReq{ -// Instance: instance, -// BoardUri: "/dev/ttyACM0", -// SketchPath: filepath.Join(currDir, "hello.ino"), -// }) -// -// if err != nil { -// log.Fatalf("Attach error: %s", err) -// } -// -// // Loop and consume the server stream until all the operations are done. -// for { -// attachResp, err := boardattachresp.Recv() -// -// // The server is done. -// if err == io.EOF { -// log.Print("Attach done") -// break -// } -// -// // There was an error. -// if err != nil { -// log.Fatalf("Attach error: %s\n", err) -// } -// -// // When an overall task is ongoing, log the progress -// if attachResp.GetTaskProgress() != nil { -// log.Printf("TASK: %s", attachResp.GetTaskProgress()) -// } -// } -//} -// -//func callCompile(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// currDir, _ := os.Getwd() -// compRespStream, err := client.Compile(context.Background(), -// &rpc.CompileReq{ -// Instance: instance, -// Fqbn: "arduino:samd:mkr1000", -// SketchPath: filepath.Join(currDir, "hello.ino"), -// Verbose: true, -// }) -// -// if err != nil { -// log.Fatalf("Compile error: %s\n", err) -// } -// -// // Loop and consume the server stream until all the operations are done. -// for { -// compResp, err := compRespStream.Recv() -// -// // The server is done. -// if err == io.EOF { -// log.Print("Compilation done") -// break -// } -// -// // There was an error. -// if err != nil { -// log.Fatalf("Compile error: %s\n", err) -// } -// -// // When an operation is ongoing you can get its output -// if resp := compResp.GetOutStream(); resp != nil { -// log.Printf("STDOUT: %s", resp) -// } -// if resperr := compResp.GetErrStream(); resperr != nil { -// log.Printf("STDERR: %s", resperr) -// } -// } -//} -// -//func callUpload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// currDir, _ := os.Getwd() -// uplRespStream, err := client.Upload(context.Background(), -// &rpc.UploadReq{ -// Instance: instance, -// Fqbn: "arduino:samd:mkr1000", -// SketchPath: filepath.Join(currDir, "hello.ino"), -// Port: "/dev/ttyACM0", -// Verbose: true, -// }) -// -// if err != nil { -// log.Fatalf("Upload error: %s\n", err) -// } -// -// for { -// uplResp, err := uplRespStream.Recv() -// if err == io.EOF { -// log.Printf("Upload done") -// break -// } -// -// if err != nil { -// log.Fatalf("Upload error: %s", err) -// break -// } -// -// // When an operation is ongoing you can get its output -// if resp := uplResp.GetOutStream(); resp != nil { -// log.Printf("STDOUT: %s", resp) -// } -// if resperr := uplResp.GetErrStream(); resperr != nil { -// log.Printf("STDERR: %s", resperr) -// } -// } -//} -// -//func callListAll(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// boardListAllResp, err := client.BoardListAll(context.Background(), -// &rpc.BoardListAllReq{ -// Instance: instance, -// SearchArgs: []string{"mkr"}, -// }) -// -// if err != nil { -// log.Fatalf("Board list-all error: %s", err) -// } -// -// for _, board := range boardListAllResp.GetBoards() { -// log.Printf("%s: %s", board.GetName(), board.GetFQBN()) -// } -//} -// -//func callBoardList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// boardListResp, err := client.BoardList(context.Background(), -// &rpc.BoardListReq{Instance: instance}) -// -// if err != nil { -// log.Fatalf("Board list error: %s\n", err) -// } -// -// for _, port := range boardListResp.GetPorts() { -// log.Printf("port: %s, boards: %+v\n", port.GetAddress(), port.GetBoards()) -// } -//} -// -//func callPlatformUnInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// uninstallRespStream, err := client.PlatformUninstall(context.Background(), -// &rpc.PlatformUninstallReq{ -// Instance: instance, -// PlatformPackage: "arduino", -// Architecture: "samd", -// }) -// -// if err != nil { -// log.Fatalf("Uninstall error: %s", err) -// } -// -// // Loop and consume the server stream until all the operations are done. -// for { -// uninstallResp, err := uninstallRespStream.Recv() -// if err == io.EOF { -// log.Print("Uninstall done") -// break -// } -// -// if err != nil { -// log.Fatalf("Uninstall error: %s\n", err) -// } -// -// if uninstallResp.GetTaskProgress() != nil { -// log.Printf("TASK: %s\n", uninstallResp.GetTaskProgress()) -// } -// } -//} -// -//func callUpdateLibraryIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// libIdxUpdateStream, err := client.UpdateLibrariesIndex(context.Background(), -// &rpc.UpdateLibrariesIndexReq{Instance: instance}) -// -// if err != nil { -// log.Fatalf("Error updating libraries index: %s\n", err) -// } -// -// // Loop and consume the server stream until all the operations are done. -// for { -// resp, err := libIdxUpdateStream.Recv() -// if err == io.EOF { -// log.Print("Library index update done") -// break -// } -// -// if err != nil { -// log.Fatalf("Error updating libraries index: %s", err) -// } -// -// if resp.GetDownloadProgress() != nil { -// log.Printf("DOWNLOAD: %s", resp.GetDownloadProgress()) -// } -// } -//} -// -//func callLibDownload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// downloadRespStream, err := client.LibraryDownload(context.Background(), -// &rpc.LibraryDownloadReq{ -// Instance: instance, -// Name: "WiFi101", -// Version: "0.15.2", -// }) -// -// if err != nil { -// log.Fatalf("Error downloading library: %s", err) -// } -// -// // Loop and consume the server stream until all the operations are done. -// for { -// downloadResp, err := downloadRespStream.Recv() -// if err == io.EOF { -// log.Print("Lib download done") -// break -// } -// -// if err != nil { -// log.Fatalf("Download error: %s", err) -// } -// -// if downloadResp.GetProgress() != nil { -// log.Printf("DOWNLOAD: %s", downloadResp.GetProgress()) -// } -// } -//} -// -//func callLibInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance, version string) { -// installRespStream, err := client.LibraryInstall(context.Background(), -// &rpc.LibraryInstallReq{ -// Instance: instance, -// Name: "WiFi101", -// Version: version, -// }) -// -// if err != nil { -// log.Fatalf("Error installing library: %s", err) -// } -// -// for { -// installResp, err := installRespStream.Recv() -// if err == io.EOF { -// log.Print("Lib install done") -// break -// } -// -// if err != nil { -// log.Fatalf("Install error: %s", err) -// } -// -// if installResp.GetProgress() != nil { -// log.Printf("DOWNLOAD: %s\n", installResp.GetProgress()) -// } -// if installResp.GetTaskProgress() != nil { -// log.Printf("TASK: %s\n", installResp.GetTaskProgress()) -// } -// } -//} -// -//func callLibUpgradeAll(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// libUpgradeAllRespStream, err := client.LibraryUpgradeAll(context.Background(), -// &rpc.LibraryUpgradeAllReq{ -// Instance: instance, -// }) -// -// if err != nil { -// log.Fatalf("Error upgrading all: %s\n", err) -// } -// -// for { -// resp, err := libUpgradeAllRespStream.Recv() -// if err == io.EOF { -// log.Printf("Lib upgrade all done") -// break -// } -// -// if err != nil { -// log.Fatalf("Upgrading error: %s", err) -// } -// -// if resp.GetProgress() != nil { -// log.Printf("DOWNLOAD: %s\n", resp.GetProgress()) -// } -// if resp.GetTaskProgress() != nil { -// log.Printf("TASK: %s\n", resp.GetTaskProgress()) -// } -// } -//} -// -//func callLibSearch(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// libSearchResp, err := client.LibrarySearch(context.Background(), -// &rpc.LibrarySearchReq{ -// Instance: instance, -// Query: "audio", -// }) -// -// if err != nil { -// log.Fatalf("Error searching for library: %s", err) -// } -// -// for _, res := range libSearchResp.GetLibraries() { -// log.Printf("Result: %s - %s", res.GetName(), res.GetLatest().GetVersion()) -// } -//} -// -//func callLibraryResolveDependencies(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// libraryResolveDependenciesResp, err := client.LibraryResolveDependencies(context.Background(), -// &rpc.LibraryResolveDependenciesReq{ -// Instance: instance, -// Name: "ArduinoIoTCloud", -// }) -// -// if err != nil { -// log.Fatalf("Error listing library dependencies: %s", err) -// } -// -// for _, resp := range libraryResolveDependenciesResp.GetDependencies() { -// log.Printf("Dependency Name: %s", resp.GetName()) -// log.Printf("Version Required: %s", resp.GetVersionRequired()) -// if resp.GetVersionInstalled() != "" { -// log.Printf("Version Installed: %s\n", resp.GetVersionInstalled()) -// } -// } -//} -// -//func callLibList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// libLstResp, err := client.LibraryList(context.Background(), -// &rpc.LibraryListReq{ -// Instance: instance, -// All: false, -// Updatable: false, -// }) -// -// if err != nil { -// log.Fatalf("Error List Library: %s", err) -// } -// -// for _, res := range libLstResp.GetInstalledLibrary() { -// log.Printf("%s - %s", res.GetLibrary().GetName(), res.GetLibrary().GetVersion()) -// } -//} -// -//func callLibUninstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { -// libUninstallRespStream, err := client.LibraryUninstall(context.Background(), -// &rpc.LibraryUninstallReq{ -// Instance: instance, -// Name: "WiFi101", -// }) -// -// if err != nil { -// log.Fatalf("Error uninstalling: %s", err) -// } -// -// for { -// uninstallResp, err := libUninstallRespStream.Recv() -// if err == io.EOF { -// log.Printf("Lib uninstall done") -// break -// } -// -// if err != nil { -// log.Fatalf("Uninstall error: %s", err) -// } -// -// if uninstallResp.GetTaskProgress() != nil { -// log.Printf("TASK: %s", uninstallResp.GetTaskProgress()) -// } -// } -//} +func callUpdateIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + uiRespStream, err := client.UpdateIndex(context.Background(), &rpc.UpdateIndexReq{ + Instance: instance, + }) + if err != nil { + log.Fatalf("Error updating index: %s", err) + } + + // Loop and consume the server stream until all the operations are done. + for { + uiResp, err := uiRespStream.Recv() + + // the server is done + if err == io.EOF { + log.Print("Update index done") + break + } + + // there was an error + if err != nil { + log.Fatalf("Update error: %s", err) + } + + // operations in progress + if uiResp.GetDownloadProgress() != nil { + log.Printf("DOWNLOAD: %s", uiResp.GetDownloadProgress()) + } + } +} + +func callPlatformSearch(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + searchResp, err := client.PlatformSearch(context.Background(), &rpc.PlatformSearchReq{ + Instance: instance, + SearchArgs: "samd", + }) + + if err != nil { + log.Fatalf("Search error: %s", err) + } + + platforms := searchResp.GetSearchOutput() + for _, plat := range platforms { + // We only print ID and version of the platforms found but you can look + // at the definition for the rpc.Platform struct for more fields. + log.Printf("Search result: %+v - %+v", plat.GetID(), plat.GetLatest()) + } +} + +func callPlatformInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + installRespStream, err := client.PlatformInstall(context.Background(), + &rpc.PlatformInstallReq{ + Instance: instance, + PlatformPackage: "arduino", + Architecture: "samd", + Version: "1.6.19", + }) + + if err != nil { + log.Fatalf("Error installing platform: %s", err) + } + + // Loop and consume the server stream until all the operations are done. + for { + installResp, err := installRespStream.Recv() + + // The server is done. + if err == io.EOF { + log.Printf("Install done") + break + } + + // There was an error. + if err != nil { + log.Fatalf("Install error: %s", err) + } + + // When a download is ongoing, log the progress + if installResp.GetProgress() != nil { + log.Printf("DOWNLOAD: %s", installResp.GetProgress()) + } + + // When an overall task is ongoing, log the progress + if installResp.GetTaskProgress() != nil { + log.Printf("TASK: %s", installResp.GetTaskProgress()) + } + } +} + +func callPlatformList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + listResp, err := client.PlatformList(context.Background(), + &rpc.PlatformListReq{Instance: instance}) + + if err != nil { + log.Fatalf("List error: %s", err) + } + + for _, plat := range listResp.GetInstalledPlatform() { + // We only print ID and version of the installed platforms but you can look + // at the definition for the rpc.Platform struct for more fields. + log.Printf("Installed platform: %s - %s", plat.GetID(), plat.GetInstalled()) + } +} + +func callPlatformUpgrade(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + upgradeRespStream, err := client.PlatformUpgrade(context.Background(), + &rpc.PlatformUpgradeReq{ + Instance: instance, + PlatformPackage: "arduino", + Architecture: "samd", + }) + + if err != nil { + log.Fatalf("Error upgrading platform: %s", err) + } + + // Loop and consume the server stream until all the operations are done. + for { + upgradeResp, err := upgradeRespStream.Recv() + + // The server is done. + if err == io.EOF { + log.Printf("Upgrade done") + break + } + + // There was an error. + if err != nil { + log.Fatalf("Upgrade error: %s", err) + } + + // When a download is ongoing, log the progress + if upgradeResp.GetProgress() != nil { + log.Printf("DOWNLOAD: %s", upgradeResp.GetProgress()) + } + + // When an overall task is ongoing, log the progress + if upgradeResp.GetTaskProgress() != nil { + log.Printf("TASK: %s", upgradeResp.GetTaskProgress()) + } + } +} + +func callBoardsDetails(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + details, err := client.BoardDetails(context.Background(), + &rpc.BoardDetailsReq{ + Instance: instance, + Fqbn: "arduino:samd:mkr1000", + }) + + if err != nil { + log.Fatalf("Error getting board data: %s\n", err) + } + + log.Printf("Board details for %s", details.GetName()) + log.Printf("Required tools: %s", details.GetRequiredTools()) + log.Printf("Config options: %s", details.GetConfigOptions()) +} + +func callBoardAttach(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + currDir, _ := os.Getwd() + boardattachresp, err := client.BoardAttach(context.Background(), + &rpc.BoardAttachReq{ + Instance: instance, + BoardUri: "/dev/ttyACM0", + SketchPath: filepath.Join(currDir, "hello"), + }) + + if err != nil { + log.Fatalf("Attach error: %s", err) + } + + // Loop and consume the server stream until all the operations are done. + for { + attachResp, err := boardattachresp.Recv() + + // The server is done. + if err == io.EOF { + log.Print("Attach done") + break + } + + // There was an error. + if err != nil { + log.Fatalf("Attach error: %s\n", err) + } + + // When an overall task is ongoing, log the progress + if attachResp.GetTaskProgress() != nil { + log.Printf("TASK: %s", attachResp.GetTaskProgress()) + } + } +} + +func callCompile(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + currDir, _ := os.Getwd() + compRespStream, err := client.Compile(context.Background(), + &rpc.CompileReq{ + Instance: instance, + Fqbn: "arduino-pippo:samd:mkr1000", + SketchPath: filepath.Join(currDir, "hello"), + Verbose: true, + }) + + if err != nil { + log.Fatalf("Compile error: %s\n", err) + } + + // Loop and consume the server stream until all the operations are done. + for { + compResp, err := compRespStream.Recv() + + // The server is done. + if err == io.EOF { + log.Print("Compilation done") + break + } + + // There was an error. + if err != nil { + log.Fatalf("Compile error: %s\n", err) + } + + // When an operation is ongoing you can get its output + if resp := compResp.GetOutStream(); resp != nil { + log.Printf("STDOUT: %s", resp) + } + if resperr := compResp.GetErrStream(); resperr != nil { + log.Printf("STDERR: %s", resperr) + } + } +} + +func callUpload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + currDir, _ := os.Getwd() + uplRespStream, err := client.Upload(context.Background(), + &rpc.UploadReq{ + Instance: instance, + Fqbn: "arduino:samd:mkr1000", + SketchPath: filepath.Join(currDir, "hello"), + Port: "/dev/ttyACM0", + Verbose: true, + }) + + if err != nil { + log.Fatalf("Upload error: %s\n", err) + } + + for { + uplResp, err := uplRespStream.Recv() + if err == io.EOF { + log.Printf("Upload done") + break + } + + if err != nil { + log.Fatalf("Upload error: %s", err) + break + } + + // When an operation is ongoing you can get its output + if resp := uplResp.GetOutStream(); resp != nil { + log.Printf("STDOUT: %s", resp) + } + if resperr := uplResp.GetErrStream(); resperr != nil { + log.Printf("STDERR: %s", resperr) + } + } +} + +func callListAll(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + boardListAllResp, err := client.BoardListAll(context.Background(), + &rpc.BoardListAllReq{ + Instance: instance, + SearchArgs: []string{"mkr"}, + }) + + if err != nil { + log.Fatalf("Board list-all error: %s", err) + } + + for _, board := range boardListAllResp.GetBoards() { + log.Printf("%s: %s", board.GetName(), board.GetFQBN()) + } +} + +func callBoardList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + boardListResp, err := client.BoardList(context.Background(), + &rpc.BoardListReq{Instance: instance}) + + if err != nil { + log.Fatalf("Board list error: %s\n", err) + } + + for _, port := range boardListResp.GetPorts() { + log.Printf("port: %s, boards: %+v\n", port.GetAddress(), port.GetBoards()) + } +} + +func callPlatformUnInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + uninstallRespStream, err := client.PlatformUninstall(context.Background(), + &rpc.PlatformUninstallReq{ + Instance: instance, + PlatformPackage: "arduino", + Architecture: "samd", + }) + + if err != nil { + log.Fatalf("Uninstall error: %s", err) + } + + // Loop and consume the server stream until all the operations are done. + for { + uninstallResp, err := uninstallRespStream.Recv() + if err == io.EOF { + log.Print("Uninstall done") + break + } + + if err != nil { + log.Fatalf("Uninstall error: %s\n", err) + } + + if uninstallResp.GetTaskProgress() != nil { + log.Printf("TASK: %s\n", uninstallResp.GetTaskProgress()) + } + } +} + +func callUpdateLibraryIndex(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + libIdxUpdateStream, err := client.UpdateLibrariesIndex(context.Background(), + &rpc.UpdateLibrariesIndexReq{Instance: instance}) + + if err != nil { + log.Fatalf("Error updating libraries index: %s\n", err) + } + + // Loop and consume the server stream until all the operations are done. + for { + resp, err := libIdxUpdateStream.Recv() + if err == io.EOF { + log.Print("Library index update done") + break + } + + if err != nil { + log.Fatalf("Error updating libraries index: %s", err) + } + + if resp.GetDownloadProgress() != nil { + log.Printf("DOWNLOAD: %s", resp.GetDownloadProgress()) + } + } +} + +func callLibDownload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + downloadRespStream, err := client.LibraryDownload(context.Background(), + &rpc.LibraryDownloadReq{ + Instance: instance, + Name: "WiFi101", + Version: "0.15.2", + }) + + if err != nil { + log.Fatalf("Error downloading library: %s", err) + } + + // Loop and consume the server stream until all the operations are done. + for { + downloadResp, err := downloadRespStream.Recv() + if err == io.EOF { + log.Print("Lib download done") + break + } + + if err != nil { + log.Fatalf("Download error: %s", err) + } + + if downloadResp.GetProgress() != nil { + log.Printf("DOWNLOAD: %s", downloadResp.GetProgress()) + } + } +} + +func callLibInstall(client rpc.ArduinoCoreClient, instance *rpc.Instance, version string) { + installRespStream, err := client.LibraryInstall(context.Background(), + &rpc.LibraryInstallReq{ + Instance: instance, + Name: "WiFi101", + Version: version, + }) + + if err != nil { + log.Fatalf("Error installing library: %s", err) + } + + for { + installResp, err := installRespStream.Recv() + if err == io.EOF { + log.Print("Lib install done") + break + } + + if err != nil { + log.Fatalf("Install error: %s", err) + } + + if installResp.GetProgress() != nil { + log.Printf("DOWNLOAD: %s\n", installResp.GetProgress()) + } + if installResp.GetTaskProgress() != nil { + log.Printf("TASK: %s\n", installResp.GetTaskProgress()) + } + } +} + +func callLibUpgradeAll(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + libUpgradeAllRespStream, err := client.LibraryUpgradeAll(context.Background(), + &rpc.LibraryUpgradeAllReq{ + Instance: instance, + }) + + if err != nil { + log.Fatalf("Error upgrading all: %s\n", err) + } + + for { + resp, err := libUpgradeAllRespStream.Recv() + if err == io.EOF { + log.Printf("Lib upgrade all done") + break + } + + if err != nil { + log.Fatalf("Upgrading error: %s", err) + } + + if resp.GetProgress() != nil { + log.Printf("DOWNLOAD: %s\n", resp.GetProgress()) + } + if resp.GetTaskProgress() != nil { + log.Printf("TASK: %s\n", resp.GetTaskProgress()) + } + } +} + +func callLibSearch(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + libSearchResp, err := client.LibrarySearch(context.Background(), + &rpc.LibrarySearchReq{ + Instance: instance, + Query: "audio", + }) + + if err != nil { + log.Fatalf("Error searching for library: %s", err) + } + + for _, res := range libSearchResp.GetLibraries() { + log.Printf("Result: %s - %s", res.GetName(), res.GetLatest().GetVersion()) + } +} + +func callLibraryResolveDependencies(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + libraryResolveDependenciesResp, err := client.LibraryResolveDependencies(context.Background(), + &rpc.LibraryResolveDependenciesReq{ + Instance: instance, + Name: "ArduinoIoTCloud", + }) + + if err != nil { + log.Fatalf("Error listing library dependencies: %s", err) + } + + for _, resp := range libraryResolveDependenciesResp.GetDependencies() { + log.Printf("Dependency Name: %s", resp.GetName()) + log.Printf("Version Required: %s", resp.GetVersionRequired()) + if resp.GetVersionInstalled() != "" { + log.Printf("Version Installed: %s\n", resp.GetVersionInstalled()) + } + } +} + +func callLibList(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + libLstResp, err := client.LibraryList(context.Background(), + &rpc.LibraryListReq{ + Instance: instance, + All: false, + Updatable: false, + }) + + if err != nil { + log.Fatalf("Error List Library: %s", err) + } + + for _, res := range libLstResp.GetInstalledLibrary() { + log.Printf("%s - %s", res.GetLibrary().GetName(), res.GetLibrary().GetVersion()) + } +} + +func callLibUninstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { + libUninstallRespStream, err := client.LibraryUninstall(context.Background(), + &rpc.LibraryUninstallReq{ + Instance: instance, + Name: "WiFi101", + }) + + if err != nil { + log.Fatalf("Error uninstalling: %s", err) + } + + for { + uninstallResp, err := libUninstallRespStream.Recv() + if err == io.EOF { + log.Printf("Lib uninstall done") + break + } + + if err != nil { + log.Fatalf("Uninstall error: %s", err) + } + + if uninstallResp.GetTaskProgress() != nil { + log.Printf("TASK: %s", uninstallResp.GetTaskProgress()) + } + } +} + +func callDebugger(debugStreamingOpenClient dbg.Debug_DebugClient, instance *rpc.Instance) { + currDir, _ := os.Getwd() + log.Printf("Send debug request") + err := debugStreamingOpenClient.Send(&dbg.DebugReq{ + DebugReq: &dbg.DebugConfigReq{ + Instance: &dbg.Instance{Id: instance.GetId()}, + Fqbn: "arduino-pippo:samd:mkr1000", + SketchPath: filepath.Join(currDir, "hello"), + Port: "none", + }}) + if err != nil { + log.Fatalf("Send error: %s\n", err) + } + // Loop and consume the server stream until all the operations are done. + waitForPrompt(debugStreamingOpenClient, "(gdb)") + // wait for gdb to init and show the prompt + log.Printf("Send 'info registers' rcommand") + err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("info registers\n")}) + if err != nil { + log.Fatalf("Send error: %s\n", err) + } + + // Loop and consume the server stream until all the operations are done. + waitForPrompt(debugStreamingOpenClient, "(gdb)") + + // Send quit command to gdb + log.Printf("Send 'quit' command") + err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("quit\n")}) + if err != nil { + log.Fatalf("Send error: %s\n", err) + } + + // Close connection with the debug server + log.Printf("Close session") + err = debugStreamingOpenClient.CloseSend() + if err != nil { + log.Fatalf("Send error: %s\n", err) + } +} + +func waitForPrompt(debugStreamingOpenClient dbg.Debug_DebugClient, prompt string) { + var buffer bytes.Buffer + for { + compResp, err := debugStreamingOpenClient.Recv() + + // There was an error. + if err != nil { + log.Fatalf("debug error: %s\n", err) + } + + // Consume output and search for the gdb prompt to exit the loop + if resp := compResp.GetData(); resp != nil { + fmt.Printf("%s", resp) + buffer.Write(resp) + if strings.HasSuffix(strings.TrimRight(buffer.String(), " "), prompt) { + break + } + } + } +} From e8d907184efe55a0b8fdbe7d00671a3f0f524073 Mon Sep 17 00:00:00 2001 From: rsora Date: Thu, 20 Feb 2020 10:20:02 +0100 Subject: [PATCH 16/29] Replace with utils function --- commands/daemon/daemon.go | 4 +- rpc/debug/debug.pb.go | 395 -------------------------------------- 2 files changed, 2 insertions(+), 397 deletions(-) delete mode 100644 rpc/debug/debug.pb.go diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index d11ba0c06a2..7212c1749a3 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -213,8 +213,8 @@ func (s *ArduinoCoreServerImpl) PlatformList(ctx context.Context, req *rpc.Platf func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadReq, stream rpc.ArduinoCore_UploadServer) error { resp, err := upload.Upload( stream.Context(), req, - feedStream(func(data []byte) { stream.Send(&rpc.UploadResp{OutStream: data}) }), - feedStream(func(data []byte) { stream.Send(&rpc.UploadResp{ErrStream: data}) }), + utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.UploadResp{OutStream: data}) }), + utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.UploadResp{ErrStream: data}) }), ) if err != nil { return err diff --git a/rpc/debug/debug.pb.go b/rpc/debug/debug.pb.go deleted file mode 100644 index 2090e87850f..00000000000 --- a/rpc/debug/debug.pb.go +++ /dev/null @@ -1,395 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: debug/debug.proto - -package commands - -import ( - context "context" - fmt "fmt" - proto "github.com/golang/protobuf/proto" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -// The top-level message sent by the client for the `Debug` method. -// Multiple `DebugReq` messages can be sent but the first message -// must contain a `DebugReq` message to initialize the debug session. -// All subsequent messages must contain bytes to be sent to the debug session -// and must not contain a `DebugReq` message. -type DebugReq struct { - // Provides information to the debug that specifies which is the target. - // The first `StreamingOpenReq` message must contain a `DebugReq` - // message. - DebugReq *DebugConfigReq `protobuf:"bytes,1,opt,name=debugReq,proto3" json:"debugReq,omitempty"` - // The data to be sent to the target being monitored. - Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DebugReq) Reset() { *m = DebugReq{} } -func (m *DebugReq) String() string { return proto.CompactTextString(m) } -func (*DebugReq) ProtoMessage() {} -func (*DebugReq) Descriptor() ([]byte, []int) { - return fileDescriptor_5ae24eab94cb53d5, []int{0} -} - -func (m *DebugReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DebugReq.Unmarshal(m, b) -} -func (m *DebugReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DebugReq.Marshal(b, m, deterministic) -} -func (m *DebugReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_DebugReq.Merge(m, src) -} -func (m *DebugReq) XXX_Size() int { - return xxx_messageInfo_DebugReq.Size(m) -} -func (m *DebugReq) XXX_DiscardUnknown() { - xxx_messageInfo_DebugReq.DiscardUnknown(m) -} - -var xxx_messageInfo_DebugReq proto.InternalMessageInfo - -func (m *DebugReq) GetDebugReq() *DebugConfigReq { - if m != nil { - return m.DebugReq - } - return nil -} - -func (m *DebugReq) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -type DebugConfigReq struct { - Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` - Fqbn string `protobuf:"bytes,2,opt,name=fqbn,proto3" json:"fqbn,omitempty"` - SketchPath string `protobuf:"bytes,3,opt,name=sketch_path,json=sketchPath,proto3" json:"sketch_path,omitempty"` - Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"` - Verbose bool `protobuf:"varint,5,opt,name=verbose,proto3" json:"verbose,omitempty"` - ImportFile string `protobuf:"bytes,7,opt,name=import_file,json=importFile,proto3" json:"import_file,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DebugConfigReq) Reset() { *m = DebugConfigReq{} } -func (m *DebugConfigReq) String() string { return proto.CompactTextString(m) } -func (*DebugConfigReq) ProtoMessage() {} -func (*DebugConfigReq) Descriptor() ([]byte, []int) { - return fileDescriptor_5ae24eab94cb53d5, []int{1} -} - -func (m *DebugConfigReq) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DebugConfigReq.Unmarshal(m, b) -} -func (m *DebugConfigReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DebugConfigReq.Marshal(b, m, deterministic) -} -func (m *DebugConfigReq) XXX_Merge(src proto.Message) { - xxx_messageInfo_DebugConfigReq.Merge(m, src) -} -func (m *DebugConfigReq) XXX_Size() int { - return xxx_messageInfo_DebugConfigReq.Size(m) -} -func (m *DebugConfigReq) XXX_DiscardUnknown() { - xxx_messageInfo_DebugConfigReq.DiscardUnknown(m) -} - -var xxx_messageInfo_DebugConfigReq proto.InternalMessageInfo - -func (m *DebugConfigReq) GetInstance() *Instance { - if m != nil { - return m.Instance - } - return nil -} - -func (m *DebugConfigReq) GetFqbn() string { - if m != nil { - return m.Fqbn - } - return "" -} - -func (m *DebugConfigReq) GetSketchPath() string { - if m != nil { - return m.SketchPath - } - return "" -} - -func (m *DebugConfigReq) GetPort() string { - if m != nil { - return m.Port - } - return "" -} - -func (m *DebugConfigReq) GetVerbose() bool { - if m != nil { - return m.Verbose - } - return false -} - -func (m *DebugConfigReq) GetImportFile() string { - if m != nil { - return m.ImportFile - } - return "" -} - -// -type DebugResp struct { - Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DebugResp) Reset() { *m = DebugResp{} } -func (m *DebugResp) String() string { return proto.CompactTextString(m) } -func (*DebugResp) ProtoMessage() {} -func (*DebugResp) Descriptor() ([]byte, []int) { - return fileDescriptor_5ae24eab94cb53d5, []int{2} -} - -func (m *DebugResp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DebugResp.Unmarshal(m, b) -} -func (m *DebugResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DebugResp.Marshal(b, m, deterministic) -} -func (m *DebugResp) XXX_Merge(src proto.Message) { - xxx_messageInfo_DebugResp.Merge(m, src) -} -func (m *DebugResp) XXX_Size() int { - return xxx_messageInfo_DebugResp.Size(m) -} -func (m *DebugResp) XXX_DiscardUnknown() { - xxx_messageInfo_DebugResp.DiscardUnknown(m) -} - -var xxx_messageInfo_DebugResp proto.InternalMessageInfo - -func (m *DebugResp) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -func (m *DebugResp) GetError() string { - if m != nil { - return m.Error - } - return "" -} - -// duplicate from commands/common.proto -// as module imports seems not to work -type Instance struct { - Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Instance) Reset() { *m = Instance{} } -func (m *Instance) String() string { return proto.CompactTextString(m) } -func (*Instance) ProtoMessage() {} -func (*Instance) Descriptor() ([]byte, []int) { - return fileDescriptor_5ae24eab94cb53d5, []int{3} -} - -func (m *Instance) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Instance.Unmarshal(m, b) -} -func (m *Instance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Instance.Marshal(b, m, deterministic) -} -func (m *Instance) XXX_Merge(src proto.Message) { - xxx_messageInfo_Instance.Merge(m, src) -} -func (m *Instance) XXX_Size() int { - return xxx_messageInfo_Instance.Size(m) -} -func (m *Instance) XXX_DiscardUnknown() { - xxx_messageInfo_Instance.DiscardUnknown(m) -} - -var xxx_messageInfo_Instance proto.InternalMessageInfo - -func (m *Instance) GetId() int32 { - if m != nil { - return m.Id - } - return 0 -} - -func init() { - proto.RegisterType((*DebugReq)(nil), "cc.arduino.cli.commands.DebugReq") - proto.RegisterType((*DebugConfigReq)(nil), "cc.arduino.cli.commands.DebugConfigReq") - proto.RegisterType((*DebugResp)(nil), "cc.arduino.cli.commands.DebugResp") - proto.RegisterType((*Instance)(nil), "cc.arduino.cli.commands.Instance") -} - -func init() { proto.RegisterFile("debug/debug.proto", fileDescriptor_5ae24eab94cb53d5) } - -var fileDescriptor_5ae24eab94cb53d5 = []byte{ - // 335 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xd1, 0x4b, 0xeb, 0x30, - 0x14, 0xc6, 0x6f, 0x76, 0xd7, 0xbb, 0xee, 0xec, 0x32, 0x30, 0x08, 0x86, 0xbd, 0xb8, 0xf5, 0xc5, - 0x82, 0xac, 0x95, 0x89, 0x8f, 0xbe, 0x38, 0x11, 0x7c, 0x93, 0xe0, 0x93, 0x20, 0x23, 0x4d, 0xb2, - 0x35, 0xd8, 0x35, 0x5d, 0x9a, 0xf9, 0x8f, 0xfa, 0x0f, 0x49, 0xd2, 0x76, 0xe2, 0xc3, 0xf4, 0xa5, - 0xfd, 0xce, 0xe9, 0xf7, 0x3b, 0x5f, 0x4f, 0x1b, 0x38, 0x11, 0x32, 0xdb, 0x6f, 0x52, 0x7f, 0x4d, - 0x2a, 0xa3, 0xad, 0xc6, 0x67, 0x9c, 0x27, 0xcc, 0x88, 0xbd, 0x2a, 0x75, 0xc2, 0x0b, 0x95, 0x70, - 0xbd, 0xdd, 0xb2, 0x52, 0xd4, 0x11, 0x87, 0xf0, 0xde, 0xf9, 0xa8, 0xdc, 0xe1, 0x25, 0x84, 0xa2, - 0xd5, 0x04, 0x4d, 0x51, 0x3c, 0x5a, 0x5c, 0x24, 0x47, 0xb8, 0xc4, 0x43, 0x4b, 0x5d, 0xae, 0x95, - 0xb3, 0xd3, 0x03, 0x88, 0x31, 0xf4, 0x05, 0xb3, 0x8c, 0xf4, 0xa6, 0x28, 0xfe, 0x4f, 0xbd, 0x8e, - 0x3e, 0x10, 0x8c, 0xbf, 0x03, 0xf8, 0x16, 0x42, 0x55, 0xd6, 0x96, 0x95, 0x5c, 0xb6, 0x59, 0xb3, - 0xa3, 0x59, 0x8f, 0xad, 0x91, 0x1e, 0x10, 0x97, 0xb2, 0xde, 0x65, 0xa5, 0x4f, 0x19, 0x52, 0xaf, - 0xf1, 0x39, 0x8c, 0xea, 0x37, 0x69, 0x79, 0xbe, 0xaa, 0x98, 0xcd, 0xc9, 0x5f, 0xff, 0x08, 0x9a, - 0xd6, 0x13, 0xb3, 0xb9, 0x83, 0x2a, 0x6d, 0x2c, 0xe9, 0x37, 0x90, 0xd3, 0x98, 0xc0, 0xe0, 0x5d, - 0x9a, 0x4c, 0xd7, 0x92, 0x04, 0x53, 0x14, 0x87, 0xb4, 0x2b, 0xdd, 0x38, 0xb5, 0x75, 0x9e, 0xd5, - 0x5a, 0x15, 0x92, 0x0c, 0x9a, 0x71, 0x4d, 0xeb, 0x41, 0x15, 0x32, 0xba, 0x81, 0x61, 0xfb, 0xe9, - 0xea, 0xea, 0xb0, 0x36, 0xfa, 0x5a, 0x1b, 0x9f, 0x42, 0x20, 0x8d, 0xd1, 0xa6, 0x7d, 0xcb, 0xa6, - 0x88, 0x26, 0x10, 0x76, 0x0b, 0xe1, 0x31, 0xf4, 0x94, 0xf0, 0x4c, 0x40, 0x7b, 0x4a, 0x2c, 0x5e, - 0x21, 0xf0, 0x23, 0xf1, 0x73, 0x27, 0x66, 0x3f, 0xff, 0x01, 0x2a, 0x77, 0x93, 0xe8, 0x37, 0x4b, - 0x5d, 0x45, 0x7f, 0x62, 0x74, 0x85, 0xee, 0xe6, 0x2f, 0x97, 0x1b, 0x65, 0xf3, 0x7d, 0xe6, 0x2c, - 0x69, 0x8b, 0x74, 0xf7, 0x39, 0x2f, 0x54, 0x6a, 0x2a, 0x9e, 0x76, 0x78, 0xf6, 0xcf, 0x9f, 0x9d, - 0xeb, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x86, 0x6c, 0xb4, 0xc7, 0x50, 0x02, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 - -// DebugClient is the client API for Debug service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type DebugClient interface { - Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) -} - -type debugClient struct { - cc grpc.ClientConnInterface -} - -func NewDebugClient(cc grpc.ClientConnInterface) DebugClient { - return &debugClient{cc} -} - -func (c *debugClient) Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) { - stream, err := c.cc.NewStream(ctx, &_Debug_serviceDesc.Streams[0], "/cc.arduino.cli.commands.Debug/Debug", opts...) - if err != nil { - return nil, err - } - x := &debugDebugClient{stream} - return x, nil -} - -type Debug_DebugClient interface { - Send(*DebugReq) error - Recv() (*DebugResp, error) - grpc.ClientStream -} - -type debugDebugClient struct { - grpc.ClientStream -} - -func (x *debugDebugClient) Send(m *DebugReq) error { - return x.ClientStream.SendMsg(m) -} - -func (x *debugDebugClient) Recv() (*DebugResp, error) { - m := new(DebugResp) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// DebugServer is the server API for Debug service. -type DebugServer interface { - Debug(Debug_DebugServer) error -} - -// UnimplementedDebugServer can be embedded to have forward compatible implementations. -type UnimplementedDebugServer struct { -} - -func (*UnimplementedDebugServer) Debug(srv Debug_DebugServer) error { - return status.Errorf(codes.Unimplemented, "method Debug not implemented") -} - -func RegisterDebugServer(s *grpc.Server, srv DebugServer) { - s.RegisterService(&_Debug_serviceDesc, srv) -} - -func _Debug_Debug_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(DebugServer).Debug(&debugDebugServer{stream}) -} - -type Debug_DebugServer interface { - Send(*DebugResp) error - Recv() (*DebugReq, error) - grpc.ServerStream -} - -type debugDebugServer struct { - grpc.ServerStream -} - -func (x *debugDebugServer) Send(m *DebugResp) error { - return x.ServerStream.SendMsg(m) -} - -func (x *debugDebugServer) Recv() (*DebugReq, error) { - m := new(DebugReq) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -var _Debug_serviceDesc = grpc.ServiceDesc{ - ServiceName: "cc.arduino.cli.commands.Debug", - HandlerType: (*DebugServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{ - { - StreamName: "Debug", - Handler: _Debug_Debug_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "debug/debug.proto", -} From 38880170dc27adb516b8c161c9a5afee58183c53 Mon Sep 17 00:00:00 2001 From: rsora Date: Thu, 20 Feb 2020 10:48:00 +0100 Subject: [PATCH 17/29] Remove debug leftover --- arduino/cores/packagemanager/package_manager.go | 1 - 1 file changed, 1 deletion(-) diff --git a/arduino/cores/packagemanager/package_manager.go b/arduino/cores/packagemanager/package_manager.go index 3d4a2b33d55..d7016566ef4 100644 --- a/arduino/cores/packagemanager/package_manager.go +++ b/arduino/cores/packagemanager/package_manager.go @@ -323,7 +323,6 @@ func (tr *ToolReleaseActions) Get() (*cores.ToolRelease, error) { // GetInstalledPlatformRelease returns the PlatformRelease installed (it is chosen) func (pm *PackageManager) GetInstalledPlatformRelease(platform *cores.Platform) *cores.PlatformRelease { - pm.Log.Infof("Selecting installed platform release for %s", platform) releases := platform.GetAllInstalled() if len(releases) == 0 { return nil From e0e07c5dfb5ee92d70c259fe50e2116da8fdf040 Mon Sep 17 00:00:00 2001 From: rsora Date: Thu, 20 Feb 2020 10:59:34 +0100 Subject: [PATCH 18/29] Refreshed client example --- client_example/{ => hello}/hello.ino | 0 client_example/hello/sketch.json | 6 ++++++ client_example/main.go | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 12 deletions(-) rename client_example/{ => hello}/hello.ino (100%) create mode 100644 client_example/hello/sketch.json diff --git a/client_example/hello.ino b/client_example/hello/hello.ino similarity index 100% rename from client_example/hello.ino rename to client_example/hello/hello.ino diff --git a/client_example/hello/sketch.json b/client_example/hello/sketch.json new file mode 100644 index 00000000000..c9ec3aa3bac --- /dev/null +++ b/client_example/hello/sketch.json @@ -0,0 +1,6 @@ +{ + "cpu": { + "fqbn": "arduino:samd:mkr1000", + "name": "Arduino MKR1000" + } +} \ No newline at end of file diff --git a/client_example/main.go b/client_example/main.go index 71b06d0cff1..e37d7cdb9b5 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -94,9 +94,9 @@ func main() { // With a brand new instance, the first operation should always be updatating // the index. - //log.Println("calling UpdateIndex") - //callUpdateIndex(client, instance) - // + log.Println("calling UpdateIndex") + callUpdateIndex(client, instance) + // Let's search for a platform (also known as 'core') called 'samd'. log.Println("calling PlatformSearch(samd)") callPlatformSearch(client, instance) @@ -120,17 +120,17 @@ func main() { // Attach a board to a sketch. // Uncomment if you do have an actual board connected. - // log.Println("calling BoardAttach(serial:///dev/ttyACM0)") - // callBoardAttach(client, instance) + //log.Println("calling BoardAttach(serial:///dev/ttyACM0)") + //callBoardAttach(client, instance) // Compile a sketch - log.Println("calling Compile(arduino-pippo:samd:mkr1000, VERBOSE, hello.ino)") + log.Println("calling Compile(arduino:samd:mkr1000, VERBOSE, hello.ino)") callCompile(client, instance) // Upload a sketch // Uncomment if you do have an actual board connected. - // log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") - // callUpload(client, instance) + //log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") + //callUpload(client, instance) // Debug a sketch on a board // Uncomment if you do have an actual board connected via debug port, @@ -140,8 +140,8 @@ func main() { //if err != nil { // log.Fatalf("debug steraming open error: %s\n", err) //} - // log.Println("calling Debug(arduino:samd:mkr1000, hello.ino)") - // callDebugger(debugStreamingClient, instance) + //log.Println("calling Debug(arduino:samd:mkr1000, hello.ino)") + //callDebugger(debugStreamingClient, instance) // List all boards log.Println("calling BoardListAll(mkr)") @@ -489,7 +489,7 @@ func callCompile(client rpc.ArduinoCoreClient, instance *rpc.Instance) { compRespStream, err := client.Compile(context.Background(), &rpc.CompileReq{ Instance: instance, - Fqbn: "arduino-pippo:samd:mkr1000", + Fqbn: "arduino:samd:mkr1000", SketchPath: filepath.Join(currDir, "hello"), Verbose: true, }) @@ -824,7 +824,7 @@ func callDebugger(debugStreamingOpenClient dbg.Debug_DebugClient, instance *rpc. err := debugStreamingOpenClient.Send(&dbg.DebugReq{ DebugReq: &dbg.DebugConfigReq{ Instance: &dbg.Instance{Id: instance.GetId()}, - Fqbn: "arduino-pippo:samd:mkr1000", + Fqbn: "arduino:samd:mkr1000", SketchPath: filepath.Join(currDir, "hello"), Port: "none", }}) From c2681b35fe1774077f53c948763c5db64a285811 Mon Sep 17 00:00:00 2001 From: rsora Date: Thu, 20 Feb 2020 11:02:13 +0100 Subject: [PATCH 19/29] Moved debug proto to its package --- rpc/commands/commands.pb.go | 90 +-------- rpc/debug/debug.pb.go | 385 ++++++++++++++++++++++++++++++++++++ rpc/debug/debug.proto | 4 +- rpc/monitor/monitor.pb.go | 18 +- rpc/settings/settings.pb.go | 27 +-- 5 files changed, 399 insertions(+), 125 deletions(-) create mode 100644 rpc/debug/debug.pb.go diff --git a/rpc/commands/commands.pb.go b/rpc/commands/commands.pb.go index 780bbed2f1e..59fe7937ed8 100644 --- a/rpc/commands/commands.pb.go +++ b/rpc/commands/commands.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -599,11 +597,11 @@ var fileDescriptor_3690061a1131852d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // ArduinoCoreClient is the client API for ArduinoCore service. // @@ -643,10 +641,10 @@ type ArduinoCoreClient interface { } type arduinoCoreClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewArduinoCoreClient(cc grpc.ClientConnInterface) ArduinoCoreClient { +func NewArduinoCoreClient(cc *grpc.ClientConn) ArduinoCoreClient { return &arduinoCoreClient{cc} } @@ -1232,86 +1230,6 @@ type ArduinoCoreServer interface { LibraryList(context.Context, *LibraryListReq) (*LibraryListResp, error) } -// UnimplementedArduinoCoreServer can be embedded to have forward compatible implementations. -type UnimplementedArduinoCoreServer struct { -} - -func (*UnimplementedArduinoCoreServer) Init(req *InitReq, srv ArduinoCore_InitServer) error { - return status.Errorf(codes.Unimplemented, "method Init not implemented") -} -func (*UnimplementedArduinoCoreServer) Destroy(ctx context.Context, req *DestroyReq) (*DestroyResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Destroy not implemented") -} -func (*UnimplementedArduinoCoreServer) Rescan(ctx context.Context, req *RescanReq) (*RescanResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Rescan not implemented") -} -func (*UnimplementedArduinoCoreServer) UpdateIndex(req *UpdateIndexReq, srv ArduinoCore_UpdateIndexServer) error { - return status.Errorf(codes.Unimplemented, "method UpdateIndex not implemented") -} -func (*UnimplementedArduinoCoreServer) UpdateLibrariesIndex(req *UpdateLibrariesIndexReq, srv ArduinoCore_UpdateLibrariesIndexServer) error { - return status.Errorf(codes.Unimplemented, "method UpdateLibrariesIndex not implemented") -} -func (*UnimplementedArduinoCoreServer) Version(ctx context.Context, req *VersionReq) (*VersionResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardDetails(ctx context.Context, req *BoardDetailsReq) (*BoardDetailsResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardDetails not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardAttach(req *BoardAttachReq, srv ArduinoCore_BoardAttachServer) error { - return status.Errorf(codes.Unimplemented, "method BoardAttach not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardList(ctx context.Context, req *BoardListReq) (*BoardListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardList not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardListAll(ctx context.Context, req *BoardListAllReq) (*BoardListAllResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardListAll not implemented") -} -func (*UnimplementedArduinoCoreServer) Compile(req *CompileReq, srv ArduinoCore_CompileServer) error { - return status.Errorf(codes.Unimplemented, "method Compile not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformInstall(req *PlatformInstallReq, srv ArduinoCore_PlatformInstallServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformInstall not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformDownload(req *PlatformDownloadReq, srv ArduinoCore_PlatformDownloadServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformDownload not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformUninstall(req *PlatformUninstallReq, srv ArduinoCore_PlatformUninstallServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformUninstall not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformUpgrade(req *PlatformUpgradeReq, srv ArduinoCore_PlatformUpgradeServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformUpgrade not implemented") -} -func (*UnimplementedArduinoCoreServer) Upload(req *UploadReq, srv ArduinoCore_UploadServer) error { - return status.Errorf(codes.Unimplemented, "method Upload not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformSearch(ctx context.Context, req *PlatformSearchReq) (*PlatformSearchResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlatformSearch not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformList(ctx context.Context, req *PlatformListReq) (*PlatformListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlatformList not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryDownload(req *LibraryDownloadReq, srv ArduinoCore_LibraryDownloadServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryDownload not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryInstall(req *LibraryInstallReq, srv ArduinoCore_LibraryInstallServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryInstall not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryUninstall(req *LibraryUninstallReq, srv ArduinoCore_LibraryUninstallServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryUninstall not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryUpgradeAll(req *LibraryUpgradeAllReq, srv ArduinoCore_LibraryUpgradeAllServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryUpgradeAll not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryResolveDependencies(ctx context.Context, req *LibraryResolveDependenciesReq) (*LibraryResolveDependenciesResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibraryResolveDependencies not implemented") -} -func (*UnimplementedArduinoCoreServer) LibrarySearch(ctx context.Context, req *LibrarySearchReq) (*LibrarySearchResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibrarySearch not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryList(ctx context.Context, req *LibraryListReq) (*LibraryListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibraryList not implemented") -} - func RegisterArduinoCoreServer(s *grpc.Server, srv ArduinoCoreServer) { s.RegisterService(&_ArduinoCore_serviceDesc, srv) } diff --git a/rpc/debug/debug.pb.go b/rpc/debug/debug.pb.go new file mode 100644 index 00000000000..fad8b92d951 --- /dev/null +++ b/rpc/debug/debug.pb.go @@ -0,0 +1,385 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: debug/debug.proto + +package debug + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// The top-level message sent by the client for the `Debug` method. +// Multiple `DebugReq` messages can be sent but the first message +// must contain a `DebugReq` message to initialize the debug session. +// All subsequent messages must contain bytes to be sent to the debug session +// and must not contain a `DebugReq` message. +type DebugReq struct { + // Provides information to the debug that specifies which is the target. + // The first `StreamingOpenReq` message must contain a `DebugReq` + // message. + DebugReq *DebugConfigReq `protobuf:"bytes,1,opt,name=debugReq,proto3" json:"debugReq,omitempty"` + // The data to be sent to the target being monitored. + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DebugReq) Reset() { *m = DebugReq{} } +func (m *DebugReq) String() string { return proto.CompactTextString(m) } +func (*DebugReq) ProtoMessage() {} +func (*DebugReq) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{0} +} + +func (m *DebugReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugReq.Unmarshal(m, b) +} +func (m *DebugReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugReq.Marshal(b, m, deterministic) +} +func (m *DebugReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugReq.Merge(m, src) +} +func (m *DebugReq) XXX_Size() int { + return xxx_messageInfo_DebugReq.Size(m) +} +func (m *DebugReq) XXX_DiscardUnknown() { + xxx_messageInfo_DebugReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DebugReq proto.InternalMessageInfo + +func (m *DebugReq) GetDebugReq() *DebugConfigReq { + if m != nil { + return m.DebugReq + } + return nil +} + +func (m *DebugReq) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +type DebugConfigReq struct { + Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` + Fqbn string `protobuf:"bytes,2,opt,name=fqbn,proto3" json:"fqbn,omitempty"` + SketchPath string `protobuf:"bytes,3,opt,name=sketch_path,json=sketchPath,proto3" json:"sketch_path,omitempty"` + Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"` + Verbose bool `protobuf:"varint,5,opt,name=verbose,proto3" json:"verbose,omitempty"` + ImportFile string `protobuf:"bytes,7,opt,name=import_file,json=importFile,proto3" json:"import_file,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DebugConfigReq) Reset() { *m = DebugConfigReq{} } +func (m *DebugConfigReq) String() string { return proto.CompactTextString(m) } +func (*DebugConfigReq) ProtoMessage() {} +func (*DebugConfigReq) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{1} +} + +func (m *DebugConfigReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugConfigReq.Unmarshal(m, b) +} +func (m *DebugConfigReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugConfigReq.Marshal(b, m, deterministic) +} +func (m *DebugConfigReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugConfigReq.Merge(m, src) +} +func (m *DebugConfigReq) XXX_Size() int { + return xxx_messageInfo_DebugConfigReq.Size(m) +} +func (m *DebugConfigReq) XXX_DiscardUnknown() { + xxx_messageInfo_DebugConfigReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DebugConfigReq proto.InternalMessageInfo + +func (m *DebugConfigReq) GetInstance() *Instance { + if m != nil { + return m.Instance + } + return nil +} + +func (m *DebugConfigReq) GetFqbn() string { + if m != nil { + return m.Fqbn + } + return "" +} + +func (m *DebugConfigReq) GetSketchPath() string { + if m != nil { + return m.SketchPath + } + return "" +} + +func (m *DebugConfigReq) GetPort() string { + if m != nil { + return m.Port + } + return "" +} + +func (m *DebugConfigReq) GetVerbose() bool { + if m != nil { + return m.Verbose + } + return false +} + +func (m *DebugConfigReq) GetImportFile() string { + if m != nil { + return m.ImportFile + } + return "" +} + +// +type DebugResp struct { + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DebugResp) Reset() { *m = DebugResp{} } +func (m *DebugResp) String() string { return proto.CompactTextString(m) } +func (*DebugResp) ProtoMessage() {} +func (*DebugResp) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{2} +} + +func (m *DebugResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugResp.Unmarshal(m, b) +} +func (m *DebugResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugResp.Marshal(b, m, deterministic) +} +func (m *DebugResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugResp.Merge(m, src) +} +func (m *DebugResp) XXX_Size() int { + return xxx_messageInfo_DebugResp.Size(m) +} +func (m *DebugResp) XXX_DiscardUnknown() { + xxx_messageInfo_DebugResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DebugResp proto.InternalMessageInfo + +func (m *DebugResp) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *DebugResp) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +// duplicate from commands/common.proto +// as module imports seems not to work +type Instance struct { + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Instance) Reset() { *m = Instance{} } +func (m *Instance) String() string { return proto.CompactTextString(m) } +func (*Instance) ProtoMessage() {} +func (*Instance) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{3} +} + +func (m *Instance) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Instance.Unmarshal(m, b) +} +func (m *Instance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Instance.Marshal(b, m, deterministic) +} +func (m *Instance) XXX_Merge(src proto.Message) { + xxx_messageInfo_Instance.Merge(m, src) +} +func (m *Instance) XXX_Size() int { + return xxx_messageInfo_Instance.Size(m) +} +func (m *Instance) XXX_DiscardUnknown() { + xxx_messageInfo_Instance.DiscardUnknown(m) +} + +var xxx_messageInfo_Instance proto.InternalMessageInfo + +func (m *Instance) GetId() int32 { + if m != nil { + return m.Id + } + return 0 +} + +func init() { + proto.RegisterType((*DebugReq)(nil), "cc.arduino.cli.debug.DebugReq") + proto.RegisterType((*DebugConfigReq)(nil), "cc.arduino.cli.debug.DebugConfigReq") + proto.RegisterType((*DebugResp)(nil), "cc.arduino.cli.debug.DebugResp") + proto.RegisterType((*Instance)(nil), "cc.arduino.cli.debug.Instance") +} + +func init() { proto.RegisterFile("debug/debug.proto", fileDescriptor_5ae24eab94cb53d5) } + +var fileDescriptor_5ae24eab94cb53d5 = []byte{ + // 332 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0x41, 0x4b, 0xf3, 0x40, + 0x10, 0xfd, 0xb6, 0x5f, 0x63, 0xd3, 0xa9, 0x14, 0x5c, 0x7a, 0x58, 0x7a, 0x68, 0x4b, 0xf0, 0x10, + 0x04, 0xb7, 0x52, 0xf1, 0xe2, 0x49, 0x54, 0x04, 0x2f, 0x22, 0x7b, 0x11, 0xbc, 0xd4, 0x64, 0xb3, + 0x6d, 0x16, 0xd3, 0x6c, 0xba, 0xd9, 0xfa, 0x3b, 0xfd, 0x49, 0xb2, 0x9b, 0x4d, 0x45, 0x28, 0xbd, + 0x24, 0x6f, 0x66, 0xde, 0x9b, 0xb7, 0x33, 0x0c, 0x9c, 0x65, 0x22, 0xdd, 0xad, 0xe7, 0xee, 0x4b, + 0x2b, 0xad, 0x8c, 0xc2, 0x23, 0xce, 0x69, 0xa2, 0xb3, 0x9d, 0x2c, 0x15, 0xe5, 0x85, 0xa4, 0xae, + 0x16, 0x7d, 0x40, 0xf8, 0x68, 0x01, 0x13, 0x5b, 0x7c, 0x07, 0x61, 0xe6, 0x31, 0x41, 0x33, 0x14, + 0x0f, 0x16, 0xe7, 0xf4, 0x90, 0x88, 0x3a, 0xc5, 0x83, 0x2a, 0x57, 0xd2, 0x72, 0xd9, 0x5e, 0x85, + 0x31, 0x74, 0xb3, 0xc4, 0x24, 0xa4, 0x33, 0x43, 0xf1, 0x29, 0x73, 0x38, 0xfa, 0x46, 0x30, 0xfc, + 0x2b, 0xc0, 0xb7, 0x10, 0xca, 0xb2, 0x36, 0x49, 0xc9, 0x85, 0x37, 0x9a, 0x1c, 0x36, 0x7a, 0xf6, + 0x2c, 0xb6, 0xe7, 0x5b, 0x8b, 0xd5, 0x36, 0x2d, 0x9d, 0x45, 0x9f, 0x39, 0x8c, 0xa7, 0x30, 0xa8, + 0x3f, 0x85, 0xe1, 0xf9, 0xb2, 0x4a, 0x4c, 0x4e, 0xfe, 0xbb, 0x12, 0x34, 0xa9, 0xd7, 0xc4, 0xe4, + 0x56, 0x54, 0x29, 0x6d, 0x48, 0xb7, 0x11, 0x59, 0x8c, 0x09, 0xf4, 0xbe, 0x84, 0x4e, 0x55, 0x2d, + 0x48, 0x30, 0x43, 0x71, 0xc8, 0xda, 0xd0, 0xb6, 0x93, 0x1b, 0xcb, 0x59, 0xae, 0x64, 0x21, 0x48, + 0xaf, 0x69, 0xd7, 0xa4, 0x9e, 0x64, 0x21, 0xa2, 0x1b, 0xe8, 0xfb, 0xa5, 0xd5, 0xd5, 0x7e, 0x66, + 0xf4, 0x3b, 0x33, 0x1e, 0x41, 0x20, 0xb4, 0x56, 0xda, 0xbf, 0xb2, 0x09, 0xa2, 0x31, 0x84, 0xed, + 0x40, 0x78, 0x08, 0x1d, 0x99, 0x39, 0x4d, 0xc0, 0x3a, 0x32, 0x5b, 0xbc, 0x41, 0xe0, 0x5a, 0xe2, + 0x97, 0x16, 0x4c, 0x8e, 0xec, 0x9e, 0x89, 0xed, 0x78, 0x7a, 0xb4, 0x5e, 0x57, 0xd1, 0xbf, 0x18, + 0x5d, 0xa1, 0xfb, 0x8b, 0xf7, 0x78, 0x2d, 0x4d, 0xbe, 0x4b, 0x29, 0x57, 0x9b, 0xb9, 0xe7, 0xb7, + 0xff, 0x4b, 0x5e, 0xc8, 0xb9, 0xae, 0x78, 0x73, 0x28, 0xe9, 0x89, 0xbb, 0x94, 0xeb, 0x9f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xfc, 0x58, 0x74, 0x88, 0x3e, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// DebugClient is the client API for Debug service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DebugClient interface { + Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) +} + +type debugClient struct { + cc *grpc.ClientConn +} + +func NewDebugClient(cc *grpc.ClientConn) DebugClient { + return &debugClient{cc} +} + +func (c *debugClient) Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) { + stream, err := c.cc.NewStream(ctx, &_Debug_serviceDesc.Streams[0], "/cc.arduino.cli.debug.Debug/Debug", opts...) + if err != nil { + return nil, err + } + x := &debugDebugClient{stream} + return x, nil +} + +type Debug_DebugClient interface { + Send(*DebugReq) error + Recv() (*DebugResp, error) + grpc.ClientStream +} + +type debugDebugClient struct { + grpc.ClientStream +} + +func (x *debugDebugClient) Send(m *DebugReq) error { + return x.ClientStream.SendMsg(m) +} + +func (x *debugDebugClient) Recv() (*DebugResp, error) { + m := new(DebugResp) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// DebugServer is the server API for Debug service. +type DebugServer interface { + Debug(Debug_DebugServer) error +} + +func RegisterDebugServer(s *grpc.Server, srv DebugServer) { + s.RegisterService(&_Debug_serviceDesc, srv) +} + +func _Debug_Debug_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(DebugServer).Debug(&debugDebugServer{stream}) +} + +type Debug_DebugServer interface { + Send(*DebugResp) error + Recv() (*DebugReq, error) + grpc.ServerStream +} + +type debugDebugServer struct { + grpc.ServerStream +} + +func (x *debugDebugServer) Send(m *DebugResp) error { + return x.ServerStream.SendMsg(m) +} + +func (x *debugDebugServer) Recv() (*DebugReq, error) { + m := new(DebugReq) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _Debug_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cc.arduino.cli.debug.Debug", + HandlerType: (*DebugServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Debug", + Handler: _Debug_Debug_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "debug/debug.proto", +} diff --git a/rpc/debug/debug.proto b/rpc/debug/debug.proto index ce520fa9bda..a985c7683f1 100644 --- a/rpc/debug/debug.proto +++ b/rpc/debug/debug.proto @@ -15,9 +15,9 @@ syntax = "proto3"; -package cc.arduino.cli.commands; +package cc.arduino.cli.debug; -option go_package = "github.com/arduino/arduino-cli/rpc/commands"; +option go_package = "github.com/arduino/arduino-cli/rpc/debug"; // Service that abstract a debug Session usage diff --git a/rpc/monitor/monitor.pb.go b/rpc/monitor/monitor.pb.go index 1a06ba48521..78238c1565a 100644 --- a/rpc/monitor/monitor.pb.go +++ b/rpc/monitor/monitor.pb.go @@ -9,8 +9,6 @@ import ( proto "github.com/golang/protobuf/proto" _struct "github.com/golang/protobuf/ptypes/struct" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -268,11 +266,11 @@ var fileDescriptor_94d5950496a7550d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // MonitorClient is the client API for Monitor service. // @@ -282,10 +280,10 @@ type MonitorClient interface { } type monitorClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewMonitorClient(cc grpc.ClientConnInterface) MonitorClient { +func NewMonitorClient(cc *grpc.ClientConn) MonitorClient { return &monitorClient{cc} } @@ -325,14 +323,6 @@ type MonitorServer interface { StreamingOpen(Monitor_StreamingOpenServer) error } -// UnimplementedMonitorServer can be embedded to have forward compatible implementations. -type UnimplementedMonitorServer struct { -} - -func (*UnimplementedMonitorServer) StreamingOpen(srv Monitor_StreamingOpenServer) error { - return status.Errorf(codes.Unimplemented, "method StreamingOpen not implemented") -} - func RegisterMonitorServer(s *grpc.Server, srv MonitorServer) { s.RegisterService(&_Monitor_serviceDesc, srv) } diff --git a/rpc/settings/settings.pb.go b/rpc/settings/settings.pb.go index 0537c7d9e3a..1bbc54f255d 100644 --- a/rpc/settings/settings.pb.go +++ b/rpc/settings/settings.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -277,11 +275,11 @@ var fileDescriptor_a4bfd59e429426d0 = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // SettingsClient is the client API for Settings service. // @@ -294,10 +292,10 @@ type SettingsClient interface { } type settingsClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewSettingsClient(cc grpc.ClientConnInterface) SettingsClient { +func NewSettingsClient(cc *grpc.ClientConn) SettingsClient { return &settingsClient{cc} } @@ -345,23 +343,6 @@ type SettingsServer interface { SetValue(context.Context, *Value) (*SetValueResponse, error) } -// UnimplementedSettingsServer can be embedded to have forward compatible implementations. -type UnimplementedSettingsServer struct { -} - -func (*UnimplementedSettingsServer) GetAll(ctx context.Context, req *GetAllRequest) (*RawData, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetAll not implemented") -} -func (*UnimplementedSettingsServer) Merge(ctx context.Context, req *RawData) (*MergeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Merge not implemented") -} -func (*UnimplementedSettingsServer) GetValue(ctx context.Context, req *GetValueRequest) (*Value, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetValue not implemented") -} -func (*UnimplementedSettingsServer) SetValue(ctx context.Context, req *Value) (*SetValueResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method SetValue not implemented") -} - func RegisterSettingsServer(s *grpc.Server, srv SettingsServer) { s.RegisterService(&_Settings_serviceDesc, srv) } From 11452d5ea0a60f01d3c3ee03a6d70bc31ddf3c4a Mon Sep 17 00:00:00 2001 From: rsora Date: Thu, 20 Feb 2020 11:16:28 +0100 Subject: [PATCH 20/29] Removed sketch.json --- client_example/hello/sketch.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 client_example/hello/sketch.json diff --git a/client_example/hello/sketch.json b/client_example/hello/sketch.json deleted file mode 100644 index c9ec3aa3bac..00000000000 --- a/client_example/hello/sketch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "cpu": { - "fqbn": "arduino:samd:mkr1000", - "name": "Arduino MKR1000" - } -} \ No newline at end of file From a85376faf3ae0e702a890504a103127229c6f52d Mon Sep 17 00:00:00 2001 From: rsora Date: Thu, 20 Feb 2020 11:28:07 +0100 Subject: [PATCH 21/29] Apply general cosmetics --- cli/daemon/daemon.go | 10 +++++----- client_example/main.go | 24 ++++++++++++------------ commands/daemon/daemon.go | 2 +- commands/daemon/debug.go | 11 ++++++----- commands/debug/debug.go | 2 +- rpc/debug/debug.proto | 3 +-- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cli/daemon/daemon.go b/cli/daemon/daemon.go index dae9453707e..fc38dd11d38 100644 --- a/cli/daemon/daemon.go +++ b/cli/daemon/daemon.go @@ -74,19 +74,19 @@ func runDaemonCommand(cmd *cobra.Command, args []string) { VersionString: globals.VersionInfo.VersionString, }) - // register the monitors service + // Register the monitors service srv_monitor.RegisterMonitorServer(s, &daemon.MonitorService{}) - // register the settings service + // Register the settings service srv_settings.RegisterSettingsServer(s, &daemon.SettingsService{}) - // register the debug session service + // Register the debug session service srv_debug.RegisterDebugServer(s, &daemon.DebugService{}) if !daemonize { // When parent process ends terminate also the daemon go func() { - // stdin is closed when the controlling parent process ends + // Stdin is closed when the controlling parent process ends _, _ = io.Copy(ioutil.Discard, os.Stdin) os.Exit(0) }() @@ -119,6 +119,6 @@ func runDaemonCommand(cmd *cobra.Command, args []string) { // This message will show up on the stdout of the daemon process so that gRPC clients know it is time to connect. logrus.Infof("Daemon is listening on TCP port %s...", port) if err := s.Serve(lis); err != nil { - logrus.Fatalf("failed to serve: %v", err) + logrus.Fatalf("Failed to serve: %v", err) } } diff --git a/client_example/main.go b/client_example/main.go index e37d7cdb9b5..29892915c36 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -120,8 +120,8 @@ func main() { // Attach a board to a sketch. // Uncomment if you do have an actual board connected. - //log.Println("calling BoardAttach(serial:///dev/ttyACM0)") - //callBoardAttach(client, instance) + // log.Println("calling BoardAttach(serial:///dev/ttyACM0)") + // callBoardAttach(client, instance) // Compile a sketch log.Println("calling Compile(arduino:samd:mkr1000, VERBOSE, hello.ino)") @@ -129,19 +129,19 @@ func main() { // Upload a sketch // Uncomment if you do have an actual board connected. - //log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") - //callUpload(client, instance) + // log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") + // callUpload(client, instance) // Debug a sketch on a board // Uncomment if you do have an actual board connected via debug port, // or a board connected to a debugger. - //debugClient := dbg.NewDebugClient(conn) - //debugStreamingClient, err := debugClient.Debug(context.Background()) - //if err != nil { - // log.Fatalf("debug steraming open error: %s\n", err) - //} - //log.Println("calling Debug(arduino:samd:mkr1000, hello.ino)") - //callDebugger(debugStreamingClient, instance) + // debugClient := dbg.NewDebugClient(conn) + // debugStreamingClient, err := debugClient.Debug(context.Background()) + // if err != nil { + // log.Fatalf("debug steraming open error: %s\n", err) + // } + // log.Println("calling Debug(arduino:samd:mkr1000, hello.ino)") + // callDebugger(debugStreamingClient, instance) // List all boards log.Println("calling BoardListAll(mkr)") @@ -833,7 +833,7 @@ func callDebugger(debugStreamingOpenClient dbg.Debug_DebugClient, instance *rpc. } // Loop and consume the server stream until all the operations are done. waitForPrompt(debugStreamingOpenClient, "(gdb)") - // wait for gdb to init and show the prompt + // Wait for gdb to init and show the prompt log.Printf("Send 'info registers' rcommand") err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("info registers\n")}) if err != nil { diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index 7212c1749a3..579e4abd0f2 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -127,7 +127,7 @@ func (s *ArduinoCoreServerImpl) Compile(req *rpc.CompileReq, stream rpc.ArduinoC stream.Context(), req, utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.CompileResp{OutStream: data}) }), utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.CompileResp{ErrStream: data}) }), - false) // set debug to false + false) // Set debug to false if err != nil { return err } diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go index 6107fac57df..9cf08a02510 100644 --- a/commands/daemon/debug.go +++ b/commands/daemon/debug.go @@ -17,6 +17,7 @@ package daemon import ( "fmt" + "github.com/arduino/arduino-cli/arduino/utils" cmd "github.com/arduino/arduino-cli/commands/debug" dbg "github.com/arduino/arduino-cli/rpc/debug" @@ -27,22 +28,22 @@ type DebugService struct{} // Debug returns a stream response that can be used to fetch data from the // target. The first message passed through the `Debug` request must -// contain DebugConfigReq configuration params, not data. +// contain DebugReq configuration params, not data. func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { - // grab the first message + // Grab the first message msg, err := stream.Recv() if err != nil { return err } - // ensure it's a config message and not data + // Ensure it's a config message and not data req := msg.GetDebugReq() if req == nil { - return fmt.Errorf("first message must contain debug request, not data") + return fmt.Errorf("First message must contain debug request, not data") } - // launch debug recipe attaching stdin and out to grpc streaming + // Launch debug recipe attaching stdin and out to grpc streaming resp, err := cmd.Debug(stream.Context(), req, utils.ConsumeStreamFrom(func() ([]byte, error) { command, err := stream.Recv() diff --git a/commands/debug/debug.go b/commands/debug/debug.go index 8a888a41c95..047d0c03896 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -75,7 +75,7 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out } go func() { - // copy data from passed inStream into command stdIn + // Copy data from passed inStream into command stdIn io.Copy(in, inStream) // In any case, try process termination after a second to avoid leaving // zombie process. diff --git a/rpc/debug/debug.proto b/rpc/debug/debug.proto index a985c7683f1..7a8b7bb2eec 100644 --- a/rpc/debug/debug.proto +++ b/rpc/debug/debug.proto @@ -58,6 +58,5 @@ message DebugResp { string error = 2; } -// duplicate from commands/common.proto -// as module imports seems not to work +// TODO remove this in next proto refactoring because is a duplicate from commands/common.proto message Instance { int32 id = 1; } From 83cf94e240b0d91096488ea0d57b44b86726aaf1 Mon Sep 17 00:00:00 2001 From: rsora Date: Thu, 20 Feb 2020 15:40:11 +0100 Subject: [PATCH 22/29] Add test binaries --- commands/debug/testdata/.gitignore | 1 - .../testdata/hello/hello.arduino-test.samd.arduino_zero_edbg.bin | 0 .../debug/testdata/hello/hello.arduino-test.samd.mkr1000.bin | 0 3 files changed, 1 deletion(-) delete mode 100644 commands/debug/testdata/.gitignore create mode 100644 commands/debug/testdata/hello/hello.arduino-test.samd.arduino_zero_edbg.bin create mode 100644 commands/debug/testdata/hello/hello.arduino-test.samd.mkr1000.bin diff --git a/commands/debug/testdata/.gitignore b/commands/debug/testdata/.gitignore deleted file mode 100644 index a4337a420ca..00000000000 --- a/commands/debug/testdata/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!arduino \ No newline at end of file diff --git a/commands/debug/testdata/hello/hello.arduino-test.samd.arduino_zero_edbg.bin b/commands/debug/testdata/hello/hello.arduino-test.samd.arduino_zero_edbg.bin new file mode 100644 index 00000000000..e69de29bb2d diff --git a/commands/debug/testdata/hello/hello.arduino-test.samd.mkr1000.bin b/commands/debug/testdata/hello/hello.arduino-test.samd.mkr1000.bin new file mode 100644 index 00000000000..e69de29bb2d From da07d3debc92d78ac066d4cfa255d7fc0ccd2a2a Mon Sep 17 00:00:00 2001 From: rsora Date: Thu, 20 Feb 2020 18:57:08 +0100 Subject: [PATCH 23/29] Added test case for windows path flavor --- commands/debug/debug_test.go | 64 +++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/commands/debug/debug_test.go b/commands/debug/debug_test.go index f6975f67c4b..7f7f47db6bc 100644 --- a/commands/debug/debug_test.go +++ b/commands/debug/debug_test.go @@ -12,11 +12,11 @@ // modify or otherwise use the software for commercial activities involving the // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. - package debug import ( "fmt" + "runtime" "strings" "testing" @@ -29,7 +29,7 @@ import ( var customHardware = paths.New("testdata", "custom_hardware") var dataDir = paths.New("testdata", "data_dir", "packages") var sketch = "hello" -var sketchPath = paths.New("testdata", sketch).String() +var sketchPath = paths.New("testdata", sketch) func TestGetCommandLine(t *testing.T) { pm := packagemanager.NewPackageManager(nil, nil, nil, nil) @@ -40,52 +40,56 @@ func TestGetCommandLine(t *testing.T) { req := &dbg.DebugConfigReq{ Instance: &dbg.Instance{Id: 1}, Fqbn: "arduino-test:samd:arduino_zero_edbg", - SketchPath: sketchPath, + SketchPath: sketchPath.String(), Port: "none", } - packageName := strings.Split(req.Fqbn, ":")[0] - processor := strings.Split(req.Fqbn, ":")[1] - // This boardFamily variable is necessary for this particular board as it is represented in the core as 2 separated - // boards, to expose the programming port and the debug (edbg) port. So we point at the same openocd configuration - // variant for upload in both cases - boardFamily := "arduino_zero" - goldCommand := []string{ - fmt.Sprintf("%s/%s/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb", dataDir, packageName), - fmt.Sprintf("-ex"), - fmt.Sprintf("target extended-remote | %s/%s/tools/openocd/0.10.0-arduino7/bin/openocd", dataDir, packageName) + " " + - fmt.Sprintf("-s \"%s/%s/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir, packageName) + " " + - fmt.Sprintf("--file \"%s/%s/%s/variants/%s/openocd_scripts/arduino_zero.cfg\" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt", customHardware, packageName, processor, boardFamily), - fmt.Sprintf("%s/%s.%s.elf", sketchPath, sketch, strings.ReplaceAll(req.Fqbn, ":", ".")), + goldCommand := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb", dataDir) + + " -ex target extended-remote |" + + fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd", dataDir) + + fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + + fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg\"", customHardware) + + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.arduino_zero_edbg.elf", sketchPath) + + if runtime.GOOS == "windows" { + goldCommand = fmt.Sprintf("%s\\arduino-test\\tools\\arm-none-eabi-gcc\\7-2017q4/bin//arm-none-eabi-gdb.exe", dataDir) + + " -ex target extended-remote |" + + fmt.Sprintf(" %s\\arduino-test\\tools\\openocd\\0.10.0-arduino7/bin/openocd.exe", dataDir) + + fmt.Sprintf(" -s \"%s\\arduino-test\\tools\\openocd\\0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + + fmt.Sprintf(" --file \"%s\\arduino-test\\samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg\"", customHardware) + + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.arduino_zero_edbg.elf", sketchPath) } command, err := getCommandLine(req, pm) assert.Nil(t, err) - assert.Equal(t, goldCommand, command) + assert.Equal(t, goldCommand, strings.Join(command[:], " ")) // Other samd boards such as mkr1000 can be debugged using an external tool such as Atmel ICE connected to // the board debug port req2 := &dbg.DebugConfigReq{ Instance: &dbg.Instance{Id: 1}, Fqbn: "arduino-test:samd:mkr1000", - SketchPath: sketchPath, + SketchPath: sketchPath.String(), Port: "none", } - packageName2 := strings.Split(req2.Fqbn, ":")[0] - processor2 := strings.Split(req2.Fqbn, ":")[1] - name2 := strings.Split(req2.Fqbn, ":")[2] - goldCommand2 := []string{ - fmt.Sprintf("%s/%s/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb", dataDir, packageName2), - fmt.Sprintf("-ex"), - fmt.Sprintf("target extended-remote | %s/%s/tools/openocd/0.10.0-arduino7/bin/openocd", dataDir, packageName2) + " " + - fmt.Sprintf("-s \"%s/%s/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir, packageName2) + " " + - fmt.Sprintf("--file \"%s/%s/%s/variants/%s/openocd_scripts/arduino_zero.cfg\" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt", customHardware, packageName2, processor2, name2), - fmt.Sprintf("%s/%s.%s.elf", sketchPath, sketch, strings.ReplaceAll(req2.Fqbn, ":", ".")), + goldCommand2 := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb", dataDir) + + " -ex target extended-remote |" + + fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd", dataDir) + + fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + + fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/mkr1000/openocd_scripts/arduino_zero.cfg\"", customHardware) + + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.mkr1000.elf", sketchPath) + + if runtime.GOOS == "windows" { + goldCommand2 = fmt.Sprintf("%s\\arduino-test\\tools\\arm-none-eabi-gcc\\7-2017q4/bin//arm-none-eabi-gdb.exe", dataDir) + + " -ex target extended-remote |" + + fmt.Sprintf(" %s\\arduino-test\\tools\\openocd\\0.10.0-arduino7/bin/openocd.exe", dataDir) + + fmt.Sprintf(" -s \"%s\\arduino-test\\tools\\openocd\\0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + + fmt.Sprintf(" --file \"%s\\arduino-test\\samd/variants/mkr1000/openocd_scripts/arduino_zero.cfg\"", customHardware) + + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.mkr1000.elf", sketchPath) } command2, err := getCommandLine(req2, pm) assert.Nil(t, err) - assert.Equal(t, goldCommand2, command2) - + assert.Equal(t, goldCommand2, strings.Join(command2[:], " ")) } From abc9353f0d0fdcd74f7f24fc9801aec4d8d33b59 Mon Sep 17 00:00:00 2001 From: rsora Date: Fri, 21 Feb 2020 14:38:22 +0100 Subject: [PATCH 24/29] Use path.FromSlash to test debug tool command generation cross platform easily --- commands/debug/debug_test.go | 40 +++++++++++++++--------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/commands/debug/debug_test.go b/commands/debug/debug_test.go index 7f7f47db6bc..73d0a1f4c43 100644 --- a/commands/debug/debug_test.go +++ b/commands/debug/debug_test.go @@ -16,6 +16,7 @@ package debug import ( "fmt" + "path/filepath" "runtime" "strings" "testing" @@ -36,6 +37,12 @@ func TestGetCommandLine(t *testing.T) { pm.LoadHardwareFromDirectory(customHardware) pm.LoadHardwareFromDirectory(dataDir) + // Windows tools have .exe extension + var toolExtension = "" + if runtime.GOOS == "windows" { + toolExtension = ".exe" + } + // Arduino Zero has an integrated debugger port, anc it could be debugged directly using USB req := &dbg.DebugConfigReq{ Instance: &dbg.Instance{Id: 1}, @@ -44,25 +51,17 @@ func TestGetCommandLine(t *testing.T) { Port: "none", } - goldCommand := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb", dataDir) + + goldCommand := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb%s", dataDir, toolExtension) + " -ex target extended-remote |" + - fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd", dataDir) + + fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s", dataDir, toolExtension) + fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg\"", customHardware) + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.arduino_zero_edbg.elf", sketchPath) - if runtime.GOOS == "windows" { - goldCommand = fmt.Sprintf("%s\\arduino-test\\tools\\arm-none-eabi-gcc\\7-2017q4/bin//arm-none-eabi-gdb.exe", dataDir) + - " -ex target extended-remote |" + - fmt.Sprintf(" %s\\arduino-test\\tools\\openocd\\0.10.0-arduino7/bin/openocd.exe", dataDir) + - fmt.Sprintf(" -s \"%s\\arduino-test\\tools\\openocd\\0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + - fmt.Sprintf(" --file \"%s\\arduino-test\\samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg\"", customHardware) + - fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.arduino_zero_edbg.elf", sketchPath) - } - command, err := getCommandLine(req, pm) assert.Nil(t, err) - assert.Equal(t, goldCommand, strings.Join(command[:], " ")) + commandToTest := strings.Join(command[:], " ") + assert.Equal(t, filepath.FromSlash(goldCommand), filepath.FromSlash(commandToTest)) // Other samd boards such as mkr1000 can be debugged using an external tool such as Atmel ICE connected to // the board debug port @@ -73,23 +72,16 @@ func TestGetCommandLine(t *testing.T) { Port: "none", } - goldCommand2 := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb", dataDir) + + goldCommand2 := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb%s", dataDir, toolExtension) + " -ex target extended-remote |" + - fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd", dataDir) + + fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s", dataDir, toolExtension) + fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/mkr1000/openocd_scripts/arduino_zero.cfg\"", customHardware) + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.mkr1000.elf", sketchPath) - if runtime.GOOS == "windows" { - goldCommand2 = fmt.Sprintf("%s\\arduino-test\\tools\\arm-none-eabi-gcc\\7-2017q4/bin//arm-none-eabi-gdb.exe", dataDir) + - " -ex target extended-remote |" + - fmt.Sprintf(" %s\\arduino-test\\tools\\openocd\\0.10.0-arduino7/bin/openocd.exe", dataDir) + - fmt.Sprintf(" -s \"%s\\arduino-test\\tools\\openocd\\0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + - fmt.Sprintf(" --file \"%s\\arduino-test\\samd/variants/mkr1000/openocd_scripts/arduino_zero.cfg\"", customHardware) + - fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.mkr1000.elf", sketchPath) - } - command2, err := getCommandLine(req2, pm) assert.Nil(t, err) - assert.Equal(t, goldCommand2, strings.Join(command2[:], " ")) + commandToTest2 := strings.Join(command2[:], " ") + assert.Equal(t, filepath.FromSlash(goldCommand2), filepath.FromSlash(commandToTest2)) + } From fa396750f70df24c350302b68a5561c8afa8b2f0 Mon Sep 17 00:00:00 2001 From: rsora Date: Fri, 21 Feb 2020 15:59:55 +0100 Subject: [PATCH 25/29] Avoid pipe leaking via closing readers and writes in case of abnormal termination --- arduino/utils/stream.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arduino/utils/stream.go b/arduino/utils/stream.go index 019934cdb41..c8894a6403b 100644 --- a/arduino/utils/stream.go +++ b/arduino/utils/stream.go @@ -27,6 +27,7 @@ func FeedStreamTo(writer func(data []byte)) io.Writer { if n, err := r.Read(data); err == nil { writer(data[:n]) } else { + r.Close() return } } @@ -41,8 +42,14 @@ func ConsumeStreamFrom(reader func() ([]byte, error)) io.Reader { go func() { for { if data, err := reader(); err != nil { + if err == io.EOF { + w.Close() + } else { + w.CloseWithError(err) + } return } else if _, err := w.Write(data); err != nil { + w.Close() return } } From 3650865e7147cea372631865cc8b1335af3118fc Mon Sep 17 00:00:00 2001 From: rsora Date: Fri, 21 Feb 2020 16:00:20 +0100 Subject: [PATCH 26/29] Update client example to better catch gdb prompt --- client_example/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_example/main.go b/client_example/main.go index 29892915c36..314c4b44edd 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -872,7 +872,7 @@ func waitForPrompt(debugStreamingOpenClient dbg.Debug_DebugClient, prompt string if resp := compResp.GetData(); resp != nil { fmt.Printf("%s", resp) buffer.Write(resp) - if strings.HasSuffix(strings.TrimRight(buffer.String(), " "), prompt) { + if strings.Contains(buffer.String(), prompt) { break } } From 34e7854e613837b33fb1431d8c559b353c7ef9a5 Mon Sep 17 00:00:00 2001 From: rsora Date: Fri, 21 Feb 2020 16:06:35 +0100 Subject: [PATCH 27/29] Error messages cosmetics --- commands/daemon/debug.go | 5 ++--- commands/debug/debug.go | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go index 9cf08a02510..a373f8c1c82 100644 --- a/commands/daemon/debug.go +++ b/commands/daemon/debug.go @@ -16,11 +16,10 @@ package daemon import ( - "fmt" - "github.com/arduino/arduino-cli/arduino/utils" cmd "github.com/arduino/arduino-cli/commands/debug" dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/pkg/errors" ) // DebugService implements the `Debug` service @@ -40,7 +39,7 @@ func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { // Ensure it's a config message and not data req := msg.GetDebugReq() if req == nil { - return fmt.Errorf("First message must contain debug request, not data") + return errors.Errorf("First message must contain debug request, not data") } // Launch debug recipe attaching stdin and out to grpc streaming diff --git a/commands/debug/debug.go b/commands/debug/debug.go index 047d0c03896..e93575f5529 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -18,6 +18,7 @@ package debug import ( "context" "fmt" + "github.com/pkg/errors" "io" "os" "path/filepath" @@ -47,19 +48,18 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out pm := commands.GetPackageManager(req.GetInstance().GetId()) commandLine, err := getCommandLine(req, pm) if err != nil { - return nil, fmt.Errorf("cannot get command line for tool: %s", err) + return nil, errors.Wrap(err, "Cannot get command line for tool") } // Run Tool cmd, err := executils.Command(commandLine) if err != nil { - return nil, fmt.Errorf("cannot execute debug tool: %s", err) + return nil, errors.Wrap(err, "Cannot execute debug tool") } // Get stdIn pipe from tool in, err := cmd.StdinPipe() if err != nil { - fmt.Printf("%v\n", err) return &dbg.DebugResp{Error: err.Error()}, nil } defer in.Close() @@ -70,7 +70,6 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out // Start the debug command if err := cmd.Start(); err != nil { - fmt.Printf("%v\n", err) return &dbg.DebugResp{Error: err.Error()}, nil } From 5d9be12f22862e0eb003b81863d4f795f6607f79 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 21 Feb 2020 17:03:43 +0100 Subject: [PATCH 28/29] Use errors.Wrap instead of fmt.Errorf Co-Authored-By: Massimiliano Pippi --- commands/debug/debug.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/debug/debug.go b/commands/debug/debug.go index e93575f5529..5cda8386a77 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -99,7 +99,7 @@ func getCommandLine(req *dbg.DebugConfigReq, pm *packagemanager.PackageManager) sketchPath := paths.New(req.GetSketchPath()) sketch, err := sketches.NewSketchFromPath(sketchPath) if err != nil { - return nil, fmt.Errorf("opening sketch: %s", err) + return nil, errors.Wrap(err, "opening sketch") } // FIXME: make a specification on how a port is specified via command line From 600c1d5a1c6a76bbd12f2e16fd547de75b4e9562 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 21 Feb 2020 17:04:53 +0100 Subject: [PATCH 29/29] Use errors.Wrap instead of fmt.Errorf Co-Authored-By: Massimiliano Pippi --- commands/debug/debug.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/debug/debug.go b/commands/debug/debug.go index 5cda8386a77..f329f3b911f 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -117,13 +117,13 @@ func getCommandLine(req *dbg.DebugConfigReq, pm *packagemanager.PackageManager) } fqbn, err := cores.ParseFQBN(fqbnIn) if err != nil { - return nil, fmt.Errorf("incorrect FQBN: %s", err) + return nil, errors.Wrap(err, "error parsing FQBN") } // Find target board and board properties _, _, board, boardProperties, _, err := pm.ResolveFQBN(fqbn) if err != nil { - return nil, fmt.Errorf("incorrect FQBN: %s", err) + return nil, errors.Wrap(err, "error resolving FQBN") } // Load programmer tool @@ -199,7 +199,7 @@ func getCommandLine(req *dbg.DebugConfigReq, pm *packagemanager.PackageManager) if os.IsNotExist(err) { return nil, fmt.Errorf("compiled sketch %s not found", uploadFile.String()) } - return nil, fmt.Errorf("cannot open sketch: %s", err) + return nil, errors.Wrap(err, "cannot open sketch") } // Set debug port property