refactor(archive): rewrite based on new storage

This commit is contained in:
iyear 2023-12-04 11:54:09 +08:00
parent 92ab241ce6
commit c660507b7d
4 changed files with 54 additions and 52 deletions

View File

@ -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)

View File

@ -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
}

View File

@ -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

View File

@ -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)
})
})
})