@@ -18,6 +18,7 @@ package arguments
1818import (
1919 "fmt"
2020 "net/url"
21+ "time"
2122
2223 "github.com/arduino/arduino-cli/arduino/discovery"
2324 "github.com/arduino/arduino-cli/arduino/sketch"
@@ -34,25 +35,21 @@ import (
3435type Port struct {
3536 address string
3637 protocol string
38+ timeout time.Duration
3739}
3840
3941// AddToCommand adds the flags used to set port and protocol to the specified Command
4042func (p * Port ) AddToCommand (cmd * cobra.Command ) {
4143 cmd .Flags ().StringVarP (& p .address , "port" , "p" , "" , "Upload port address, e.g.: COM3 or /dev/ttyACM2" )
4244 cmd .Flags ().StringVarP (& p .protocol , "protocol" , "l" , "" , "Upload port protocol, e.g: serial" )
45+ cmd .Flags ().DurationVar (& p .timeout , "discovery-timeout" , 5 * time .Second , "Max time to wait for port discovery, e.g.: 30s, 1m" )
4346}
4447
4548// GetPort returns the Port obtained by parsing command line arguments.
4649// The extra metadata for the ports is obtained using the pluggable discoveries.
4750func (p * Port ) GetPort (instance * rpc.Instance , sk * sketch.Sketch ) (* discovery.Port , error ) {
4851 address := p .address
4952 protocol := p .protocol
50- if address != "" && protocol != "" {
51- return & discovery.Port {
52- Address : address ,
53- Protocol : protocol ,
54- }, nil
55- }
5653
5754 if address == "" && sk != nil && sk .Metadata != nil {
5855 deviceURI , err := url .Parse (sk .Metadata .CPU .Port )
@@ -76,8 +73,9 @@ func (p *Port) GetPort(instance *rpc.Instance, sk *sketch.Sketch) (*discovery.Po
7673 if err := pm .DiscoveryManager ().RunAll (); err != nil {
7774 return nil , err
7875 }
79- if err := pm .DiscoveryManager ().StartAll (); err != nil {
80- return nil , err
76+ eventChan , errs := pm .DiscoveryManager ().StartSyncAll ()
77+ if len (errs ) > 0 {
78+ return nil , fmt .Errorf ("%v" , errs )
8179 }
8280
8381 defer func () {
@@ -88,28 +86,27 @@ func (p *Port) GetPort(instance *rpc.Instance, sk *sketch.Sketch) (*discovery.Po
8886 }
8987 }()
9088
91- ports := pm .DiscoveryManager ().List ()
89+ deadline := time .After (p .timeout )
90+ for {
91+ select {
92+ case portEvent := <- eventChan :
93+ if portEvent .Type != "add" {
94+ continue
95+ }
96+ port := portEvent .Port
97+ if (protocol == "" || protocol == port .Protocol ) && address == port .Address {
98+ return port , nil
99+ }
92100
93- matchingPorts := []* discovery.Port {}
94- for _ , port := range ports {
95- if address == port .Address {
96- matchingPorts = append (matchingPorts , port )
97- if len (matchingPorts ) > 1 {
98- // Too many matching ports found, can't handle this case.
99- // This must never happen.
100- return nil , fmt .Errorf ("multiple ports found matching address %s" , address )
101+ case <- deadline :
102+ // No matching port found
103+ if protocol == "" {
104+ return & discovery.Port {
105+ Address : address ,
106+ Protocol : "serial" ,
107+ }, nil
101108 }
109+ return nil , fmt .Errorf ("port not found: %s %s" , address , protocol )
102110 }
103111 }
104-
105- if len (matchingPorts ) == 1 {
106- // Only one matching port found, use it
107- return matchingPorts [0 ], nil
108- }
109-
110- // In case no matching port is found assume the address refers to a serial port
111- return & discovery.Port {
112- Address : address ,
113- Protocol : "serial" ,
114- }, nil
115112}
0 commit comments