@@ -24,6 +24,7 @@ import (
2424 "github.com/cloudposse/atmos/pkg/auth/credentials"
2525 "github.com/cloudposse/atmos/pkg/auth/validation"
2626 cfg "github.com/cloudposse/atmos/pkg/config"
27+ "github.com/cloudposse/atmos/pkg/dependencies"
2728 envpkg "github.com/cloudposse/atmos/pkg/env"
2829 l "github.com/cloudposse/atmos/pkg/list"
2930 log "github.com/cloudposse/atmos/pkg/logger"
@@ -430,6 +431,26 @@ func executeCustomCommand(
430431 finalArgs = args
431432 }
432433
434+ // Resolve and install command dependencies
435+ resolver := dependencies .NewResolver (& atmosConfig )
436+ deps , err := resolver .ResolveCommandDependencies (commandConfig )
437+ if err != nil {
438+ errUtils .CheckErrorPrintAndExit (err , "" , fmt .Sprintf ("Failed to resolve dependencies for command '%s'" , commandConfig .Name ))
439+ }
440+
441+ if len (deps ) > 0 {
442+ log .Debug ("Installing command dependencies" , "command" , commandConfig .Name , "tools" , deps )
443+ installer := dependencies .NewInstaller (& atmosConfig )
444+ if err := installer .EnsureTools (deps ); err != nil {
445+ errUtils .CheckErrorPrintAndExit (err , "" , fmt .Sprintf ("Failed to install dependencies for command '%s'" , commandConfig .Name ))
446+ }
447+
448+ // Update PATH to include installed tools
449+ if err := dependencies .UpdatePathForTools (& atmosConfig , deps ); err != nil {
450+ errUtils .CheckErrorPrintAndExit (err , "" , fmt .Sprintf ("Failed to update PATH for command '%s'" , commandConfig .Name ))
451+ }
452+ }
453+
433454 // Create auth manager if identity is specified for this custom command.
434455 // Check for --identity flag first (it overrides the config).
435456 var authManager auth.AuthManager
@@ -806,6 +827,31 @@ func isVersionCommand() bool {
806827 return len (os .Args ) > 1 && (os .Args [1 ] == "version" || os .Args [1 ] == "--version" )
807828}
808829
830+ // isVersionManagementCommand checks if the current command is a version management command.
831+ // These commands should not trigger re-exec to avoid infinite loops.
832+ func isVersionManagementCommand (cmd * cobra.Command ) bool {
833+ if cmd == nil {
834+ return false
835+ }
836+
837+ // Check the command hierarchy.
838+ cmdName := cmd .Name ()
839+
840+ // Direct version subcommands that manage local installations (install, uninstall).
841+ // Note: "list" is excluded because it can reasonably work with --use-version
842+ // to list releases using a different Atmos version.
843+ if cmd .Parent () != nil && cmd .Parent ().Name () == "version" {
844+ return cmdName == "install" || cmdName == "uninstall"
845+ }
846+
847+ // The version command itself (shows current version).
848+ if cmdName == "version" && cmd .Parent () != nil && cmd .Parent ().Name () == "atmos" {
849+ return true
850+ }
851+
852+ return false
853+ }
854+
809855// handleHelpRequest shows help content and exits only if the first argument is "help" or "--help" or "-h".
810856func handleHelpRequest (cmd * cobra.Command , args []string ) {
811857 if (len (args ) > 0 && args [0 ] == "help" ) || Contains (args , "--help" ) || Contains (args , "-h" ) {
0 commit comments