feat: handle multiple commands sync and list duplicates
This commit is contained in:
parent
2ca045913d
commit
022d56dc8e
|
@ -0,0 +1,52 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"gitea.urkob.com/urko/backblaze-backup/internal/services"
|
||||||
|
"gitea.urkob.com/urko/backblaze-backup/kit/config"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Versions = &cobra.Command{
|
||||||
|
Use: "versions",
|
||||||
|
Short: "Handle versions of files in Backblaze",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
log.SetFlags(log.Lmicroseconds)
|
||||||
|
ctx, cancel := context.WithCancel(signalContext(cmd.Context()))
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
envFile := ""
|
||||||
|
if os.Getenv("BACKBLAZE_ENV") == "dev" {
|
||||||
|
envFile = ".env"
|
||||||
|
}
|
||||||
|
cfg := config.NewConfig(envFile)
|
||||||
|
|
||||||
|
bbService := services.NewBackBlaze(cfg.BbId, cfg.BbKey)
|
||||||
|
if err := bbService.ListDuplicateVersions(ctx); err != nil {
|
||||||
|
log.Fatalln("bbService.ListDuplicateVersions()", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func signalContext(ctx context.Context) context.Context {
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
|
sigs := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigs, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
log.Println("listening for shutdown signal")
|
||||||
|
<-sigs
|
||||||
|
log.Println("shutdown signal received")
|
||||||
|
signal.Stop(sigs)
|
||||||
|
close(sigs)
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -10,11 +10,14 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var Sync = &cobra.Command{
|
||||||
Use: "backblaze-backup",
|
Use: "sync",
|
||||||
Short: "Backblaze backup tool",
|
Short: "Sync files or directories to Backblaze",
|
||||||
Long: `A tool to backup files and directories to Backblaze.`,
|
Long: `A tool to backup files and directories to Backblaze.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
ctx, cancel := context.WithCancel(signalContext(cmd.Context()))
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
log.SetFlags(log.Lmicroseconds)
|
log.SetFlags(log.Lmicroseconds)
|
||||||
filePath, err := cmd.Flags().GetString("file")
|
filePath, err := cmd.Flags().GetString("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -36,21 +39,8 @@ var rootCmd = &cobra.Command{
|
||||||
cfg := config.NewConfig(envFile)
|
cfg := config.NewConfig(envFile)
|
||||||
|
|
||||||
bbService := services.NewBackBlaze(cfg.BbId, cfg.BbKey).WithBucket(bucketName).WithDir(dir).WithFile(filePath)
|
bbService := services.NewBackBlaze(cfg.BbId, cfg.BbKey).WithBucket(bucketName).WithDir(dir).WithFile(filePath)
|
||||||
if err := bbService.Sync(); err != nil {
|
if err := bbService.Sync(ctx); err != nil {
|
||||||
log.Fatalln("bbService.Sync()", err)
|
log.Fatalln("bbService.Sync()", err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.PersistentFlags().String("file", "", "absolute path of the file you want to upload to backblaze")
|
|
||||||
rootCmd.PersistentFlags().String("dir", "", "absolute path of the directory you want to upload to backblaze")
|
|
||||||
rootCmd.PersistentFlags().String("bucket", "", "backblaze bucket name")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -50,7 +50,7 @@ func (b *BackBalze) WithFile(filePath string) *BackBalze {
|
||||||
b.filePath = filePath
|
b.filePath = filePath
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
func (b *BackBalze) Sync() error {
|
func (b *BackBalze) Sync(ctx context.Context) error {
|
||||||
if b.bucketName == "" && (b.filePath == "" || b.dir == "") {
|
if b.bucketName == "" && (b.filePath == "" || b.dir == "") {
|
||||||
return fmt.Errorf("bucket name is %v | filePath is %v | dir is %v", b.bucketName, b.filePath, b.dir)
|
return fmt.Errorf("bucket name is %v | filePath is %v | dir is %v", b.bucketName, b.filePath, b.dir)
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,6 @@ func (b *BackBalze) Sync() error {
|
||||||
return errors.New("you must select just 1 option, dir or file")
|
return errors.New("you must select just 1 option, dir or file")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
b2Client, err := b2.NewClient(ctx, b.bbID, b.bbKey)
|
b2Client, err := b2.NewClient(ctx, b.bbID, b.bbKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("b2.NewClient %w", err)
|
return fmt.Errorf("b2.NewClient %w", err)
|
||||||
|
@ -302,3 +301,63 @@ func bucketFiles(ctx context.Context, bucket *b2.Bucket) ([]string, error) {
|
||||||
}
|
}
|
||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type duplicate struct {
|
||||||
|
bucket string
|
||||||
|
file string
|
||||||
|
count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BackBalze) ListDuplicateVersions(ctx context.Context) error {
|
||||||
|
b2Client, err := b2.NewClient(ctx, b.bbID, b.bbKey)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("b2.NewClient %w", err)
|
||||||
|
}
|
||||||
|
log.Println("b2Client ok")
|
||||||
|
|
||||||
|
buckets, err := b2Client.ListBuckets(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("b2Client.Bucket %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dups := make([]duplicate, 0)
|
||||||
|
|
||||||
|
log.Println("len(buckets)", len(buckets))
|
||||||
|
for _, bc := range buckets {
|
||||||
|
files := make(map[string]int, 0)
|
||||||
|
|
||||||
|
bucketIter := bc.List(ctx, b2.ListHidden())
|
||||||
|
if bucketIter == nil {
|
||||||
|
return fmt.Errorf("bucket list cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if !bucketIter.Next() {
|
||||||
|
if bucketIter.Err() != nil {
|
||||||
|
return fmt.Errorf("bucketIter err %w", bucketIter.Err())
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if bucketIter.Object() == nil {
|
||||||
|
log.Println("bucketIter Object is nil")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
files[bucketIter.Object().Name()]++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search duplicates
|
||||||
|
for file, count := range files {
|
||||||
|
if count > 1 {
|
||||||
|
dups = append(dups, duplicate{
|
||||||
|
bucket: bc.Name(),
|
||||||
|
file: file,
|
||||||
|
count: count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(dups) > 0 {
|
||||||
|
return fmt.Errorf("found duplicates: %+v", dups)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"gitea.urkob.com/urko/backblaze-backup/cmd"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "backblaze-backup",
|
||||||
|
Short: "Backblaze backup tool",
|
||||||
|
Long: `A tool to backup files and directories to Backblaze.`,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(cmd.Sync, cmd.Versions)
|
||||||
|
cmd.Sync.PersistentFlags().String("file", "", "absolute path of the file you want to upload to backblaze")
|
||||||
|
cmd.Sync.PersistentFlags().String("dir", "", "absolute path of the directory you want to upload to backblaze")
|
||||||
|
cmd.Sync.PersistentFlags().String("bucket", "", "backblaze bucket name")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := cmd.Sync.Execute(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue