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

package xflags

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"os"
	"reflect"
)

type dummyCopyArg struct{}

func (n dummyCopyArg) Copy(_ map[string]any) {}

// Execute executes the command line arguments and calls the functions.
func Execute[C any](cmd C, cpy ...Copyable) *Settings[C] {

	if cpy == nil {
		return execute(cmd, dummyCopyArg{}, os.Args[0], os.Args[1:])
	}

	if len(cpy) > 1 {
		panic("too many arguments")
	}

	return execute(cmd, cpy[0], os.Args[0], os.Args[1:])
}

// PrintFlagOutput prints the flag output to the standard output.
func (s *Settings[C]) PrintFlagOutput() {
	fmt.Println(s.command.flagSet.Output())
}

// GetFlagOutput returns the flag output.
func (s *Settings[C]) GetFlagOutput() {
	fmt.Println(s.command.flagSet.Output())
}

// execute is the internal implementation of Execute.
func execute[C any, D Copyable](cmd C, proxy D, name string, args []string) *Settings[C] {
	instance := New(name, cmd)
	if instance.HasErrors() {
		return instance
	}

	if (reflect.ValueOf(&proxy).Elem().Type() != reflect.TypeOf(dummyCopyArg{})) {
		instance.SetMappedObject(proxy)
		if instance.HasErrors() {
			return instance
		}
	}

	instance.Parse(args)
	if instance.HelpRequested() {
		return instance
	}

	if instance.HasErrors() {
		return instance
	}

	instance.Execute()
	if instance.HasErrors() {
		return instance
	}
	return instance
}

// New creates a new instance of the settings.
// name should be the name of the command and comes from the first argument of the command line.
// os.Args[0] is a good choice.
func New[C any](name string, definitions C) *Settings[C] {

	s := &Settings[C]{
		config: config{
			errorHandling: flag.ContinueOnError,
		},
	}

	if reflect.TypeOf(definitions).Kind() != reflect.Struct {
		s.errors = append(s.errors, newUnsupportedReflectKindError(reflect.TypeOf(definitions)))
		return s
	}

	s.mapping = make(map[string]any)

	buf := bytes.NewBufferString("")
	s.flagOutput = io.Writer(buf)
	s.definitions = definitions
	s.initCommands(name)

	return s
}

// Output returns the writer where the flag package writes its output.
func (s *Settings[C]) Output() string {
	return s.flagOutput.(*bytes.Buffer).String()
}

// Args Returns not parsed arguments.
func (s *Settings[C]) Args() []string {
	return s.args
}

// GetDefaults returns the default values of the settings.
func (s *Settings[C]) GetDefaults() string {
	mem := s.flagOutput
	s.flagOutput.(*bytes.Buffer).Reset()
	s.command.flagSet.PrintDefaults()
	r := s.flagOutput.(*bytes.Buffer).String()
	s.flagOutput = mem
	return r
}

func (s *Settings[C]) GetMap() map[string]any {
	return s.mapping
}