Skip to content
Snippets Groups Projects
execute.go 2.30 KiB
// Copyright 2022 schukai GmbH
// SPDX-License-Identifier: AGPL-3.0

package xflags

import (
	"flag"
	"fmt"
	"reflect"
	"strings"
)

func (s *Settings[C]) Execute() *Settings[C] {
	s.mu.Lock()
	defer s.mu.Unlock()

	if len(s.errors) > 0 {
		return s
	}

	if s.command == nil {
		s.errors = append(s.errors, MissingCommandError)
		return s
	}

	if !s.command.flagSet.Parsed() {
		s.errors = append(s.errors, NotParsedError)
	} else {
		s.wasExecuted = callCmdFunctions(s, s.command.commands)
	}

	return s
}

func callCmdFunctions[C any](settings *Settings[C], commands []*cmd[C]) bool {

	wasExecuted := false
	shouldExecute := false

	var availableCommands []string
	currentCommand := ""

	for _, command := range commands {
		if command.flagSet.Parsed() {

			shouldExecute = true
			currentCommand = command.name

			if len(command.commands) > 0 {
				r := callCmdFunctions(settings, command.commands)
				if r {
					wasExecuted = true
				}
			}

			if !wasExecuted {
				f := reflect.ValueOf(&command.settings.definitions).MethodByName(command.functionName)
				if f.IsValid() {
					m := command.settings
					in := []reflect.Value{reflect.ValueOf(m)}
					f.Call(in)
					wasExecuted = true
				}
			}

			break
		} else {
			availableCommands = append(availableCommands, command.name)
		}
	}

	if shouldExecute {
		if !wasExecuted {
			settings.errors = append(settings.errors, newMissingFunctionError(currentCommand))
			return false
		}

		return true
	}

	if len(availableCommands) > 0 {
		if settings.hint == "" {
			settings.hint = fmt.Sprintf("Did you mean: %v?", strings.Join(availableCommands, ", "))
		}
		settings.errors = append(settings.errors, MissingCommandError)
	}

	return false

}

// HelpRequested indicates if the help flag was set.
func (s *Settings[C]) HelpRequested() bool {
	s.mu.Lock()
	defer s.mu.Unlock()

	for _, err := range s.errors {
		if err == flag.ErrHelp {
			return true
		}
	}

	return false
}

// MissingCommand returns true if the command was not found
func (s *Settings[C]) MissingCommand() bool {
	s.mu.Lock()
	defer s.mu.Unlock()

	for _, err := range s.errors {
		if err == MissingCommandError {
			return true
		}
	}

	return false
}

// WasExecuted returns true if the call function was executed
func (s *Settings[C]) WasExecuted() bool {
	s.mu.Lock()
	defer s.mu.Unlock()

	return s.wasExecuted
}