pgcli/internal/pg/pgpass.go

121 lines
3.0 KiB
Go

package pg
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"time"
"github.com/balabanovds/pgcli/internal/core"
"github.com/balabanovds/pgcli/internal/kube"
)
type PgPassHandler struct {
orig string
bckp string
deleteOriginal bool
}
func NewPgPassHandler() (*PgPassHandler, error) {
if core.Homedir() == "" {
return nil, fmt.Errorf("unable to figure out your home dir")
}
h := &PgPassHandler{}
h.orig = filepath.Join(core.Homedir(), ".pgpass")
h.bckp = fmt.Sprintf("%s-%d", h.orig, time.Now().UnixMilli())
if !h.fileExists(h.orig) {
_, err := os.Create(h.orig)
if err != nil {
return nil, fmt.Errorf("failed to create .pgpass file for portforward: %w", err)
}
h.deleteOriginal = true
} else {
err := h.copyFile(h.orig, h.bckp)
if err != nil {
return nil, fmt.Errorf("failed to copy original file %s to backup %s: %w", h.orig, h.bckp, err)
}
}
return h, nil
}
func (h *PgPassHandler) Close() error {
if err := h.deleteFile(h.orig); err != nil {
return fmt.Errorf("failed to delete file %s: %w", h.orig, err)
}
if err := h.copyFile(h.bckp, h.orig); err != nil {
return fmt.Errorf("failed to copy file from %s to %s: %w", h.bckp, h.orig, err)
}
if h.deleteOriginal {
if err := h.deleteFile(h.orig); err != nil {
return fmt.Errorf("failed to delete file %s: %w", h.orig, err)
}
}
if err := h.deleteFile(h.bckp); err != nil {
return fmt.Errorf("failed to delete file %s: %w", h.bckp, err)
}
return nil
}
func (h *PgPassHandler) Append(sec *kube.Secret, localhost string, localport int) error {
f, err := os.OpenFile(h.orig, os.O_APPEND|os.O_WRONLY, 0o600)
if err != nil {
return fmt.Errorf("failed to append data to file %s: %w", h.orig, err)
}
defer func() {
if cerr := f.Close(); cerr != nil {
fmt.Printf("failed to close file %s during appendL %s", h.orig, cerr)
}
}()
_, err = fmt.Fprintf(f, "# added by programm pgpf\n%s:%d:%s:%s:%s\n", localhost, localport, sec.DBName, sec.User, sec.Password)
return err
}
func (h *PgPassHandler) copyFile(src, dst string) error {
src = filepath.Clean(src)
fsrc, err := os.Open(src)
if err != nil {
return fmt.Errorf("failed to open file %s: %w", src, err)
}
defer func() {
if cerr := fsrc.Close(); cerr != nil {
fmt.Printf("failed to close source file %s during copy: %s\n", src, cerr)
}
}()
dst = filepath.Clean(dst)
fdst, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0o600)
if err != nil {
return fmt.Errorf("failed to open file %s: %w", dst, err)
}
defer func() {
if cerr := fdst.Close(); cerr != nil {
fmt.Printf("faled to close destination file %s during copy: %s\n", dst, cerr)
}
}()
_, err = io.Copy(fdst, fsrc)
if err != nil {
return fmt.Errorf("failed to copy file from %s to %s: %w", src, dst, err)
}
return nil
}
func (h *PgPassHandler) fileExists(src string) bool {
_, err := os.Stat(src)
return err == nil || errors.Is(err, os.ErrNotExist)
}
func (h *PgPassHandler) deleteFile(src string) error {
return os.Remove(src)
}