mirror of
https://github.com/iyear/tdl
synced 2025-01-07 03:16:41 +08:00
refactor(archive): rewrite based on new storage
This commit is contained in:
parent
92ab241ce6
commit
c660507b7d
@ -2,34 +2,42 @@ package archive
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/mholt/archiver/v4"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/kv"
|
||||
)
|
||||
|
||||
func Backup(ctx context.Context, dst string) error {
|
||||
func Backup(ctx context.Context, dst string) (rerr error) {
|
||||
meta, err := kv.From(ctx).MigrateTo()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read metadata")
|
||||
}
|
||||
|
||||
f, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create file")
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
_ = f.Close()
|
||||
}(f)
|
||||
defer multierr.AppendInvoke(&rerr, multierr.Close(f))
|
||||
|
||||
files, err := archiver.FilesFromDisk(nil, map[string]string{
|
||||
consts.KVPath: "",
|
||||
})
|
||||
enc, err := zstd.NewWriter(f, zstd.WithEncoderLevel(zstd.SpeedBestCompression))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "walk files")
|
||||
return errors.Wrap(err, "create zstd encoder")
|
||||
}
|
||||
defer multierr.AppendInvoke(&rerr, multierr.Close(enc))
|
||||
|
||||
metaB, err := json.Marshal(meta)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "marshal metadata")
|
||||
}
|
||||
|
||||
format := archiver.Zip{}
|
||||
if err = format.Archive(ctx, f, files); err != nil {
|
||||
return err
|
||||
if _, err = enc.Write(metaB); err != nil {
|
||||
return errors.Wrap(err, "write metadata")
|
||||
}
|
||||
|
||||
color.Green("Backup successfully, file: %s", dst)
|
||||
|
@ -1,52 +1,46 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/mholt/archiver/v4"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/kv"
|
||||
)
|
||||
|
||||
func Recover(ctx context.Context, file string) error {
|
||||
func Recover(ctx context.Context, file string) (rerr error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "open file")
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
_ = f.Close()
|
||||
}(f)
|
||||
defer multierr.AppendInvoke(&rerr, multierr.Close(f))
|
||||
|
||||
format := archiver.Zip{}
|
||||
dec, err := zstd.NewReader(f)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create zstd decoder")
|
||||
}
|
||||
defer dec.Close()
|
||||
|
||||
if err = format.Extract(ctx, f, nil, func(ctx context.Context, af archiver.File) error {
|
||||
if af.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
v, err := af.Open()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "open archiver file")
|
||||
}
|
||||
defer func(v io.ReadCloser) {
|
||||
_ = v.Close()
|
||||
}(v)
|
||||
|
||||
bytes, err := io.ReadAll(v)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read all")
|
||||
}
|
||||
|
||||
return os.WriteFile(filepath.Join(consts.DataDir, af.Name()), bytes, 0o644)
|
||||
}); err != nil {
|
||||
metaB := bytes.NewBuffer(nil)
|
||||
if _, err = dec.WriteTo(metaB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var meta kv.Meta
|
||||
if err = json.Unmarshal(metaB.Bytes(), &meta); err != nil {
|
||||
return errors.Wrap(err, "unmarshal metadata")
|
||||
}
|
||||
|
||||
if err = kv.From(ctx).MigrateFrom(meta); err != nil {
|
||||
return errors.Wrap(err, "migrate from")
|
||||
}
|
||||
|
||||
color.Green("Recover successfully, file: %s", file)
|
||||
return nil
|
||||
}
|
||||
|
@ -17,14 +17,14 @@ func NewBackup() *cobra.Command {
|
||||
Short: "Backup your data",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if dst == "" {
|
||||
dst = fmt.Sprintf("tdl-backup-%s.zip", time.Now().Format("2006-01-02-15_04_05"))
|
||||
dst = fmt.Sprintf("%s.backup.tdl", time.Now().Format("2006-01-02-15_04_05"))
|
||||
}
|
||||
|
||||
return archive.Backup(cmd.Context(), dst)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&dst, "dst", "d", "", "destination file path. Default: tdl-backup-<time>.zip")
|
||||
cmd.Flags().StringVarP(&dst, "dst", "d", "", "destination file path. Default: <date>.backup.tdl")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -45,7 +45,7 @@ func NewRecover() *cobra.Command {
|
||||
cmd.Flags().StringVarP(&file, fileFlag, "f", "", "backup file path")
|
||||
|
||||
// completion and validation
|
||||
_ = cmd.RegisterFlagCompletionFunc(fileFlag, completeExtFiles("zip"))
|
||||
_ = cmd.RegisterFlagCompletionFunc(fileFlag, completeExtFiles("tdl"))
|
||||
_ = cmd.MarkFlagRequired(fileFlag)
|
||||
|
||||
return cmd
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
var _ = Describe("Test tdl archive", func() {
|
||||
AfterEach(func() {
|
||||
// remove zip files
|
||||
files, err := filepath.Glob("*.zip")
|
||||
files, err := filepath.Glob("*.tdl")
|
||||
Expect(err).To(Succeed())
|
||||
for _, file := range files {
|
||||
Expect(os.Remove(file)).To(Succeed())
|
||||
@ -22,7 +22,7 @@ var _ = Describe("Test tdl archive", func() {
|
||||
It("should success", func() {
|
||||
exec(cmd, []string{"backup"}, true)
|
||||
|
||||
files, err := filepath.Glob("tdl-backup-*.zip")
|
||||
files, err := filepath.Glob("*.tdl")
|
||||
Expect(err).To(Succeed())
|
||||
Expect(len(files)).To(Equal(1))
|
||||
|
||||
@ -31,18 +31,18 @@ var _ = Describe("Test tdl archive", func() {
|
||||
})
|
||||
|
||||
It("should success with custom file name", func() {
|
||||
exec(cmd, []string{"backup", "-d", "custom.zip"}, true)
|
||||
exec(cmd, []string{"backup", "-d", "custom.tdl"}, true)
|
||||
|
||||
_, err := os.Stat("custom.zip")
|
||||
_, err := os.Stat("custom.tdl")
|
||||
Expect(err).To(Succeed())
|
||||
})
|
||||
})
|
||||
|
||||
When("recover", func() {
|
||||
It("should success", func() {
|
||||
exec(cmd, []string{"backup", "-d", "custom.zip"}, true)
|
||||
exec(cmd, []string{"backup", "-d", "custom.tdl"}, true)
|
||||
|
||||
exec(cmd, []string{"recover", "-f", "custom.zip"}, true)
|
||||
exec(cmd, []string{"recover", "-f", "custom.tdl"}, true)
|
||||
})
|
||||
|
||||
It("should fail if do not specify file name", func() {
|
||||
@ -50,7 +50,7 @@ var _ = Describe("Test tdl archive", func() {
|
||||
})
|
||||
|
||||
It("should fail with invalid file name", func() {
|
||||
exec(cmd, []string{"recover", "-f", "foo.zip"}, false)
|
||||
exec(cmd, []string{"recover", "-f", "foo.tdl"}, false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user