@@ -384,12 +384,27 @@ func getVideoDevices() map[int]string {
384384 return deviceMap
385385}
386386
387- func stopAppWithCmd (ctx context.Context , docker command.Cli , app app.ArduinoApp , cmd string ) iter.Seq [StreamMessage ] {
387+ type StopOptions struct {
388+ Command string
389+ RequireRunning bool
390+ RemoveVolumes bool
391+ RemoveOrphans bool
392+ }
393+
394+ func stopAppWithCmd (ctx context.Context , docker command.Cli , app app.ArduinoApp , opts StopOptions ) iter.Seq [StreamMessage ] {
388395 return func (yield func (StreamMessage ) bool ) {
389396 ctx , cancel := context .WithCancel (ctx )
390397 defer cancel ()
391398
392- if ! yield (StreamMessage {data : fmt .Sprintf ("Stopping app %q" , app .Name )}) {
399+ var message string
400+ switch opts .Command {
401+ case "stop" :
402+ message = fmt .Sprintf ("Stopping app %q" , app .Name )
403+ case "down" :
404+ message = fmt .Sprintf ("destroying app %q" , app .Name )
405+ }
406+
407+ if ! yield (StreamMessage {data : message }) {
393408 return
394409 }
395410 if err := setStatusLeds (LedTriggerDefault ); err != nil {
@@ -410,7 +425,7 @@ func stopAppWithCmd(ctx context.Context, docker command.Cli, app app.ArduinoApp,
410425 yield (StreamMessage {error : err })
411426 return
412427 }
413- if appStatus .Status != StatusStarting && appStatus .Status != StatusRunning {
428+ if opts . RequireRunning && appStatus .Status != StatusStarting && appStatus .Status != StatusRunning {
414429 yield (StreamMessage {data : fmt .Sprintf ("app %q is not running" , app .Name )})
415430 return
416431 }
@@ -425,11 +440,26 @@ func stopAppWithCmd(ctx context.Context, docker command.Cli, app app.ArduinoApp,
425440 mainCompose := app .AppComposeFilePath ()
426441 // In case the app was never started
427442 if mainCompose .Exist () {
428- process , err := paths .NewProcess (nil , "docker" , "compose" , "-f" , mainCompose .String (), cmd , fmt .Sprintf ("--timeout=%d" , DefaultDockerStopTimeoutSeconds ))
443+ cmd := "docker"
444+ args := []string {
445+ "compose" ,
446+ "-f" , mainCompose .String (),
447+ opts .Command ,
448+ fmt .Sprintf ("--timeout=%d" , DefaultDockerStopTimeoutSeconds ),
449+ }
450+ if opts .RemoveVolumes {
451+ args = append (args , "--volumes" )
452+ }
453+ if opts .RemoveOrphans {
454+ args = append (args , "--remove-orphans" )
455+ }
456+ fullCommand := append ([]string {cmd }, args ... )
457+ process , err := paths .NewProcess (nil , fullCommand ... )
429458 if err != nil {
430459 yield (StreamMessage {error : err })
431460 return
432461 }
462+
433463 process .RedirectStderrTo (callbackWriter )
434464 process .RedirectStdoutTo (callbackWriter )
435465 if err := process .RunWithinContext (ctx ); err != nil {
@@ -443,17 +473,20 @@ func stopAppWithCmd(ctx context.Context, docker command.Cli, app app.ArduinoApp,
443473}
444474
445475func StopApp (ctx context.Context , dockerClient command.Cli , app app.ArduinoApp ) iter.Seq [StreamMessage ] {
446- return stopAppWithCmd (ctx , dockerClient , app , "stop" )
476+ return stopAppWithCmd (ctx , dockerClient , app , StopOptions {
477+ Command : "stop" ,
478+ RequireRunning : true ,
479+ })
447480}
448481
449482func StopAndDestroyApp (ctx context.Context , dockerClient command.Cli , app app.ArduinoApp ) iter.Seq [StreamMessage ] {
450- return stopAppWithCmd (ctx , dockerClient , app , "down" )
451- }
452-
453- func DestroyAndCleanApp (ctx context.Context , app app.ArduinoApp ) iter.Seq [StreamMessage ] {
454483 return func (yield func (StreamMessage ) bool ) {
455-
456- for msg := range destroyAppContainers (ctx , app ) {
484+ for msg := range stopAppWithCmd (ctx , dockerClient , app , StopOptions {
485+ Command : "down" ,
486+ RemoveVolumes : true ,
487+ RemoveOrphans : true ,
488+ RequireRunning : false ,
489+ }) {
457490 if ! yield (msg ) {
458491 return
459492 }
@@ -466,55 +499,6 @@ func DestroyAndCleanApp(ctx context.Context, app app.ArduinoApp) iter.Seq[Stream
466499 }
467500}
468501
469- func destroyAppContainers (ctx context.Context , app app.ArduinoApp ) iter.Seq [StreamMessage ] {
470- return func (yield func (StreamMessage ) bool ) {
471- ctx , cancel := context .WithCancel (ctx )
472- defer cancel ()
473-
474- if ! yield (StreamMessage {data : fmt .Sprintf ("Destroying app %q containers and data..." , app .Name )}) {
475- return
476- }
477- callbackWriter := NewCallbackWriter (func (line string ) {
478- if ! yield (StreamMessage {data : line }) {
479- cancel ()
480- return
481- }
482- })
483- if _ , ok := app .GetSketchPath (); ok {
484- if err := micro .Disable (); err != nil {
485- slog .Debug ("unable to disable micro (might be already stopped)" , slog .String ("error" , err .Error ()))
486- }
487- }
488- if app .MainPythonFile != nil {
489- mainCompose := app .AppComposeFilePath ()
490- if mainCompose .Exist () {
491- process , err := paths .NewProcess (
492- nil ,
493- "docker" , "compose" ,
494- "-f" , mainCompose .String (),
495- "down" ,
496- "--volumes" ,
497- "--remove-orphans" ,
498- fmt .Sprintf ("--timeout=%d" , DefaultDockerStopTimeoutSeconds ),
499- )
500-
501- if err != nil {
502- yield (StreamMessage {error : err })
503- return
504- }
505-
506- process .RedirectStderrTo (callbackWriter )
507- process .RedirectStdoutTo (callbackWriter )
508- if err := process .RunWithinContext (ctx ); err != nil {
509- yield (StreamMessage {error : fmt .Errorf ("failed to destroy containers: %w" , err )})
510- return
511- }
512- }
513- }
514- yield (StreamMessage {data : "App containers and volumes removed." })
515- }
516- }
517-
518502func cleanAppCacheFiles (app app.ArduinoApp ) iter.Seq [StreamMessage ] {
519503 return func (yield func (StreamMessage ) bool ) {
520504 cachePath := app .FullPath .Join (".cache" )
0 commit comments