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, "://[[username]:[password]@]:[/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] }