From 38479dc706f27b2640cabad0bf39cd24e4f049c7 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 18 Aug 2023 10:27:47 +0200 Subject: [PATCH] feature: Detect board port change after upload (#2253) * UploadResponse now has 'oneof' clause for better API design * Added scaffolding to return updated-port after upload * Upload port change detection (first draft) * Simplified port detection using a Future-style abstraction * Perform watcher-flush higher in the call tree * Do not infer upload port if 'upload.wait_for_upload_port' is false * Further simplified port detection subroutine structure * fixed linter issue * Always return an updatedUploadPort. Arduino CLI should always return the port after an upload, even in the case where no port change is expected. The consumer shouldn't be required to implement "if not updated_upload_port, use original port" logic. The whole point is that all the logic for determining which port should be selected after an upload should be implemented in Arduino CLI. The consumer should be able to simply select the port Arduino CLI tells it to select in all cases. * Updated docs * Perform a deep-copy of upload ports where needed. Previously only the pointer was copied, thus making changes in `actualPort` to be reflected also to `port`. This lead to some weird result in the `updatedUploadPort` result: { "stdout": "Verify 11344 bytes of flash with checksum.\nVerify successful\ndone in 0.010 seconds\nCPU reset.\n", "stderr": "", "updated_upload_port": { "address": "/dev/tty.usbmodem14101", <------- this address... "label": "/dev/cu.usbmodem14101", <------- ...is different from the label "protocol": "serial", "protocol_label": "Serial Port (USB)", "properties": { "pid": "0x804E", "serialNumber": "94A3397C5150435437202020FF150838", "vid": "0x2341" }, "hardware_id": "94A3397C5150435437202020FF150838" } } * When updating `actualPort` address, update also the address label. * Fixed some potential nil pointer exceptions * Further simplified board watcher We must acesss the gRPC API only until we cross the `command` package border. Once we are inside the `command` package we should use the internal API only. * Before returning from upload, check if the port is still alive Now the upload detects cases when the upload port is "unstable", i.e. the port changes even if it shouldn't (because the wait_for_upload_port property in boards.txt is set to false). This change should make the upload process more resilient. * Apply suggestions from code review Co-authored-by: per1234 * Fixed nil exception * Improved tracking algorithm for upload-port reconnection The new algorithm takes into account the case where a single board may expose multiple ports, in this case the selection will increase priority to ports that: 1. have the same HW id as the user specified port for upload 2. have the same protocol as the user specified port for upload 3. have the same address as the user specified port for upload --------- Co-authored-by: per1234 --- arduino/discovery/discovery.go | 36 ++ arduino/discovery/discovery_client/main.go | 10 +- commands/board/list.go | 13 +- commands/board/list_test.go | 5 +- commands/daemon/daemon.go | 24 +- commands/upload/burnbootloader.go | 2 +- commands/upload/upload.go | 212 ++++++-- commands/upload/upload_test.go | 2 +- docs/UPGRADING.md | 52 ++ internal/algorithms/channels.go | 55 +++ internal/cli/compile/compile.go | 8 +- internal/cli/upload/upload.go | 27 +- rpc/cc/arduino/cli/commands/v1/upload.pb.go | 517 ++++++++++++-------- rpc/cc/arduino/cli/commands/v1/upload.proto | 18 +- 14 files changed, 717 insertions(+), 264 deletions(-) create mode 100644 internal/algorithms/channels.go diff --git a/arduino/discovery/discovery.go b/arduino/discovery/discovery.go index b8c3537b5f4..1832f1e77d3 100644 --- a/arduino/discovery/discovery.go +++ b/arduino/discovery/discovery.go @@ -97,6 +97,12 @@ type Port struct { var tr = i18n.Tr +// Equals returns true if the given port has the same address and protocol +// of the current port. +func (p *Port) Equals(o *Port) bool { + return p.Address == o.Address && p.Protocol == o.Protocol +} + // ToRPC converts Port into rpc.Port func (p *Port) ToRPC() *rpc.Port { props := p.Properties @@ -113,6 +119,24 @@ func (p *Port) ToRPC() *rpc.Port { } } +// PortFromRPCPort converts an *rpc.Port to a *Port +func PortFromRPCPort(o *rpc.Port) (p *Port) { + if o == nil { + return nil + } + res := &Port{ + Address: o.Address, + AddressLabel: o.Label, + Protocol: o.Protocol, + ProtocolLabel: o.ProtocolLabel, + HardwareID: o.HardwareId, + } + if o.Properties != nil { + res.Properties = properties.NewFromHashmap(o.Properties) + } + return res +} + func (p *Port) String() string { if p == nil { return "none" @@ -120,6 +144,18 @@ func (p *Port) String() string { return p.Address } +// Clone creates a copy of this Port +func (p *Port) Clone() *Port { + if p == nil { + return nil + } + var res Port = *p + if p.Properties != nil { + res.Properties = p.Properties.Clone() + } + return &res +} + // Event is a pluggable discovery event type Event struct { Type string diff --git a/arduino/discovery/discovery_client/main.go b/arduino/discovery/discovery_client/main.go index dd556691fe4..b9e1cfd0988 100644 --- a/arduino/discovery/discovery_client/main.go +++ b/arduino/discovery/discovery_client/main.go @@ -51,10 +51,12 @@ func main() { fmt.Printf(" Address: %s\n", port.Address) fmt.Printf(" Protocol: %s\n", port.Protocol) if ev.Type == "add" { - keys := port.Properties.Keys() - sort.Strings(keys) - for _, k := range keys { - fmt.Printf(" %s=%s\n", k, port.Properties.Get(k)) + if port.Properties != nil { + keys := port.Properties.Keys() + sort.Strings(keys) + for _, k := range keys { + fmt.Printf(" %s=%s\n", k, port.Properties.Get(k)) + } } } fmt.Println() diff --git a/commands/board/list.go b/commands/board/list.go index 5098ced4cfd..1ac055253b9 100644 --- a/commands/board/list.go +++ b/commands/board/list.go @@ -34,6 +34,7 @@ import ( "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/internal/inventory" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -128,20 +129,22 @@ func apiByVidPid(vid, pid string) ([]*rpc.BoardListItem, error) { }, nil } -func identifyViaCloudAPI(port *discovery.Port) ([]*rpc.BoardListItem, error) { +func identifyViaCloudAPI(props *properties.Map) ([]*rpc.BoardListItem, error) { // If the port is not USB do not try identification via cloud - id := port.Properties - if !id.ContainsKey("vid") || !id.ContainsKey("pid") { + if !props.ContainsKey("vid") || !props.ContainsKey("pid") { return nil, nil } logrus.Debug("Querying builder API for board identification...") - return cachedAPIByVidPid(id.Get("vid"), id.Get("pid")) + return cachedAPIByVidPid(props.Get("vid"), props.Get("pid")) } // identify returns a list of boards checking first the installed platforms or the Cloud API func identify(pme *packagemanager.Explorer, port *discovery.Port) ([]*rpc.BoardListItem, error) { boards := []*rpc.BoardListItem{} + if port.Properties == nil { + return boards, nil + } // first query installed cores through the Package Manager logrus.Debug("Querying installed cores for board identification...") @@ -167,7 +170,7 @@ func identify(pme *packagemanager.Explorer, port *discovery.Port) ([]*rpc.BoardL // if installed cores didn't recognize the board, try querying // the builder API if the board is a USB device port if len(boards) == 0 { - items, err := identifyViaCloudAPI(port) + items, err := identifyViaCloudAPI(port.Properties) if err != nil { // this is bad, but keep going logrus.WithError(err).Debug("Error querying builder API") diff --git a/commands/board/list_test.go b/commands/board/list_test.go index cf1dca37e4c..f99d942cf29 100644 --- a/commands/board/list_test.go +++ b/commands/board/list_test.go @@ -103,10 +103,7 @@ func TestGetByVidPidMalformedResponse(t *testing.T) { } func TestBoardDetectionViaAPIWithNonUSBPort(t *testing.T) { - port := &discovery.Port{ - Properties: properties.NewMap(), - } - items, err := identifyViaCloudAPI(port) + items, err := identifyViaCloudAPI(properties.NewMap()) require.NoError(t, err) require.Empty(t, items) } diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index bcf173381c7..1cb5a667b60 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -297,15 +297,27 @@ func (s *ArduinoCoreServerImpl) PlatformList(ctx context.Context, req *rpc.Platf // Upload FIXMEDOC func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadRequest, stream rpc.ArduinoCoreService_UploadServer) error { syncSend := NewSynchronizedSend(stream.Send) - outStream := feedStreamTo(func(data []byte) { syncSend.Send(&rpc.UploadResponse{OutStream: data}) }) - errStream := feedStreamTo(func(data []byte) { syncSend.Send(&rpc.UploadResponse{ErrStream: data}) }) - err := upload.Upload(stream.Context(), req, outStream, errStream) + outStream := feedStreamTo(func(data []byte) { + syncSend.Send(&rpc.UploadResponse{ + Message: &rpc.UploadResponse_OutStream{OutStream: data}, + }) + }) + errStream := feedStreamTo(func(data []byte) { + syncSend.Send(&rpc.UploadResponse{ + Message: &rpc.UploadResponse_ErrStream{ErrStream: data}, + }) + }) + res, err := upload.Upload(stream.Context(), req, outStream, errStream) outStream.Close() errStream.Close() - if err != nil { - return convertErrorToRPCStatus(err) + if res != nil { + syncSend.Send(&rpc.UploadResponse{ + Message: &rpc.UploadResponse_Result{ + Result: res, + }, + }) } - return nil + return convertErrorToRPCStatus(err) } // UploadUsingProgrammer FIXMEDOC diff --git a/commands/upload/burnbootloader.go b/commands/upload/burnbootloader.go index f47e22fd239..99efe2be757 100644 --- a/commands/upload/burnbootloader.go +++ b/commands/upload/burnbootloader.go @@ -39,7 +39,7 @@ func BurnBootloader(ctx context.Context, req *rpc.BurnBootloaderRequest, outStre } defer release() - err := runProgramAction( + _, err := runProgramAction( pme, nil, // sketch "", // importFile diff --git a/commands/upload/upload.go b/commands/upload/upload.go index 8de4bc009f6..75f8aae9238 100644 --- a/commands/upload/upload.go +++ b/commands/upload/upload.go @@ -21,16 +21,19 @@ import ( "io" "path/filepath" "strings" + "time" "github.com/arduino/arduino-cli/arduino" "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" + "github.com/arduino/arduino-cli/arduino/discovery" "github.com/arduino/arduino-cli/arduino/globals" "github.com/arduino/arduino-cli/arduino/serialutils" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/executils" "github.com/arduino/arduino-cli/i18n" + f "github.com/arduino/arduino-cli/internal/algorithms" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" @@ -123,7 +126,7 @@ func getUserFields(toolID string, platformRelease *cores.PlatformRelease) []*rpc } // Upload FIXMEDOC -func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, errStream io.Writer) error { +func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, errStream io.Writer) (*rpc.UploadResult, error) { logrus.Tracef("Upload %s on %s started", req.GetSketchPath(), req.GetFqbn()) // TODO: make a generic function to extract sketch from request @@ -131,16 +134,16 @@ func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, er sketchPath := paths.New(req.GetSketchPath()) sk, err := sketch.New(sketchPath) if err != nil && req.GetImportDir() == "" && req.GetImportFile() == "" { - return &arduino.CantOpenSketchError{Cause: err} + return nil, &arduino.CantOpenSketchError{Cause: err} } - pme, release := commands.GetPackageManagerExplorer(req) + pme, pmeRelease := commands.GetPackageManagerExplorer(req) if pme == nil { - return &arduino.InvalidInstanceError{} + return nil, &arduino.InvalidInstanceError{} } - defer release() + defer pmeRelease() - if err := runProgramAction( + updatedPort, err := runProgramAction( pme, sk, req.GetImportFile(), @@ -155,11 +158,14 @@ func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, er errStream, req.GetDryRun(), req.GetUserFields(), - ); err != nil { - return err + ) + if err != nil { + return nil, err } - return nil + return &rpc.UploadResult{ + UpdatedUploadPort: updatedPort, + }, nil } // UsingProgrammer FIXMEDOC @@ -169,7 +175,7 @@ func UsingProgrammer(ctx context.Context, req *rpc.UploadUsingProgrammerRequest, if req.GetProgrammer() == "" { return &arduino.MissingProgrammerError{} } - err := Upload(ctx, &rpc.UploadRequest{ + _, err := Upload(ctx, &rpc.UploadRequest{ Instance: req.GetInstance(), SketchPath: req.GetSketchPath(), ImportFile: req.GetImportFile(), @@ -186,36 +192,38 @@ func UsingProgrammer(ctx context.Context, req *rpc.UploadUsingProgrammerRequest, func runProgramAction(pme *packagemanager.Explorer, sk *sketch.Sketch, - importFile, importDir, fqbnIn string, port *rpc.Port, + importFile, importDir, fqbnIn string, userPort *rpc.Port, programmerID string, verbose, verify, burnBootloader bool, outStream, errStream io.Writer, - dryRun bool, userFields map[string]string) error { - - if burnBootloader && programmerID == "" { - return &arduino.MissingProgrammerError{} - } + dryRun bool, userFields map[string]string, +) (*rpc.Port, error) { + port := discovery.PortFromRPCPort(userPort) if port == nil || (port.Address == "" && port.Protocol == "") { // For no-port uploads use "default" protocol - port = &rpc.Port{Protocol: "default"} + port = &discovery.Port{Protocol: "default"} } logrus.WithField("port", port).Tracef("Upload port") + if burnBootloader && programmerID == "" { + return nil, &arduino.MissingProgrammerError{} + } + fqbn, err := cores.ParseFQBN(fqbnIn) if err != nil { - return &arduino.InvalidFQBNError{Cause: err} + return nil, &arduino.InvalidFQBNError{Cause: err} } logrus.WithField("fqbn", fqbn).Tracef("Detected FQBN") // Find target board and board properties _, boardPlatform, board, boardProperties, buildPlatform, err := pme.ResolveFQBN(fqbn) if boardPlatform == nil { - return &arduino.PlatformNotFoundError{ + return nil, &arduino.PlatformNotFoundError{ Platform: fmt.Sprintf("%s:%s", fqbn.Package, fqbn.PlatformArch), Cause: err, } } else if err != nil { - return &arduino.UnknownFQBNError{Cause: err} + return nil, &arduino.UnknownFQBNError{Cause: err} } logrus. WithField("boardPlatform", boardPlatform). @@ -232,7 +240,7 @@ func runProgramAction(pme *packagemanager.Explorer, programmer = buildPlatform.Programmers[programmerID] } if programmer == nil { - return &arduino.ProgrammerNotFoundError{Programmer: programmerID} + return nil, &arduino.ProgrammerNotFoundError{Programmer: programmerID} } } @@ -253,7 +261,7 @@ func runProgramAction(pme *packagemanager.Explorer, } uploadToolID, err := getToolID(props, action, port.Protocol) if err != nil { - return err + return nil, err } var uploadToolPlatform *cores.PlatformRelease @@ -268,7 +276,7 @@ func runProgramAction(pme *packagemanager.Explorer, Trace("Upload tool") if split := strings.Split(uploadToolID, ":"); len(split) > 2 { - return &arduino.InvalidPlatformPropertyError{ + return nil, &arduino.InvalidPlatformPropertyError{ Property: fmt.Sprintf("%s.tool.%s", action, port.Protocol), // TODO: Can be done better, maybe inline getToolID(...) Value: uploadToolID} } else if len(split) == 2 { @@ -277,12 +285,12 @@ func runProgramAction(pme *packagemanager.Explorer, PlatformArchitecture: boardPlatform.Platform.Architecture, }) if p == nil { - return &arduino.PlatformNotFoundError{Platform: split[0] + ":" + boardPlatform.Platform.Architecture} + return nil, &arduino.PlatformNotFoundError{Platform: split[0] + ":" + boardPlatform.Platform.Architecture} } uploadToolID = split[1] uploadToolPlatform = pme.GetInstalledPlatformRelease(p) if uploadToolPlatform == nil { - return &arduino.PlatformNotFoundError{Platform: split[0] + ":" + boardPlatform.Platform.Architecture} + return nil, &arduino.PlatformNotFoundError{Platform: split[0] + ":" + boardPlatform.Platform.Architecture} } } @@ -309,7 +317,7 @@ func runProgramAction(pme *packagemanager.Explorer, } if !uploadProperties.ContainsKey("upload.protocol") && programmer == nil { - return &arduino.ProgrammerRequiredForUploadError{} + return nil, &arduino.ProgrammerRequiredForUploadError{} } // Set properties for verbose upload @@ -357,18 +365,35 @@ func runProgramAction(pme *packagemanager.Explorer, if !burnBootloader { importPath, sketchName, err := determineBuildPathAndSketchName(importFile, importDir, sk, fqbn) if err != nil { - return &arduino.NotFoundError{Message: tr("Error finding build artifacts"), Cause: err} + return nil, &arduino.NotFoundError{Message: tr("Error finding build artifacts"), Cause: err} } if !importPath.Exist() { - return &arduino.NotFoundError{Message: tr("Compiled sketch not found in %s", importPath)} + return nil, &arduino.NotFoundError{Message: tr("Compiled sketch not found in %s", importPath)} } if !importPath.IsDir() { - return &arduino.NotFoundError{Message: tr("Expected compiled sketch in directory %s, but is a file instead", importPath)} + return nil, &arduino.NotFoundError{Message: tr("Expected compiled sketch in directory %s, but is a file instead", importPath)} } uploadProperties.SetPath("build.path", importPath) uploadProperties.Set("build.project_name", sketchName) } + // This context is kept alive for the entire duration of the upload + uploadCtx, uploadCompleted := context.WithCancel(context.Background()) + defer uploadCompleted() + + // Start the upload port change detector. + watcher, err := pme.DiscoveryManager().Watch() + if err != nil { + return nil, err + } + defer watcher.Close() + updatedUploadPort := f.NewFuture[*discovery.Port]() + go detectUploadPort( + uploadCtx, + port, watcher.Feed(), + uploadProperties.GetBoolean("upload.wait_for_upload_port"), + updatedUploadPort) + // Force port wait to make easier to unbrick boards like the Arduino Leonardo, or similar with native USB, // when a sketch causes a crash and the native USB serial port is lost. // See https://github.com/arduino/arduino-cli/issues/1943 for the details. @@ -385,7 +410,7 @@ func runProgramAction(pme *packagemanager.Explorer, // If not using programmer perform some action required // to set the board in bootloader mode - actualPort := port + actualPort := port.Clone() if programmer == nil && !burnBootloader && (port.Protocol == "serial" || forcedSerialPortWait) { // Perform reset via 1200bps touch if requested and wait for upload port also if requested. touch := uploadProperties.GetBoolean("upload.use_1200bps_touch") @@ -439,6 +464,7 @@ func runProgramAction(pme *packagemanager.Explorer, } else { if newPortAddress != "" { actualPort.Address = newPortAddress + actualPort.AddressLabel = newPortAddress } } } @@ -455,34 +481,144 @@ func runProgramAction(pme *packagemanager.Explorer, // Get Port properties gathered using pluggable discovery uploadProperties.Set("upload.port.address", port.Address) - uploadProperties.Set("upload.port.label", port.Label) + uploadProperties.Set("upload.port.label", port.AddressLabel) uploadProperties.Set("upload.port.protocol", port.Protocol) uploadProperties.Set("upload.port.protocolLabel", port.ProtocolLabel) - for prop, value := range actualPort.Properties { - uploadProperties.Set(fmt.Sprintf("upload.port.properties.%s", prop), value) + if actualPort.Properties != nil { + for prop, value := range actualPort.Properties.AsMap() { + uploadProperties.Set(fmt.Sprintf("upload.port.properties.%s", prop), value) + } } // Run recipes for upload toolEnv := pme.GetEnvVarsForSpawnedProcess() if burnBootloader { if err := runTool("erase.pattern", uploadProperties, outStream, errStream, verbose, dryRun, toolEnv); err != nil { - return &arduino.FailedUploadError{Message: tr("Failed chip erase"), Cause: err} + return nil, &arduino.FailedUploadError{Message: tr("Failed chip erase"), Cause: err} } if err := runTool("bootloader.pattern", uploadProperties, outStream, errStream, verbose, dryRun, toolEnv); err != nil { - return &arduino.FailedUploadError{Message: tr("Failed to burn bootloader"), Cause: err} + return nil, &arduino.FailedUploadError{Message: tr("Failed to burn bootloader"), Cause: err} } } else if programmer != nil { if err := runTool("program.pattern", uploadProperties, outStream, errStream, verbose, dryRun, toolEnv); err != nil { - return &arduino.FailedUploadError{Message: tr("Failed programming"), Cause: err} + return nil, &arduino.FailedUploadError{Message: tr("Failed programming"), Cause: err} } } else { if err := runTool("upload.pattern", uploadProperties, outStream, errStream, verbose, dryRun, toolEnv); err != nil { - return &arduino.FailedUploadError{Message: tr("Failed uploading"), Cause: err} + return nil, &arduino.FailedUploadError{Message: tr("Failed uploading"), Cause: err} } } + uploadCompleted() logrus.Tracef("Upload successful") - return nil + + updatedPort := updatedUploadPort.Await() + if updatedPort == nil { + return nil, nil + } + return updatedPort.ToRPC(), nil +} + +func detectUploadPort( + uploadCtx context.Context, + uploadPort *discovery.Port, watch <-chan *discovery.Event, + waitForUploadPort bool, + result f.Future[*discovery.Port], +) { + log := logrus.WithField("task", "port_detection") + log.Tracef("Detecting new board port after upload") + + candidate := uploadPort.Clone() + defer func() { + result.Send(candidate) + }() + + // Ignore all events during the upload + for { + select { + case ev, ok := <-watch: + if !ok { + log.Error("Upload port detection failed, watcher closed") + return + } + if candidate != nil && ev.Type == "remove" && ev.Port.Equals(candidate) { + log.WithField("event", ev).Trace("User-specified port has been disconnected, forcing wait for upload port") + waitForUploadPort = true + candidate = nil + } else { + log.WithField("event", ev).Trace("Ignored watcher event before upload") + } + continue + case <-uploadCtx.Done(): + // Upload completed, move to the next phase + } + break + } + + // Pick the first port that is detected after the upload + timeout := time.After(5 * time.Second) + if !waitForUploadPort { + timeout = time.After(time.Second) + } + for { + select { + case ev, ok := <-watch: + if !ok { + log.Error("Upload port detection failed, watcher closed") + return + } + if candidate != nil && ev.Type == "remove" && candidate.Equals(ev.Port) { + log.WithField("event", ev).Trace("Candidate port is no longer available") + candidate = nil + if !waitForUploadPort { + waitForUploadPort = true + timeout = time.After(5 * time.Second) + log.Trace("User-specified port has been disconnected, now waiting for upload port, timeout extended by 5 seconds") + } + continue + } + if ev.Type != "add" { + log.WithField("event", ev).Trace("Ignored non-add event") + continue + } + + portPriority := func(port *discovery.Port) int { + if port == nil { + return 0 + } + prio := 0 + if port.HardwareID == uploadPort.HardwareID { + prio += 1000 + } + if port.Protocol == uploadPort.Protocol { + prio += 100 + } + if port.Address == uploadPort.Address { + prio += 10 + } + return prio + } + evPortPriority := portPriority(ev.Port) + candidatePriority := portPriority(candidate) + if evPortPriority <= candidatePriority { + log.WithField("event", ev).Tracef("New upload port candidate is worse than the current one (prio=%d)", evPortPriority) + continue + } + log.WithField("event", ev).Tracef("Found new upload port candidate (prio=%d)", evPortPriority) + candidate = ev.Port + + // If the current candidate have the desired HW-ID return it quickly. + if candidate.HardwareID == ev.Port.HardwareID { + timeout = time.After(time.Second) + log.Trace("New candidate port match the desired HW ID, timeout reduced to 1 second.") + continue + } + + case <-timeout: + log.WithField("selected_port", candidate).Trace("Timeout waiting for candidate port") + return + } + } } func runTool(recipeID string, props *properties.Map, outStream, errStream io.Writer, verbose bool, dryRun bool, toolEnv []string) error { diff --git a/commands/upload/upload_test.go b/commands/upload/upload_test.go index d3f69fd1baf..e1f87cd9832 100644 --- a/commands/upload/upload_test.go +++ b/commands/upload/upload_test.go @@ -184,7 +184,7 @@ func TestUploadPropertiesComposition(t *testing.T) { testRunner := func(t *testing.T, test test, verboseVerify bool) { outStream := &bytes.Buffer{} errStream := &bytes.Buffer{} - err := runProgramAction( + _, err := runProgramAction( pme, nil, // sketch "", // importFile diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index 31490513af2..d1821cf87fa 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -4,6 +4,58 @@ Here you can find a list of migration guides to handle breaking changes between ## 0.34.0 +### The gRPC `cc.arduino.cli.commands.v1.UploadRepsonse` command response has been changed. + +Previously the `UploadResponse` was used only to stream the tool output: + +``` +message UploadResponse { + // The output of the upload process. + bytes out_stream = 1; + // The error output of the upload process. + bytes err_stream = 2; +} +``` + +Now the API logic has been clarified using the `oneof` clause and another field has been added providing an +`UploadResult` message that is sent when a successful upload completes. + +``` +message UploadResponse { + oneof message { + // The output of the upload process. + bytes out_stream = 1; + // The error output of the upload process. + bytes err_stream = 2; + // The upload result + UploadResult result = 3; + } +} + +message UploadResult { + // When a board requires a port disconnection to perform the upload, this + // field returns the port where the board reconnects after the upload. + Port updated_upload_port = 1; +} +``` + +### golang API: method `github.com/arduino/arduino-cli/commands/upload.Upload` changed signature + +The `Upload` method signature has been changed from: + +```go +func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, errStream io.Writer) error { ... } +``` + +to: + +```go +func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, errStream io.Writer) (*rpc.UploadResult, error) { ... } +``` + +Now an `UploadResult` structure is returned together with the error. If you are not interested in the information +contained in the structure you can safely ignore it. + ### golang package `github.com/arduino/arduino-cli/inventory` removed from public API The package `inventory` is no more a public golang API. diff --git a/internal/algorithms/channels.go b/internal/algorithms/channels.go new file mode 100644 index 00000000000..982925322cb --- /dev/null +++ b/internal/algorithms/channels.go @@ -0,0 +1,55 @@ +// This file is part of arduino-cli. +// +// Copyright 2023 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 f + +import "sync" + +// DiscardCh consumes all incoming messages from the given channel until it's closed. +func DiscardCh[T any](ch <-chan T) { + for range ch { + } +} + +// Future is an object that holds a result value. The value may be read and +// written asynchronously. +type Future[T any] interface { + Send(T) + Await() T +} + +type future[T any] struct { + wg sync.WaitGroup + value T +} + +// NewFuture creates a new Future[T] +func NewFuture[T any]() Future[T] { + res := &future[T]{} + res.wg.Add(1) + return res +} + +// Send a result in the Future. Threads waiting for result will be unlocked. +func (f *future[T]) Send(value T) { + f.value = value + f.wg.Done() +} + +// Await for a result from the Future, blocks until a result is available. +func (f *future[T]) Await() T { + f.wg.Wait() + return f.value +} diff --git a/internal/cli/compile/compile.go b/internal/cli/compile/compile.go index b208cc79dfd..baa1dff5f89 100644 --- a/internal/cli/compile/compile.go +++ b/internal/cli/compile/compile.go @@ -236,6 +236,8 @@ func runCompileCommand(cmd *cobra.Command, args []string) { DoNotExpandBuildProperties: showProperties == arguments.ShowPropertiesUnexpanded, } compileRes, compileError := compile.Compile(context.Background(), compileRequest, stdOut, stdErr, nil) + + var uploadRes *rpc.UploadResult if compileError == nil && uploadAfterCompile { userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: inst, @@ -268,8 +270,10 @@ func runCompileCommand(cmd *cobra.Command, args []string) { UserFields: fields, } - if err := upload.Upload(context.Background(), uploadRequest, stdOut, stdErr); err != nil { + if res, err := upload.Upload(context.Background(), uploadRequest, stdOut, stdErr); err != nil { feedback.Fatal(tr("Error during Upload: %v", err), feedback.ErrGeneric) + } else { + uploadRes = res } } @@ -330,6 +334,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) { CompilerOut: stdIO.Stdout, CompilerErr: stdIO.Stderr, BuilderResult: compileRes, + UploadResult: uploadRes, ProfileOut: profileOut, Success: compileError == nil, showPropertiesMode: showProperties, @@ -375,6 +380,7 @@ type compileResult struct { CompilerOut string `json:"compiler_out"` CompilerErr string `json:"compiler_err"` BuilderResult *rpc.CompileResponse `json:"builder_result"` + UploadResult *rpc.UploadResult `json:"upload_result"` Success bool `json:"success"` ProfileOut string `json:"profile_out,omitempty"` Error string `json:"error,omitempty"` diff --git a/internal/cli/upload/upload.go b/internal/cli/upload/upload.go index 739bb7d29e4..1fa91086ac0 100644 --- a/internal/cli/upload/upload.go +++ b/internal/cli/upload/upload.go @@ -168,8 +168,31 @@ func runUploadCommand(command *cobra.Command, args []string) { DryRun: dryRun, UserFields: fields, } - if err := upload.Upload(context.Background(), req, stdOut, stdErr); err != nil { + if res, err := upload.Upload(context.Background(), req, stdOut, stdErr); err != nil { feedback.FatalError(err, feedback.ErrGeneric) + } else { + io := stdIOResult() + feedback.PrintResult(&uploadResult{ + Stdout: io.Stdout, + Stderr: io.Stderr, + UpdatedUploadPort: res.UpdatedUploadPort, + }) } - feedback.PrintResult(stdIOResult()) +} + +type uploadResult struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr"` + UpdatedUploadPort *rpc.Port `json:"updated_upload_port,omitempty"` +} + +func (r *uploadResult) Data() interface{} { + return r +} + +func (r *uploadResult) String() string { + if r.UpdatedUploadPort == nil { + return "" + } + return tr("New upload port: %[1]s (%[2]s)", r.UpdatedUploadPort.Address, r.UpdatedUploadPort.Protocol) } diff --git a/rpc/cc/arduino/cli/commands/v1/upload.pb.go b/rpc/cc/arduino/cli/commands/v1/upload.pb.go index 50176927a47..0398a460ba1 100644 --- a/rpc/cc/arduino/cli/commands/v1/upload.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/upload.pb.go @@ -192,10 +192,12 @@ type UploadResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The output of the upload process. - OutStream []byte `protobuf:"bytes,1,opt,name=out_stream,json=outStream,proto3" json:"out_stream,omitempty"` - // The error output of the upload process. - ErrStream []byte `protobuf:"bytes,2,opt,name=err_stream,json=errStream,proto3" json:"err_stream,omitempty"` + // Types that are assignable to Message: + // + // *UploadResponse_OutStream + // *UploadResponse_ErrStream + // *UploadResponse_Result + Message isUploadResponse_Message `protobuf_oneof:"message"` } func (x *UploadResponse) Reset() { @@ -230,20 +232,108 @@ func (*UploadResponse) Descriptor() ([]byte, []int) { return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{1} } +func (m *UploadResponse) GetMessage() isUploadResponse_Message { + if m != nil { + return m.Message + } + return nil +} + func (x *UploadResponse) GetOutStream() []byte { - if x != nil { + if x, ok := x.GetMessage().(*UploadResponse_OutStream); ok { return x.OutStream } return nil } func (x *UploadResponse) GetErrStream() []byte { - if x != nil { + if x, ok := x.GetMessage().(*UploadResponse_ErrStream); ok { return x.ErrStream } return nil } +func (x *UploadResponse) GetResult() *UploadResult { + if x, ok := x.GetMessage().(*UploadResponse_Result); ok { + return x.Result + } + return nil +} + +type isUploadResponse_Message interface { + isUploadResponse_Message() +} + +type UploadResponse_OutStream struct { + // The output of the upload process. + OutStream []byte `protobuf:"bytes,1,opt,name=out_stream,json=outStream,proto3,oneof"` +} + +type UploadResponse_ErrStream struct { + // The error output of the upload process. + ErrStream []byte `protobuf:"bytes,2,opt,name=err_stream,json=errStream,proto3,oneof"` +} + +type UploadResponse_Result struct { + // The upload result + Result *UploadResult `protobuf:"bytes,3,opt,name=result,proto3,oneof"` +} + +func (*UploadResponse_OutStream) isUploadResponse_Message() {} + +func (*UploadResponse_ErrStream) isUploadResponse_Message() {} + +func (*UploadResponse_Result) isUploadResponse_Message() {} + +type UploadResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // When a board requires a port disconnection to perform the upload, this + // field returns the port where the board reconnects after the upload. + UpdatedUploadPort *Port `protobuf:"bytes,1,opt,name=updated_upload_port,json=updatedUploadPort,proto3" json:"updated_upload_port,omitempty"` +} + +func (x *UploadResult) Reset() { + *x = UploadResult{} + if protoimpl.UnsafeEnabled { + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UploadResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadResult) ProtoMessage() {} + +func (x *UploadResult) ProtoReflect() protoreflect.Message { + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadResult.ProtoReflect.Descriptor instead. +func (*UploadResult) Descriptor() ([]byte, []int) { + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{2} +} + +func (x *UploadResult) GetUpdatedUploadPort() *Port { + if x != nil { + return x.UpdatedUploadPort + } + return nil +} + type ProgrammerIsRequiredForUploadError struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -253,7 +343,7 @@ type ProgrammerIsRequiredForUploadError struct { func (x *ProgrammerIsRequiredForUploadError) Reset() { *x = ProgrammerIsRequiredForUploadError{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[2] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -266,7 +356,7 @@ func (x *ProgrammerIsRequiredForUploadError) String() string { func (*ProgrammerIsRequiredForUploadError) ProtoMessage() {} func (x *ProgrammerIsRequiredForUploadError) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[2] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -279,7 +369,7 @@ func (x *ProgrammerIsRequiredForUploadError) ProtoReflect() protoreflect.Message // Deprecated: Use ProgrammerIsRequiredForUploadError.ProtoReflect.Descriptor instead. func (*ProgrammerIsRequiredForUploadError) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{2} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{3} } type UploadUsingProgrammerRequest struct { @@ -326,7 +416,7 @@ type UploadUsingProgrammerRequest struct { func (x *UploadUsingProgrammerRequest) Reset() { *x = UploadUsingProgrammerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[3] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -339,7 +429,7 @@ func (x *UploadUsingProgrammerRequest) String() string { func (*UploadUsingProgrammerRequest) ProtoMessage() {} func (x *UploadUsingProgrammerRequest) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[3] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -352,7 +442,7 @@ func (x *UploadUsingProgrammerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UploadUsingProgrammerRequest.ProtoReflect.Descriptor instead. func (*UploadUsingProgrammerRequest) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{3} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{4} } func (x *UploadUsingProgrammerRequest) GetInstance() *Instance { @@ -446,7 +536,7 @@ type UploadUsingProgrammerResponse struct { func (x *UploadUsingProgrammerResponse) Reset() { *x = UploadUsingProgrammerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[4] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -459,7 +549,7 @@ func (x *UploadUsingProgrammerResponse) String() string { func (*UploadUsingProgrammerResponse) ProtoMessage() {} func (x *UploadUsingProgrammerResponse) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[4] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -472,7 +562,7 @@ func (x *UploadUsingProgrammerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UploadUsingProgrammerResponse.ProtoReflect.Descriptor instead. func (*UploadUsingProgrammerResponse) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{4} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{5} } func (x *UploadUsingProgrammerResponse) GetOutStream() []byte { @@ -521,7 +611,7 @@ type BurnBootloaderRequest struct { func (x *BurnBootloaderRequest) Reset() { *x = BurnBootloaderRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[5] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -534,7 +624,7 @@ func (x *BurnBootloaderRequest) String() string { func (*BurnBootloaderRequest) ProtoMessage() {} func (x *BurnBootloaderRequest) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[5] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -547,7 +637,7 @@ func (x *BurnBootloaderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BurnBootloaderRequest.ProtoReflect.Descriptor instead. func (*BurnBootloaderRequest) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{5} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{6} } func (x *BurnBootloaderRequest) GetInstance() *Instance { @@ -620,7 +710,7 @@ type BurnBootloaderResponse struct { func (x *BurnBootloaderResponse) Reset() { *x = BurnBootloaderResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[6] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -633,7 +723,7 @@ func (x *BurnBootloaderResponse) String() string { func (*BurnBootloaderResponse) ProtoMessage() {} func (x *BurnBootloaderResponse) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[6] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -646,7 +736,7 @@ func (x *BurnBootloaderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BurnBootloaderResponse.ProtoReflect.Descriptor instead. func (*BurnBootloaderResponse) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{6} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{7} } func (x *BurnBootloaderResponse) GetOutStream() []byte { @@ -675,7 +765,7 @@ type ListProgrammersAvailableForUploadRequest struct { func (x *ListProgrammersAvailableForUploadRequest) Reset() { *x = ListProgrammersAvailableForUploadRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[7] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -688,7 +778,7 @@ func (x *ListProgrammersAvailableForUploadRequest) String() string { func (*ListProgrammersAvailableForUploadRequest) ProtoMessage() {} func (x *ListProgrammersAvailableForUploadRequest) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[7] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -701,7 +791,7 @@ func (x *ListProgrammersAvailableForUploadRequest) ProtoReflect() protoreflect.M // Deprecated: Use ListProgrammersAvailableForUploadRequest.ProtoReflect.Descriptor instead. func (*ListProgrammersAvailableForUploadRequest) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{7} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{8} } func (x *ListProgrammersAvailableForUploadRequest) GetInstance() *Instance { @@ -729,7 +819,7 @@ type ListProgrammersAvailableForUploadResponse struct { func (x *ListProgrammersAvailableForUploadResponse) Reset() { *x = ListProgrammersAvailableForUploadResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[8] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -742,7 +832,7 @@ func (x *ListProgrammersAvailableForUploadResponse) String() string { func (*ListProgrammersAvailableForUploadResponse) ProtoMessage() {} func (x *ListProgrammersAvailableForUploadResponse) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[8] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -755,7 +845,7 @@ func (x *ListProgrammersAvailableForUploadResponse) ProtoReflect() protoreflect. // Deprecated: Use ListProgrammersAvailableForUploadResponse.ProtoReflect.Descriptor instead. func (*ListProgrammersAvailableForUploadResponse) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{8} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{9} } func (x *ListProgrammersAvailableForUploadResponse) GetProgrammers() []*Programmer { @@ -781,7 +871,7 @@ type SupportedUserFieldsRequest struct { func (x *SupportedUserFieldsRequest) Reset() { *x = SupportedUserFieldsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[9] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -794,7 +884,7 @@ func (x *SupportedUserFieldsRequest) String() string { func (*SupportedUserFieldsRequest) ProtoMessage() {} func (x *SupportedUserFieldsRequest) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[9] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -807,7 +897,7 @@ func (x *SupportedUserFieldsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SupportedUserFieldsRequest.ProtoReflect.Descriptor instead. func (*SupportedUserFieldsRequest) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{9} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{10} } func (x *SupportedUserFieldsRequest) GetInstance() *Instance { @@ -850,7 +940,7 @@ type UserField struct { func (x *UserField) Reset() { *x = UserField{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[10] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -863,7 +953,7 @@ func (x *UserField) String() string { func (*UserField) ProtoMessage() {} func (x *UserField) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[10] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -876,7 +966,7 @@ func (x *UserField) ProtoReflect() protoreflect.Message { // Deprecated: Use UserField.ProtoReflect.Descriptor instead. func (*UserField) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{10} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{11} } func (x *UserField) GetToolId() string { @@ -920,7 +1010,7 @@ type SupportedUserFieldsResponse struct { func (x *SupportedUserFieldsResponse) Reset() { *x = SupportedUserFieldsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[11] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -933,7 +1023,7 @@ func (x *SupportedUserFieldsResponse) String() string { func (*SupportedUserFieldsResponse) ProtoMessage() {} func (x *SupportedUserFieldsResponse) ProtoReflect() protoreflect.Message { - mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[11] + mi := &file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -946,7 +1036,7 @@ func (x *SupportedUserFieldsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SupportedUserFieldsResponse.ProtoReflect.Descriptor instead. func (*SupportedUserFieldsResponse) Descriptor() ([]byte, []int) { - return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{11} + return file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP(), []int{12} } func (x *SupportedUserFieldsResponse) GetUserFields() []*UserField { @@ -1000,130 +1090,141 @@ var file_cc_arduino_cli_commands_v1_upload_proto_rawDesc = []byte{ 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4e, 0x0a, 0x0e, 0x55, 0x70, - 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x09, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x65, - 0x72, 0x72, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x09, 0x65, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x22, 0x24, 0x0a, 0x22, 0x50, 0x72, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x49, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x64, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x22, 0xa0, 0x04, 0x0a, 0x1c, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x73, 0x69, 0x6e, 0x67, - 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, - 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6b, 0x65, 0x74, 0x63, - 0x68, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6b, - 0x65, 0x74, 0x63, 0x68, 0x50, 0x61, 0x74, 0x68, 0x12, 0x34, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa1, 0x01, 0x0a, 0x0e, 0x55, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, + 0x0a, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x48, 0x00, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1f, + 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x65, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, + 0x42, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x60, + 0x0a, 0x0c, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x50, + 0x0a, 0x13, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x63, + 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x11, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x6f, 0x72, 0x74, + 0x22, 0x24, 0x0a, 0x22, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x49, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xa0, 0x04, 0x0a, 0x1c, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, + 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, + 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x12, 0x1f, 0x0a, + 0x0b, 0x73, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x50, 0x61, 0x74, 0x68, 0x12, 0x34, + 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, + 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x04, + 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6d, 0x70, + 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x70, + 0x6f, 0x72, 0x74, 0x44, 0x69, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x6d, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, + 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, + 0x69, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x0b, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x48, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, + 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, + 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, + 0x75, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x55, 0x73, + 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x5d, 0x0a, 0x1d, 0x55, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x75, + 0x74, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, + 0x6f, 0x75, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, + 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, + 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x22, 0xb1, 0x03, 0x0a, 0x15, 0x42, 0x75, 0x72, + 0x6e, 0x42, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, + 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, - 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, - 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x69, 0x72, - 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x18, 0x09, + 0x66, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, - 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x69, 0x0a, 0x0b, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x48, - 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, - 0x61, 0x64, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, - 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x46, 0x69, - 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0x5d, 0x0a, 0x1d, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x73, 0x69, - 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x22, 0xb1, 0x03, 0x0a, 0x15, 0x42, 0x75, 0x72, 0x6e, 0x42, 0x6f, 0x6f, 0x74, 0x6c, - 0x6f, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, + 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x62, 0x0a, 0x0b, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, - 0x62, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, - 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, - 0x72, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, - 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, - 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x06, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, - 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, - 0x52, 0x75, 0x6e, 0x12, 0x62, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, - 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x72, 0x6e, 0x42, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, - 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x75, 0x73, 0x65, - 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x56, 0x0a, 0x16, 0x42, 0x75, 0x72, 0x6e, 0x42, 0x6f, - 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, - 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x22, 0x80, - 0x01, 0x0a, 0x28, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, - 0x72, 0x73, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x55, 0x70, - 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, - 0x6e, 0x22, 0x75, 0x0a, 0x29, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x6d, 0x65, 0x72, 0x73, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x6f, 0x72, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, - 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x72, 0x6e, + 0x42, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x3d, 0x0a, + 0x0f, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x56, 0x0a, 0x16, + 0x42, 0x75, 0x72, 0x6e, 0x42, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x5f, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, 0x72, 0x72, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x22, 0x80, 0x01, 0x0a, 0x28, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, + 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, + 0x65, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x52, 0x0b, 0x70, 0x72, 0x6f, - 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x1a, 0x53, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, + 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, 0x75, 0x0a, 0x29, 0x4c, 0x69, 0x73, 0x74, 0x50, + 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, + 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x66, 0x0a, 0x09, 0x55, 0x73, 0x65, - 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x6f, 0x6c, 0x49, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x22, 0x65, 0x0a, 0x1b, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x55, 0x73, - 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x46, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, - 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x0a, 0x75, 0x73, - 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, - 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, - 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, + 0x72, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x22, 0x8e, + 0x01, 0x0a, 0x1a, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, + 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, + 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, + 0x71, 0x62, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, + 0x66, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x17, 0x0a, 0x07, + 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, + 0x6f, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x65, 0x0a, 0x1b, 0x53, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x63, + 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x42, 0x48, + 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, + 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, + 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1138,46 +1239,49 @@ func file_cc_arduino_cli_commands_v1_upload_proto_rawDescGZIP() []byte { return file_cc_arduino_cli_commands_v1_upload_proto_rawDescData } -var file_cc_arduino_cli_commands_v1_upload_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_cc_arduino_cli_commands_v1_upload_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_cc_arduino_cli_commands_v1_upload_proto_goTypes = []interface{}{ (*UploadRequest)(nil), // 0: cc.arduino.cli.commands.v1.UploadRequest (*UploadResponse)(nil), // 1: cc.arduino.cli.commands.v1.UploadResponse - (*ProgrammerIsRequiredForUploadError)(nil), // 2: cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError - (*UploadUsingProgrammerRequest)(nil), // 3: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest - (*UploadUsingProgrammerResponse)(nil), // 4: cc.arduino.cli.commands.v1.UploadUsingProgrammerResponse - (*BurnBootloaderRequest)(nil), // 5: cc.arduino.cli.commands.v1.BurnBootloaderRequest - (*BurnBootloaderResponse)(nil), // 6: cc.arduino.cli.commands.v1.BurnBootloaderResponse - (*ListProgrammersAvailableForUploadRequest)(nil), // 7: cc.arduino.cli.commands.v1.ListProgrammersAvailableForUploadRequest - (*ListProgrammersAvailableForUploadResponse)(nil), // 8: cc.arduino.cli.commands.v1.ListProgrammersAvailableForUploadResponse - (*SupportedUserFieldsRequest)(nil), // 9: cc.arduino.cli.commands.v1.SupportedUserFieldsRequest - (*UserField)(nil), // 10: cc.arduino.cli.commands.v1.UserField - (*SupportedUserFieldsResponse)(nil), // 11: cc.arduino.cli.commands.v1.SupportedUserFieldsResponse - nil, // 12: cc.arduino.cli.commands.v1.UploadRequest.UserFieldsEntry - nil, // 13: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.UserFieldsEntry - nil, // 14: cc.arduino.cli.commands.v1.BurnBootloaderRequest.UserFieldsEntry - (*Instance)(nil), // 15: cc.arduino.cli.commands.v1.Instance - (*Port)(nil), // 16: cc.arduino.cli.commands.v1.Port - (*Programmer)(nil), // 17: cc.arduino.cli.commands.v1.Programmer + (*UploadResult)(nil), // 2: cc.arduino.cli.commands.v1.UploadResult + (*ProgrammerIsRequiredForUploadError)(nil), // 3: cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError + (*UploadUsingProgrammerRequest)(nil), // 4: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest + (*UploadUsingProgrammerResponse)(nil), // 5: cc.arduino.cli.commands.v1.UploadUsingProgrammerResponse + (*BurnBootloaderRequest)(nil), // 6: cc.arduino.cli.commands.v1.BurnBootloaderRequest + (*BurnBootloaderResponse)(nil), // 7: cc.arduino.cli.commands.v1.BurnBootloaderResponse + (*ListProgrammersAvailableForUploadRequest)(nil), // 8: cc.arduino.cli.commands.v1.ListProgrammersAvailableForUploadRequest + (*ListProgrammersAvailableForUploadResponse)(nil), // 9: cc.arduino.cli.commands.v1.ListProgrammersAvailableForUploadResponse + (*SupportedUserFieldsRequest)(nil), // 10: cc.arduino.cli.commands.v1.SupportedUserFieldsRequest + (*UserField)(nil), // 11: cc.arduino.cli.commands.v1.UserField + (*SupportedUserFieldsResponse)(nil), // 12: cc.arduino.cli.commands.v1.SupportedUserFieldsResponse + nil, // 13: cc.arduino.cli.commands.v1.UploadRequest.UserFieldsEntry + nil, // 14: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.UserFieldsEntry + nil, // 15: cc.arduino.cli.commands.v1.BurnBootloaderRequest.UserFieldsEntry + (*Instance)(nil), // 16: cc.arduino.cli.commands.v1.Instance + (*Port)(nil), // 17: cc.arduino.cli.commands.v1.Port + (*Programmer)(nil), // 18: cc.arduino.cli.commands.v1.Programmer } var file_cc_arduino_cli_commands_v1_upload_proto_depIdxs = []int32{ - 15, // 0: cc.arduino.cli.commands.v1.UploadRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance - 16, // 1: cc.arduino.cli.commands.v1.UploadRequest.port:type_name -> cc.arduino.cli.commands.v1.Port - 12, // 2: cc.arduino.cli.commands.v1.UploadRequest.user_fields:type_name -> cc.arduino.cli.commands.v1.UploadRequest.UserFieldsEntry - 15, // 3: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance - 16, // 4: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.port:type_name -> cc.arduino.cli.commands.v1.Port - 13, // 5: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.user_fields:type_name -> cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.UserFieldsEntry - 15, // 6: cc.arduino.cli.commands.v1.BurnBootloaderRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance - 16, // 7: cc.arduino.cli.commands.v1.BurnBootloaderRequest.port:type_name -> cc.arduino.cli.commands.v1.Port - 14, // 8: cc.arduino.cli.commands.v1.BurnBootloaderRequest.user_fields:type_name -> cc.arduino.cli.commands.v1.BurnBootloaderRequest.UserFieldsEntry - 15, // 9: cc.arduino.cli.commands.v1.ListProgrammersAvailableForUploadRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance - 17, // 10: cc.arduino.cli.commands.v1.ListProgrammersAvailableForUploadResponse.programmers:type_name -> cc.arduino.cli.commands.v1.Programmer - 15, // 11: cc.arduino.cli.commands.v1.SupportedUserFieldsRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance - 10, // 12: cc.arduino.cli.commands.v1.SupportedUserFieldsResponse.user_fields:type_name -> cc.arduino.cli.commands.v1.UserField - 13, // [13:13] is the sub-list for method output_type - 13, // [13:13] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 16, // 0: cc.arduino.cli.commands.v1.UploadRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance + 17, // 1: cc.arduino.cli.commands.v1.UploadRequest.port:type_name -> cc.arduino.cli.commands.v1.Port + 13, // 2: cc.arduino.cli.commands.v1.UploadRequest.user_fields:type_name -> cc.arduino.cli.commands.v1.UploadRequest.UserFieldsEntry + 2, // 3: cc.arduino.cli.commands.v1.UploadResponse.result:type_name -> cc.arduino.cli.commands.v1.UploadResult + 17, // 4: cc.arduino.cli.commands.v1.UploadResult.updated_upload_port:type_name -> cc.arduino.cli.commands.v1.Port + 16, // 5: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance + 17, // 6: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.port:type_name -> cc.arduino.cli.commands.v1.Port + 14, // 7: cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.user_fields:type_name -> cc.arduino.cli.commands.v1.UploadUsingProgrammerRequest.UserFieldsEntry + 16, // 8: cc.arduino.cli.commands.v1.BurnBootloaderRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance + 17, // 9: cc.arduino.cli.commands.v1.BurnBootloaderRequest.port:type_name -> cc.arduino.cli.commands.v1.Port + 15, // 10: cc.arduino.cli.commands.v1.BurnBootloaderRequest.user_fields:type_name -> cc.arduino.cli.commands.v1.BurnBootloaderRequest.UserFieldsEntry + 16, // 11: cc.arduino.cli.commands.v1.ListProgrammersAvailableForUploadRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance + 18, // 12: cc.arduino.cli.commands.v1.ListProgrammersAvailableForUploadResponse.programmers:type_name -> cc.arduino.cli.commands.v1.Programmer + 16, // 13: cc.arduino.cli.commands.v1.SupportedUserFieldsRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance + 11, // 14: cc.arduino.cli.commands.v1.SupportedUserFieldsResponse.user_fields:type_name -> cc.arduino.cli.commands.v1.UserField + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_cc_arduino_cli_commands_v1_upload_proto_init() } @@ -1213,7 +1317,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProgrammerIsRequiredForUploadError); i { + switch v := v.(*UploadResult); i { case 0: return &v.state case 1: @@ -1225,7 +1329,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UploadUsingProgrammerRequest); i { + switch v := v.(*ProgrammerIsRequiredForUploadError); i { case 0: return &v.state case 1: @@ -1237,7 +1341,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UploadUsingProgrammerResponse); i { + switch v := v.(*UploadUsingProgrammerRequest); i { case 0: return &v.state case 1: @@ -1249,7 +1353,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BurnBootloaderRequest); i { + switch v := v.(*UploadUsingProgrammerResponse); i { case 0: return &v.state case 1: @@ -1261,7 +1365,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BurnBootloaderResponse); i { + switch v := v.(*BurnBootloaderRequest); i { case 0: return &v.state case 1: @@ -1273,7 +1377,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListProgrammersAvailableForUploadRequest); i { + switch v := v.(*BurnBootloaderResponse); i { case 0: return &v.state case 1: @@ -1285,7 +1389,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListProgrammersAvailableForUploadResponse); i { + switch v := v.(*ListProgrammersAvailableForUploadRequest); i { case 0: return &v.state case 1: @@ -1297,7 +1401,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SupportedUserFieldsRequest); i { + switch v := v.(*ListProgrammersAvailableForUploadResponse); i { case 0: return &v.state case 1: @@ -1309,7 +1413,7 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserField); i { + switch v := v.(*SupportedUserFieldsRequest); i { case 0: return &v.state case 1: @@ -1321,6 +1425,18 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserField); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SupportedUserFieldsResponse); i { case 0: return &v.state @@ -1333,13 +1449,18 @@ func file_cc_arduino_cli_commands_v1_upload_proto_init() { } } } + file_cc_arduino_cli_commands_v1_upload_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*UploadResponse_OutStream)(nil), + (*UploadResponse_ErrStream)(nil), + (*UploadResponse_Result)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cc_arduino_cli_commands_v1_upload_proto_rawDesc, NumEnums: 0, - NumMessages: 15, + NumMessages: 16, NumExtensions: 0, NumServices: 0, }, diff --git a/rpc/cc/arduino/cli/commands/v1/upload.proto b/rpc/cc/arduino/cli/commands/v1/upload.proto index d0aa108c0ef..8a2b6b0215d 100644 --- a/rpc/cc/arduino/cli/commands/v1/upload.proto +++ b/rpc/cc/arduino/cli/commands/v1/upload.proto @@ -62,10 +62,20 @@ message UploadRequest { } message UploadResponse { - // The output of the upload process. - bytes out_stream = 1; - // The error output of the upload process. - bytes err_stream = 2; + oneof message { + // The output of the upload process. + bytes out_stream = 1; + // The error output of the upload process. + bytes err_stream = 2; + // The upload result + UploadResult result = 3; + } +} + +message UploadResult { + // When a board requires a port disconnection to perform the upload, this + // field returns the port where the board reconnects after the upload. + Port updated_upload_port = 1; } message ProgrammerIsRequiredForUploadError {}