Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 dump 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 Completer combining dump 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/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.2.3 // indirect
|
github.com/charmbracelet/x/ansi v0.2.3 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // 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/locafero v0.6.0 // indirect
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
github.com/sourcegraph/conc v0.3.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/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.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/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.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 h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/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 h1:keZ4vJpYOVm6yrjLzZ6QgozbEBaT0GjfH30ihbO67+4=
|
||||||
github.com/ka-weihe/fast-levenshtein v0.0.0-20201227151214-4c99ee36a1ba/go.mod h1:kaXTPU4xitQT0rfT7/i9O9Gm8acSh3DXr0p4y3vKqiE=
|
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 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
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/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 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
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 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
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 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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=
|
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 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
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/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 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
|
||||||
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
|
|||||||
284
internal/dump/dump.go
Normal file
284
internal/dump/dump.go
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
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.Purple).Render(c.hostname),
|
||||||
|
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||||
|
)
|
||||||
|
|
||||||
|
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",
|
||||||
|
"--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.Purple).Render(c.hostname),
|
||||||
|
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||||
|
)
|
||||||
|
// Construct data output
|
||||||
|
|
||||||
|
fmt.Printf("%s Dumping data %s from %s\n\r",
|
||||||
|
style.Success(icon.Info),
|
||||||
|
lipgloss.NewStyle().Foreground(color.Purple).Render(c.hostname),
|
||||||
|
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = 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",
|
||||||
|
"--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.Purple).Render(c.hostname),
|
||||||
|
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Construct routines/triggers output
|
||||||
|
fmt.Printf("%s Dumping routines %s from %s\n\r",
|
||||||
|
style.Success(icon.Info),
|
||||||
|
lipgloss.NewStyle().Foreground(color.Purple).Render(c.hostname),
|
||||||
|
lipgloss.NewStyle().Foreground(color.Yellow).Render(fmt.Sprint(c.databaseName)),
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = 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",
|
||||||
|
"--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)
|
||||||
|
// TODO: Add routine body to strip definers.
|
||||||
|
expressions := make([]string, 3)
|
||||||
|
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`
|
||||||
|
|
||||||
|
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 [3]string
|
||||||
|
files[0] = "schema"
|
||||||
|
files[1] = "data"
|
||||||
|
files[2] = "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"),
|
||||||
|
)
|
||||||
|
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) {
|
||||||
|
fmt.Println("creating zip archive")
|
||||||
|
//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()
|
||||||
|
fmt.Println("archive file created successfully....")
|
||||||
|
|
||||||
|
//Create a new zip writer
|
||||||
|
zipWriter := zip.NewWriter(archive)
|
||||||
|
fmt.Println("opening .sql file")
|
||||||
|
|
||||||
|
f1, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer f1.Close()
|
||||||
|
fmt.Println("adding file to archive..")
|
||||||
|
w1, err := zipWriter.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(w1, f1); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Println("closing archive")
|
||||||
|
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))
|
||||||
|
}
|
||||||
4
justfile
4
justfile
@@ -9,6 +9,10 @@ install:
|
|||||||
build:
|
build:
|
||||||
@echo -n "Building app ... "
|
@echo -n "Building app ... "
|
||||||
@go build {{flags}} -o bin/ && echo "OK" || echo "FAILED"
|
@go build {{flags}} -o bin/ && echo "OK" || echo "FAILED"
|
||||||
|
|
||||||
|
build-win:
|
||||||
|
@echo -n "Building app for windows ... "
|
||||||
|
@GOOS=windows GOARCH=amd64 go build {{flags}} -o bin/ && echo "OK" || echo "FAILED"
|
||||||
update:
|
update:
|
||||||
go get -u
|
go get -u
|
||||||
go mod tidy -v
|
go mod tidy -v
|
||||||
|
|||||||
Reference in New Issue
Block a user