Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 26eabab106 | |||
| d44cad5ebd | |||
| 0cbfb81096 | |||
| 254183ceff | |||
| 676ed11c3f | |||
| 5d9be49f6c | |||
| 3c5014e90b | |||
| 1cef099a37 | |||
| 292d582a45 | |||
| 8cc2fce727 | |||
| 924bf85a9e |
101
cmd/dump.go
Normal file
101
cmd/dump.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"hub.cybercinch.nz/guisea/gosqldump/internal/color"
|
||||
"hub.cybercinch.nz/guisea/gosqldump/internal/dump"
|
||||
"hub.cybercinch.nz/guisea/gosqldump/internal/icon"
|
||||
"hub.cybercinch.nz/guisea/gosqldump/internal/style"
|
||||
"time"
|
||||
)
|
||||
|
||||
// dumpCmd represents the dump command
|
||||
var dumpCmd = &cobra.Command{
|
||||
Use: "dump",
|
||||
Short: "Use this command to initiate dumping of MySQL/MariaDB Database",
|
||||
Long: `A longer description that spans multiple lines and likely contains examples
|
||||
and usage of using your command. For example:
|
||||
|
||||
Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
to quickly create a Cobra application.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.Info("dump called")
|
||||
start := time.Now()
|
||||
hostname, _ := cmd.Flags().GetString("host")
|
||||
databaseName, _ := cmd.Flags().GetString("database")
|
||||
//port, _ := cmd.Flags().GetInt("port")
|
||||
|
||||
// Retrieve user from config
|
||||
user := viper.GetViper().GetString("mysql.user")
|
||||
// Retrieve password from config
|
||||
pass := viper.GetViper().GetString("mysql.password")
|
||||
myDump := dump.NewClient(
|
||||
dump.WithHostName(hostname),
|
||||
dump.WithDatabaseName(databaseName),
|
||||
dump.WithPort(3306),
|
||||
dump.WithUserName(user),
|
||||
dump.WithPassword(pass),
|
||||
)
|
||||
|
||||
err := myDump.Dump()
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %s", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(
|
||||
"%s Combining files\n\r",
|
||||
style.Success(icon.Info),
|
||||
)
|
||||
|
||||
filename, err := myDump.Combine()
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
fmt.Printf(
|
||||
"%s could not combine backup file: %s\n\r",
|
||||
style.Failure(icon.Cross),
|
||||
lipgloss.NewStyle().Foreground(color.Red).Render(err.Error()),
|
||||
)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
fmt.Printf(
|
||||
"%s Completed combining files\n\r",
|
||||
style.Success(icon.Check),
|
||||
)
|
||||
fmt.Printf(
|
||||
"%s Zipping file\n\r",
|
||||
style.Success(icon.Info),
|
||||
)
|
||||
filename, _ = dump.ZipFile(filename)
|
||||
timeElapsed := time.Since(start)
|
||||
fmt.Printf(
|
||||
"%s Dump file available at %s\r\nTook %s\n\r",
|
||||
style.Success(icon.Check),
|
||||
filename,
|
||||
timeElapsed,
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(dumpCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// dumpCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// dumpCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
dumpCmd.Flags().StringP("host", "H", "localhost", "database host")
|
||||
dumpCmd.Flags().StringP("port", "p", "3306", "database port")
|
||||
dumpCmd.Flags().StringP("database", "d", "~", "database name")
|
||||
}
|
||||
6
go.mod
6
go.mod
@@ -17,6 +17,12 @@ require (
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.2.3 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/kortschak/utter v1.7.0 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/paulvollmer/go-concatenate v0.1.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
github.com/rwtodd/Go.Sed v0.0.0-20240405174034-bb8ed5da0fd0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.6.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@@ -12,6 +12,7 @@ github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqo
|
||||
github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -38,6 +39,8 @@ github.com/ivanpirog/coloredcobra v1.0.1 h1:aURSdEmlR90/tSiWS0dMjdwOvCVUeYLfltLf
|
||||
github.com/ivanpirog/coloredcobra v1.0.1/go.mod h1:iho4nEKcnwZFiniGSdcgdvRgZNjxm+h20acv8vqmN6Q=
|
||||
github.com/ka-weihe/fast-levenshtein v0.0.0-20201227151214-4c99ee36a1ba h1:keZ4vJpYOVm6yrjLzZ6QgozbEBaT0GjfH30ihbO67+4=
|
||||
github.com/ka-weihe/fast-levenshtein v0.0.0-20201227151214-4c99ee36a1ba/go.mod h1:kaXTPU4xitQT0rfT7/i9O9Gm8acSh3DXr0p4y3vKqiE=
|
||||
github.com/kortschak/utter v1.7.0 h1:6NKMynvGUyqfeMTawfah4zyInlrgwzjkDAHrT+skx/w=
|
||||
github.com/kortschak/utter v1.7.0/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -60,8 +63,11 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||
github.com/paulvollmer/go-concatenate v0.1.0 h1:LZ9CdhNXIo6JKW7UGTYMzR1/wRsd0Cv6HYaL1oumxrg=
|
||||
github.com/paulvollmer/go-concatenate v0.1.0/go.mod h1:U2NPShgMlzNi1oyK4Uvh/QUplGeiWGCgEtFPdReflwo=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
@@ -70,6 +76,8 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/rwtodd/Go.Sed v0.0.0-20240405174034-bb8ed5da0fd0 h1:Sm5QvnDuFhkajkdjAHX51h+gyuv+LmkjX//zjpZwIvA=
|
||||
github.com/rwtodd/Go.Sed v0.0.0-20240405174034-bb8ed5da0fd0/go.mod h1:c6qgHcSUeSISur4+Kcf3WYTvpL07S8eAsoP40hDiQ1I=
|
||||
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
|
||||
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
|
||||
309
internal/dump/dump.go
Normal file
309
internal/dump/dump.go
Normal file
@@ -0,0 +1,309 @@
|
||||
package dump
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/paulvollmer/go-concatenate"
|
||||
"github.com/rwtodd/Go.Sed/sed"
|
||||
"hub.cybercinch.nz/guisea/gosqldump/internal/color"
|
||||
"hub.cybercinch.nz/guisea/gosqldump/internal/icon"
|
||||
"hub.cybercinch.nz/guisea/gosqldump/internal/style"
|
||||
"hub.cybercinch.nz/guisea/gosqldump/internal/util"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Client represents our mysqldump client.
|
||||
type Client struct {
|
||||
executable string
|
||||
hostname string
|
||||
port int
|
||||
databaseName string
|
||||
username string
|
||||
password string
|
||||
storagePath string
|
||||
}
|
||||
|
||||
// Option is a functional option type that allows us to configure the Client.
|
||||
type Option func(*Client)
|
||||
|
||||
func NewClient(options ...Option) *Client {
|
||||
client := &Client{
|
||||
executable: "mysqldump",
|
||||
}
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
client.storagePath = filepath.Join("/tmp")
|
||||
case "linux":
|
||||
client.storagePath = filepath.Join("/tmp")
|
||||
case "windows":
|
||||
client.storagePath = filepath.Join("C:\\", "Temp")
|
||||
}
|
||||
|
||||
err := os.MkdirAll(client.storagePath, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
|
||||
// Apply all the functional options to configure the client.
|
||||
for _, opt := range options {
|
||||
opt(client)
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
// WithDatabaseName sets the Database Name to work with
|
||||
func WithDatabaseName(databaseName string) Option {
|
||||
return func(c *Client) {
|
||||
c.databaseName = databaseName
|
||||
}
|
||||
}
|
||||
|
||||
// WithHostName is a functional option to set the Database Hostname.
|
||||
func WithHostName(hostName string) Option {
|
||||
return func(c *Client) {
|
||||
c.hostname = hostName
|
||||
}
|
||||
}
|
||||
|
||||
// WithPort is a functional option to set the Database Hostname.
|
||||
func WithPort(port int) Option {
|
||||
return func(c *Client) {
|
||||
c.port = port
|
||||
}
|
||||
}
|
||||
|
||||
// WithUserName is a functional option to set the Database Hostname.
|
||||
func WithUserName(userName string) Option {
|
||||
return func(c *Client) {
|
||||
c.username = userName
|
||||
}
|
||||
}
|
||||
|
||||
// WithPassword is a functional option to set the Database Hostname.
|
||||
func WithPassword(password string) Option {
|
||||
return func(c *Client) {
|
||||
c.password = password
|
||||
}
|
||||
}
|
||||
func (c *Client) Dump() error {
|
||||
|
||||
// Construct schema output
|
||||
fmt.Printf("%s Dumping schema %s from %s\n\r",
|
||||
style.Success(icon.Info),
|
||||
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||
lipgloss.NewStyle().Foreground(color.Purple).Render(c.hostname),
|
||||
)
|
||||
|
||||
f, _ := os.OpenFile(filepath.Join(c.storagePath, c.databaseName+"-keys.sql"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
|
||||
_, err := f.WriteString("SET FOREIGN_KEY_CHECKS=0;\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Close()
|
||||
|
||||
response, err := exec.Command(c.executable,
|
||||
"--host="+c.hostname,
|
||||
"--port="+strconv.Itoa(c.port),
|
||||
"--user="+c.username,
|
||||
"--password="+c.password,
|
||||
"--no-create-db",
|
||||
"--no-data",
|
||||
"--skip-triggers",
|
||||
"--compact",
|
||||
"--result-file", filepath.Join(c.storagePath, c.databaseName+"-schema.sql"),
|
||||
c.databaseName).CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Printf(
|
||||
"%s mysqldump error: %s\n\r",
|
||||
style.Failure(icon.Cross),
|
||||
lipgloss.NewStyle().Foreground(color.Purple).Render(string(response)),
|
||||
)
|
||||
return err
|
||||
}
|
||||
removeDefiners(filepath.Join(c.storagePath, c.databaseName+"-schema.sql"))
|
||||
|
||||
fmt.Printf(
|
||||
"%s Done dumping schema %s from %s\n\r",
|
||||
style.Success(icon.Check),
|
||||
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||
lipgloss.NewStyle().Foreground(color.Purple).Render(c.hostname),
|
||||
)
|
||||
// Construct data output
|
||||
|
||||
fmt.Printf("%s Dumping data %s from %s\n\r",
|
||||
style.Success(icon.Info),
|
||||
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||
lipgloss.NewStyle().Foreground(color.Purple).Render(c.hostname),
|
||||
)
|
||||
|
||||
_ = exec.Command(c.executable,
|
||||
"--host="+c.hostname,
|
||||
"--port="+strconv.Itoa(c.port),
|
||||
"--user="+c.username,
|
||||
"--password="+c.password,
|
||||
"--no-create-db",
|
||||
"--no-create-info",
|
||||
"--skip-triggers",
|
||||
"--compact",
|
||||
"--result-file", filepath.Join(c.storagePath, c.databaseName+"-data.sql"),
|
||||
c.databaseName).Run()
|
||||
removeDefiners(filepath.Join(c.storagePath, c.databaseName+"-data.sql"))
|
||||
fmt.Printf(
|
||||
"%s Done dumping data %s from %s\n\r",
|
||||
style.Success(icon.Check),
|
||||
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||
lipgloss.NewStyle().Foreground(color.Purple).Render(c.hostname),
|
||||
)
|
||||
|
||||
// Construct routines/triggers output
|
||||
fmt.Printf("%s Dumping routines %s from %s\n\r",
|
||||
style.Success(icon.Info),
|
||||
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||
lipgloss.NewStyle().Foreground(color.Purple).Render(c.hostname),
|
||||
)
|
||||
|
||||
_ = exec.Command(c.executable,
|
||||
"--host="+c.hostname,
|
||||
"--port="+strconv.Itoa(c.port),
|
||||
"--user="+c.username,
|
||||
"--password="+c.password,
|
||||
"--no-create-db",
|
||||
"--no-create-info",
|
||||
"--no-data",
|
||||
"--triggers",
|
||||
"--routines",
|
||||
"--compact",
|
||||
"--result-file", filepath.Join(c.storagePath, c.databaseName+"-routines.sql"),
|
||||
c.databaseName).Run()
|
||||
removeDefiners(filepath.Join(c.storagePath, c.databaseName+"-routines.sql"))
|
||||
fmt.Printf(
|
||||
"%s Done dumping routines %s from %s\n\r",
|
||||
style.Success(icon.Check),
|
||||
lipgloss.NewStyle().Foreground(color.Purple).Render(c.hostname),
|
||||
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeDefiners(filename string) {
|
||||
// Regex 1: .*(DEFINER=[a-zA-Z0-9\x60%@]+).* (Used by procedures/funcs)
|
||||
// Regex 2: .*(\/\*\!50003.*!50003+).* (Used by triggers)
|
||||
// Regex 3: (\/\*\!50013.*DEFINER \*\/) (Used in schema)
|
||||
// Regex 4: ^(.TRIGGER).(\x60.*) (Fix the create triggers)
|
||||
|
||||
expressions := make([]string, 4)
|
||||
expressions[0] = `s/(^.*)(.DEFINER=[a-zA-Z0-9_\x60%@]+)(.*)/$1$3/g`
|
||||
expressions[1] = `s/(.*)(\/\*\!50003.*!50003+)(.*)/$1$3/g`
|
||||
expressions[2] = `s/(\/\*\!50013.*DEFINER \*\/)//g`
|
||||
expressions[3] = `s/(^.TRIGGER).(\x60.*)/CREATE$1 $2/g`
|
||||
|
||||
if !strings.Contains(filename, "data") {
|
||||
for _, re := range expressions {
|
||||
inputFile, err := os.Open(filename)
|
||||
engine, err := sed.New(strings.NewReader(re))
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
|
||||
outputFile, err := os.OpenFile(filename+".new", os.O_WRONLY|os.O_CREATE, 0666)
|
||||
_, _ = io.Copy(outputFile, engine.Wrap(inputFile))
|
||||
_ = inputFile.Close()
|
||||
_ = outputFile.Close()
|
||||
err = util.MoveFile(filename+".new", filename)
|
||||
if err != nil {
|
||||
fmt.Printf(
|
||||
"%s could not move file: %s\n\r",
|
||||
style.Failure(icon.Cross),
|
||||
lipgloss.NewStyle().Foreground(color.Purple).Render(err.Error()),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Combine() (string, error) {
|
||||
var files [4]string
|
||||
files[0] = "keys"
|
||||
files[1] = "schema"
|
||||
files[2] = "data"
|
||||
files[3] = "routines"
|
||||
|
||||
filepath.Join(c.storagePath, c.databaseName+"-backup.sql")
|
||||
err := concatenate.FilesToFile(filepath.Join(c.storagePath, c.databaseName+"-backup.sql"),
|
||||
0666,
|
||||
"",
|
||||
filepath.Join(c.storagePath, c.databaseName+"-"+files[0]+".sql"),
|
||||
filepath.Join(c.storagePath, c.databaseName+"-"+files[1]+".sql"),
|
||||
filepath.Join(c.storagePath, c.databaseName+"-"+files[2]+".sql"),
|
||||
filepath.Join(c.storagePath, c.databaseName+"-"+files[3]+".sql"),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
err = os.Remove(filepath.Join(c.storagePath, c.databaseName+"-"+file+`.sql`))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return filepath.Join(c.storagePath, c.databaseName+"-backup.sql"), nil
|
||||
}
|
||||
|
||||
func ZipFile(filename string) (string, error) {
|
||||
//Create a new zip archive and named archive.zip
|
||||
archive, err := os.Create(util.FileNameWithoutExt(filename) + ".zip")
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
// this is to catch errors if any
|
||||
}
|
||||
defer archive.Close()
|
||||
_, file := filepath.Split(filename)
|
||||
|
||||
//Create a new zip writer
|
||||
zipWriter := zip.NewWriter(archive)
|
||||
fmt.Printf(
|
||||
"%s Opening .sql file\n\r",
|
||||
style.Success(icon.Info),
|
||||
)
|
||||
|
||||
f1, err := os.Open(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f1.Close()
|
||||
fmt.Printf(
|
||||
"%s Adding file to archive\n\r",
|
||||
style.Success(icon.Info),
|
||||
)
|
||||
w1, err := zipWriter.Create(file)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err := io.Copy(w1, f1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf(
|
||||
"%s Closing archive\n\r",
|
||||
style.Success(icon.Info),
|
||||
)
|
||||
zipWriter.Close()
|
||||
f1.Close()
|
||||
os.Remove(filename)
|
||||
|
||||
return util.FileNameWithoutExt(filename) + ".zip", nil
|
||||
}
|
||||
58
internal/util/files.go
Normal file
58
internal/util/files.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func MoveFile(src, dst string) error {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't open source file: %s", err)
|
||||
}
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
in.Close()
|
||||
return fmt.Errorf("couldn't open dest file: %s", err)
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
in.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing to output file failed: %s", err)
|
||||
}
|
||||
|
||||
err = out.Sync()
|
||||
if err != nil {
|
||||
return fmt.Errorf("sync error: %s", err)
|
||||
}
|
||||
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stat error: %s", err)
|
||||
}
|
||||
err = os.Chmod(dst, si.Mode())
|
||||
if err != nil {
|
||||
return fmt.Errorf("chmod error: %s", err)
|
||||
}
|
||||
|
||||
//err = in.Close()
|
||||
//if err != nil {
|
||||
// return fmt.Errorf("closing file failed: %s", err)
|
||||
//}
|
||||
//time.Sleep(time.Second * 10)
|
||||
err = os.Remove(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed removing original file: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FileNameWithoutExt(fileName string) string {
|
||||
return strings.TrimSuffix(fileName, filepath.Ext(fileName))
|
||||
}
|
||||
6
justfile
6
justfile
@@ -8,7 +8,11 @@ install:
|
||||
|
||||
build:
|
||||
@echo -n "Building app ... "
|
||||
@go build {{flags}} -o bin/ && echo "OK" || echo "FAILED"
|
||||
@go build {{flags}} -o bin/gosqldump ./main.go && echo "OK" || echo "FAILED"
|
||||
|
||||
build-win:
|
||||
@echo -n "Building app for windows ... "
|
||||
@GOOS=windows GOARCH=amd64 go build {{flags}} -o bin/gosqldump.exe ./main.go && echo "OK" || echo "FAILED"
|
||||
update:
|
||||
go get -u
|
||||
go mod tidy -v
|
||||
|
||||
Reference in New Issue
Block a user