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 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy