pilgrim/internal/pilgrim_conf/cli.go

280 lines
9.3 KiB
Go
Raw Normal View History

2025-03-15 19:03:22 +02:00
package pilgrim_conf
import (
"flag"
"sync"
)
const (
Flag_Url string = "url"
Flag_Driver string = "driver"
Flag_Username string = "username"
Flag_Password string = "password"
Flag_Host string = "host"
Flag_Port string = "port"
Flag_Segments string = "segments"
Flag_Args string = "args"
Flag_Directory string = "dir"
Flag_Up string = "up"
Flag_Down string = "down"
Flag_Script string = "script"
Flag_Schema string = "schema"
Flag_Table string = "table"
Flag_DisableChecksumValidation string = "disable_checksum_validation"
Flag_StrictOrdering string = "strict_ordering"
Flag_ValidateMigrationOrder string = "validate_migration_order"
Flag_ValidateLatest string = "validate_latest"
Flag_ValidateChecksums string = "validate_checksums"
)
type CliFlagRetriever interface {
Url() (value string, isProvided bool)
Driver() (value DbDriver, isProvided bool)
Username() (value string, isProvided bool)
Password() (value string, isProvided bool)
Host() (value string, isProvided bool)
Port() (value string, isProvided bool)
Segments() (value []string, isProvided bool)
Args() (value map[string]string, isProvided bool)
Directory() (value string, isProvided bool)
IsUp() (value bool, isProvided bool)
IsDown() (value bool, isProvided bool)
// Can be a script name, or "latest"
Script() (value string, isProvided bool)
MigrationTable() (value string, isProvided bool)
MigrationTableSchema() (value string, isProvided bool)
IsChecksumValidationEnabled() (value bool, isProvided bool)
IsStrictOrderingEnabled() (value bool, isProvided bool)
IsValidatingMigrationOrder() (value bool, isProvided bool)
IsValidatingLatest() (value bool, isProvided bool)
IsValidatingChecksums() (value bool, isProvided bool)
ParseFlags()
}
var ctxSingleton *cliContext
var once sync.Once
type cliContext struct {
isProvided map[string]bool
url,
driver,
username,
password,
host,
port,
segments,
args,
directory,
script,
migrationTable,
migrationTableSchema *string
up,
down,
strictOrdering,
disableChecksumValidation,
validateChecksums,
validateMigrationOrder,
validateLatest *bool
}
// Creates the cliContext singleton
// Using any of the flags here requires a call to `ParseFlags`
func CliContext() *cliContext {
once.Do(func() {
ctxSingleton = &cliContext{
url: flag.String(Flag_Url, EmptyString, "<driver>://[[username]:[password]@]<host>:<port>[/database[?arg1=value[&arg2=value ...]]]"),
driver: flag.String(Flag_Driver, EmptyString, "The database driver ( mysql, postgres, sqlite, mariadb, oracle, mssql )"),
username: flag.String(Flag_Username, EmptyString, "The user"),
password: flag.String(Flag_Password, EmptyString, "Password for user"),
host: flag.String(Flag_Host, EmptyString, "The database host"),
port: flag.String(Flag_Port, EmptyString, "The database port"),
segments: flag.String(Flag_Segments, EmptyString, "The segments ( often the database name, in format \"segment1/segment2\" )"),
args: flag.String(Flag_Args, EmptyString, "Additional arguments to provide the database connection ( in format 'arg1=value&arg2=value' )"),
directory: flag.String(Flag_Directory, "./migrations", "The migration directory"),
script: flag.String(Flag_Script, "latest", "The script to upgrade/downgrade to."),
migrationTable: flag.String(Flag_Table, "pilgrim_migrations", "The database table to store migration information. WARNING: Changing this after running migrations once WILL NOT automagically move migration metadata from one table to another and will run all migrations from scratch."),
migrationTableSchema: flag.String(Flag_Schema, "", "The schema the database table belongs to. Default depends on driver. See WARNING of migration table."),
up: flag.Bool(Flag_Up, false, "Upgrade the database."),
down: flag.Bool(Flag_Down, false, "Upgrade the database."),
strictOrdering: flag.Bool(Flag_StrictOrdering, false, "Enforce strict ordering, pilgrim will run a validation of migration execution order before running the migrations"),
disableChecksumValidation: flag.Bool(Flag_DisableChecksumValidation, false, "Disable checksum validation when running database migration"),
validateChecksums: flag.Bool(Flag_ValidateChecksums, false, "(Special) Validate that all current checksums of migration files match the ones stored in the migration table"),
validateMigrationOrder: flag.Bool(Flag_ValidateMigrationOrder, false, "(Special) Runs a validation of the migration directory to ensure there is no uncertainty in migration order of execution."),
validateLatest: flag.Bool(Flag_ValidateLatest, false, "(Special) Validate that the provided database contains all migrations in the migration directory"),
isProvided: make(map[string]bool),
}
})
return ctxSingleton
}
func (cli *cliContext) ParseFlags() {
flag.Parse()
flag.Visit(func(f *flag.Flag) {
cli.isProvided[f.Name] = true
})
}
func (cli *cliContext) Url() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Url)
}
func (cli *cliContext) Driver() (value DbDriver, isProvided bool) {
val, provided := cli.fetchStringFlagValue(Flag_Driver)
return DbDriver(val), provided
}
func (cli *cliContext) Username() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Username)
}
func (cli *cliContext) Password() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Password)
}
func (cli *cliContext) Host() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Host)
}
func (cli *cliContext) Port() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Port)
}
func (cli *cliContext) Segments() (value []string, isProvided bool) {
rawVal, provided := cli.fetchStringFlagValue(Flag_Segments)
if rawVal == EmptyString {
return []string{}, false
}
return ParseSegments(rawVal), provided
}
func (cli *cliContext) Args() (value map[string]string, isProvided bool) {
rawVal, provided := cli.fetchStringFlagValue(Flag_Args)
if rawVal == EmptyString {
return make(map[string]string), false
}
return ParseArguments(rawVal), provided
}
func (cli *cliContext) Directory() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Directory)
}
func (cli *cliContext) IsUp() (value bool, isProvided bool) {
return cli.fetchBoolFlagValue(Flag_Up)
}
func (cli *cliContext) IsDown() (value bool, isProvided bool) {
return cli.fetchBoolFlagValue(Flag_Down)
}
// Can be a script name, or "latest"
func (cli *cliContext) Script() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Script)
}
func (cli *cliContext) MigrationTable() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Table)
}
func (cli *cliContext) MigrationTableSchema() (value string, isProvided bool) {
return cli.fetchStringFlagValue(Flag_Schema)
}
func (cli *cliContext) IsChecksumValidationEnabled() (value bool, isProvided bool) {
disabled, provided := cli.fetchBoolFlagValue(Flag_DisableChecksumValidation)
return !disabled, provided
}
func (cli *cliContext) IsStrictOrderingEnabled() (value bool, isProvided bool) {
return cli.fetchBoolFlagValue(Flag_StrictOrdering)
}
func (cli *cliContext) IsValidatingMigrationOrder() (value bool, isProvided bool) {
return cli.fetchBoolFlagValue(Flag_ValidateMigrationOrder)
}
func (cli *cliContext) IsValidatingLatest() (value bool, isProvided bool) {
return cli.fetchBoolFlagValue(Flag_ValidateLatest)
}
func (cli *cliContext) IsValidatingChecksums() (value bool, isProvided bool) {
return cli.fetchBoolFlagValue(Flag_ValidateChecksums)
}
func (cli *cliContext) fetchStringFlagValue(f string) (value string, isProvided bool) {
var valPtr *string = nil
switch f {
case Flag_Url:
valPtr = cli.url
case Flag_Driver:
valPtr = cli.driver
case Flag_Username:
valPtr = cli.username
case Flag_Password:
valPtr = cli.password
case Flag_Host:
valPtr = cli.host
case Flag_Port:
valPtr = cli.port
case Flag_Segments:
valPtr = cli.segments
case Flag_Args:
valPtr = cli.args
case Flag_Directory:
valPtr = cli.directory
case Flag_Script:
valPtr = cli.script
case Flag_Schema:
valPtr = cli.migrationTableSchema
case Flag_Table:
valPtr = cli.migrationTable
}
if valPtr == nil {
return EmptyString, cli.isProvided[f]
}
return *valPtr, cli.isProvided[f]
}
func (cli *cliContext) fetchBoolFlagValue(f string) (value bool, isProvided bool) {
var valPtr *bool = nil
switch f {
case Flag_Up:
valPtr = cli.up
case Flag_Down:
valPtr = cli.down
case Flag_StrictOrdering:
valPtr = cli.strictOrdering
case Flag_DisableChecksumValidation:
valPtr = cli.disableChecksumValidation
case Flag_ValidateChecksums:
valPtr = cli.validateChecksums
case Flag_ValidateMigrationOrder:
valPtr = cli.validateMigrationOrder
case Flag_ValidateLatest:
valPtr = cli.validateLatest
}
if valPtr == nil {
return false, cli.isProvided[f]
}
return *valPtr, cli.isProvided[f]
}