mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 15:17:33 +00:00
init configure
This commit is contained in:
@@ -1,45 +1,74 @@
|
||||
/*
|
||||
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"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",
|
||||
// Long: `A longer description that spans multiple lines and likely contains examples
|
||||
// and usage of using your command. For example:
|
||||
type Config struct {
|
||||
Version Version
|
||||
}
|
||||
|
||||
// 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())
|
||||
viper.en
|
||||
},
|
||||
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")
|
||||
}
|
||||
|
||||
upgrade bool
|
||||
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 init() {
|
||||
// Here you will define your flags and configuration settings.
|
||||
ConfigureCmd.Flags().BoolVarP(&upgrade, "upgrade", "u", false, "Only changed configuration values since the previously used version will be asked for")
|
||||
func decodeVersion(from, to reflect.Value) (_ interface{}, err error) {
|
||||
if to.Type() != reflect.TypeOf(Version(0)) {
|
||||
return from.Interface(), nil
|
||||
}
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// configureCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
switch from.Interface().(string) {
|
||||
case "":
|
||||
return VersionUnknown, nil
|
||||
case "v3":
|
||||
return V3, nil
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unsupported version: %v", from.Interface())
|
||||
}
|
||||
|
@@ -1,41 +1,48 @@
|
||||
package configure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/storage/database/dialect"
|
||||
"github.com/zitadel/zitadel/backend/cmd/config"
|
||||
)
|
||||
|
||||
var (
|
||||
// ConfigureCmd represents the config command
|
||||
ConfigureCmd = &cobra.Command{
|
||||
Use: "configure",
|
||||
Short: "Guides you through configuring Zitadel",
|
||||
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) {
|
||||
fmt.Println("config called")
|
||||
fmt.Println(viper.AllSettings())
|
||||
fmt.Println(viper.Sub("database").AllSettings())
|
||||
pool, err := config.Database.Connect(cmd.Context())
|
||||
_, _ = pool, err
|
||||
t := new(test)
|
||||
// Update2(*t)
|
||||
Update("test", "test", t.Fields())(cmd, args)
|
||||
},
|
||||
PreRun: ReadConfigPreRun[Config](viper.GetViper(), &config),
|
||||
}
|
||||
|
||||
config Config
|
||||
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.Flags().BoolVarP(&config.upgrade, "upgrade", "u", false, "Only changed configuration values since the previously used version will be asked for")
|
||||
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.:
|
||||
@@ -46,11 +53,63 @@ func init() {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Database dialect.Config
|
||||
|
||||
upgrade bool
|
||||
upgrade bool `mapstructure:"-"`
|
||||
}
|
||||
|
||||
func (c Config) Hooks() []viper.DecoderConfigOption {
|
||||
return c.Database.Hooks()
|
||||
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: &s.F1,
|
||||
Default: "",
|
||||
Description: "field 1",
|
||||
Version: config.V3,
|
||||
},
|
||||
Field[int]{
|
||||
FieldName: "f2",
|
||||
Value: &s.F2,
|
||||
Default: 0,
|
||||
Description: "field 2",
|
||||
Version: config.V3,
|
||||
},
|
||||
Field[*bool]{
|
||||
FieldName: "f3",
|
||||
Value: &s.F3,
|
||||
Default: nil,
|
||||
Description: "field 3",
|
||||
Version: config.V3,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type test struct {
|
||||
F1 string
|
||||
Sub sub
|
||||
}
|
||||
|
||||
func (t test) Fields() []Updater {
|
||||
return []Updater{
|
||||
Field[string]{
|
||||
FieldName: "f1",
|
||||
Value: &t.F1,
|
||||
Default: "",
|
||||
Description: "field 1",
|
||||
Version: config.V3,
|
||||
},
|
||||
Struct{
|
||||
FieldName: "sub",
|
||||
Description: "sub field",
|
||||
SubFields: t.Sub.Fields(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@@ -9,18 +9,17 @@ type Unmarshaller interface {
|
||||
Hooks() []viper.DecoderConfigOption
|
||||
}
|
||||
|
||||
func ReadConfigPreRun[C Unmarshaller](v *viper.Viper, config *C) func(cmd *cobra.Command, args []string) {
|
||||
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 {
|
||||
if err := v.Unmarshal(config, config.Hooks()...); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ReadConfig[C Unmarshaller](v *viper.Viper) (*C, error) {
|
||||
var config C
|
||||
func ReadConfig[C Unmarshaller](v *viper.Viper) (config C, err error) {
|
||||
if err := v.Unmarshal(&config, config.Hooks()...); err != nil {
|
||||
return nil, err
|
||||
return config, err
|
||||
}
|
||||
return &config, nil
|
||||
return config, nil
|
||||
}
|
||||
|
243
backend/cmd/configure/update_config.go
Normal file
243
backend/cmd/configure/update_config.go
Normal file
@@ -0,0 +1,243 @@
|
||||
package configure
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/zitadel/zitadel/backend/cmd/config"
|
||||
)
|
||||
|
||||
func Update(name, description string, fields []Updater) func(cmd *cobra.Command, args []string) {
|
||||
return func(cmd *cobra.Command, args []string) {
|
||||
u := Struct{
|
||||
FieldName: name,
|
||||
Description: description,
|
||||
SubFields: fields,
|
||||
}
|
||||
fields := viper.AllSettings()
|
||||
updateStruct(u, fields, 1)
|
||||
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed(), "fields:", fields)
|
||||
// viper.MergeConfigMap(fields)
|
||||
// if err := viper.WriteConfig(); err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
func updateStruct(updater StructUpdater, fields map[string]any, depth int) {
|
||||
for _, field := range updater.Fields() {
|
||||
// fmt.Printf("field: %s.%s\n %s\n", parent, field.Name(), field.Describe())
|
||||
setField(field, fields, depth)
|
||||
}
|
||||
}
|
||||
|
||||
func setField(field Updater, fields map[string]any, depth int) {
|
||||
if !field.ShouldUpdate(config.V3) {
|
||||
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
|
||||
}
|
||||
return
|
||||
}
|
||||
fmt.Println(field.Name(), field.Describe())
|
||||
switch f := field.(type) {
|
||||
case StructUpdater:
|
||||
if fields[f.Name()] == nil {
|
||||
fields[f.Name()] = map[string]any{}
|
||||
}
|
||||
fmt.Printf("%.*s %s: %s\n", depth*2, "-", f.Name(), f.Describe())
|
||||
updateStruct(f, fields[f.Name()].(map[string]any), depth+1)
|
||||
case FieldUpdater:
|
||||
prompt := promptui.Prompt{
|
||||
Label: fmt.Sprintf("%s (%s) (%T)", f.Name(), f.Describe(), f.DefaultValue()),
|
||||
Default: fmt.Sprintf("%v", f.DefaultValue()),
|
||||
Validate: func(s string) error {
|
||||
if isConfirm(reflect.TypeOf(f.DefaultValue())) {
|
||||
return nil
|
||||
}
|
||||
return f.Set(s)
|
||||
},
|
||||
IsConfirm: isConfirm(reflect.TypeOf(f.DefaultValue())),
|
||||
}
|
||||
val, err := prompt.Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fields[f.Name()] = f.Set(val)
|
||||
case OneOfUpdater:
|
||||
var possibilities []string
|
||||
for _, subField := range f.Fields() {
|
||||
possibilities = append(possibilities, subField.Name())
|
||||
fields[subField.Name()] = subField
|
||||
}
|
||||
|
||||
prompt := promptui.Select{
|
||||
Label: fmt.Sprintf("Select one of %s: (%s)", f.Name(), f.Describe()),
|
||||
Items: possibilities,
|
||||
}
|
||||
i, _, err := prompt.Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
setField(f.Fields()[i], fields, depth+1)
|
||||
}
|
||||
}
|
||||
|
||||
func isConfirm(t reflect.Type) bool {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
return isConfirm(t.Elem())
|
||||
}
|
||||
return t.Kind() == reflect.Bool
|
||||
}
|
||||
|
||||
type Updater interface {
|
||||
Name() string
|
||||
Describe() string
|
||||
ShouldUpdate(version config.Version) bool
|
||||
}
|
||||
|
||||
type FieldUpdater interface {
|
||||
Updater
|
||||
DefaultValue() any
|
||||
Set(value string) error
|
||||
_field()
|
||||
}
|
||||
|
||||
type StructUpdater interface {
|
||||
Updater
|
||||
Fields() []Updater
|
||||
_struct()
|
||||
}
|
||||
|
||||
type OneOfUpdater interface {
|
||||
Updater
|
||||
Fields() []Updater
|
||||
_oneOf()
|
||||
}
|
||||
|
||||
var _ FieldUpdater = (*Field[string])(nil)
|
||||
|
||||
type Field[T any] struct {
|
||||
FieldName string
|
||||
Default T
|
||||
Value *T
|
||||
Description string
|
||||
Version config.Version
|
||||
}
|
||||
|
||||
// DefaultValue implements [FieldUpdater].
|
||||
func (uf Field[T]) DefaultValue() any {
|
||||
return uf.Default
|
||||
}
|
||||
|
||||
// Describe implements [FieldUpdater].
|
||||
func (uf Field[T]) Describe() string {
|
||||
return uf.Description
|
||||
}
|
||||
|
||||
// Set implements [FieldUpdater].
|
||||
func (uf Field[T]) Set(value string) error {
|
||||
var v T
|
||||
if err := json.Unmarshal([]byte(value), &v); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal value: %v", err)
|
||||
}
|
||||
*uf.Value = v
|
||||
return nil
|
||||
}
|
||||
|
||||
// Field implements [FieldUpdater].
|
||||
func (uf Field[T]) Name() string {
|
||||
return uf.FieldName
|
||||
}
|
||||
|
||||
// ShouldUpdate implements [FieldUpdater].
|
||||
func (uf Field[T]) ShouldUpdate(version config.Version) bool {
|
||||
return uf.Version <= version
|
||||
}
|
||||
|
||||
func (f Field[T]) _field() {}
|
||||
|
||||
var _ StructUpdater = (*Struct)(nil)
|
||||
|
||||
type Struct struct {
|
||||
FieldName string
|
||||
Description string
|
||||
SubFields []Updater
|
||||
}
|
||||
|
||||
// Describe implements [StructUpdater].
|
||||
func (us Struct) Describe() string {
|
||||
return us.Description
|
||||
}
|
||||
|
||||
func (us Struct) Name() string {
|
||||
return us.FieldName
|
||||
}
|
||||
|
||||
func (us Struct) Fields() []Updater {
|
||||
return us.SubFields
|
||||
}
|
||||
|
||||
func (f 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 (f OneOf) _oneOf() {}
|
||||
|
||||
// ShouldUpdate implements [OneOfUpdater].
|
||||
func (o OneOf) ShouldUpdate(version config.Version) bool {
|
||||
for _, field := range o.SubFields {
|
||||
if !field.ShouldUpdate(version) {
|
||||
continue
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var _ OneOfUpdater = (*OneOf)(nil)
|
||||
|
||||
func (us Struct) ShouldUpdate(version config.Version) bool {
|
||||
for _, field := range us.SubFields {
|
||||
if !field.ShouldUpdate(version) {
|
||||
continue
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func FieldName(parent, field string) string {
|
||||
if parent == "" {
|
||||
return field
|
||||
}
|
||||
return parent + "." + field
|
||||
}
|
109
backend/cmd/configure/update_config2.go
Normal file
109
backend/cmd/configure/update_config2.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package configure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/manifoldco/promptui"
|
||||
)
|
||||
|
||||
func Update2(config any) {
|
||||
// Print the intro
|
||||
printIntro()
|
||||
|
||||
// Start the interactive CLI
|
||||
interactiveCLI(reflect.ValueOf(config), 0)
|
||||
fmt.Println(config)
|
||||
}
|
||||
|
||||
const (
|
||||
ExitValue = "<Exit>"
|
||||
BackValue = "⬅ Back"
|
||||
Prefix = "📁 "
|
||||
)
|
||||
|
||||
var introTemplate = `
|
||||
+----------------------------------------+
|
||||
| 🛠 Config Interactive CLI 🛠 |
|
||||
+----------------------------------------+
|
||||
| |
|
||||
| %5s : Dive into nested config |
|
||||
| %6s : Return to previous menu |
|
||||
| %6s : Exit application |
|
||||
| |
|
||||
| Choose an option to explore! |
|
||||
| |
|
||||
+----------------------------------------+
|
||||
`
|
||||
|
||||
func printIntro() {
|
||||
fmt.Printf(introTemplate, Prefix, BackValue, ExitValue)
|
||||
}
|
||||
|
||||
// interactiveCLI handles the interactive CLI
|
||||
func interactiveCLI(v reflect.Value, depth int) {
|
||||
for {
|
||||
var items []string
|
||||
|
||||
// If depth is greater than 0, we are in a nested struct and should add a "Back" option
|
||||
if depth > 0 {
|
||||
items = append(items, BackValue)
|
||||
}
|
||||
|
||||
// Add all the field names
|
||||
items = append(items, getFieldNames(v)...)
|
||||
|
||||
// Add an "Exit" option
|
||||
items = append(items, ExitValue)
|
||||
|
||||
prompt := promptui.Select{
|
||||
Label: "Select Field",
|
||||
Items: items,
|
||||
}
|
||||
|
||||
_, result, err := prompt.Run()
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Prompt failed %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case BackValue:
|
||||
return
|
||||
case ExitValue:
|
||||
// Exit the entire application
|
||||
os.Exit(0)
|
||||
default:
|
||||
fieldName := strings.TrimPrefix(result, Prefix)
|
||||
selectedField := v.FieldByName(fieldName)
|
||||
if selectedField.Kind() == reflect.Struct {
|
||||
interactiveCLI(selectedField, depth+1)
|
||||
} else {
|
||||
prompt := promptui.Prompt{
|
||||
Label: fmt.Sprintf("Field %s (%s)", result, selectedField.Kind()),
|
||||
Default: fmt.Sprintf("%v", selectedField.Interface()),
|
||||
}
|
||||
res, err := prompt.Run()
|
||||
fmt.Println(res, err)
|
||||
// fmt.Printf("%s: %v\n", result, selectedField.Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getFieldNames returns all the field names
|
||||
func getFieldNames(v reflect.Value) []string {
|
||||
t := v.Type()
|
||||
var fieldNames []string
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
fieldName := t.Field(i).Name
|
||||
if v.Field(i).Kind() == reflect.Struct {
|
||||
fieldName = Prefix + fieldName
|
||||
}
|
||||
fieldNames = append(fieldNames, fieldName)
|
||||
}
|
||||
return fieldNames
|
||||
}
|
1
backend/cmd/prepare/001/sql/001_user.sql
Normal file
1
backend/cmd/prepare/001/sql/001_user.sql
Normal file
@@ -0,0 +1 @@
|
||||
CREATE USER IF NOT EXISTS {{ .Username}};
|
1
backend/cmd/prepare/001/sql/002_database.sql
Normal file
1
backend/cmd/prepare/001/sql/002_database.sql
Normal file
@@ -0,0 +1 @@
|
||||
CREATE DATABASE IF NOT EXISTS {{ .DatabaseName }} WITH OWNER {{ .Username }};
|
68
backend/cmd/prepare/001/step_001.go
Normal file
68
backend/cmd/prepare/001/step_001.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package step001
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/cmd/config"
|
||||
"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:"-"`
|
||||
|
||||
DatabaseName string `configure:"added:"v3",default:"zitadel"`
|
||||
Username string `configure:"added:"v3",default:"zitadel"`
|
||||
}
|
||||
|
||||
// Fields implements configure.StructUpdater.
|
||||
func (v Step001) Fields() []configure.Updater {
|
||||
return []configure.Updater{
|
||||
configure.Field[string]{
|
||||
FieldName: "databaseName",
|
||||
Default: "zitadel",
|
||||
Value: &v.DatabaseName,
|
||||
Description: "The name of the database Zitadel will store its data in",
|
||||
Version: config.V3,
|
||||
},
|
||||
configure.Field[string]{
|
||||
FieldName: "username",
|
||||
Default: "zitadel",
|
||||
Value: &v.Username,
|
||||
Description: "The username Zitadel will use to connect to the database",
|
||||
Version: config.V3,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
114
backend/cmd/prepare/config.go
Normal file
114
backend/cmd/prepare/config.go
Normal file
@@ -0,0 +1,114 @@
|
||||
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"
|
||||
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(),
|
||||
),
|
||||
PreRun: configure.ReadConfigPreRun(viper.GetViper(), &configuration),
|
||||
}
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
config.Config `mapstructure:",squash"`
|
||||
|
||||
Database dialect.Config
|
||||
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 config.Version) bool {
|
||||
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(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
@@ -1,18 +1,15 @@
|
||||
/*
|
||||
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package prepare
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
step001 "github.com/zitadel/zitadel/backend/cmd/prepare/001"
|
||||
)
|
||||
|
||||
// PrepareCmd represents the prepare command
|
||||
var PrepareCmd = &cobra.Command{
|
||||
var (
|
||||
// PrepareCmd represents the prepare command
|
||||
PrepareCmd = &cobra.Command{
|
||||
Use: "prepare",
|
||||
Short: "Prepares the environment before starting Zitadel",
|
||||
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:
|
||||
|
||||
@@ -20,18 +17,18 @@ var PrepareCmd = &cobra.Command{
|
||||
// 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("prepare called")
|
||||
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)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
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.:
|
||||
// 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")
|
||||
}
|
||||
)
|
||||
|
||||
type Migration interface {
|
||||
}
|
||||
|
@@ -1,23 +0,0 @@
|
||||
package prepare
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/storage/database"
|
||||
"github.com/zitadel/zitadel/backend/storage/eventstore"
|
||||
)
|
||||
|
||||
type Step001 struct {
|
||||
Database database.Pool
|
||||
}
|
||||
|
||||
func (v *Step001) Migrate(ctx context.Context) error {
|
||||
conn, err := v.Database.Acquire(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Release(ctx)
|
||||
|
||||
eventstore.New(conn).
|
||||
return nil
|
||||
}
|
@@ -1,29 +1,21 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"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/prepare"
|
||||
"github.com/zitadel/zitadel/backend/cmd/start"
|
||||
"github.com/zitadel/zitadel/backend/cmd/upgrade"
|
||||
)
|
||||
|
||||
var cfgFile string
|
||||
|
||||
// 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: `A longer description that spans multiple lines and likely contains
|
||||
examples and usage of using your application. 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.`,
|
||||
Long: `zitadel`,
|
||||
// Uncomment the following line if your bare application
|
||||
// has an action associated with it:
|
||||
// Run: func(cmd *cobra.Command, args []string) { },
|
||||
@@ -39,46 +31,22 @@ func Execute() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(config.ConfigureCmd)
|
||||
RootCmd.AddCommand(prepare.PrepareCmd)
|
||||
RootCmd.AddCommand(start.StartCmd)
|
||||
RootCmd.AddCommand(upgrade.UpgradeCmd)
|
||||
RootCmd.AddCommand(
|
||||
configure.ConfigureCmd,
|
||||
prepare.PrepareCmd,
|
||||
start.StartCmd,
|
||||
upgrade.UpgradeCmd,
|
||||
)
|
||||
|
||||
cobra.OnInitialize(initConfig)
|
||||
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(&cfgFile, "config", "", "config file (default is $HOME/.zitadel.yaml)")
|
||||
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")
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
func initConfig() {
|
||||
if cfgFile != "" {
|
||||
// Use config file from the flag.
|
||||
viper.SetConfigFile(cfgFile)
|
||||
} 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.AllowEmptyEnv(true)
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Database dialect.Config
|
||||
Database dialect.Config `version:"v3"`
|
||||
}
|
||||
|
||||
func (c Config) Hooks() []viper.DecoderConfigOption {
|
||||
|
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package start
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/zitadel/zitadel/backend/cmd/configure"
|
||||
)
|
||||
|
||||
// StartCmd represents the start command
|
||||
var StartCmd = &cobra.Command{
|
||||
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
|
||||
@@ -22,7 +22,11 @@ var StartCmd = &cobra.Command{
|
||||
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.
|
||||
|
@@ -1,5 +1,19 @@
|
||||
database:
|
||||
postgres: 'something'
|
||||
cockroach:
|
||||
host: localhost
|
||||
port: 26257
|
||||
gosql:
|
||||
fieldname: gosql
|
||||
default: null
|
||||
value: null
|
||||
description: Configuration for connection string for gosql
|
||||
version: 1
|
||||
postgres:
|
||||
fieldname: postgres
|
||||
default: null
|
||||
value: null
|
||||
description: Configuration for connection string for postgres
|
||||
version: 1
|
||||
step001:
|
||||
databasename: zitadel
|
||||
username: zitadel
|
||||
|
@@ -1,6 +1,3 @@
|
||||
/*
|
||||
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package upgrade
|
||||
|
||||
import (
|
||||
@@ -25,7 +22,6 @@ var UpgradeCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package database
|
||||
|
||||
var Config = make(map[string]any)
|
||||
import "context"
|
||||
|
||||
func AddDatabaseConfig(name string, configure func(map[string]any) error) {
|
||||
Config[name] = configure
|
||||
type Connector interface {
|
||||
Connect(ctx context.Context) (Pool, error)
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ type Row interface {
|
||||
type Rows interface {
|
||||
Row
|
||||
Next() bool
|
||||
Close()
|
||||
Close() error
|
||||
Err() error
|
||||
}
|
||||
|
||||
|
@@ -3,11 +3,14 @@ package dialect
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/cmd/config"
|
||||
"github.com/zitadel/zitadel/backend/cmd/configure"
|
||||
"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"
|
||||
@@ -16,6 +19,7 @@ import (
|
||||
type Hook struct {
|
||||
Match func(string) bool
|
||||
Decode func(name string, config any) (database.Connector, error)
|
||||
Name string
|
||||
}
|
||||
|
||||
var hooks = make([]Hook, 0)
|
||||
@@ -25,10 +29,12 @@ func init() {
|
||||
Hook{
|
||||
Match: postgres.NameMatcher,
|
||||
Decode: postgres.DecodeConfig,
|
||||
Name: postgres.Name,
|
||||
},
|
||||
Hook{
|
||||
Match: gosql.NameMatcher,
|
||||
Decode: gosql.DecodeConfig,
|
||||
Name: gosql.Name,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -39,6 +45,42 @@ type Config struct {
|
||||
connector database.Connector
|
||||
}
|
||||
|
||||
// Fields implements [configure.StructUpdater].
|
||||
func (c *Config) Fields() []configure.Updater {
|
||||
dialects := configure.OneOf{
|
||||
FieldName: "dialect",
|
||||
Description: "The database dialect Zitadel connects to",
|
||||
SubFields: []configure.Updater{},
|
||||
}
|
||||
for _, hook := range hooks {
|
||||
value := c.Dialects[hook.Name]
|
||||
dialects.SubFields = append(dialects.SubFields, &configure.Field[any]{
|
||||
FieldName: hook.Name,
|
||||
Default: nil,
|
||||
Description: fmt.Sprintf("Configuration for connection string for %s", hook.Name),
|
||||
Version: config.V3,
|
||||
Value: &value,
|
||||
})
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
return c.connector.Connect(ctx)
|
||||
}
|
||||
|
||||
// Hooks implements [configure.Unmarshaller].
|
||||
func (c Config) Hooks() []viper.DecoderConfigOption {
|
||||
return []viper.DecoderConfigOption{
|
||||
@@ -46,8 +88,10 @@ func (c Config) Hooks() []viper.DecoderConfigOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (c Config) Connect(ctx context.Context) (database.Pool, error) {
|
||||
return c.connector.Connect(ctx)
|
||||
// var _ configure.StructUpdater = (*Config)(nil)
|
||||
|
||||
func (c Config) Configure(v *viper.Viper, currentVersion config.Version) Config {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Config) decodeDialect() error {
|
||||
|
@@ -9,7 +9,10 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/storage/database"
|
||||
)
|
||||
|
||||
var _ database.Connector = (*Config)(nil)
|
||||
var (
|
||||
_ database.Connector = (*Config)(nil)
|
||||
Name = "gosql"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
db *sql.DB
|
||||
|
@@ -11,7 +11,10 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/storage/database"
|
||||
)
|
||||
|
||||
var _ database.Connector = (*Config)(nil)
|
||||
var (
|
||||
_ database.Connector = (*Config)(nil)
|
||||
Name = "postgres"
|
||||
)
|
||||
|
||||
type Config struct{ *pgxpool.Config }
|
||||
|
||||
|
@@ -1,4 +0,0 @@
|
||||
package postgres
|
||||
|
||||
type Config struct {
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/zitadel/zitadel/backend/storage/database"
|
||||
)
|
||||
|
||||
type pgxConn struct{ *pgxpool.Conn }
|
||||
|
||||
var _ database.Client = (*pgxConn)(nil)
|
||||
|
||||
// Release implements [database.Client].
|
||||
func (c *pgxConn) Release(_ context.Context) error {
|
||||
c.Conn.Release()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Begin implements [database.Client].
|
||||
func (c *pgxConn) Begin(ctx context.Context, opts *database.TransactionOptions) (database.Transaction, error) {
|
||||
tx, err := c.Conn.BeginTx(ctx, transactionOptionsToPgx(opts))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pgxTx{tx}, nil
|
||||
}
|
||||
|
||||
// Query implements sql.Client.
|
||||
// Subtle: this method shadows the method (*Conn).Query of pgxConn.Conn.
|
||||
func (c *pgxConn) Query(ctx context.Context, sql string, args ...any) (database.Rows, error) {
|
||||
return c.Conn.Query(ctx, sql, args...)
|
||||
}
|
||||
|
||||
// QueryRow implements sql.Client.
|
||||
// Subtle: this method shadows the method (*Conn).QueryRow of pgxConn.Conn.
|
||||
func (c *pgxConn) QueryRow(ctx context.Context, sql string, args ...any) database.Row {
|
||||
return c.Conn.QueryRow(ctx, sql, args...)
|
||||
}
|
||||
|
||||
// Exec implements [database.Pool].
|
||||
// Subtle: this method shadows the method (Pool).Exec of pgxPool.Pool.
|
||||
func (c *pgxConn) Exec(ctx context.Context, sql string, args ...any) error {
|
||||
_, err := c.Conn.Exec(ctx, sql, args...)
|
||||
return err
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/zitadel/zitadel/backend/storage/database"
|
||||
)
|
||||
|
||||
type pgxPool struct{ pgxpool.Pool }
|
||||
|
||||
var _ database.Pool = (*pgxPool)(nil)
|
||||
|
||||
// Acquire implements [database.Pool].
|
||||
func (c *pgxPool) Acquire(ctx context.Context) (database.Client, error) {
|
||||
conn, err := c.Pool.Acquire(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pgxConn{conn}, nil
|
||||
}
|
||||
|
||||
// Query implements [database.Pool].
|
||||
// Subtle: this method shadows the method (Pool).Query of pgxPool.Pool.
|
||||
func (c *pgxPool) Query(ctx context.Context, sql string, args ...any) (database.Rows, error) {
|
||||
return c.Pool.Query(ctx, sql, args...)
|
||||
}
|
||||
|
||||
// QueryRow implements [database.Pool].
|
||||
// Subtle: this method shadows the method (Pool).QueryRow of pgxPool.Pool.
|
||||
func (c *pgxPool) QueryRow(ctx context.Context, sql string, args ...any) database.Row {
|
||||
return c.Pool.QueryRow(ctx, sql, args...)
|
||||
}
|
||||
|
||||
// Exec implements [database.Pool].
|
||||
// Subtle: this method shadows the method (Pool).Exec of pgxPool.Pool.
|
||||
func (c *pgxPool) Exec(ctx context.Context, sql string, args ...any) error {
|
||||
_, err := c.Pool.Exec(ctx, sql, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// Begin implements [database.Pool].
|
||||
func (c *pgxPool) Begin(ctx context.Context, opts *database.TransactionOptions) (database.Transaction, error) {
|
||||
tx, err := c.Pool.BeginTx(ctx, transactionOptionsToPgx(opts))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pgxTx{tx}, nil
|
||||
}
|
||||
|
||||
// Close implements [database.Pool].
|
||||
func (c *pgxPool) Close(_ context.Context) error {
|
||||
c.Pool.Close()
|
||||
return nil
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/zitadel/zitadel/backend/storage/database"
|
||||
)
|
||||
|
||||
type pgxTx struct{ pgx.Tx }
|
||||
|
||||
var _ database.Transaction = (*pgxTx)(nil)
|
||||
|
||||
// Commit implements [database.Transaction].
|
||||
func (tx *pgxTx) Commit(ctx context.Context) error {
|
||||
return tx.Tx.Commit(ctx)
|
||||
}
|
||||
|
||||
// Rollback implements [database.Transaction].
|
||||
func (tx *pgxTx) Rollback(ctx context.Context) error {
|
||||
return tx.Tx.Rollback(ctx)
|
||||
}
|
||||
|
||||
// End implements [database.Transaction].
|
||||
func (tx *pgxTx) End(ctx context.Context, err error) error {
|
||||
if err != nil {
|
||||
tx.Rollback(ctx)
|
||||
return err
|
||||
}
|
||||
return tx.Commit(ctx)
|
||||
}
|
||||
|
||||
// Query implements [database.Transaction].
|
||||
// Subtle: this method shadows the method (Tx).Query of pgxTx.Tx.
|
||||
func (tx *pgxTx) Query(ctx context.Context, sql string, args ...any) (database.Rows, error) {
|
||||
return tx.Tx.Query(ctx, sql, args...)
|
||||
}
|
||||
|
||||
// QueryRow implements [database.Transaction].
|
||||
// Subtle: this method shadows the method (Tx).QueryRow of pgxTx.Tx.
|
||||
func (tx *pgxTx) QueryRow(ctx context.Context, sql string, args ...any) database.Row {
|
||||
return tx.Tx.QueryRow(ctx, sql, args...)
|
||||
}
|
||||
|
||||
// Exec implements [database.Pool].
|
||||
// Subtle: this method shadows the method (Pool).Exec of pgxPool.Pool.
|
||||
func (tx *pgxTx) Exec(ctx context.Context, sql string, args ...any) error {
|
||||
_, err := tx.Tx.Exec(ctx, sql, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
func transactionOptionsToPgx(opts *database.TransactionOptions) pgx.TxOptions {
|
||||
if opts == nil {
|
||||
return pgx.TxOptions{}
|
||||
}
|
||||
|
||||
return pgx.TxOptions{
|
||||
IsoLevel: isolationToPgx(opts.IsolationLevel),
|
||||
AccessMode: accessModeToPgx(opts.AccessMode),
|
||||
}
|
||||
}
|
||||
|
||||
func isolationToPgx(isolation database.IsolationLevel) pgx.TxIsoLevel {
|
||||
switch isolation {
|
||||
case database.IsolationLevelSerializable:
|
||||
return pgx.Serializable
|
||||
case database.IsolationLevelReadCommitted:
|
||||
return pgx.ReadCommitted
|
||||
default:
|
||||
return pgx.Serializable
|
||||
}
|
||||
}
|
||||
|
||||
func accessModeToPgx(accessMode database.AccessMode) pgx.TxAccessMode {
|
||||
switch accessMode {
|
||||
case database.AccessModeReadWrite:
|
||||
return pgx.ReadWrite
|
||||
case database.AccessModeReadOnly:
|
||||
return pgx.ReadOnly
|
||||
default:
|
||||
return pgx.ReadWrite
|
||||
}
|
||||
}
|
BIN
backend/zitadel
Executable file
BIN
backend/zitadel
Executable file
Binary file not shown.
2
go.mod
2
go.mod
@@ -102,6 +102,7 @@ require (
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.0 // indirect
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/crewjam/httperr v0.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
@@ -118,6 +119,7 @@ require (
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/manifoldco/promptui v0.9.0 // indirect
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
|
10
go.sum
10
go.sum
@@ -110,6 +110,13 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
@@ -509,6 +516,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
|
||||
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
@@ -961,6 +970,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
Reference in New Issue
Block a user