package main import ( "bytes" "database/sql" "fmt" "os" "os/exec" "path/filepath" "runtime" "strconv" "strings" "github.com/coder/coder/v2/coderd/database/migrations" "github.com/coder/coder/v2/coderd/database/postgres" ) const minimumPostgreSQLVersion = 13 func main() { connection, closeFn, err := postgres.Open() if err != nil { panic(err) } defer closeFn() db, err := sql.Open("postgres", connection) if err != nil { panic(err) } err = migrations.Up(db) if err != nil { panic(err) } hasPGDump := false if _, err = exec.LookPath("pg_dump"); err == nil { out, err := exec.Command("pg_dump", "--version").Output() if err == nil { // Parse output: // pg_dump (PostgreSQL) 14.5 (Ubuntu 14.5-0ubuntu0.22.04.1) parts := strings.Split(string(out), " ") if len(parts) > 2 { version, err := strconv.Atoi(strings.Split(parts[2], ".")[0]) if err == nil && version >= minimumPostgreSQLVersion { hasPGDump = true } } } } cmdArgs := []string{ "pg_dump", "--schema-only", connection, "--no-privileges", "--no-owner", // We never want to manually generate // queries executing against this table. "--exclude-table=schema_migrations", } if !hasPGDump { cmdArgs = append([]string{ "docker", "run", "--rm", "--network=host", fmt.Sprintf("gcr.io/coder-dev-1/postgres:%d", minimumPostgreSQLVersion), }, cmdArgs...) } cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) //#nosec cmd.Env = append(os.Environ(), []string{ "PGTZ=UTC", "PGCLIENTENCODING=UTF8", }...) var output bytes.Buffer cmd.Stdout = &output cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { panic(err) } for _, sed := range []string{ // Remove all comments. "/^--/d", // Public is implicit in the schema. "s/ public\\./ /g", "s/::public\\./::/g", "s/'public\\./'/g", // Remove database settings. "s/SET .* = .*;//g", // Remove select statements. These aren't useful // to a reader of the dump. "s/SELECT.*;//g", // Removes multiple newlines. "/^$/N;/^\\n$/D", } { cmd := exec.Command("sed", "-e", sed) cmd.Stdin = bytes.NewReader(output.Bytes()) output = bytes.Buffer{} cmd.Stdout = &output cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { panic(err) } } dump := fmt.Sprintf("-- Code generated by 'make coderd/database/generate'. DO NOT EDIT.\n%s", output.Bytes()) _, mainPath, _, ok := runtime.Caller(0) if !ok { panic("couldn't get caller path") } err = os.WriteFile(filepath.Join(mainPath, "..", "..", "..", "dump.sql"), []byte(dump), 0o600) if err != nil { panic(err) } }