diff --git a/backend/cmd/config/config.go b/backend/cmd/config/config.go deleted file mode 100644 index a3b079bb92..0000000000 --- a/backend/cmd/config/config.go +++ /dev/null @@ -1,74 +0,0 @@ -package config - -import ( - "fmt" - "os" - "reflect" - - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -type Config struct { - Version Version -} - -func (c Config) Hooks() []viper.DecoderConfigOption { - return []viper.DecoderConfigOption{ - viper.DecodeHook(decodeVersion), - } -} - -func (c Config) CurrentVersion() Version { - return c.Version -} - -var Path string - -// InitConfig reads in config file and ENV variables if set. -func InitConfig() { - if Path != "" { - // Use config file from the flag. - viper.SetConfigFile(Path) - } else { - // Find home directory. - home, err := os.UserHomeDir() - cobra.CheckErr(err) - - // Search config in home directory with name ".zitadel" (without extension). - viper.AddConfigPath(home) - viper.SetConfigType("yaml") - viper.SetConfigName(".zitadel") - } - - viper.AutomaticEnv() // read in environment variables that match - viper.SetEnvPrefix("ZITADEL") - - // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) - } -} - -type Version uint8 - -const ( - VersionUnknown Version = iota - V3 -) - -func decodeVersion(from, to reflect.Value) (_ interface{}, err error) { - if to.Type() != reflect.TypeOf(Version(0)) { - return from.Interface(), nil - } - - switch from.Interface().(string) { - case "": - return VersionUnknown, nil - case "v3": - return V3, nil - - } - - return nil, fmt.Errorf("unsupported version: %v", from.Interface()) -} diff --git a/backend/cmd/configure/bla/update_config4.go b/backend/cmd/configure/bla/update_config4.go deleted file mode 100644 index 794e339a6f..0000000000 --- a/backend/cmd/configure/bla/update_config4.go +++ /dev/null @@ -1,278 +0,0 @@ -package bla - -import ( - "errors" - "fmt" - "os" - "reflect" - "strconv" - "strings" - - "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) { - 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" -) - -func handleStruct(v *viper.Viper, val reflect.Value, config configuration) error { - val = reflect.Indirect(val) - if val.Type().Kind() != reflect.Struct { - return errors.New("object is not a struct") - } - - for i := range val.NumField() { - if err := handleField(v, val.Type().Field(i), val.Field(i)); err != nil { - return err - } - } - return nil -} - -func handlePrimitive(field reflect.StructField, primitive reflect.Value, config configuration) error { - if config.customPrimitiveHandler != nil { - return config.customPrimitiveHandler(config.defaultValue) - } - prompt := promptui.Prompt{ - Label: fmt.Sprintf("%s: %s", field.Name, config.description), - Validate: func(s string) error { - _, err := mapValue(primitive.Type(), s) - return err - }, - } - if config.defaultValue != nil { - prompt.Default = fmt.Sprintf("%v", config.defaultValue) - } - res, err := prompt.Run() - if err != nil { - return err - } - value, _ := mapValue(primitive.Type(), res) - primitive.Set(reflect.ValueOf(value)) - - return nil -} - -func handleField(v *viper.Viper, field reflect.StructField, value reflect.Value) error { - fmt.Println(field.Name) - fieldConfig, err := fieldConfiguration(field, v.Get(field.Name)) - if err != nil { - return err - } - if fieldConfig.skip { - return nil - } - - // check if potential pointer implements [OneOfField] - if value.Type().Implements(reflect.TypeFor[OneOfField]()) { - return handleOneOf(v, field, value, fieldConfig) - } - - 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) - } - //nolint: exhaustive - // Default are all primitive types - switch value.Kind() { - case reflect.Struct: - if v.Get(field.Name) == nil { - defaultValue := fieldConfig.defaultValue - if defaultValue == nil { - defaultValue = map[string]any{} - } - v.Set(field.Name, defaultValue) - } - sub := v.Sub(field.Name) - if err := handleStruct(sub, value, fieldConfig); err != nil { - return err - } - v.Set(field.Name, sub.AllSettings()) - return nil - case reflect.Uintptr, reflect.Array, reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Slice, reflect.UnsafePointer: - return fmt.Errorf("unsupported kind: %s", value.Type().Kind().String()) - default: - if err := handlePrimitive(field, value, fieldConfig); err != nil { - return err - } - v.Set(field.Name, value.Interface()) - return nil - } -} - -func handleOneOf(v *viper.Viper, field reflect.StructField, value reflect.Value, config configuration) error { - possibilities := value.MethodByName("Possibilities").Call(nil)[0].Interface().([]string) - prompt := promptui.Select{ - Label: config.description, - Items: possibilities, - } - - idx, _, err := prompt.Run() - if err != nil { - return err - } - - selectedValue := value.MethodByName("ConfigForIndex").Call([]reflect.Value{reflect.ValueOf(idx)})[0].Interface() - return handleField(v, field, reflect.ValueOf(selectedValue)) -} - -type OneOfField interface { - Possibilities() []string - // ConfigForIndex returns a pointer to the field that was selected - ConfigForIndex(int) any -} - -type configuration struct { - skip bool - defaultValue any - description string - - isOneOf bool - oneOfValues []any - - customPrimitiveHandler func(current any) error - customStructHandler func(*viper.Viper) error - customRepeatedHandler func(*viper.Viper) error - customOneOfHandler func(*viper.Viper) error -} - -func fieldConfiguration(field reflect.StructField, current any) (config configuration, err error) { - value, ok := field.Tag.Lookup(tagName) - if !ok { - return config, nil - } - if value == "-" { - config.skip = true - return config, nil - } - - fields := strings.Split(value, ",") - for _, f := range fields { - configSplit := strings.Split(f, "=") - switch strings.ToLower(configSplit[0]) { - case defaultKey: - config.defaultValue, err = mapValue(field.Type, configSplit[1]) - if err != nil { - return config, err - } - case oneOfKey: - config.isOneOf = true - oneOfValues := strings.Split(configSplit[1], "|") - for _, oneOfValue := range oneOfValues { - value, err := mapValue(field.Type, oneOfValue) - if err != nil { - return config, err - } - config.oneOfValues = append(config.oneOfValues, value) - } - } - } - if current != nil { - config.defaultValue = current - } - - return config, nil -} - -func mapValue(typ reflect.Type, value string) (_ any, err error) { - var val any - switch typ.Kind() { - case reflect.String: - val = value - case reflect.Bool: - val, err = strconv.ParseBool(value) - case reflect.Int: - val, err = strconv.Atoi(value) - case reflect.Int8: - val, err = strconv.ParseInt(value, 10, 8) - val = int8(val.(int64)) - case reflect.Int16: - val, err = strconv.ParseInt(value, 10, 16) - val = int16(val.(int64)) - case reflect.Int32: - val, err = strconv.ParseInt(value, 10, 32) - val = int32(val.(int64)) - case reflect.Int64: - val, err = strconv.ParseInt(value, 10, 64) - case reflect.Uint: - val, err = strconv.ParseUint(value, 10, 0) - val = uint(val.(uint64)) - case reflect.Uint8: - val, err = strconv.ParseUint(value, 10, 8) - val = uint8(val.(uint64)) - case reflect.Uint16: - val, err = strconv.ParseUint(value, 10, 16) - val = uint16(val.(uint64)) - case reflect.Uint32: - val, err = strconv.ParseUint(value, 10, 32) - val = uint32(val.(uint64)) - case reflect.Uint64: - val, err = strconv.ParseUint(value, 10, 64) - case reflect.Float32: - val, err = strconv.ParseFloat(value, 32) - val = float32(val.(float64)) - case reflect.Float64: - val, err = strconv.ParseFloat(value, 64) - default: - return nil, fmt.Errorf("unsupported type: %s", typ.Kind().String()) - } - if err != nil { - return nil, err - } - - res := reflect.ValueOf(val) - if !res.CanConvert(typ) { - return nil, fmt.Errorf("cannot convert %T to %s", val, typ.Kind().String()) - } - return res.Convert(typ).Interface(), nil -} diff --git a/backend/cmd/configure/bla2/primitive.go b/backend/cmd/configure/bla2/primitive.go deleted file mode 100644 index 425d604e87..0000000000 --- a/backend/cmd/configure/bla2/primitive.go +++ /dev/null @@ -1,48 +0,0 @@ -package bla2 - -import ( - "fmt" - "reflect" - - "github.com/manifoldco/promptui" -) - -type primitive struct { - typ reflect.Type - - tag fieldTag -} - -func (p *primitive) defaultValue() any { - if p.tag.currentValue != nil { - return p.tag.currentValue - } - return reflect.Zero(p.typ).Interface() -} - -func (p *primitive) label() string { - if p.tag.description == "" { - return p.tag.fieldName - } - return fmt.Sprintf("%s (%s)", p.tag.fieldName, p.tag.description) -} - -func (p *primitive) toPrompt() prompt { - return &linePrompt{ - Prompt: promptui.Prompt{ - Label: p.label(), - Default: fmt.Sprintf("%v", p.defaultValue()), - Validate: p.validateInput, - IsConfirm: p.typ.Kind() == reflect.Bool, - }, - } -} - -func promptFromPrimitive(p *primitive) prompt { - return p.toPrompt() -} - -func (p *primitive) validateInput(s string) error { - _, err := mapValue(p.typ, s) - return err -} diff --git a/backend/cmd/configure/bla2/prompt.go b/backend/cmd/configure/bla2/prompt.go deleted file mode 100644 index 79642b8d63..0000000000 --- a/backend/cmd/configure/bla2/prompt.go +++ /dev/null @@ -1,61 +0,0 @@ -package bla2 - -import "github.com/manifoldco/promptui" - -type prompt interface { - Run() (err error) - Result() string -} - -var ( - _ prompt = (*selectPrompt)(nil) - _ prompt = (*selectWithAddPrompt)(nil) - _ prompt = (*linePrompt)(nil) -) - -type selectPrompt struct { - promptui.Select - - selectedIndex int - selectedValue string -} - -func (p *selectPrompt) Run() (err error) { - p.selectedIndex, p.selectedValue, err = p.Select.Run() - return err -} - -func (p *selectPrompt) Result() string { - return p.selectedValue -} - -type selectWithAddPrompt struct { - promptui.SelectWithAdd - - selectedIndex int - selectedValue string -} - -func (p *selectWithAddPrompt) Run() (err error) { - p.selectedIndex, p.selectedValue, err = p.SelectWithAdd.Run() - return err -} - -func (p *selectWithAddPrompt) Result() string { - return p.selectedValue -} - -type linePrompt struct { - promptui.Prompt - - selectedValue string -} - -func (p *linePrompt) Run() (err error) { - p.selectedValue, err = p.Prompt.Run() - return err -} - -func (p *linePrompt) Result() string { - return p.selectedValue -} diff --git a/backend/cmd/configure/bla2/struct.go b/backend/cmd/configure/bla2/struct.go deleted file mode 100644 index b174390e72..0000000000 --- a/backend/cmd/configure/bla2/struct.go +++ /dev/null @@ -1,112 +0,0 @@ -package bla2 - -import ( - "log/slog" - "reflect" - - "github.com/spf13/viper" -) - -type object struct { - value reflect.Value - viper *viper.Viper -} - -func (o *object) fields() ([]*Field, error) { - fields := make([]*Field, 0, o.value.NumField()) - for i := range o.value.NumField() { - if !o.value.CanSet() { - slog.Info("skipping field because it is not settable", slog.String("field", o.value.Type().Field(i).Name)) - continue - } - var currentValue any - if !o.value.Field(i).IsZero() { - currentValue = o.value.Field(i).Interface() - } - tag, err := newFieldTag(o.value.Type().Field(i), currentValue) - if err != nil { - return nil, err - } - - if tag.skip { - continue - } - - field, err := o.field(o.value.Field(i), tag) - if err != nil { - return nil, err - } - // field can be nil if the fields kind is not supported - if field != nil { - fields = append(fields, field) - } - } - - return fields, nil -} - -func (o *object) field(field reflect.Value, tag fieldTag) (*Field, error) { - switch field.Kind() { - case reflect.Bool, - reflect.Int, - reflect.Int8, - reflect.Int16, - reflect.Int32, - reflect.Int64, - reflect.Uint, - reflect.Uint8, - reflect.Uint16, - reflect.Uint32, - reflect.Uint64, - reflect.Uintptr, - reflect.Float32, - reflect.Float64, - reflect.Complex64, - reflect.Complex128, - reflect.String: - - prompt := promptFromPrimitive(&primitive{ - typ: field.Type(), - tag: tag, - }) - return &Field{ - Prompt: prompt, - Set: func() { - o.viper.Set(tag.fieldName, prompt.Result()) - }, - }, nil - case reflect.Struct: - if o.viper.Get(tag.fieldName) == nil { - o.viper.Set(tag.fieldName, make(map[string]any)) - } - sub := &object{ - value: reflect.Indirect(field), - viper: o.viper.Sub(tag.fieldName), - } - subFields, err := sub.fields() - if err != nil { - return nil, err - } - return &Field{ - Sub: subFields, - Set: func() { - o.viper.Set(tag.fieldName, sub.viper.AllSettings()) - }, - }, nil - case reflect.Pointer: - return o.field(field.Elem(), tag) - case reflect.Array, reflect.Interface, reflect.Map, reflect.Slice: - slog.Info( - "skipping field because type is not implemented", - slog.String("field", tag.fieldName), - slog.String("kind", field.Kind().String()), - ) - case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Invalid: - slog.Info( - "skipping field because field type is invalid, add `configure=\"-\"` to skip", - slog.String("field", tag.fieldName), - slog.String("kind", field.Kind().String()), - ) - } - return nil, nil -} diff --git a/backend/cmd/configure/bla2/tag.go b/backend/cmd/configure/bla2/tag.go deleted file mode 100644 index 0a93e1e0a8..0000000000 --- a/backend/cmd/configure/bla2/tag.go +++ /dev/null @@ -1,53 +0,0 @@ -package bla2 - -import ( - "reflect" - "strings" -) - -type fieldTag struct { - skip bool - - fieldName string - description string - - currentValue any -} - -const ( - tagName = "configure" - defaultKey = "default" - descriptionKey = "description" -) - -func newFieldTag(field reflect.StructField, current any) (config fieldTag, err error) { - config.fieldName = field.Name - - value, ok := field.Tag.Lookup(tagName) - if !ok { - return config, nil - } - if value == "-" { - config.skip = true - return config, nil - } - - fields := strings.Split(value, ",") - for _, f := range fields { - configSplit := strings.Split(f, "=") - switch strings.ToLower(configSplit[0]) { - case defaultKey: - config.currentValue, err = mapValue(field.Type, configSplit[1]) - if err != nil { - return config, err - } - case descriptionKey: - config.description = configSplit[1] - } - } - if current != nil { - config.currentValue = current - } - - return config, nil -} diff --git a/backend/cmd/configure/bla2/update_config5.go b/backend/cmd/configure/bla2/update_config5.go deleted file mode 100644 index c14416c85d..0000000000 --- a/backend/cmd/configure/bla2/update_config5.go +++ /dev/null @@ -1,146 +0,0 @@ -package bla2 - -import ( - "fmt" - "os" - "reflect" - "strconv" - - "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) { - s := object{ - value: reflect.Indirect(reflect.ValueOf(config)), - viper: v, - } - fields, err := s.fields() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - for _, field := range fields { - err = field.execute() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - } - err = v.WriteConfig() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - } -} - -type Field struct { - // Either Prompt or Sub must be set - Prompt prompt - Sub []*Field - Set func() -} - -func (f *Field) execute() error { - if f.Prompt != nil { - if err := f.Prompt.Run(); err != nil { - return err - } - f.Set() - return nil - } - for _, sub := range f.Sub { - err := sub.execute() - if err != nil { - return err - } - sub.Set() - } - f.Set() - return nil -} - -func mapValue(typ reflect.Type, value string) (v reflect.Value, err error) { - var val any - switch typ.Kind() { - case reflect.String: - val = value - case reflect.Bool: - val, err = strconv.ParseBool(value) - case reflect.Int: - val, err = strconv.Atoi(value) - case reflect.Int8: - val, err = strconv.ParseInt(value, 10, 8) - val = int8(val.(int64)) - case reflect.Int16: - val, err = strconv.ParseInt(value, 10, 16) - val = int16(val.(int64)) - case reflect.Int32: - val, err = strconv.ParseInt(value, 10, 32) - val = int32(val.(int64)) - case reflect.Int64: - val, err = strconv.ParseInt(value, 10, 64) - case reflect.Uint: - val, err = strconv.ParseUint(value, 10, 0) - val = uint(val.(uint64)) - case reflect.Uint8: - val, err = strconv.ParseUint(value, 10, 8) - val = uint8(val.(uint64)) - case reflect.Uint16: - val, err = strconv.ParseUint(value, 10, 16) - val = uint16(val.(uint64)) - case reflect.Uint32: - val, err = strconv.ParseUint(value, 10, 32) - val = uint32(val.(uint64)) - case reflect.Uint64: - val, err = strconv.ParseUint(value, 10, 64) - case reflect.Float32: - val, err = strconv.ParseFloat(value, 32) - val = float32(val.(float64)) - case reflect.Float64: - val, err = strconv.ParseFloat(value, 64) - case reflect.Complex64: - val, err = strconv.ParseComplex(value, 64) - val = complex64(val.(complex128)) - case reflect.Complex128: - val, err = strconv.ParseComplex(value, 128) - default: - return v, fmt.Errorf("unsupported type: %s", typ.Kind().String()) - } - if err != nil { - return v, err - } - - res := reflect.ValueOf(val) - if !res.CanConvert(typ) { - return v, fmt.Errorf("cannot convert %T to %s", val, typ.Kind().String()) - } - return res.Convert(typ), nil -} diff --git a/backend/cmd/configure/bla3/prompt.go b/backend/cmd/configure/bla3/prompt.go deleted file mode 100644 index 1ba0fd8f79..0000000000 --- a/backend/cmd/configure/bla3/prompt.go +++ /dev/null @@ -1,183 +0,0 @@ -package bla3 - -import ( - "fmt" - "log/slog" - "reflect" - - "github.com/manifoldco/promptui" - "github.com/spf13/viper" -) - -var customType = reflect.TypeFor[Custom]() - -type Custom interface { - Configure() (value any, err error) -} - -type Object struct { - value reflect.Value - - tag fieldTag -} - -func NewObject(value any) Object { - return Object{ - value: reflect.Indirect(reflect.ValueOf(value)), - } -} - -func (o *Object) Configure(v *viper.Viper) error { - if o.tag.label() != "" { - fmt.Println("\n", o.tag.label()) - } - for i := range o.value.NumField() { - if !o.value.Type().Field(i).IsExported() { - continue - } - structField := o.value.Field(i) - - f := Field{ - value: structField, - structField: o.value.Type().Field(i), - } - err := f.Configure(v) - if err != nil { - return err - } - } - - return nil -} - -type Field struct { - value reflect.Value - - structField reflect.StructField - - tag fieldTag -} - -func NewField(value any) Field { - return Field{ - value: reflect.ValueOf(value), - } -} - -func (f *Field) validate(input string) (err error) { - configuredValue, err := mapValue(f.value.Type(), input) - if err != nil { - return err - } - f.value.Set(configuredValue) - return nil -} - -func (f *Field) callCustom(v *viper.Viper) (ok bool, err error) { - if !f.value.Type().Implements(customType) { - return false, nil - } - - custom := f.value.Interface().(Custom) - value, err := custom.Configure() - if err != nil { - return true, err - } - switch val := value.(type) { - case Field: - val.tag, err = newFieldTag(f.structField, val.value.Interface()) - val.structField = f.structField - if err != nil { - return false, err - } - return true, val.Configure(v) - default: - v.Set(f.tag.fieldName, val) - return true, nil - } -} - -func (f *Field) Configure(v *viper.Viper) error { - if f.value.IsNil() { - f.value.Set(reflect.New(f.value.Type().Elem())) - } - - tag, err := newFieldTag(f.structField, f.value.Interface()) - if err != nil { - return err - } - if tag.skip { - return nil - } - - if ok, err := f.callCustom(v); ok || err != nil { - return err - } - f.value = reflect.Indirect(f.value) - if ok, err := f.callCustom(v); ok || err != nil { - return err - } - - kind := f.value.Kind() - switch kind { - case reflect.Bool: - prompt := promptui.Prompt{ - Label: f.tag.label(), - IsConfirm: true, - } - _, err := prompt.Run() - selected := true - if err != nil { - if err.Error() != "" { - return err - } - selected = false - } - f.value.SetBool(selected) - v.Set(f.tag.fieldName, f.value.Interface()) - return nil - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, - reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String: - - prompt := promptui.Prompt{ - Label: f.tag.label(), - Validate: f.validate, - Default: f.tag.defaultValue(), - } - _, err := prompt.Run() - if err != nil { - return err - } - v.Set(f.tag.fieldName, f.value.Interface()) - return nil - case reflect.Struct: - o := Object{ - value: f.value, - tag: f.tag, - } - if !v.IsSet(f.tag.fieldName) { - v.Set(f.tag.fieldName, map[string]any{}) - } - sub := v.Sub(f.tag.fieldName) - err := o.Configure(sub) - if err != nil { - return err - } - v.Set(f.tag.fieldName, sub.AllSettings()) - return nil - case reflect.Pointer: - if f.value.IsNil() { - f.value = reflect.New(f.value.Type().Elem()) - } - f.value = f.value.Elem() - return f.Configure(v) - case reflect.Array, reflect.Slice, reflect.Map: - slog.Warn("skipping because kind is unimplemented", slog.String("field", f.tag.fieldName), slog.String("kind", kind.String())) - return nil - case reflect.Chan, reflect.Func, reflect.Interface, reflect.UnsafePointer, reflect.Invalid: - slog.Error("skipping because kind is unsupported", slog.String("field", f.tag.fieldName), slog.String("kind", kind.String())) - return nil - } - return nil -} diff --git a/backend/cmd/configure/bla3/tag.go b/backend/cmd/configure/bla3/tag.go deleted file mode 100644 index 08fa04565f..0000000000 --- a/backend/cmd/configure/bla3/tag.go +++ /dev/null @@ -1,81 +0,0 @@ -package bla3 - -import ( - "fmt" - "reflect" - "strings" -) - -type fieldTag struct { - skip bool - - fieldName string - description string - - currentValue any -} - -const ( - tagName = "configure" - defaultKey = "default" - descriptionKey = "description" -) - -func newFieldTag(field reflect.StructField, current any) (config fieldTag, err error) { - config.fieldName = field.Name - if current != nil { - config.currentValue = current - } - - value, ok := field.Tag.Lookup(tagName) - if !ok { - if config.currentValue == nil { - config.currentValue = reflect.New(field.Type).Elem().Interface() - } - return config, nil - } - if value == "-" { - config.skip = true - return config, nil - } - - fields := strings.Split(value, ",") - for _, f := range fields { - configSplit := strings.Split(f, "=") - switch strings.ToLower(configSplit[0]) { - case defaultKey: - config.currentValue, err = mapValue(field.Type, configSplit[1]) - if err != nil { - return config, err - } - case descriptionKey: - config.description = configSplit[1] - } - } - if config.currentValue == nil { - config.currentValue = reflect.New(field.Type).Elem().Interface() - } - - return config, nil -} - -func (tag fieldTag) label() string { - if tag.fieldName == "" { - return "" - } - valueType := reflect.TypeOf(tag.currentValue) - typ := valueType.Kind().String() - if typeParsers[valueType] != nil { - typ = valueType.Name() - } - - label := fmt.Sprintf("%s (%s)", tag.fieldName, typ) - if tag.description == "" { - return label - } - return fmt.Sprintf("%s (%s)", label, tag.description) -} - -func (tag fieldTag) defaultValue() string { - return fmt.Sprintf("%v", tag.currentValue) -} diff --git a/backend/cmd/configure/bla3/update_config6.go b/backend/cmd/configure/bla3/update_config6.go deleted file mode 100644 index 126501bb0e..0000000000 --- a/backend/cmd/configure/bla3/update_config6.go +++ /dev/null @@ -1,140 +0,0 @@ -package bla3 - -import ( - "fmt" - "os" - "reflect" - "strconv" - "time" - - "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:""` -} - -func Update(v *viper.Viper, config any) func(cmd *cobra.Command, args []string) { - return func(cmd *cobra.Command, args []string) { - s := NewObject(config) - if err := s.Configure(v); err != nil { - fmt.Println(err) - os.Exit(1) - } - err := v.WriteConfig() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - } -} - -var typeParsers = map[reflect.Type]func(string) (any, error){ - reflect.TypeFor[time.Duration](): func(value string) (any, error) { - return time.ParseDuration(value) - }, - reflect.TypeFor[time.Time](): func(value string) (any, error) { - if t, err := time.Parse(time.DateTime, value); err == nil { - return t, nil - } - if t, err := time.Parse(time.DateOnly, value); err == nil { - return t, nil - } - if t, err := time.Parse(time.TimeOnly, value); err == nil { - return t, nil - } - return time.Parse(time.RFC3339, value) - }, -} - -func SetTypeParser[T any](fn func(string) (any, error)) { - typeParsers[reflect.TypeFor[T]()] = fn -} - -func mapValue(typ reflect.Type, value string) (v reflect.Value, err error) { - if fn, ok := typeParsers[typ]; ok { - mappedValue, err := fn(value) - if err != nil { - return v, err - } - res := reflect.ValueOf(mappedValue) - if !res.CanConvert(typ) { - return v, fmt.Errorf("cannot convert %T to %s", mappedValue, typ.Kind().String()) - } - return res.Convert(typ), nil - } - - var val any - switch typ.Kind() { - case reflect.String: - val = value - case reflect.Bool: - val, err = strconv.ParseBool(value) - case reflect.Int: - val, err = strconv.Atoi(value) - case reflect.Int8: - val, err = strconv.ParseInt(value, 10, 8) - val = int8(val.(int64)) - case reflect.Int16: - val, err = strconv.ParseInt(value, 10, 16) - val = int16(val.(int64)) - case reflect.Int32: - val, err = strconv.ParseInt(value, 10, 32) - val = int32(val.(int64)) - case reflect.Int64: - val, err = strconv.ParseInt(value, 10, 64) - case reflect.Uint: - val, err = strconv.ParseUint(value, 10, 0) - val = uint(val.(uint64)) - case reflect.Uint8: - val, err = strconv.ParseUint(value, 10, 8) - val = uint8(val.(uint64)) - case reflect.Uint16: - val, err = strconv.ParseUint(value, 10, 16) - val = uint16(val.(uint64)) - case reflect.Uint32: - val, err = strconv.ParseUint(value, 10, 32) - val = uint32(val.(uint64)) - case reflect.Uint64: - val, err = strconv.ParseUint(value, 10, 64) - case reflect.Float32: - val, err = strconv.ParseFloat(value, 32) - val = float32(val.(float64)) - case reflect.Float64: - val, err = strconv.ParseFloat(value, 64) - case reflect.Complex64: - val, err = strconv.ParseComplex(value, 64) - val = complex64(val.(complex128)) - case reflect.Complex128: - val, err = strconv.ParseComplex(value, 128) - default: - return v, fmt.Errorf("unsupported type: %s", typ.Kind().String()) - } - if err != nil { - return v, err - } - - res := reflect.ValueOf(val) - if !res.CanConvert(typ) { - return v, fmt.Errorf("cannot convert %T to %s", val, typ.Kind().String()) - } - return res.Convert(typ), nil -} diff --git a/backend/cmd/configure/bla4/field_tag.go b/backend/cmd/configure/bla4/field_tag.go deleted file mode 100644 index 1a2ccbc9a0..0000000000 --- a/backend/cmd/configure/bla4/field_tag.go +++ /dev/null @@ -1,115 +0,0 @@ -package bla4 - -import ( - "fmt" - "reflect" - "strings" - - "github.com/spf13/viper" -) - -type field struct { - info reflect.StructField - viper *viper.Viper - - tag -} - -func (f *field) label() string { - var builder strings.Builder - builder.WriteString(f.info.Name) - builder.WriteString(" (") - builder.WriteString(f.info.Type.Kind().String()) - builder.WriteString(")") - if f.description != "" { - builder.WriteString(": ") - builder.WriteString(f.description) - } - return builder.String() -} - -func (f *field) sub() *viper.Viper { - if !f.viper.IsSet(f.fieldName) { - f.viper.Set(f.fieldName, map[string]any{}) - } - return f.viper.Sub(f.fieldName) -} - -func (f *field) printStructInfo() { - var builder strings.Builder - builder.WriteString("------- ") - builder.WriteString(f.info.Name) - builder.WriteString(" -------") - if f.description != "" { - builder.WriteString(": ") - builder.WriteString(f.description) - } - fmt.Println(builder.String()) -} - -type tag struct { - skip bool - - fieldName string - description string - - value reflect.Value -} - -const ( - tagName = "configure" - defaultKey = "default" - descriptionKey = "description" -) - -func newTag(field reflect.StructField, current reflect.Value) (config tag, err error) { - config.fieldName = field.Name - defer func() { - if !config.value.IsValid() { - if field.Type.Kind() == reflect.Pointer { - config.value = reflect.New(field.Type.Elem()) - return - } - config.value = reflect.New(field.Type).Elem() - } - }() - if !current.IsZero() { - config.value = current - } - - value, ok := field.Tag.Lookup(tagName) - if !ok { - return config, nil - } - if value == "-" { - config.skip = true - return config, nil - } - - fields := strings.Split(value, ",") - for _, f := range fields { - configSplit := strings.Split(f, "=") - switch strings.ToLower(configSplit[0]) { - case defaultKey: - if !config.value.IsZero() { - continue - } - value, err := kindMapper(field.Type.Kind())(configSplit[1]) - if err != nil { - return config, err - } - config.value.Set(reflect.ValueOf(value)) - case descriptionKey: - config.description = configSplit[1] - } - } - - return config, nil -} - -func (tag tag) defaultValue() string { - if tag.value.IsZero() { - return "" - } - return fmt.Sprintf("%v", tag.value.Interface()) -} diff --git a/backend/cmd/configure/bla4/iterator.go b/backend/cmd/configure/bla4/iterator.go deleted file mode 100644 index b5acca0dfb..0000000000 --- a/backend/cmd/configure/bla4/iterator.go +++ /dev/null @@ -1,70 +0,0 @@ -package bla4 - -import ( - "fmt" - "log/slog" - "reflect" - - "github.com/manifoldco/promptui" -) - -type Iterator interface { - // NextField returns the name of the next field to configure. - // If it returns an empty string, the configuration is complete. - NextField() string - // FinishAllowed returns true if the configuration is complete and the user can skip the remaining fields. - FinishAllowed() bool -} - -func fieldFunctionByIterator(l *slog.Logger, f *field) Configure { - if !f.value.Type().Implements(reflect.TypeFor[Iterator]()) { - return nil - } - - return func() (value any, err error) { - iter := f.value.Interface().(Iterator) - sub := f.sub() - for { - fieldName := iter.NextField() - if fieldName == "" { - break - } - if iter.FinishAllowed() { - prompt := promptui.Prompt{ - Label: fmt.Sprintf("Finish configuration of %s", f.info.Name), - IsConfirm: true, - } - _, err := prompt.Run() - if err == nil { - break - } - } - info, ok := f.value.Type().FieldByName(fieldName) - if !ok { - return nil, fmt.Errorf("field %s not found", fieldName) - } - tag, err := newTag(info, f.value.FieldByName(fieldName)) - if err != nil { - return nil, err - } - if tag.skip { - continue - } - - res, err := fieldFunction( - l.With(slog.String("field", fieldName)), - &field{ - info: info, - viper: sub, //TODO: sub of sub - tag: tag, - }, - )() - if err != nil { - return nil, err - } - reflect.Indirect(f.value).FieldByName(fieldName).Set(reflect.ValueOf(res)) - } - f.viper.Set(f.tag.fieldName, sub.AllSettings()) - return value, err - } -} diff --git a/backend/cmd/configure/bla4/mapper.go b/backend/cmd/configure/bla4/mapper.go deleted file mode 100644 index 8776e6122c..0000000000 --- a/backend/cmd/configure/bla4/mapper.go +++ /dev/null @@ -1,121 +0,0 @@ -package bla4 - -import ( - "reflect" - "strconv" - "sync" - "time" -) - -var writeMu sync.RWMutex - -func SetTypeMapper(typ reflect.Type, mapper func(input string) (any, error)) { - writeMu.Lock() - defer writeMu.Unlock() - - typeMappers[typ] = mapper -} - -func SetTypeMapperFor[T any](mapper func(input string) (any, error)) { - writeMu.Lock() - defer writeMu.Unlock() - - typeMappers[reflect.TypeFor[T]()] = mapper -} - -func typeMapper(typ reflect.Type) func(input string) (any, error) { - writeMu.RLock() - defer writeMu.RUnlock() - - return typeMappers[typ] -} - -var typeMappers = map[reflect.Type]func(string) (any, error){ - reflect.TypeFor[time.Duration](): func(input string) (any, error) { - return time.ParseDuration(input) - }, -} - -// SetKindMapper overwrites the mapper for the given kind. -func SetKindMapper(kind reflect.Kind, mapper func(input string) (any, error)) { - writeMu.Lock() - defer writeMu.Unlock() - - kindMappers[kind] = mapper -} - -func kindMapper(kind reflect.Kind) func(input string) (any, error) { - writeMu.RLock() - defer writeMu.RUnlock() - - return kindMappers[kind] -} - -var kindMappers = map[reflect.Kind]func(input string) (any, error){ - reflect.String: func(input string) (any, error) { - return input, nil - }, - reflect.Bool: func(input string) (any, error) { - return strconv.ParseBool(input) - }, - reflect.Int: func(input string) (any, error) { - return strconv.Atoi(input) - }, - reflect.Int8: func(input string) (val any, err error) { - val, err = strconv.ParseInt(input, 10, 8) - val = int8(val.(int64)) - return val, err - }, - reflect.Int16: func(input string) (val any, err error) { - val, err = strconv.ParseInt(input, 10, 16) - val = int16(val.(int64)) - return val, err - }, - reflect.Int32: func(input string) (val any, err error) { - val, err = strconv.ParseInt(input, 10, 32) - val = int32(val.(int64)) - return val, err - }, - reflect.Int64: func(input string) (any, error) { - return strconv.ParseInt(input, 10, 64) - }, - reflect.Uint: func(input string) (val any, err error) { - val, err = strconv.ParseUint(input, 10, 0) - val = uint(val.(uint64)) - return val, err - }, - reflect.Uint8: func(input string) (val any, err error) { - val, err = strconv.ParseUint(input, 10, 8) - val = uint8(val.(uint64)) - return val, err - }, - reflect.Uint16: func(input string) (val any, err error) { - val, err = strconv.ParseUint(input, 10, 16) - val = uint16(val.(uint64)) - return val, err - }, - reflect.Uint32: func(input string) (val any, err error) { - val, err = strconv.ParseUint(input, 10, 32) - val = uint32(val.(uint64)) - return val, err - }, - reflect.Uint64: func(input string) (any, error) { - return strconv.ParseUint(input, 10, 64) - }, - reflect.Float32: func(input string) (val any, err error) { - val, err = strconv.ParseFloat(input, 32) - val = float32(val.(float64)) - return val, err - }, - reflect.Float64: func(input string) (any, error) { - return strconv.ParseFloat(input, 64) - }, - reflect.Complex64: func(input string) (val any, err error) { - val, err = strconv.ParseComplex(input, 64) - val = complex64(val.(complex128)) - return val, err - }, - reflect.Complex128: func(input string) (any, error) { - return strconv.ParseComplex(input, 128) - }, -} diff --git a/backend/cmd/configure/bla4/update_config7.go b/backend/cmd/configure/bla4/update_config7.go deleted file mode 100644 index 7479a26171..0000000000 --- a/backend/cmd/configure/bla4/update_config7.go +++ /dev/null @@ -1,189 +0,0 @@ -package bla4 - -import ( - "fmt" - "log/slog" - "os" - "reflect" - - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var Logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ - AddSource: true, - Level: slog.LevelDebug, -})) - -type Configure func() (value any, err error) - -type Configurer interface { - // Configure is called to configure the value. - // It must return the same type as itself. Otherwise [Update] will panic because it is not able to set the value. - Configure() (value any, err error) -} - -func Update(v *viper.Viper, config any) func(cmd *cobra.Command, args []string) { - return func(cmd *cobra.Command, args []string) { - value := reflect.ValueOf(config) - structConfigures := structToConfigureMap(Logger, v, value) - for key, configure := range structConfigures { - result, err := configure() - if err != nil { - Logger.Error("error configuring field", slog.String("field", key), slog.Any("cause", err)) - return - } - value.Elem().FieldByName(key).Set(reflect.ValueOf(result)) - } - - err := v.WriteConfig() - if err != nil { - Logger.Error("error writing config", slog.Any("cause", err)) - os.Exit(1) - } - } -} - -func structToConfigureMap(l *slog.Logger, v *viper.Viper, object reflect.Value) map[string]Configure { - if object.Kind() == reflect.Pointer { - if object.IsNil() { - l.Debug("initialize object") - object = reflect.New(object.Type().Elem()) - } - return structToConfigureMap(l, v, object.Elem()) - } - if object.Kind() != reflect.Struct { - panic("config must be a struct") - } - - fields := make(map[string]Configure, object.NumField()) - - for i := range object.NumField() { - if !object.Type().Field(i).IsExported() { - continue - } - - tag, err := newTag(object.Type().Field(i), object.Field(i)) - if err != nil { - l.Error("failed to parse field tag", slog.Any("cause", err)) - continue - } - if tag.skip { - l.Debug("skipping field", slog.String("field", object.Type().Field(i).Name)) - continue - } - - fields[object.Type().Field(i).Name] = fieldFunction( - l.With(slog.String("field", object.Type().Field(i).Name)), - &field{ - info: object.Type().Field(i), - tag: tag, - viper: v, - }, - ) - } - return fields -} - -func fieldFunction(l *slog.Logger, f *field) (configure Configure) { - for _, mapper := range []func(*slog.Logger, *field) Configure{ - fieldFunctionByConfigurer, - fieldFunctionByIterator, - fieldFunctionByReflection, - } { - if configure = mapper(l, f); configure != nil { - return configure - } - } - panic(fmt.Sprintf("unsupported field type: %s", f.info.Type.String())) -} - -func fieldFunctionByConfigurer(l *slog.Logger, f *field) Configure { - if f.value.Type().Implements(reflect.TypeFor[Configurer]()) { - return func() (value any, err error) { - f.printStructInfo() - res, err := f.value.Interface().(Configurer).Configure() - if err != nil { - return nil, err - } - f.viper.Set(f.tag.fieldName, res) - return res, nil - } - } - return nil -} - -func fieldFunctionByReflection(l *slog.Logger, f *field) Configure { - kind := f.value.Kind() - - //nolint:exhaustive // only types that require special treatment are covered - switch kind { - case reflect.Pointer: - if f.value.IsNil() { - f.value.Set(reflect.New(f.value.Type().Elem())) - } - sub := f.sub() - m := structToConfigureMap(l, sub, f.value) - return func() (value any, err error) { - f.printStructInfo() - for key, configure := range m { - value, err = configure() - if err != nil { - return nil, err - } - f.value.Elem().FieldByName(key).Set(reflect.ValueOf(value)) - } - f.viper.Set(f.tag.fieldName, sub.AllSettings()) - return f.value.Interface(), nil - } - case reflect.Struct: - sub := f.sub() - m := structToConfigureMap(l, sub, f.value) - return func() (value any, err error) { - f.printStructInfo() - for key, configure := range m { - value, err = configure() - if err != nil { - return nil, err - } - f.value.FieldByName(key).Set(reflect.ValueOf(value)) - } - f.viper.Set(f.tag.fieldName, sub.AllSettings()) - return f.value.Interface(), nil - } - - case reflect.Array, reflect.Slice, reflect.Map: - l.Warn("skipping because kind is unimplemented", slog.String("kind", kind.String())) - return nil - case reflect.Chan, reflect.Func, reflect.Interface, reflect.UnsafePointer, reflect.Invalid: - slog.Error("skipping because kind is unsupported", slog.String("kind", kind.String())) - return nil - } - - mapper := typeMapper(f.info.Type) - if mapper == nil { - mapper = kindMapper(kind) - } - if mapper == nil { - l.Error("unsupported kind", slog.String("kind", kind.String())) - panic(fmt.Sprintf("unsupported kind: %s", kind.String())) - } - - return func() (value any, err error) { - prompt := promptui.Prompt{ - Label: f.label(), - Validate: func(input string) error { - value, err = mapper(input) - return err - }, - Default: f.defaultValue(), - } - _, err = prompt.Run() - if err != nil { - return nil, err - } - f.viper.Set(f.tag.fieldName, value) - return value, nil - } -} diff --git a/backend/cmd/configure/bla5/generator.go b/backend/cmd/configure/bla5/generator.go deleted file mode 100644 index d58d474609..0000000000 --- a/backend/cmd/configure/bla5/generator.go +++ /dev/null @@ -1 +0,0 @@ -package bla5 diff --git a/backend/cmd/configure/bla5/update_config8.go b/backend/cmd/configure/bla5/update_config8.go deleted file mode 100644 index e283d5be3f..0000000000 --- a/backend/cmd/configure/bla5/update_config8.go +++ /dev/null @@ -1,75 +0,0 @@ -package bla5 - -import ( - "log/slog" - "os" - - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var Logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ - AddSource: true, - Level: slog.LevelDebug, -})) - -type Configure func() (value any, err error) - -// Configurer should be implemented by each field of the configuration struct. -// It is used to configure the value of the field. -type Configurer interface { - // Configure is called to configure the value. - // It must return the same type as itself. Otherwise [Update] will panic because it is not able to set the value. - Configure() (value any, err error) -} - -func Update(v *viper.Viper, config any) func(cmd *cobra.Command, args []string) { - return func(cmd *cobra.Command, args []string) { - // value := reflect.ValueOf(config) - // structConfigures := structToConfigureMap(Logger, v, value) - // for key, configure := range structConfigures { - // result, err := configure() - // if err != nil { - // Logger.Error("error configuring field", slog.String("field", key), slog.Any("cause", err)) - // return - // } - // value.Elem().FieldByName(key).Set(reflect.ValueOf(result)) - // } - - // err := v.WriteConfig() - // if err != nil { - // Logger.Error("error writing config", slog.Any("cause", err)) - // os.Exit(1) - // } - } -} - -// func objectToFlow(l *slog.Logger, value reflect.Value) { -// if value.Kind() == reflect.Pointer { -// if value.IsNil() { -// value = reflect.New(value.Type().Elem()) -// } -// value = value.Elem() -// } - -// typeOfValue := value.Type() -// for i := 0; i < value.NumField(); i++ { -// fieldValue := value.Field(i) -// fieldType := typeOfValue.Field(i) - -// l.Info("Processing field", slog.String("field", fieldType.Name)) -// } -// } - -// type field struct { -// set func(value reflect.Value) error -// } - -// type structField struct { -// name string - -// fields []field -// } - -// type primitiveField struct { -// } diff --git a/backend/cmd/configure/configure.go b/backend/cmd/configure/configure.go deleted file mode 100644 index ea2a6070c1..0000000000 --- a/backend/cmd/configure/configure.go +++ /dev/null @@ -1,111 +0,0 @@ -package configure - -import ( - "github.com/Masterminds/semver/v3" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var ( - // ConfigureCmd represents the config command - ConfigureCmd = &cobra.Command{ - Use: "configure", - Short: "Guides you through configuring Zitadel for the specified command", - // Long: `A longer description that spans multiple lines and likely contains examples - // and usage of using your command. For example: - - // Cobra is a CLI library for Go that empowers applications. - // This application is a tool to generate the needed files - // to quickly create a Cobra application.`, - // Run: func(cmd *cobra.Command, args []string) { - // fmt.Println("config called") - // // fmt.Println(viper.AllSettings()) - // // fmt.Println(viper.Sub("database").AllSettings()) - // // pool, err := config.Database.Connect(cmd.Context()) - // // _, _ = pool, err - // }, - PersistentPreRun: configurePreRun, - Run: func(cmd *cobra.Command, args []string) { - t := new(test) - // Update2(*t) - Update("test", "test", t.Fields())(cmd, args) - }, - } - - configuration Config -) - -func configurePreRun(cmd *cobra.Command, args []string) { - // cmd.InheritedFlags().Lookup("config").Hidden = true - ReadConfigPreRun(viper.GetViper(), &configuration)(cmd, args) -} - -func init() { - // Here you will define your flags and configuration settings. - ConfigureCmd.PersistentFlags().BoolVarP(&configuration.upgrade, "upgrade", "u", false, "Only changed configuration values since the previously used version will be asked for") - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // configureCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: -} - -type Config struct { - upgrade bool `mapstructure:"-"` -} - -func (c *Config) Hooks() []viper.DecoderConfigOption { - return nil -} - -type sub struct { - F1 string - F2 int - F3 *bool -} - -func (s sub) Fields() []Updater { - return []Updater{ - Field[string]{ - FieldName: "f1", - Value: "", - Description: "field 1", - Version: semver.MustParse("3"), - }, - Field[int]{ - FieldName: "f2", - Value: 0, - Description: "field 2", - Version: semver.MustParse("3"), - }, - Field[*bool]{ - FieldName: "f3", - Value: nil, - Description: "field 3", - Version: semver.MustParse("3"), - }, - } -} - -type test struct { - F1 string - Sub sub -} - -func (t test) Fields() []Updater { - return []Updater{ - Field[string]{ - FieldName: "f1", - Value: "", - Description: "field 1", - Version: semver.MustParse("3"), - }, - Struct{ - FieldName: "sub", - Description: "sub field", - SubFields: t.Sub.Fields(), - }, - } -} diff --git a/backend/cmd/configure/read.go b/backend/cmd/configure/read.go deleted file mode 100644 index 8656b5a4cc..0000000000 --- a/backend/cmd/configure/read.go +++ /dev/null @@ -1,25 +0,0 @@ -package configure - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -type Unmarshaller interface { - Hooks() []viper.DecoderConfigOption -} - -func ReadConfigPreRun[C Unmarshaller](v *viper.Viper, config C) func(cmd *cobra.Command, args []string) { - return func(cmd *cobra.Command, args []string) { - if err := v.Unmarshal(config, config.Hooks()...); err != nil { - panic(err) - } - } -} - -func ReadConfig[C Unmarshaller](v *viper.Viper) (config C, err error) { - if err := v.Unmarshal(&config, config.Hooks()...); err != nil { - return config, err - } - return config, nil -} diff --git a/backend/cmd/configure/update_config.go b/backend/cmd/configure/update_config.go deleted file mode 100644 index 2745e4bb40..0000000000 --- a/backend/cmd/configure/update_config.go +++ /dev/null @@ -1,449 +0,0 @@ -package configure - -import ( - "encoding/json" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - - "github.com/Masterminds/semver/v3" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/zitadel/zitadel/backend/cmd/info" -) - -var lastConfiguredVersion *semver.Version - -func Update(name, description string, fields []Updater) func(cmd *cobra.Command, args []string) { - return func(cmd *cobra.Command, args []string) { - configVersion := viper.GetString("configuredVersion") - if configVersion != "" { - lastConfiguredVersion, _ = semver.NewVersion(configVersion) - } - for _, field := range fields { - if err := setField(field, "", 1); err != nil { - panic(err) - } - } - - fmt.Println("Using config file:", viper.ConfigFileUsed(), "fields:", fields) - fmt.Println(viper.AllSettings()) - viper.Set("configuredVersion", info.Version().String()) - // viper.MergeConfigMap(fields) - // if err := viper.WriteConfig(); err != nil { - // panic(err) - // } - if err := viper.WriteConfig(); err != nil { - panic(err) - } - } -} - -func setField(field Updater, parentPath string, depth int) error { - if !field.ShouldUpdate(lastConfiguredVersion) { - prompt := promptui.Prompt{ - Label: field.Name() + " did not change since last configure, skip?", - IsConfirm: true, - } - if _, err := prompt.Run(); err == nil { - fmt.Println("skip") - return nil - } - } - fieldPath := path(parentPath, field.Name()) - switch f := field.(type) { - case StructUpdater: - fmt.Printf("\n%.*s %s: %s\n\n", depth*2, "-", f.Name(), f.Describe()) - for _, subField := range f.Fields() { - err := setField(subField, fieldPath, depth+1) - if err != nil { - return err - } - } - case FieldUpdater: - value := viper.Get(fieldPath) - if value == nil { - value = f.ValueOrDefault() - } - prompt := promptui.Prompt{ - Label: fmt.Sprintf("%s (%s) (%T)", f.Name(), f.Describe(), f.ValueOrDefault()), - Default: fmt.Sprintf("%v", value), - Validate: func(s string) error { - if isConfirm(reflect.TypeOf(value)) { - return nil - } - return f.Set(s) - }, - HideEntered: f.ShouldHide(), - IsConfirm: isConfirm(reflect.TypeOf(value)), - } - _, err := prompt.Run() - if err != nil { - panic(err) - } - viper.Set(fieldPath, f.ValueOrDefault()) - case OneOfUpdater: - var possibilities []string - for _, subField := range f.Fields() { - possibility := subField.Name() - if possibility == "" { - possibility = subField.Describe() - } - possibilities = append(possibilities, possibility) - } - - prompt := promptui.Select{ - Label: fmt.Sprintf("Select one of %s: (%s)", f.Name(), f.Describe()), - Items: possibilities, - } - i, _, err := prompt.Run() - if err != nil { - fmt.Println("panic", err) - panic(err) - } - setField(f.Fields()[i], fieldPath, depth-1) - // TODO: fv is result of decoder (postgres.config in this case) - case ConstantUpdater: - viper.Set(fieldPath, f.Value()) - } - return nil -} - -func path(parent, field string) string { - if parent == "" { - return field - } - if strings.HasSuffix(parent, field) { - return parent - } - if field == "" { - return parent - } - return parent + "." + field -} - -func isConfirm(t reflect.Type) bool { - if t == nil { - return false - } - if t.Kind() == reflect.Ptr { - return isConfirm(t.Elem()) - } - return t.Kind() == reflect.Bool -} - -type Updater interface { - Name() string - Describe() string - ShouldUpdate(version *semver.Version) bool -} - -type FieldUpdater interface { - Updater - // DefaultValue() any - Set(value any) error - ValueOrDefault() any - _field() - ShouldHide() bool -} - -type StructUpdater interface { - Updater - Fields() []Updater - _struct() -} - -type OneOfUpdater interface { - Updater - Fields() []Updater - _oneOf() -} - -type ConstantUpdater interface { - Updater - Value() any -} - -var _ FieldUpdater = (*Field[string])(nil) - -type Field[T any] struct { - FieldName string - Value T - HideInput bool - Description string - Version *semver.Version - Validate func(T) error -} - -// Describe implements [FieldUpdater]. -func (f Field[T]) Describe() string { - return f.Description -} - -// Set implements [FieldUpdater]. -func (f *Field[T]) Set(value any) (err error) { - switch v := value.(type) { - case string: - f.Value, err = mapString[T](v) - case map[string]any: - f.Value, err = mapMap[T](v) - case T: - f.Value = v - default: - err = fmt.Errorf("unsupported type %T", v) - } - - if err != nil || f.Validate == nil { - return err - } - - return f.Validate(f.Value) -} - -func (f Field[T]) ValueOrDefault() any { - return f.Value -} - -func mapMap[T any](value map[string]any) (t T, err error) { - jsonValue, err := json.Marshal(value) - if err != nil { - return t, err - } - return t, json.Unmarshal(jsonValue, &t) -} - -func mapString[T any](value string) (t T, err error) { - var v any - switch reflect.TypeFor[T]().Kind() { - case reflect.Bool: - v, err = strconv.ParseBool(value) - if err != nil { - return t, err - } - case reflect.Int: - i, err := strconv.ParseInt(value, 10, 0) - if err != nil { - return t, err - } - v = int(i) - case reflect.Int8: - i, err := strconv.ParseInt(value, 10, 8) - if err != nil { - return t, err - } - v = int8(i) - case reflect.Int16: - i, err := strconv.ParseInt(value, 10, 16) - if err != nil { - return t, err - } - v = int16(i) - case reflect.Int32: - i, err := strconv.ParseInt(value, 10, 32) - if err != nil { - return t, err - } - v = int32(i) - case reflect.Int64: - i, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return t, err - } - v = int64(i) - case reflect.Uint: - i, err := strconv.ParseUint(value, 10, 0) - if err != nil { - return t, err - } - v = uint(i) - case reflect.Uint8: - i, err := strconv.ParseUint(value, 10, 8) - if err != nil { - return t, err - } - v = uint8(i) - case reflect.Uint16: - i, err := strconv.ParseUint(value, 10, 16) - if err != nil { - return t, err - } - v = uint16(i) - case reflect.Uint32: - i, err := strconv.ParseUint(value, 10, 32) - if err != nil { - return t, err - } - v = uint32(i) - case reflect.Uint64: - i, err := strconv.ParseUint(value, 10, 64) - if err != nil { - return t, err - } - v = uint64(i) - case reflect.Float32: - i, err := strconv.ParseFloat(value, 32) - if err != nil { - return t, err - } - v = float32(i) - case reflect.Float64: - i, err := strconv.ParseFloat(value, 64) - if err != nil { - return t, err - } - v = float64(i) - case reflect.Complex64: - i, err := strconv.ParseComplex(value, 64) - if err != nil { - return t, err - } - v = complex64(i) - case reflect.Complex128: - v, err = strconv.ParseComplex(value, 128) - case reflect.String: - v = value - default: - k := reflect.TypeFor[T]().Kind() - _ = k - return t, errors.New("not implemented") - } - return v.(T), nil -} - -// Field implements [FieldUpdater]. -func (f Field[T]) Name() string { - return f.FieldName -} - -// ShouldUpdate implements [FieldUpdater]. -func (f Field[T]) ShouldUpdate(version *semver.Version) bool { - if version == nil { - return true - } - return f.Version.GreaterThan(version) -} - -// ShouldHide implements [FieldUpdater]. -func (f Field[T]) ShouldHide() bool { - return f.HideInput -} - -func (f Field[T]) _field() {} - -var _ StructUpdater = (*Struct)(nil) - -type Struct struct { - FieldName string - Description string - SubFields []Updater -} - -// Describe implements [StructUpdater]. -func (s Struct) Describe() string { - return s.Description -} - -func (s Struct) Name() string { - return s.FieldName -} - -func (s Struct) Fields() []Updater { - return s.SubFields -} - -func (s Struct) ShouldUpdate(version *semver.Version) bool { - if version == nil { - return true - } - for _, field := range s.SubFields { - if !field.ShouldUpdate(version) { - continue - } - return true - } - return false -} - -func (Struct) _struct() {} - -type OneOf struct { - FieldName string - Description string - SubFields []Updater -} - -// Describe implements [OneOfUpdater]. -func (o OneOf) Describe() string { - return o.Description -} - -// Fields implements [OneOfUpdater]. -func (o OneOf) Fields() []Updater { - return o.SubFields -} - -// Name implements [FieldUpdater]. -func (o OneOf) Name() string { - return o.FieldName -} - -func (OneOf) _oneOf() {} - -// ShouldUpdate implements [OneOfUpdater]. -func (o OneOf) ShouldUpdate(version *semver.Version) bool { - if version == nil { - return true - } - - for _, field := range o.SubFields { - if !field.ShouldUpdate(version) { - continue - } - return true - } - return false -} - -var _ OneOfUpdater = (*OneOf)(nil) - -func FieldName(parent, field string) string { - if parent == "" { - return field - } - return parent + "." + field -} - -type Constant[T any] struct { - Description string - Constant T - Version *semver.Version -} - -var _ ConstantUpdater = (*Constant[any])(nil) - -// Describe implements [ConstantUpdater]. -func (c Constant[T]) Describe() string { - return c.Description -} - -// Name implements [ConstantUpdater]. -func (c Constant[T]) Name() string { - return "" -} - -// ShouldUpdate implements [ConstantUpdater]. -func (c Constant[T]) ShouldUpdate(version *semver.Version) bool { - if version == nil { - return true - } - return c.Version.GreaterThan(version) -} - -// Value implements [ConstantUpdater]. -func (c Constant[T]) Value() any { - return c.Constant -} diff --git a/backend/cmd/info/config.go b/backend/cmd/info/config.go deleted file mode 100644 index f5ac8cf5a7..0000000000 --- a/backend/cmd/info/config.go +++ /dev/null @@ -1,36 +0,0 @@ -package info - -import ( - "time" - - "github.com/Masterminds/semver/v3" -) - -var ( - version string - commit string - date string -) - -func Version() *semver.Version { - v, _ := semver.NewVersion(version) - if v != nil { - return v - } - return semver.New(uint64(Date().Year()), uint64(Date().Month()), uint64(Date().Day()), "", "") -} - -func Commit() string { - return commit -} - -func Date() time.Time { - if date == "" { - return time.Now() - } - d, err := time.Parse(time.RFC3339, date) - if err != nil { - return time.Now() - } - return d -} diff --git a/backend/cmd/prepare/001/sql/001_user.sql b/backend/cmd/prepare/001/sql/001_user.sql deleted file mode 100644 index 95b6c5b98a..0000000000 --- a/backend/cmd/prepare/001/sql/001_user.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE USER IF NOT EXISTS {{ .Username}}; \ No newline at end of file diff --git a/backend/cmd/prepare/001/sql/002_database.sql b/backend/cmd/prepare/001/sql/002_database.sql deleted file mode 100644 index f80389acad..0000000000 --- a/backend/cmd/prepare/001/sql/002_database.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE DATABASE IF NOT EXISTS {{ .DatabaseName }} WITH OWNER {{ .Username }}; \ No newline at end of file diff --git a/backend/cmd/prepare/001/step_001.go b/backend/cmd/prepare/001/step_001.go deleted file mode 100644 index ba9d077c97..0000000000 --- a/backend/cmd/prepare/001/step_001.go +++ /dev/null @@ -1,67 +0,0 @@ -package step001 - -import ( - "context" - "embed" - "fmt" - - "github.com/Masterminds/semver/v3" - - "github.com/zitadel/zitadel/backend/cmd/configure" - "github.com/zitadel/zitadel/backend/storage/database" -) - -var ( - //go:embed sql/*.sql - migrations embed.FS -) - -type Step001 struct { - Database database.Pool `mapstructure:"-" configure:"-"` - - DatabaseName string `configure:"default=zitadel"` - Username string `configure:"default=zitadel"` -} - -// Fields implements configure.StructUpdater. -func (v Step001) Fields() []configure.Updater { - return []configure.Updater{ - &configure.Field[string]{ - FieldName: "databaseName", - Value: "zitadel", - Description: "The name of the database Zitadel will store its data in", - Version: semver.MustParse("3"), - }, - &configure.Field[string]{ - FieldName: "username", - Value: "zitadel", - Description: "The username Zitadel will use to connect to the database", - Version: semver.MustParse("3"), - }, - } -} - -// Name implements configure.StructUpdater. -func (v *Step001) Name() string { - return "step001" -} - -// var _ configure.StructUpdater = (*Step001)(nil) - -func (v *Step001) Migrate(ctx context.Context) error { - files, err := migrations.ReadDir("sql") - if err != nil { - return err - } - for _, file := range files { - fmt.Println(file.Name()) - fmt.Println(migrations.ReadFile(file.Name())) - } - conn, err := v.Database.Acquire(ctx) - if err != nil { - return err - } - defer conn.Release(ctx) - - return nil -} diff --git a/backend/cmd/prepare/config.go b/backend/cmd/prepare/config.go deleted file mode 100644 index 3c22efea14..0000000000 --- a/backend/cmd/prepare/config.go +++ /dev/null @@ -1,83 +0,0 @@ -package prepare - -import ( - "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/bla4" - step001 "github.com/zitadel/zitadel/backend/cmd/prepare/001" - "github.com/zitadel/zitadel/backend/storage/database" - "github.com/zitadel/zitadel/backend/storage/database/dialect" -) - -var ( - configuration Config - - // configurePrepare represents the prepare command - configurePrepare = &cobra.Command{ - Use: "prepare", - Short: "Writes the configuration for the prepare command", - // Long: `A longer description that spans multiple lines and likely contains examples - // and usage of using your command. For example: - - // Cobra is a CLI library for Go that empowers applications. - // 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 - // config.Client, err = config.Database.Connect(cmd.Context()) - // if err != nil { - // panic(err) - // } - // defer config.Client.Close(cmd.Context()) - // if err := (&step001.Step001{Database: config.Client}).Migrate(cmd.Context()); err != nil { - // panic(err) - // } - // }, - // Run: configure.Update( - // "prepare", - // "Writes the configuration for the prepare command", - // configuration.Fields(), - // ), - Run: func(cmd *cobra.Command, args []string) { - bla4.Update(viper.GetViper(), &configuration)(cmd, args) - }, - PreRun: configure.ReadConfigPreRun(viper.GetViper(), &configuration), - } -) - -type Config struct { - config.Config `mapstructure:",squash" configure:"-"` - - Database *dialect.Config // `configure:"-"` - Step001 step001.Step001 - Step002 *step001.Step001 - - // runtime config - Client database.Pool `mapstructure:"-" configure:"-"` -} - -func (c *Config) Hooks() (decoders []viper.DecoderConfigOption) { - // for _, hooks := range []configure.Unmarshaller{ - // c.Config, - // c.Database, - // } { - // decoders = append(decoders, hooks.Hooks()...) - // } - return decoders -} - -func init() { - configure.ConfigureCmd.AddCommand(configurePrepare) - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // prepareCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // prepareCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/backend/cmd/prepare/prepare.go b/backend/cmd/prepare/prepare.go deleted file mode 100644 index 7e71f1f5a1..0000000000 --- a/backend/cmd/prepare/prepare.go +++ /dev/null @@ -1,35 +0,0 @@ -package prepare - -import ( - "github.com/spf13/cobra" - - step001 "github.com/zitadel/zitadel/backend/cmd/prepare/001" -) - -var ( - // PrepareCmd represents the prepare command - PrepareCmd = &cobra.Command{ - Use: "prepare", - Short: "Prepares external services before starting Zitadel", - // Long: `A longer description that spans multiple lines and likely contains examples - // and usage of using your command. For example: - - // Cobra is a CLI library for Go that empowers applications. - // 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) - // } - defer configuration.Client.Close(cmd.Context()) - if err := (&step001.Step001{Database: configuration.Client}).Migrate(cmd.Context()); err != nil { - panic(err) - } - }, - } -) - -type Migration interface { -} diff --git a/backend/cmd/root.go b/backend/cmd/root.go deleted file mode 100644 index 06233f2676..0000000000 --- a/backend/cmd/root.go +++ /dev/null @@ -1,52 +0,0 @@ -package cmd - -import ( - "os" - - "github.com/spf13/cobra" - "github.com/zitadel/zitadel/backend/cmd/config" - "github.com/zitadel/zitadel/backend/cmd/configure" - "github.com/zitadel/zitadel/backend/cmd/prepare" - "github.com/zitadel/zitadel/backend/cmd/start" - "github.com/zitadel/zitadel/backend/cmd/upgrade" -) - -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ - Use: "zitadel [subcommand]", - Short: "A brief description of your application", - Long: `zitadel`, - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, -} - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - err := RootCmd.Execute() - if err != nil { - os.Exit(1) - } -} - -func init() { - RootCmd.AddCommand( - configure.ConfigureCmd, - prepare.PrepareCmd, - start.StartCmd, - upgrade.UpgradeCmd, - ) - - cobra.OnInitialize(config.InitConfig) - - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - - RootCmd.PersistentFlags().StringVar(&config.Path, "config", "", "config file (default is $HOME/.zitadel.yaml)") - - // Cobra also supports local flags, which will only run - // when this action is called directly. - RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/backend/cmd/start/config.go b/backend/cmd/start/config.go deleted file mode 100644 index 52e9ee1e60..0000000000 --- a/backend/cmd/start/config.go +++ /dev/null @@ -1,15 +0,0 @@ -package start - -import ( - "github.com/spf13/viper" - - "github.com/zitadel/zitadel/backend/storage/database/dialect" -) - -type Config struct { - Database dialect.Config `version:"v3"` -} - -func (c Config) Hooks() []viper.DecoderConfigOption { - return c.Database.Hooks() -} diff --git a/backend/cmd/start/start.go b/backend/cmd/start/start.go deleted file mode 100644 index fb045cd9a3..0000000000 --- a/backend/cmd/start/start.go +++ /dev/null @@ -1,41 +0,0 @@ -package start - -import ( - "fmt" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/zitadel/zitadel/backend/cmd/configure" -) - -var ( - // StartCmd represents the start command - StartCmd = &cobra.Command{ - Use: "start", - Short: "Starts the Zitadel server", - // Long: `A longer description that spans multiple lines and likely contains examples - // and usage of using your command. For example: - - // Cobra is a CLI library for Go that empowers applications. - // This application is a tool to generate the needed files - // to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("start called") - }, - PreRun: configure.ReadConfigPreRun(viper.GetViper(), &config), - } - - config Config -) - -func init() { - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // startCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // startCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/backend/cmd/test.yaml b/backend/cmd/test.yaml deleted file mode 100644 index 094bc2899c..0000000000 --- a/backend/cmd/test.yaml +++ /dev/null @@ -1,8 +0,0 @@ -database: - postgres: host=localhost user=zitadel password= dbname=zitadel sslmode=disable test=test -step001: - databasename: qwer - username: asdf -step002: - databasename: yuio - username: hjkl diff --git a/backend/cmd/upgrade/upgrade.go b/backend/cmd/upgrade/upgrade.go deleted file mode 100644 index 9d92aca3a5..0000000000 --- a/backend/cmd/upgrade/upgrade.go +++ /dev/null @@ -1,34 +0,0 @@ -package upgrade - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -// UpgradeCmd represents the upgrade command -var UpgradeCmd = &cobra.Command{ - Use: "upgrade", - Short: "Upgrades Zitadel from a previous version", - // Long: `A longer description that spans multiple lines and likely contains examples - // and usage of using your command. For example: - - // Cobra is a CLI library for Go that empowers applications. - // This application is a tool to generate the needed files - // to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("upgrade called") - }, -} - -func init() { - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // upgradeCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // upgradeCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -}