101 lines
2.2 KiB
Go
101 lines
2.2 KiB
Go
package pgdump
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"git.tswf.io/infra/go-synapse-backupper/pkg/domain/pgdump"
|
|
)
|
|
|
|
// adapter provides pg_dump functionality using the system's pg_dump binary.
|
|
type adapter struct {
|
|
commandContext func(ctx context.Context, name string, arg ...string) *exec.Cmd
|
|
}
|
|
|
|
// New creates a new pg_dump adapter.
|
|
func New() pgdump.Dumper {
|
|
return &adapter{
|
|
commandContext: exec.CommandContext,
|
|
}
|
|
}
|
|
|
|
// Dump executes pg_dump and writes the output to sink.
|
|
func (a *adapter) Dump(
|
|
ctx context.Context,
|
|
opts pgdump.Options,
|
|
sink io.Writer,
|
|
) (retErr error) {
|
|
defer func() {
|
|
if pipeWriter, ok := sink.(*io.PipeWriter); ok {
|
|
if retErr != nil {
|
|
_ = pipeWriter.CloseWithError(retErr)
|
|
} else {
|
|
_ = pipeWriter.Close()
|
|
}
|
|
}
|
|
}()
|
|
|
|
args := buildArgs(opts)
|
|
|
|
cmd := a.commandContext(ctx, "pg_dump", args...)
|
|
|
|
env := os.Environ()
|
|
if opts.Password != "" {
|
|
env = append(env, fmt.Sprintf("PGPASSWORD=%s", opts.Password))
|
|
}
|
|
if opts.Host != "" {
|
|
env = append(env, fmt.Sprintf("PGHOST=%s", opts.Host))
|
|
}
|
|
if opts.Port != 0 {
|
|
env = append(env, fmt.Sprintf("PGPORT=%d", opts.Port))
|
|
}
|
|
if opts.User != "" {
|
|
env = append(env, fmt.Sprintf("PGUSER=%s", opts.User))
|
|
}
|
|
if opts.Database != "" {
|
|
env = append(env, fmt.Sprintf("PGDATABASE=%s", opts.Database))
|
|
}
|
|
cmd.Env = env
|
|
|
|
var stderrBuilder strings.Builder
|
|
cmd.Stderr = &stderrBuilder
|
|
cmd.Stdout = sink
|
|
|
|
runErr := cmd.Run()
|
|
stderr := strings.TrimSpace(stderrBuilder.String())
|
|
|
|
if runErr != nil {
|
|
if exitErr, ok := runErr.(*exec.ExitError); ok {
|
|
return fmt.Errorf("%w (exit %d): %s", pgdump.ErrPgDumpFailed(exitErr.ExitCode()), exitErr.ExitCode(), stderr)
|
|
}
|
|
return runErr
|
|
}
|
|
|
|
if cmd.ProcessState.ExitCode() != 0 {
|
|
return fmt.Errorf("%w (exit %d): %s", pgdump.ErrPgDumpFailed(cmd.ProcessState.ExitCode()), cmd.ProcessState.ExitCode(), stderr)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func buildArgs(opts pgdump.Options) []string {
|
|
excludeTables := opts.ExcludeTables
|
|
if len(excludeTables) == 0 {
|
|
excludeTables = make([]string, 1)
|
|
excludeTables[0] = "e2e_one_time_keys_json"
|
|
}
|
|
|
|
args := make([]string, 0, len(excludeTables)+1)
|
|
args = append(args, "--format=custom")
|
|
|
|
for _, table := range excludeTables {
|
|
args = append(args, "--exclude-table="+table)
|
|
}
|
|
|
|
return args
|
|
}
|