From e1da26dd72392231b00782986a19b984ee6be79f Mon Sep 17 00:00:00 2001 From: 70sh1 <70sh1@proton.me> Date: Fri, 15 Mar 2024 11:17:36 +0300 Subject: [PATCH] refactor: rename 'bar' package to 'ui', move AskPassword func --- eddy.go | 43 ++++++++----------------------------- ui/ui.go | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ ui/ui_test.go | 24 +++++++++++++++++++++ 3 files changed, 92 insertions(+), 34 deletions(-) create mode 100644 ui/ui.go create mode 100644 ui/ui_test.go diff --git a/eddy.go b/eddy.go index a37cc8f..1ff2e31 100644 --- a/eddy.go +++ b/eddy.go @@ -6,20 +6,17 @@ import ( "log" "os" "path/filepath" - "slices" "strings" "sync" "sync/atomic" - "syscall" "time" - "github.com/70sh1/eddy/bars" "github.com/70sh1/eddy/core" "github.com/70sh1/eddy/format" "github.com/70sh1/eddy/pathutils" + "github.com/70sh1/eddy/ui" "github.com/fatih/color" "github.com/urfave/cli/v2" - "golang.org/x/term" ) func main() { @@ -92,28 +89,6 @@ func main() { } } -func askPassword(mode core.Mode, noEmojiAndColor bool) (string, error) { - fmt.Print(format.CondPrefix("🔑 ", "Password: ", noEmojiAndColor)) - password, err := term.ReadPassword(int(syscall.Stdin)) - if err != nil { - return "", err - } - fmt.Print("\r") - if mode == core.Encryption { - fmt.Print(format.CondPrefix("🔑 ", "Confirm password: ", noEmojiAndColor)) - password2, err := term.ReadPassword(int(syscall.Stdin)) - if err != nil { - return "", err - } - if !slices.Equal(password, password2) { - fmt.Print("\r") - return "", errors.New("passwords do not match") - } - } - - return string(password), nil -} - func printDoneMessage(startTime time.Time, noEmojiAndColor bool) { fmt.Println() deltaTime := time.Since(startTime).Round(time.Millisecond) @@ -136,7 +111,7 @@ func encrypt(cCtx *cli.Context) error { return err } if password == "" && passGenLen == 0 { - if password, err = askPassword(core.Encryption, noEmojiAndColor); err != nil { + if password, err = ui.AskPassword(core.Encryption, noEmojiAndColor); err != nil { return err } passGenLen = 6 @@ -169,7 +144,7 @@ func EncryptFiles(paths []string, outputDir, password string, overwrite, noEmoji var wg sync.WaitGroup var numProcessed atomic.Uint64 - barPool, pbars := bars.NewPool(paths, noEmojiAndColor) + barPool, pbars := ui.NewBarPool(paths, noEmojiAndColor) if err := barPool.Start(); err != nil { return 0, err } @@ -186,11 +161,11 @@ func EncryptFiles(paths []string, outputDir, password string, overwrite, noEmoji fileOut = filepath.Join(outputDir, filepath.Base(fileOut)) } if _, err := os.Stat(fileOut); !errors.Is(err, os.ErrNotExist) && !overwrite { - bars.Fail(bar, errors.New("output already exists"), noEmojiAndColor) + ui.BarFail(bar, errors.New("output already exists"), noEmojiAndColor) return } if err := core.EncryptFile(fileIn, fileOut, password, bar); err != nil { - bars.Fail(bar, err, noEmojiAndColor) + ui.BarFail(bar, err, noEmojiAndColor) return } bar.SetCurrent(bar.Total()) @@ -217,7 +192,7 @@ func decrypt(cCtx *cli.Context) error { return err } if password == "" { - if password, err = askPassword(core.Decryption, noEmojiAndColor); err != nil { + if password, err = ui.AskPassword(core.Decryption, noEmojiAndColor); err != nil { return err } } @@ -234,7 +209,7 @@ func decrypt(cCtx *cli.Context) error { func decryptFiles(paths []string, outputDir, password string, overwrite, noEmojiAndColor bool) error { var wg sync.WaitGroup - barPool, pbars := bars.NewPool(paths, noEmojiAndColor) + barPool, pbars := ui.NewBarPool(paths, noEmojiAndColor) if err := barPool.Start(); err != nil { return err } @@ -251,11 +226,11 @@ func decryptFiles(paths []string, outputDir, password string, overwrite, noEmoji fileOut = filepath.Join(outputDir, filepath.Base(fileOut)) } if _, err := os.Stat(fileOut); !errors.Is(err, os.ErrNotExist) && !overwrite { - bars.Fail(bar, errors.New("output already exists"), noEmojiAndColor) + ui.BarFail(bar, errors.New("output already exists"), noEmojiAndColor) return } if err := core.DecryptFile(fileIn, fileOut, password, bar); err != nil { - bars.Fail(bar, err, noEmojiAndColor) + ui.BarFail(bar, err, noEmojiAndColor) return } bar.SetCurrent(bar.Total()) diff --git a/ui/ui.go b/ui/ui.go new file mode 100644 index 0000000..0aef815 --- /dev/null +++ b/ui/ui.go @@ -0,0 +1,59 @@ +package ui + +import ( + "errors" + "fmt" + "path/filepath" + "slices" + "syscall" + + "github.com/70sh1/eddy/core" + "github.com/70sh1/eddy/format" + "github.com/70sh1/eddy/pathutils" + "github.com/cheggaaa/pb/v3" + "github.com/fatih/color" + "golang.org/x/term" +) + +// Creates new progress bar pool. +func NewBarPool(paths []string, noEmojiAndColor bool) (pool *pb.Pool, bars []*pb.ProgressBar) { + barTmpl := `{{ string . "status" }} {{ string . "filename" }} {{ string . "filesize" }} {{ bar . "[" "-" ">" " " "]" }} {{ string . "error" }}` + for _, path := range paths { + bar := pb.New64(1).SetTemplateString(barTmpl).SetWidth(90) + bar.Set("status", format.CondPrefix(" ", "", noEmojiAndColor)) + bar.Set("filename", pathutils.FilenameOverflow(filepath.Base(path), 25)) + bars = append(bars, bar) + } + return pb.NewPool(bars...), bars +} + +func BarFail(bar *pb.ProgressBar, err error, noEmojiAndColor bool) { + errText := err.Error() + if !noEmojiAndColor { + errText = color.RedString(errText) + } + bar.Set("status", format.CondPrefix("❌", "", noEmojiAndColor)) + bar.Set("error", errText) +} + +func AskPassword(mode core.Mode, noEmojiAndColor bool) (string, error) { + fmt.Print(format.CondPrefix("🔑 ", "Password: ", noEmojiAndColor)) + password, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return "", err + } + fmt.Print("\r") + if mode == core.Encryption { + fmt.Print(format.CondPrefix("🔑 ", "Confirm password: ", noEmojiAndColor)) + password2, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return "", err + } + if !slices.Equal(password, password2) { + fmt.Print("\r") + return "", errors.New("passwords do not match") + } + } + + return string(password), nil +} diff --git a/ui/ui_test.go b/ui/ui_test.go new file mode 100644 index 0000000..64bfa1b --- /dev/null +++ b/ui/ui_test.go @@ -0,0 +1,24 @@ +package ui + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNewPool(t *testing.T) { + cases := [][]string{ + {"file1", "path/file2.dat", "home/user/docs/file2"}, + {"C:/some/dir/file1.txt", "path/file3", "home/user/docs/file2"}, + {"file5"}, + } + for _, tCase := range cases { + barPool, bars := NewBarPool(tCase, false) + require.Len(t, bars, len(tCase)) + require.NotNil(t, barPool) + for i := 0; i < len(tCase); i++ { + require.Contains(t, bars[i].String(), filepath.Base(tCase[i])) + } + } +}