some ideas

This commit is contained in:
adlerhurst
2025-03-04 20:00:09 +01:00
parent 8f0ca7b2cd
commit b093112063
10 changed files with 165 additions and 122 deletions

View File

@@ -114,6 +114,10 @@ func handleField(v *viper.Viper, field reflect.StructField, value reflect.Value)
value = reflect.Indirect(value)
if value.IsZero() {
value = reflect.New(value.Type()).Elem()
}
// Check if potential non pointer value implements [OneOfField]
if value.Type().Implements(reflect.TypeFor[OneOfField]()) {
return handleOneOf(v, field, value, fieldConfig)

View File

@@ -0,0 +1,70 @@
package bla2
import (
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
type TestConfig struct {
API APIConfig `configure:""`
Database DatabaseOneOf `configure:"type=oneof"`
}
type APIConfig struct {
Host string `configure:""`
Port uint16 `configure:""`
}
type DatabaseOneOf struct {
ConnectionString *string `configure:""`
Config *DatabaseConfig `configure:""`
}
type DatabaseConfig struct {
Host string `configure:""`
Port uint16 `configure:""`
SSLMode string `configure:""`
}
type Config interface {
Hooks() []viper.DecoderConfigOption
}
func Update(v *viper.Viper, config any) func(cmd *cobra.Command, args []string) {
return func(cmd *cobra.Command, args []string) {
// promptui.Select
// err := handleStruct(v, reflect.ValueOf(config), configuration{})
// if err != nil {
// fmt.Println(err)
// os.Exit(1)
// }
// err = v.WriteConfig()
// if err != nil {
// fmt.Println(err)
// os.Exit(1)
// }
}
}
const (
tagName = "configure"
defaultKey = "default"
oneOfKey = "oneof"
)
type Field struct {
Name string
DefaultValue any
Prompt prompt
}
type prompt interface {
Run()
}
var (
_ prompt = (*promptui.Select)(nil)
_ prompt = (*promptui.SelectWithAdd)(nil)
_ prompt = (*promptui.Prompt)(nil)
)

View File

@@ -17,7 +17,7 @@ var (
)
type Step001 struct {
Database database.Pool `mapstructure:"-"`
Database database.Pool `mapstructure:"-" configure:"-"`
DatabaseName string `configure:"default=zitadel"`
Username string `configure:"default=zitadel"`

View File

@@ -1,12 +1,12 @@
package prepare
import (
"github.com/Masterminds/semver/v3"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/zitadel/zitadel/backend/cmd/config"
"github.com/zitadel/zitadel/backend/cmd/configure"
"github.com/zitadel/zitadel/backend/cmd/configure/bla"
step001 "github.com/zitadel/zitadel/backend/cmd/prepare/001"
"github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/storage/database/dialect"
@@ -36,62 +36,24 @@ var (
// panic(err)
// }
// },
Run: configure.Update(
"prepare",
"Writes the configuration for the prepare command",
configuration.Fields(),
),
// Run: configure.Update(
// "prepare",
// "Writes the configuration for the prepare command",
// configuration.Fields(),
// ),
Run: bla.Update(viper.GetViper(), &configuration),
PreRun: configure.ReadConfigPreRun(viper.GetViper(), &configuration),
}
)
type Config struct {
config.Config `mapstructure:",squash"`
config.Config `mapstructure:",squash" configure:"-"`
Database dialect.Config
Database dialect.Config // `configure:"-"`
Step001 step001.Step001
// runtime config
Client database.Pool `mapstructure:"-"`
}
// Describe implements configure.StructUpdater.
func (c *Config) Describe() string {
return "Configuration for the prepare command"
}
// Name implements configure.StructUpdater.
func (c *Config) Name() string {
return "prepare"
}
// ShouldUpdate implements configure.StructUpdater.
func (c *Config) ShouldUpdate(version *semver.Version) bool {
if version == nil {
return true
}
for _, field := range c.Fields() {
if field.ShouldUpdate(version) {
return true
}
}
return false
}
// Fields implements configure.UpdateConfig.
func (c Config) Fields() []configure.Updater {
return []configure.Updater{
&configure.Struct{
FieldName: "step001",
Description: "The configuration for the first step of the prepare command",
SubFields: c.Step001.Fields(),
},
&configure.Struct{
FieldName: "database",
Description: "The configuration for the database connection",
SubFields: c.Database.Fields(),
},
}
Client database.Pool `mapstructure:"-" configure:"-"`
}
func (c *Config) Hooks() (decoders []viper.DecoderConfigOption) {

View File

@@ -18,11 +18,11 @@ var (
// This application is a tool to generate the needed files
// to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
var err error
configuration.Client, err = configuration.Database.Connect(cmd.Context())
if err != nil {
panic(err)
}
// var err error
// configuration.Client, err = configuration.Database.Connect(cmd.Context())
// if err != nil {
// panic(err)
// }
defer configuration.Client.Close(cmd.Context())
if err := (&step001.Step001{Database: configuration.Client}).Migrate(cmd.Context()); err != nil {
panic(err)

View File

@@ -2,5 +2,5 @@ configuredversion: 2025.2.23
database:
postgres: host=local
step001:
databasename: zita
username: adel
databasename: asdf
username: asdf

View File

@@ -3,7 +3,6 @@ package dialect
import (
"context"
"errors"
"fmt"
"reflect"
"github.com/mitchellh/mapstructure"
@@ -11,70 +10,43 @@ import (
"github.com/zitadel/zitadel/backend/cmd/config"
"github.com/zitadel/zitadel/backend/cmd/configure"
"github.com/zitadel/zitadel/backend/cmd/configure/bla"
"github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/storage/database/dialect/gosql"
"github.com/zitadel/zitadel/backend/storage/database/dialect/postgres"
)
type Hook struct {
Match func(string) bool
Decode func(name string, config any) (database.Connector, error)
Name string
Field configure.Updater
Match func(string) bool
Decode func(name string, config any) (database.Connector, error)
Name string
Field configure.Updater
Constructor func() any
}
var hooks = make([]Hook, 0)
func init() {
hooks = append(hooks,
Hook{
Match: postgres.NameMatcher,
Decode: postgres.DecodeConfig,
Name: postgres.Name,
Field: postgres.Field,
},
Hook{
Match: gosql.NameMatcher,
Decode: gosql.DecodeConfig,
Name: gosql.Name,
Field: gosql.Field,
},
)
var hooks = []Hook{
{
Match: postgres.NameMatcher,
Decode: postgres.DecodeConfig,
Name: postgres.Name,
Field: postgres.Field,
Constructor: func() any { return new(postgres.Config) },
},
{
Match: gosql.NameMatcher,
Decode: gosql.DecodeConfig,
Name: gosql.Name,
Field: gosql.Field,
Constructor: func() any { return new(gosql.Config) },
},
}
type Config struct {
Dialects map[string]any `mapstructure:",remain"`
Dialects dialects `mapstructure:",remain"`
connector database.Connector
}
// Fields implements [configure.StructUpdater].
func (c *Config) Fields() []configure.Updater {
dialects := configure.OneOf{
Description: "The database dialect Zitadel connects to",
SubFields: []configure.Updater{},
}
for _, hook := range hooks {
if hook.Field == nil {
panic("hook must configure its config fields")
}
dialects.SubFields = append(dialects.SubFields, &configure.Struct{
FieldName: hook.Name,
Description: fmt.Sprintf("Configuration for %s", hook.Name),
SubFields: []configure.Updater{hook.Field},
})
}
return []configure.Updater{
dialects,
}
}
// Name implements [configure.StructUpdater].
func (c *Config) Name() string {
return "database"
}
func (c Config) Connect(ctx context.Context) (database.Pool, error) {
if len(c.Dialects) != 1 {
return nil, errors.New("Exactly one dialect must be configured")
@@ -131,3 +103,21 @@ func decodeHook(from, to reflect.Value) (_ interface{}, err error) {
return config, nil
}
type dialects map[string]any
// ConfigForIndex implements [bla.OneOfField].
func (d dialects) ConfigForIndex(i int) any {
return hooks[i].Constructor()
}
// Possibilities implements [bla.OneOfField].
func (d dialects) Possibilities() []string {
possibilities := make([]string, len(hooks))
for i, hook := range hooks {
possibilities[i] = hook.Name
}
return possibilities
}
var _ bla.OneOfField = (dialects)(nil)

View File

@@ -10,6 +10,7 @@ import (
"github.com/jackc/pgx/v5/pgxpool"
"github.com/zitadel/zitadel/backend/cmd/configure"
"github.com/zitadel/zitadel/backend/cmd/configure/bla"
"github.com/zitadel/zitadel/backend/storage/database"
)
@@ -93,11 +94,29 @@ var (
}
)
type Config struct{ *pgxpool.Config }
type Config struct{ pgxpool.Config }
// ConfigForIndex implements bla.OneOfField.
func (c Config) ConfigForIndex(i int) any {
switch i {
case 0:
return new(string)
case 1:
return &c.Config
}
return nil
}
// Possibilities implements bla.OneOfField.
func (c Config) Possibilities() []string {
return []string{"connection string", "fields"}
}
var _ bla.OneOfField = (*Config)(nil)
// Connect implements [database.Connector].
func (c *Config) Connect(ctx context.Context) (database.Pool, error) {
pool, err := pgxpool.NewWithConfig(ctx, c.Config)
pool, err := pgxpool.NewWithConfig(ctx, &c.Config)
if err != nil {
return nil, err
}
@@ -118,10 +137,10 @@ func DecodeConfig(_ string, config any) (database.Connector, error) {
if err != nil {
return nil, err
}
return &Config{config}, nil
return &Config{Config: *config}, nil
case map[string]any:
return &Config{
Config: &pgxpool.Config{},
Config: pgxpool.Config{},
}, nil
}
return nil, errors.New("invalid configuration")