Files
oslstats/internal/config/flags.go
2026-03-07 13:24:36 +11:00

130 lines
3.5 KiB
Go

package config
import (
"flag"
"strconv"
"github.com/pkg/errors"
)
type Flags struct {
// Utility flags
EnvDoc bool
ShowEnv bool
GenEnv string
EnvFile string
DevMode bool
Staging bool
// Database reset (destructive)
ResetDB bool
// Migration commands
MigrateUp string
MigrateRollback string
MigrateStatus bool
MigrateCreate string
MigrateDryRun bool
// Backup control
MigrateNoBackup bool
}
func SetupFlags() (*Flags, error) {
// Utility flags
envDoc := flag.Bool("envdoc", false, "Print all environment variables and their documentation")
showEnv := flag.Bool("showenv", false, "Print all environment variable values and their documentation")
genEnv := flag.String("genenv", "", "Generate a .env file with all environment variables (specify filename)")
envfile := flag.String("envfile", ".env", "Specify a .env file to use for the configuration")
devMode := flag.Bool("dev", false, "Run the server in dev mode")
staging := flag.Bool("staging", false, "Show a staging banner")
// Database reset (destructive)
resetDB := flag.Bool("reset-db", false, "⚠️ DESTRUCTIVE: Drop and recreate all tables (dev only)")
// Migration commands
migrateUp := flag.String("migrate-up", "", "Run pending database migrations (usage: --migrate-up [count|all], default: 1)")
migrateRollback := flag.String("migrate-rollback", "", "Rollback migrations (usage: --migrate-rollback [count|all], default: 1)")
migrateStatus := flag.Bool("migrate-status", false, "Show database migration status")
migrateCreate := flag.String("migrate-create", "", "Create a new migration file with the given name")
migrateDryRun := flag.Bool("migrate-dry-run", false, "Preview pending migrations without applying them")
// Backup control
migrateNoBackup := flag.Bool("no-backup", false, "Skip automatic backups (dev only - faster but less safe)")
flag.Parse()
// Validate: can't use multiple migration commands at once
commands := 0
if *migrateUp != "" {
commands++
}
if *migrateRollback != "" {
commands++
}
if *migrateStatus {
commands++
}
if *migrateDryRun {
commands++
}
if *resetDB {
commands++
}
if commands > 1 {
return nil, errors.New("cannot use multiple migration commands simultaneously")
}
// Validate migration count values
if *migrateUp != "" {
if err := validateMigrationCount(*migrateUp); err != nil {
return nil, errors.Wrap(err, "invalid --migrate-up value")
}
}
if *migrateRollback != "" {
if err := validateMigrationCount(*migrateRollback); err != nil {
return nil, errors.Wrap(err, "invalid --migrate-rollback value")
}
}
flags := &Flags{
EnvDoc: *envDoc,
ShowEnv: *showEnv,
GenEnv: *genEnv,
EnvFile: *envfile,
DevMode: *devMode,
Staging: *staging,
ResetDB: *resetDB,
MigrateUp: *migrateUp,
MigrateRollback: *migrateRollback,
MigrateStatus: *migrateStatus,
MigrateCreate: *migrateCreate,
MigrateDryRun: *migrateDryRun,
MigrateNoBackup: *migrateNoBackup,
}
return flags, nil
}
// validateMigrationCount validates a migration count value
// Valid values: "all" or a positive integer (1, 2, 3, ...)
func validateMigrationCount(value string) error {
if value == "" {
return nil
}
if value == "all" {
return nil
}
// Try parsing as integer
count, err := strconv.Atoi(value)
if err != nil {
return errors.New("must be a positive integer or 'all'")
}
if count < 1 {
return errors.New("must be a positive integer (1 or greater)")
}
return nil
}