// Command postgis-srid-migrate performs the explicitly approved EPSG:4326 metadata migration. package main import ( "context" "encoding/json" "flag" "fmt" "log" "os" "os/signal" "strings" "syscall" "time" "fire-safety-ymd/internal/migration" "github.com/jackc/pgx/v5" ) const ( migrationDSNEnv = "FIRE_SAFETY_POSTGIS_MIGRATION_DSN" runtimeDSNEnv = "FIRE_SAFETY_POSTGIS_DSN" commandTimeout = 3 * time.Minute ) func main() { apply := flag.Bool("apply", false, "commit the reviewed SRID metadata migration") confirmation := flag.String("confirm-source-crs", "", "required with --apply; must equal EPSG:4326") flag.Parse() dsn, err := selectDSN(*apply) if err != nil { log.Fatal(err) } connectionConfig, err := pgx.ParseConfig(dsn) if err != nil { log.Fatal("parse PostGIS migration configuration") } connectionConfig.RuntimeParams["application_name"] = "fire-safety-ymd-srid-migration" signalCtx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() ctx, cancel := context.WithTimeout(signalCtx, commandTimeout) defer cancel() conn, err := pgx.ConnectConfig(ctx, connectionConfig) if err != nil { log.Fatal("connect to PostGIS for SRID migration") } defer func() { _ = conn.Close(context.Background()) }() if !*apply { report, err := migration.Inspect(ctx, conn) if err != nil { log.Fatalf("inspect SRID migration state: %v", err) } writeJSON(report) if err := migration.ValidateForApply(report); err != nil { log.Fatalf("SRID migration preflight failed: %v", err) } fmt.Fprintln(os.Stderr, "preflight passed; no database changes were made") return } if *confirmation != "EPSG:4326" { log.Fatal("--apply requires --confirm-source-crs=EPSG:4326") } result, err := migration.ApplySRID4326(ctx, conn) if err != nil { log.Fatalf("apply SRID migration: %v", err) } writeJSON(result) fmt.Fprintln(os.Stderr, "SRID metadata migration committed") } func selectDSN(apply bool) (string, error) { migrationDSN := strings.TrimSpace(os.Getenv(migrationDSNEnv)) if apply { if migrationDSN == "" { return "", fmt.Errorf("%s is required with --apply", migrationDSNEnv) } return migrationDSN, nil } if migrationDSN != "" { return migrationDSN, nil } runtimeDSN := strings.TrimSpace(os.Getenv(runtimeDSNEnv)) if runtimeDSN == "" { return "", fmt.Errorf("%s or %s is required", migrationDSNEnv, runtimeDSNEnv) } return runtimeDSN, nil } func writeJSON(value any) { encoder := json.NewEncoder(os.Stdout) encoder.SetIndent("", " ") if err := encoder.Encode(value); err != nil { log.Fatalf("encode migration report: %v", err) } }