blob: 81835d2da7c2e92d860496e88932163b5a5f23f1 [file] [log] [blame]
Philipp Schrader7365d322022-03-06 16:40:08 -08001// This binary starts up a postgres server in the background.
2//
3// The server will be reachable at localhost:5432 with username and password of
4// "test" and "password", respectively.
5
6package main
7
8import (
9 "flag"
10 "fmt"
11 "io/ioutil"
12 "log"
13 "os"
14 "os/exec"
15 "os/signal"
16 "path/filepath"
17 "strconv"
18 "strings"
19 "syscall"
20
Philipp Schrader20035262023-03-05 15:03:19 -080021 "github.com/bazelbuild/rules_go/go/runfiles"
Philipp Schrader7365d322022-03-06 16:40:08 -080022)
23
24func check(err error, message string) {
25 if err != nil {
26 log.Fatal(message, ": ", err)
27 }
28}
29
30// Loads the runfiles environment variables so that subprocesses can access
31// their own runfiles properly.
32func loadRunfilesEnvironment() {
33 values, err := runfiles.Env()
34 check(err, "Failed to retrieve runfiles environment")
35 for _, value := range values {
36 parts := strings.SplitN(value, "=", 2)
37 if len(parts) != 2 {
38 log.Fatalf("Failed to split \"%s\" on \"=\".", value)
39 }
40 err = os.Setenv(parts[0], parts[1])
41 check(err, "Failed to set environment "+value)
42 }
43}
44
45func getRunfile(path string) string {
Philipp Schrader20035262023-03-05 15:03:19 -080046 result, err := runfiles.Rlocation(path)
Philipp Schrader7365d322022-03-06 16:40:08 -080047 check(err, fmt.Sprint("Failed to find runfile path for ", path))
48 return result
49}
50
51func copyTestConfig(sourceFile, destinationFile string, port int, socketDir string) {
52 input, err := ioutil.ReadFile(sourceFile)
53 check(err, fmt.Sprint("Failed to read from ", sourceFile))
54
55 config := strings.ReplaceAll(string(input), "{POSTGRES_PORT}", strconv.Itoa(port))
56 config = strings.ReplaceAll(config, "{POSTGRES_UNIX_SOCKET_DIR}", socketDir)
57
58 err = ioutil.WriteFile(destinationFile, []byte(config), 0644)
59 check(err, fmt.Sprint("Failed to write to ", destinationFile))
60}
61
62func main() {
63 portPtr := flag.Int("port", 5432, "The port number to bind to.")
64 flag.Parse()
65
66 loadRunfilesEnvironment()
67
68 // Set up temporary directories for postgres. These cannot live in
69 // TEST_TMPDIR because socket paths have a maximum of 107 bytes.
70 tmpdir, err := ioutil.TempDir("", "testdb_server")
71 check(err, "Failed to create tmpdir")
72 defer os.RemoveAll(tmpdir)
73
74 passwordPath := filepath.Join(tmpdir, "password.txt")
75 d1 := []byte("password\n")
76 err = os.WriteFile(passwordPath, d1, 0644)
77 check(err, "Failed to create password file")
78
79 dbDir := filepath.Join(tmpdir, "db")
80 initdb := exec.Command(
81 getRunfile("postgresql_amd64/initdb"),
82 "-D", dbDir,
83 "--username=test", "--pwfile="+passwordPath)
84 initdb.Stdout = os.Stdout
85 initdb.Stderr = os.Stderr
86 err = initdb.Run()
87 check(err, "Failed to run initdb")
88
89 // Set up a directory for postgres to put its socket file.
90 socketDir := filepath.Join(tmpdir, "postgres_socket")
91 err = os.MkdirAll(socketDir, 0755)
92 check(err, "Failed to create socket directory "+socketDir)
93
94 copyTestConfig(
95 getRunfile("org_frc971/scouting/db/testdb_server/postgres_test.conf"),
96 filepath.Join(dbDir, "postgresql.conf"),
97 *portPtr,
98 socketDir)
99
100 log.Println("Starting up postgres.")
101 server := exec.Command(getRunfile("postgresql_amd64/postgres"), "-D", dbDir)
102 server.Stdout = os.Stdout
103 server.Stderr = os.Stderr
104 err = server.Start()
105 check(err, "Failed to run postgres")
106 defer func() {
107 log.Println("Shutting down postgres")
108 server.Process.Signal(os.Interrupt)
109 server.Process.Wait()
110 }()
111
112 // Block until the user hits Ctrl-C.
113 sigint := make(chan os.Signal, 1)
114 signal.Notify(sigint, syscall.SIGTERM)
115 signal.Notify(sigint, syscall.SIGINT)
116 fmt.Println("Waiting for CTRL-C or SIGINT.")
117 <-sigint
118}