From 4d3fd0f0cc218632120fb619e787e828f708c4ec Mon Sep 17 00:00:00 2001
From: Volker Schukai <volker.schukai@schukai.com>
Date: Sun, 9 Oct 2022 15:24:35 +0200
Subject: [PATCH] feat new Execute() Method for the automatic execution of
 command

---
 api.go      | 42 ++++++++++++++++++++++++++++++++++++++++++
 api_test.go | 51 ++++++++++++++++++++++++++++++---------------------
 parse.go    | 16 +++++++++++++++-
 3 files changed, 87 insertions(+), 22 deletions(-)

diff --git a/api.go b/api.go
index 7ef0727..bec82e0 100644
--- a/api.go
+++ b/api.go
@@ -6,10 +6,52 @@ package xflags
 import (
 	"bytes"
 	"flag"
+	"fmt"
 	"io"
+	"os"
 	"reflect"
 )
 
+// Execute executes the command line arguments and calls the functions.
+func Execute[C any, D any](cmd C, cnf D) *Settings[C] {
+	return execute(cmd, cnf, os.Args[0], os.Args[1:])
+}
+
+func (s *Settings[C]) PrintFlagOutput() {
+	fmt.Println(s.command.flagSet.Output())
+}
+
+// execute is the internal implementation of Execute.
+func execute[C any, D any](cmd C, cnf D, name string, args []string) *Settings[C] {
+	instance := New(name, cmd)
+	if instance.HasErrors() {
+		return instance
+	}
+
+	instance.SetShadow(cnf)
+	if instance.HasErrors() {
+		return instance
+	}
+
+	instance.Parse(args)
+	if instance.HelpRequested() {
+		for i, err := range instance.errors {
+			if err == flag.ErrHelp {
+				instance.errors = append(instance.errors[:i], instance.errors[i+1:]...)
+			}
+		}
+		instance.PrintFlagOutput()
+		return instance
+	}
+
+	if instance.HasErrors() {
+		return instance
+	}
+
+	instance.Execute()
+	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.
diff --git a/api_test.go b/api_test.go
index c235b03..6b841c8 100644
--- a/api_test.go
+++ b/api_test.go
@@ -8,22 +8,31 @@ import (
 	"testing"
 )
 
-//func TestUsage(t *testing.T) {
-//
-//	commands := New("root", CmdTest1{})
-//	args := []string{"-h"}
-//
-//	commands.Parse(args)
-//
-//	assert.False(t, commands.HasErrors())
-//	if commands.HasErrors() {
-//		t.Log(commands.Errors())
-//	}
-//
-//	usage := commands.Usage()
-//	assert.NotEmpty(t, usage)
-//
-//}
+func TestUsage(t *testing.T) {
+
+	commands := New("root", CmdTest1{})
+	args := []string{"-h"}
+
+	commands.Parse(args)
+
+	assert.True(t, commands.HelpRequested())
+
+	usage := commands.GetDefaults()
+	assert.Equal(t, "  -a\tMessage A\n  -x int\n    \tMessage X\n", usage)
+
+}
+func TestExecute(t *testing.T) {
+	instance := execute("root", CmdTest1{}, "test", []string{"-a", "hello", "-x", "1"})
+	assert.NotNil(t, instance)
+}
+
+func TestExecuteHelp(t *testing.T) {
+	cnf := struct {
+	}{}
+	instance := execute(CmdTest1{}, &cnf, "test", []string{"-h"})
+	assert.False(t, instance.HasErrors())
+
+}
 
 func TestNewIntWithError(t *testing.T) {
 
@@ -47,17 +56,17 @@ func TestNew(t *testing.T) {
 }
 
 type CmdTest1 struct {
-	A    bool `short:"a"`
+	A    bool `short:"a" description:"Message A"`
 	Sub1 struct {
-		B    bool `short:"b"`
+		B    bool `short:"b" description:"Message B"`
 		Sub2 struct {
-			C    bool `short:"c"`
+			C    bool `short:"c" description:"Message C"`
 			Sub3 struct {
-				D bool `short:"d"`
+				D bool `short:"d" description:"Message D"`
 			} `command:"sub3"`
 		} `command:"sub2"`
 	} `command:"sub1"`
-	aa int `short:"x"`
+	aa int `short:"x" description:"Message X"`
 }
 
 func TestCommand2(t *testing.T) {
diff --git a/parse.go b/parse.go
index 5d10b05..9a5b720 100644
--- a/parse.go
+++ b/parse.go
@@ -3,7 +3,10 @@
 
 package xflags
 
-import "os"
+import (
+	"flag"
+	"os"
+)
 
 // ParseOsArgs parses the os.Args.
 func (s *Settings[C]) ParseOsArgs() *Settings[C] {
@@ -38,3 +41,14 @@ func (s *Settings[C]) Parse(args []string) *Settings[C] {
 
 	return s
 }
+
+func (s *Settings[C]) HelpRequested() bool {
+
+	for _, err := range s.errors {
+		if err == flag.ErrHelp {
+			return true
+		}
+	}
+	
+	return false
+}
-- 
GitLab