Files
go-synapse-backupper/pkg/adapters/pgdump/pgdump.go
T

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
}