From 1dcc5e8d4d73b2f8f060376be8184d58736e58f0 Mon Sep 17 00:00:00 2001 From: Mitchell Date: Wed, 6 Feb 2019 23:43:10 -0600 Subject: [PATCH] progress bar - rename files if exist --- .gitignore | 1 + Gopkg.lock | 17 ++++++++++++- file-util.go | 68 ++++++++++++++++++++++++++++++++----------------- main.go | 68 ++++++++++++++++++++++++++++++++++++++++++------- makefile | 15 +++++++++++ media-file.go | 4 ++- progress-bar.go | 41 +++++++++++++++++++++++++++++ 7 files changed, 180 insertions(+), 34 deletions(-) create mode 100644 makefile create mode 100644 progress-bar.go diff --git a/.gitignore b/.gitignore index e58dd9b..cd6d99a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /vendor /ignore +/dist diff --git a/Gopkg.lock b/Gopkg.lock index 10ef811..7ecb224 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,9 +1,24 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + branch = "go1" + digest = "1:af16004ff01450a8ceced637b81f167e21eb9b550821e29352da5cd641e18d6b" + name = "github.com/rwcarlsen/goexif" + packages = [ + "exif", + "mknote", + "tiff", + ] + pruneopts = "UT" + revision = "b1fd11e07dc5bc0d2ca3b79d28cbdf3c6d186247" + [solve-meta] analyzer-name = "dep" analyzer-version = 1 - input-imports = [] + input-imports = [ + "github.com/rwcarlsen/goexif/exif", + "github.com/rwcarlsen/goexif/mknote", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/file-util.go b/file-util.go index f70d2cb..a2ee931 100644 --- a/file-util.go +++ b/file-util.go @@ -3,10 +3,47 @@ package main import ( "io" "io/ioutil" + "log" "os" "path" + "path/filepath" + "strconv" + "strings" ) +func fileExists(path string) bool { + if _, err := os.Stat(path); os.IsNotExist(err) { + return false + } + return true +} + +func getFileSuffix(n int) string { + return "_" + strconv.Itoa(n) +} + +// if file already exists +// append _1 to the end. +// Keep incrementing until file +// does not exist. +func renameIfFileExists(path string) string { + fileSuffix := 1 + for fileExists(path) { + extension := filepath.Ext(path) + pathPrefix := path[0 : len(path)-len(extension)] + + previousFileSuffix := getFileSuffix(fileSuffix - 1) + if strings.HasSuffix(pathPrefix, previousFileSuffix) { + pathPrefix = pathPrefix[0 : len(pathPrefix)-len(previousFileSuffix)] + } + + path = pathPrefix + getFileSuffix(fileSuffix) + extension + fileSuffix++ + } + + return path +} + func createDirIfNotExists(dir string) { if _, err := os.Stat(dir); os.IsNotExist(err) { os.MkdirAll(dir, 0755) @@ -45,41 +82,26 @@ func copyFile(src, dest string) error { return nil } -// recursively read files in directory -func readFiles(dir string, processMetaData bool) []*MediaFile { +// recursively read directory and get all file paths +func getAllFilePaths(dir string) []string { - mediaFiles := []*MediaFile{} + filePaths := []string{} files, err := ioutil.ReadDir(dir) if err != nil { - return mediaFiles + log.Println(err) + return filePaths } for _, f := range files { if f.IsDir() { - mediaFiles = append(mediaFiles, readFiles(path.Join(dir, f.Name()), processMetaData)...) + filePaths = append(filePaths, getAllFilePaths(path.Join(dir, f.Name()))...) } else { - mediaFile := NewMediaFile(path.Join(dir, f.Name()), processMetaData) - - if mediaFile != nil { - mediaFiles = append(mediaFiles, mediaFile) - } + filePaths = append(filePaths, path.Join(dir, f.Name())) } } - return mediaFiles -} - -func scanMediaDirectory(path string, processMetaData bool) map[[20]byte]*MediaFile { - mediaFiles := readFiles(path, processMetaData) - - outputMap := map[[20]byte]*MediaFile{} - - for _, m := range mediaFiles { - outputMap[m.sha1] = m - } - - return outputMap + return filePaths } diff --git a/main.go b/main.go index ddffaf7..b5b75c0 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,6 @@ package main import ( "errors" "flag" - "fmt" "os" ) @@ -11,17 +10,23 @@ var ( inputPath string outputPath string copyDuplicates bool + version = "undefined" ) func init() { + if version != "undefined" { + println("mgphoto ", version, "\n") + } + outputPtr := flag.String("o", "./output", "Output path - defaults to ./output") dupPtr := flag.Bool("d", false, "Copy duplicates to 'duplicates' folder") flag.Parse() if len(flag.Args()) < 1 { - exit(errors.New("Invalid arguments - please supply a source directory")) + println(errors.New("Invalid arguments - please supply a source directory")) + os.Exit(0) } outputPath = *outputPtr @@ -33,15 +38,60 @@ func main() { createDirIfNotExists(outputPath) - sourceFiles := scanMediaDirectory(inputPath, true) - destFiles := scanMediaDirectory(outputPath, false) + sourceFiles := getAllFilePaths(inputPath) + destFiles := getAllFilePaths(outputPath) + + println("Processing source files...") + sourceMediaFiles := getMediaFiles(sourceFiles, true) - for k, val := range sourceFiles { - val.writeToDestination(outputPath, copyDuplicates && destFiles[k] != nil) + println("Scanning destination for duplicates...") + destMediaFiles := getMediaFiles(destFiles, false) + + // if we are not copying duplicates omit them + if !copyDuplicates { + for k := range sourceMediaFiles { + if destMediaFiles[k] != nil { + delete(sourceMediaFiles, k) + } + } } + + if len(sourceMediaFiles) == 0 { + println("No new files to copy.") + return + } + + println("Copying new files to destination...") + progressBar := NewProgressBar(len(sourceMediaFiles)) + for k, val := range sourceMediaFiles { + val.writeToDestination(outputPath, copyDuplicates && destMediaFiles[k] != nil) + progressBar.increment() + } + + progressBar.wait() } -func exit(err error) { - fmt.Println(err) - os.Exit(0) +// get media file objects from file path list +func getMediaFiles(paths []string, processMetaData bool) map[[20]byte]*MediaFile { + + outputMap := map[[20]byte]*MediaFile{} + + if len(paths) < 1 { + return outputMap + } + + progressBar := NewProgressBar(len(paths)) + + for _, path := range paths { + mediaFile := NewMediaFile(path, processMetaData) + + if mediaFile != nil { + outputMap[mediaFile.sha1] = mediaFile + } + progressBar.increment() + } + + progressBar.wait() + + return outputMap } diff --git a/makefile b/makefile new file mode 100644 index 0000000..b7e58d2 --- /dev/null +++ b/makefile @@ -0,0 +1,15 @@ +VERSION := $(shell git describe --tags) + +linux: + GOOS=darwin GOARCH=386 go build -o ./dist/mgphoto-linux -ldflags="-X main.version=${VERSION}" ./*.go + +mac: + GOOS=darwin GOARCH=amd64 go build -o ./dist/mgphoto-mac -ldflags="-X main.version=${VERSION}" ./*.go + +windows: + GOOS=windows GOARCH=386 go build -o ./dist/mgphoto-windows.exe -ldflags="-X main.version=${VERSION}" ./*.go + +clean: + rm -rf ./dist + +all: linux mac windows diff --git a/media-file.go b/media-file.go index ee75eee..d8af21f 100644 --- a/media-file.go +++ b/media-file.go @@ -99,7 +99,9 @@ func (m *MediaFile) writeToDestination(dest string, copyDuplicates bool) error { createDirIfNotExists(dir) - err := copyFile(m.path, path.Join(dir, m.name)) + fullPath := renameIfFileExists(path.Join(dir, m.name)) + + err := copyFile(m.path, fullPath) if err != nil { log.Println(err) diff --git a/progress-bar.go b/progress-bar.go new file mode 100644 index 0000000..6a277eb --- /dev/null +++ b/progress-bar.go @@ -0,0 +1,41 @@ +package main + +import ( + "time" + + "github.com/vbauerster/mpb" + "github.com/vbauerster/mpb/decor" +) + +type ProgressBar struct { + progress *mpb.Progress + bar *mpb.Bar + start time.Time +} + +// NewProgressBar - get new progress bar +func NewProgressBar(total int) *ProgressBar { + + progressBar := new(ProgressBar) + + progressBar.progress = mpb.New(mpb.WithWidth(64), mpb.WithRefreshRate(180*time.Millisecond)) + + progressBar.bar = progressBar.progress.AddBar(int64(total), + mpb.PrependDecorators( + decor.CountersNoUnit("%d / %d", decor.WCSyncWidth), + ), + mpb.AppendDecorators(decor.Elapsed(decor.ET_STYLE_MMSS)), + ) + + progressBar.start = time.Now() + + return progressBar +} + +func (p *ProgressBar) increment() { + p.bar.IncrBy(1, time.Since(p.start)) +} + +func (p *ProgressBar) wait() { + p.progress.Wait() +}