Refactor codebase for Phase 3
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
|
||||
"gitocean/internal/model"
|
||||
)
|
||||
|
||||
func Create(cfg model.ServerConfig, file string) error {
|
||||
tmp, err := os.MkdirTemp("", "gitocean-backup-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
metadata := filepath.Join(tmp, "metadata.sql")
|
||||
mysqlArgs, dbName, err := MySQLCLIArgs(cfg.MySQLDSN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command("mysqldump", append(mysqlArgs, dbName)...)
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("mysqldump failed: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(metadata, out, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
cmd = exec.Command("tar", "-czf", file, "-C", ".", cfg.Storage, "-C", tmp, "metadata.sql")
|
||||
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func Restore(cfg model.ServerConfig, file string) error {
|
||||
tmp, err := os.MkdirTemp("", "gitocean-restore-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
cmd := exec.Command("tar", "-xzf", file, "-C", tmp)
|
||||
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
mysqlArgs, dbName, err := MySQLCLIArgs(cfg.MySQLDSN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
metadata := filepath.Join(tmp, "metadata.sql")
|
||||
f, err := os.Open(metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
cmd = exec.Command("mysql", append(mysqlArgs, dbName)...)
|
||||
cmd.Stdin = f
|
||||
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
return CopyDir(filepath.Join(tmp, cfg.Storage), cfg.Storage)
|
||||
}
|
||||
|
||||
func MySQLCLIArgs(dsn string) ([]string, string, error) {
|
||||
cfg, err := mysql.ParseDSN(dsn)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
args := []string{}
|
||||
if cfg.User != "" {
|
||||
args = append(args, "-u"+cfg.User)
|
||||
}
|
||||
if cfg.Passwd != "" {
|
||||
args = append(args, "-p"+cfg.Passwd)
|
||||
}
|
||||
if cfg.Net == "tcp" && cfg.Addr != "" {
|
||||
host, port := cfg.Addr, ""
|
||||
if strings.Contains(cfg.Addr, ":") {
|
||||
host, port, _ = strings.Cut(cfg.Addr, ":")
|
||||
}
|
||||
if host != "" {
|
||||
args = append(args, "-h"+host)
|
||||
}
|
||||
if port != "" {
|
||||
args = append(args, "-P"+port)
|
||||
}
|
||||
} else if cfg.Net == "unix" && cfg.Addr != "" {
|
||||
args = append(args, "--socket", cfg.Addr)
|
||||
}
|
||||
return args, cfg.DBName, nil
|
||||
}
|
||||
|
||||
func CopyDir(src, dst string) error {
|
||||
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rel, err := filepath.Rel(src, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
to := filepath.Join(dst, rel)
|
||||
if info.IsDir() {
|
||||
return os.MkdirAll(to, info.Mode())
|
||||
}
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(to, b, info.Mode())
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user