Move packages to root folder
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 33s

Signed-off-by: Jan Tytgat <jan.tytgat@corelayer.eu>
This commit is contained in:
Jan Tytgat
2025-04-22 13:47:12 +02:00
parent 26059ea3e9
commit 4fab7c8554
17 changed files with 8 additions and 6 deletions

View File

@ -0,0 +1,38 @@
package application
import (
"context"
"fmt"
"github.com/spf13/cobra"
)
type Application interface {
Start(ctx context.Context) error
Shutdown() error
}
func New(c Config) (Application, error) {
var cmd *cobra.Command
var err error
if cmd, err = c.getRootCommand(); err != nil {
return nil, err
}
return &application{
cmd: cmd,
}, nil
}
type application struct {
cmd *cobra.Command
}
func (a *application) Start(ctx context.Context) error {
return a.cmd.ExecuteContext(ctx)
}
func (a *application) Shutdown() error {
fmt.Println("Shutdown")
return nil
}

View File

@ -0,0 +1 @@
package application

28
application/commander.go Normal file
View File

@ -0,0 +1,28 @@
package application
import "github.com/spf13/cobra"
type Commander interface {
Initialize(f func(c *cobra.Command)) *cobra.Command
}
type Command struct {
Command *cobra.Command
SubCommands []Commander
Configure func(c *cobra.Command)
}
func (c Command) Initialize(f func(c *cobra.Command)) *cobra.Command {
if f != nil {
f(c.Command)
}
if c.Configure != nil {
c.Configure(c.Command)
}
for _, sub := range c.SubCommands {
c.Command.AddCommand(sub.Initialize(f))
}
return c.Command
}

110
application/config.go Normal file
View File

@ -0,0 +1,110 @@
package application
import (
"errors"
"fmt"
"os"
"time"
"github.com/spf13/cobra"
"git.flexabyte.io/flexabyte/go-kit/semver"
)
type Config struct {
Name string
Title string
Banner string
Version string
EnableGracefulShutdown bool
OverrideRunE func(cmd *cobra.Command, args []string) error
PersistentPreRunE []func(cmd *cobra.Command, args []string) error // collection of PreRunE functions
PersistentPostRunE []func(cmd *cobra.Command, args []string) error // collection of PostRunE functions
ShutdownSignals []os.Signal
ShutdownTimeout time.Duration
SubCommands []Command
SubCommandInitializeFunc func(cmd *cobra.Command)
ValidArgs []string
}
func (c Config) getRootCommand() (*cobra.Command, error) {
var err error
if err = c.Validate(); err != nil {
return nil, err
}
var long string
if c.Banner != "" {
long = c.Banner + "\n" + c.Title
} else {
long = c.Title
}
cmd := &cobra.Command{
Use: c.Name,
Short: c.Title,
Long: long,
PersistentPreRunE: persistentPreRunFuncE,
PersistentPostRunE: persistentPostRunFuncE,
RunE: runFuncE,
SilenceErrors: true,
SilenceUsage: true,
}
if c.OverrideRunE != nil {
cmd.RunE = c.OverrideRunE
}
for _, subcommand := range c.SubCommands {
cmd.AddCommand(subcommand.Initialize(c.SubCommandInitializeFunc))
}
var v semver.Version
if v, err = c.ParseVersion(); err != nil {
return nil, err
}
configureVersionFlag(cmd, v) // Configure app for version information
configureOutputFlags(cmd) // Configure verbosity
configureLoggingFlags(cmd) // Configure logging
cmd.PersistentFlags().SetNormalizeFunc(normalizeFunc) // normalize persistent flags
return cmd, nil
}
func (c Config) ParseVersion() (semver.Version, error) {
return semver.Parse(c.Version)
}
func (c Config) RegisterCommand(cmd Commander, f func(*cobra.Command)) {
appCmd.AddCommand(cmd.Initialize(f))
}
func (c Config) RegisterCommands(cmds []Commander, f func(*cobra.Command)) {
for _, cmd := range cmds {
appCmd.AddCommand(cmd.Initialize(f))
}
}
func (c Config) RegisterPersistentPreRunE(f func(cmd *cobra.Command, args []string) error) {
persistentPreRunE = append(persistentPreRunE, f)
}
func (c Config) RegisterPersistentPostRunE(f func(cmd *cobra.Command, args []string) error) {
persistentPostRunE = append(persistentPostRunE, f)
}
func (c Config) Validate() error {
if c.Name == "" {
return errors.New("name is required")
}
if c.Title == "" {
return errors.New("title is required")
}
var err error
if _, err = semver.Parse(c.Version); err != nil {
return fmt.Errorf("invalid version: %s", c.Version)
}
return nil
}

View File

@ -0,0 +1,22 @@
package application
import (
"testing"
)
func TestConfig_Validate(t *testing.T) {
tests := []struct {
name string
config Config
wantErr bool
}{
{},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.config.Validate(); (err != nil) != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

105
application/globals.go Normal file
View File

@ -0,0 +1,105 @@
package application
import (
"io"
"log/slog"
"os"
"reflect"
"runtime"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"git.flexabyte.io/flexabyte/go-slogd/slogd"
)
var (
appName string
appCmd *cobra.Command
persistentPreRunE []func(cmd *cobra.Command, args []string) error // collection of PreRunE functions
persistentPostRunE []func(cmd *cobra.Command, args []string) error // collection of PostRunE functions
outWriter io.Writer = os.Stdout
// version semver.Version
)
func helpFuncE(cmd *cobra.Command, args []string) error {
return cmd.Help()
}
func normalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
// switch name {
// case "no-color":
// name = "log-type"
// break
// }
return pflag.NormalizedName(name)
}
func persistentPreRunFuncE(cmd *cobra.Command, args []string) error {
slogd.SetLevel(slogd.Level(logLevelFlag))
// if slogd.ActiveHandler() == slogd_colored.HandlerColor && noColorFlag {
if slogd.ActiveHandler() != slogd.HandlerJSON && noColorFlag {
slogd.UseHandler(slogd.HandlerText)
cmd.SetContext(slogd.WithContext(cmd.Context()))
}
slogd.FromContext(cmd.Context()).Log(cmd.Context(), slogd.LevelTrace, "starting application", slog.String("command", cmd.CommandPath()))
slogd.FromContext(cmd.Context()).Log(cmd.Context(), slogd.LevelTrace, "executing PersistentPreRun")
// Make sure we can always get the version
if versionFlag || cmd.Use == versionName {
slogd.FromContext(cmd.Context()).LogAttrs(cmd.Context(), slogd.LevelTrace, "overriding command", slog.String("old_function", runtime.FuncForPC(reflect.ValueOf(cmd.RunE).Pointer()).Name()), slog.String("new_function", runtime.FuncForPC(reflect.ValueOf(versionRunFuncE).Pointer()).Name()))
cmd.RunE = versionRunFuncE
return nil
}
// Make sure that we show the app help if no commands or flags are passed
if cmd.CalledAs() == appName && runtime.FuncForPC(reflect.ValueOf(cmd.RunE).Pointer()).Name() == runtime.FuncForPC(reflect.ValueOf(runFuncE).Pointer()).Name() {
slogd.FromContext(cmd.Context()).LogAttrs(cmd.Context(), slogd.LevelTrace, "overriding command", slog.String("old_function", runtime.FuncForPC(reflect.ValueOf(cmd.RunE).Pointer()).Name()), slog.String("new_function", runtime.FuncForPC(reflect.ValueOf(helpFuncE).Pointer()).Name()))
cmd.RunE = helpFuncE
return nil
}
// TODO move to front??
if quietFlag {
slogd.FromContext(cmd.Context()).LogAttrs(cmd.Context(), slogd.LevelDebug, "activating quiet mode")
outWriter = io.Discard
}
if persistentPreRunE == nil {
return nil
}
var err error
for _, preRun := range persistentPreRunE {
slogd.FromContext(cmd.Context()).Log(cmd.Context(), slogd.LevelTrace, "executing PersistentPreRun function", slog.String("function", runtime.FuncForPC(reflect.ValueOf(preRun).Pointer()).Name()))
if err = preRun(cmd, args); err != nil {
return err
}
}
return nil
}
func persistentPostRunFuncE(cmd *cobra.Command, args []string) error {
defer slogd.FromContext(cmd.Context()).Log(cmd.Context(), slogd.LevelTrace, "stopping application", slog.String("command", cmd.CommandPath()))
slogd.FromContext(cmd.Context()).Log(cmd.Context(), slogd.LevelTrace, "executing PersistentPostRunE")
if persistentPostRunE == nil {
return nil
}
var err error
for _, postRun := range persistentPostRunE {
slogd.FromContext(cmd.Context()).Log(cmd.Context(), slogd.LevelTrace, "executing PersistentPostRun function", slog.String("function", runtime.FuncForPC(reflect.ValueOf(postRun).Pointer()).Name()))
if err = postRun(cmd, args); err != nil {
return err
}
}
return nil
}
// appRunE is an empty catch function to allow overrides through persistentPreRunE
func runFuncE(cmd *cobra.Command, args []string) error {
return nil
}

35
application/logging.go Normal file
View File

@ -0,0 +1,35 @@
package application
import (
"github.com/spf13/cobra"
)
const (
LogOutputStdOut = "stdout"
LogOutputStdErr = "stderr"
LogOutputFile = "file"
)
var logLevelFlag string
var logOutputFlag string
var logTypeFlag string
func addLogLevelFlag(cmd *cobra.Command) {
cmd.PersistentFlags().StringVarP(&logLevelFlag, "log-level", "", "info", "Set log level (trace, debug, info, warn, error, fatal)")
}
func addLogOutputFlag(cmd *cobra.Command) {
cmd.PersistentFlags().StringVarP(&logOutputFlag, "log-outWriter", "", "stderr", "Set log outWriter (stdout, stderr, file)")
}
func addLogTypeFlag(cmd *cobra.Command) {
cmd.PersistentFlags().StringVarP(&logTypeFlag, "log-type", "", "text", "Set log type (text, json, color)")
}
func configureLoggingFlags(cmd *cobra.Command) {
addLogLevelFlag(cmd)
addLogOutputFlag(cmd)
addLogTypeFlag(cmd)
cmd.MarkFlagsMutuallyExclusive("no-color", "log-type")
}

36
application/output.go Normal file
View File

@ -0,0 +1,36 @@
package application
import "github.com/spf13/cobra"
var jsonOutputFlag bool
var noColorFlag bool
var quietFlag bool
var verboseFlag bool
func addJsonOutputFlag(cmd *cobra.Command) {
cmd.PersistentFlags().BoolVarP(&jsonOutputFlag, "json", "", false, "Enable JSON outWriter")
}
func addNoColorFlag(cmd *cobra.Command) {
cmd.PersistentFlags().BoolVarP(&noColorFlag, "no-color", "", false, "Disable color outWriter")
}
func addQuietFlag(cmd *cobra.Command) {
cmd.PersistentFlags().BoolVarP(&quietFlag, "quiet", "q", false, "Enable quiet mode")
}
func addVerboseFlag(cmd *cobra.Command) {
cmd.PersistentFlags().BoolVarP(&verboseFlag, "verbose", "v", false, "Enable verbose outWriter")
}
func configureOutputFlags(cmd *cobra.Command) {
addJsonOutputFlag(cmd)
addNoColorFlag(cmd)
addVerboseFlag(cmd)
addQuietFlag(cmd)
cmd.MarkFlagsMutuallyExclusive("verbose", "quiet", "json")
cmd.MarkFlagsMutuallyExclusive("json", "no-color")
cmd.MarkFlagsMutuallyExclusive("quiet", "no-color")
}

69
application/version.go Normal file
View File

@ -0,0 +1,69 @@
package application
import (
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"git.flexabyte.io/flexabyte/go-kit/semver"
)
const (
versionName = "version"
versionShortHand = "V"
versionUsage = "Show version information"
)
var (
version semver.Version
versionFlag bool
versionCmd = &cobra.Command{
Use: versionName,
Short: versionUsage,
RunE: versionRunFuncE,
}
)
func addVersionFlag(cmd *cobra.Command) {
cmd.PersistentFlags().BoolVarP(&versionFlag, versionName, versionShortHand, false, versionUsage)
}
func configureVersionFlag(cmd *cobra.Command, v semver.Version) {
version = v
cmd.AddCommand(versionCmd)
addVersionFlag(cmd)
}
func printVersion(v semver.Version) string {
var output string
if !verboseFlag {
output = v.String()
}
if jsonOutputFlag {
var b []byte
b, _ = json.Marshal(v)
output = string(b)
}
if output != "" {
return output
}
return fmt.Sprintf(
"Full: %s\nVersion: %s\nChannel: %s\nCommit: %s\nDate: %s",
v.String(),
v.Number(),
v.Release(),
v.Commit(),
v.Date(),
)
}
func versionRunFuncE(cmd *cobra.Command, args []string) error {
if _, err := fmt.Fprintln(outWriter, printVersion(version)); err != nil {
return err
}
return nil
}