@@ -38,15 +38,18 @@ import (
3838 "os"
3939 "path/filepath"
4040 "strings"
41+ "time"
4142
4243 "github.com/bcmi-labs/arduino-cli/auth"
4344 "github.com/bcmi-labs/arduino-cli/create_client_helpers"
4445 "github.com/bgentry/go-netrc/netrc"
46+ "github.com/briandowns/spinner"
4547 homedir "github.com/mitchellh/go-homedir"
4648
4749 "github.com/bcmi-labs/arduino-modules/sketches"
4850
4951 "github.com/bcmi-labs/arduino-cli/cmd/formatter"
52+ "github.com/bcmi-labs/arduino-cli/cmd/output"
5053 "github.com/bcmi-labs/arduino-cli/common"
5154
5255 "github.com/spf13/cobra"
@@ -86,12 +89,58 @@ func executeSketchSyncCommand(cmd *cobra.Command, args []string) {
8689 os .Exit (errCoreConfig )
8790 }
8891
92+ priority := arduinoSketchSyncFlags .Priority
93+
94+ if priority == "ask-once" {
95+ if ! formatter .IsCurrentFormat ("text" ) {
96+ formatter .PrintErrorMessage ("ask mode for this command is only supported using text format" )
97+ os .Exit (errBadCall )
98+ }
99+ firstAsk := true
100+ for priority != "pull-remote" &&
101+ priority != "push-local" &&
102+ priority != "skip" {
103+ if ! firstAsk {
104+ formatter .Print ("Invalid option: " + priority )
105+ }
106+ formatter .Print ("What should I do when I detect a conflict? [pull-remote | push-local | skip]" )
107+ fmt .Scanln (& priority )
108+ firstAsk = false
109+ }
110+ }
111+
112+ //loader
113+ isTextMode := formatter .IsCurrentFormat ("text" )
114+
115+ var loader * spinner.Spinner
116+
117+ if isTextMode {
118+ loader = spinner .New (spinner .CharSets [39 ], 100 * time .Millisecond )
119+ loader .Prefix = "Syncing Sketches... "
120+
121+ loader .Start ()
122+ }
123+
124+ stopSpinner := func () {
125+ if isTextMode {
126+ loader .Stop ()
127+ }
128+ }
129+
130+ startSpinner := func () {
131+ if isTextMode {
132+ loader .Start ()
133+ }
134+ }
135+
89136 username , bearerToken , err := login ()
90137 if err != nil {
91138 if GlobalFlags .Verbose == 0 {
92139 formatter .PrintErrorMessage ("Cannot login automatically: try arduino login the run again this command" )
93140 } else {
141+ stopSpinner ()
94142 formatter .PrintError (err )
143+ os .Exit (errNetwork )
95144 }
96145 }
97146
@@ -101,13 +150,15 @@ func executeSketchSyncCommand(cmd *cobra.Command, args []string) {
101150 tok := "Bearer " + bearerToken
102151 resp , err := client .SearchSketches (context .Background (), createClient .SearchSketchesPath (), nil , & username , & tok )
103152 if err != nil {
153+ stopSpinner ()
104154 formatter .PrintErrorMessage ("Cannot get create sketches, sync failed" )
105155 os .Exit (errNetwork )
106156 }
107157 defer resp .Body .Close ()
108158
109159 onlineSketches , err := client .DecodeArduinoCreateSketches (resp )
110160 if err != nil {
161+ stopSpinner ()
111162 formatter .PrintErrorMessage ("Cannot unmarshal response from create, sync failed" )
112163 os .Exit (errGeneric )
113164 }
@@ -117,32 +168,25 @@ func executeSketchSyncCommand(cmd *cobra.Command, args []string) {
117168 onlineSketchesMap [* item .Name ] = item
118169 }
119170
120- priority := arduinoSketchSyncFlags . Priority
171+ maxLength := len ( sketchMap ) + len ( onlineSketchesMap )
121172
122- if priority == "ask-once" {
123- if ! formatter .IsCurrentFormat ("text" ) {
124- formatter .PrintErrorMessage ("ask mode for this command is only supported using text format" )
125- os .Exit (errBadCall )
126- }
127- firstAsk := true
128- for priority != "pull-remote" &&
129- priority != "push-local" &&
130- priority != "skip" {
131- if ! firstAsk {
132- formatter .Print ("Invalid option: " + priority )
133- }
134- formatter .Print ("What should I do when I detect a conflict? [pull-remote | push-local | skip]" )
135- fmt .Scanln (& priority )
136- firstAsk = false
137- }
173+ // create output result struct with empty arrays.
174+ result := output.SketchSyncResult {
175+ PushedSketches : make ([]string , 0 , maxLength ),
176+ PulledSketches : make ([]string , 0 , maxLength ),
177+ SkippedSketches : make ([]string , 0 , maxLength ),
178+ Errors : make ([]output.SketchSyncError , 0 , maxLength ),
138179 }
180+
139181 for _ , item := range sketchMap {
140182
141183 itemOnline , hasConflict := onlineSketchesMap [item .Name ]
142184 if hasConflict {
143185 item .ID = itemOnline .ID .String ()
144186 //solve conflicts
145187 if priority == "ask-always" {
188+ stopSpinner ()
189+
146190 if ! formatter .IsCurrentFormat ("text" ) {
147191 formatter .PrintErrorMessage ("ask mode for this command is only supported using text format" )
148192 os .Exit (errBadCall )
@@ -158,43 +202,50 @@ func executeSketchSyncCommand(cmd *cobra.Command, args []string) {
158202 fmt .Scanln (& priority )
159203 firstAsk = false
160204 }
205+
206+ startSpinner ()
161207 }
162208 switch priority {
163209 case "push-local" :
164- if GlobalFlags .Verbose > 0 {
165- formatter .Print ("pushing edits of sketch: " + item .Name )
166- }
167210 err := editSketch (* item , sketchbook , bearerToken )
168211 if err != nil {
169- formatter .PrintError (err )
212+ result .Errors = append (result .Errors , output.SketchSyncError {
213+ Sketch : item .Name ,
214+ Error : err ,
215+ })
216+ } else {
217+ result .PushedSketches = append (result .PushedSketches , item .Name )
170218 }
171219 break
172220 case "pull-remote" :
173- if GlobalFlags .Verbose > 0 {
174- formatter .Print ("pulling " + item .Name )
175- }
176221 err := pullSketch (itemOnline , sketchbook , bearerToken )
177222 if err != nil {
178- formatter .PrintError (err )
223+ result .Errors = append (result .Errors , output.SketchSyncError {
224+ Sketch : item .Name ,
225+ Error : err ,
226+ })
227+ } else {
228+ result .PulledSketches = append (result .PulledSketches , item .Name )
179229 }
180230 break
181231 case "skip" :
182- if GlobalFlags .Verbose > 0 {
183- formatter .Print ("skipping " + item .Name )
184- }
232+ result .SkippedSketches = append (result .SkippedSketches , item .Name )
185233 break
186234 default :
187235 priority = "skip"
188- if GlobalFlags .Verbose > 0 {
189- formatter .Print ("Priority not recognized, using skipping by default" )
190- formatter .Print ("skipping " + item .Name )
191- }
192-
236+ result .SkippedSketches = append (result .SkippedSketches , item .Name )
193237 }
194238
195239 } else { //only local, push
196- formatter .Print ("pushing " + item .Name )
197- pushSketch (* item , sketchbook , bearerToken )
240+ err := pushSketch (* item , sketchbook , bearerToken )
241+ if err != nil {
242+ result .Errors = append (result .Errors , output.SketchSyncError {
243+ Sketch : item .Name ,
244+ Error : err ,
245+ })
246+ } else {
247+ result .PushedSketches = append (result .PushedSketches , item .Name )
248+ }
198249 }
199250 }
200251 for _ , item := range onlineSketches .Sketches {
@@ -203,13 +254,26 @@ func executeSketchSyncCommand(cmd *cobra.Command, args []string) {
203254 continue
204255 }
205256 //only online, pull
206- formatter .Print ("pulling " + * item .Name )
207257 err := pullSketch (item , sketchbook , bearerToken )
208258 if err != nil {
209- formatter .PrintError (err )
259+ result .Errors = append (result .Errors , output.SketchSyncError {
260+ Sketch : * item .Name ,
261+ Error : err ,
262+ })
263+ } else {
264+ result .PulledSketches = append (result .PulledSketches , * item .Name )
210265 }
211266 }
212- formatter .PrintResult ("Sync Completed" ) // Issue # : Provide output struct to print the result in a prettier way.
267+
268+ stopSpinner ()
269+
270+ // for text mode, show full info (aka String()) only if verbose > 0.
271+ // for other formats always print full info.
272+ if GlobalFlags .Verbose > 0 || ! formatter .IsCurrentFormat ("text" ) {
273+ formatter .Print (result )
274+ } else {
275+ formatter .PrintResult ("Sync Completed" )
276+ }
213277}
214278
215279func pushSketch (sketch sketches.Sketch , sketchbook string , bearerToken string ) error {
0 commit comments