diff options
| author | Petter Rasmussen | 2016-02-06 19:33:42 +0100 |
|---|---|---|
| committer | Petter Rasmussen | 2016-02-06 21:34:35 +0100 |
| commit | 69fb273d2f99604aa3fb80e88fb58f48fc1998c0 (patch) | |
| tree | 1579e3ca79517c5c92e619e22f21a0eedc23eb4b | |
| parent | b7e45b080ffe13d286be65ce396da47b36a16944 (diff) | |
| download | gdrive-69fb273d2f99604aa3fb80e88fb58f48fc1998c0.tar.bz2 | |
CachedMd5Comparer
| -rw-r--r-- | compare.go | 67 | ||||
| -rw-r--r-- | handlers_drive.go | 8 | ||||
| -rw-r--r-- | util.go | 32 |
3 files changed, 95 insertions, 12 deletions
@@ -1,27 +1,74 @@ package main import ( - "fmt" "os" - "io" - "crypto/md5" + "encoding/json" "./drive" ) +const MinCacheFileSize = 5 * 1024 * 1024 + type Md5Comparer struct {} func (self Md5Comparer) Changed(local *drive.LocalFile, remote *drive.RemoteFile) bool { return remote.Md5() != md5sum(local.AbsPath()) } -func md5sum(path string) string { - h := md5.New() +type CachedFileInfo struct { + Size int64 `json:"size"` + Modified int64 `json:"modified"` + Md5 string `json:"md5"` +} + +func NewCachedMd5Comparer(path string) CachedMd5Comparer { + cache := map[string]*CachedFileInfo{} + f, err := os.Open(path) - if err != nil { - return "" + if err == nil { + json.NewDecoder(f).Decode(&cache) + } + f.Close() + return CachedMd5Comparer{path, cache} +} + +type CachedMd5Comparer struct { + path string + cache map[string]*CachedFileInfo +} + +func (self CachedMd5Comparer) Changed(local *drive.LocalFile, remote *drive.RemoteFile) bool { + return remote.Md5() != self.md5(local) +} + +func (self CachedMd5Comparer) md5(local *drive.LocalFile) string { + // See if file exist in cache + cached, found := self.cache[local.AbsPath()] + + // If found and modification time and size has not changed, return cached md5 + if found && local.Modified().UnixNano() == cached.Modified && local.Size() == cached.Size { + return cached.Md5 + } + + // Calculate new md5 sum + md5 := md5sum(local.AbsPath()) + + // Cache file info if file meets size criteria + if local.Size() > MinCacheFileSize { + self.cacheAdd(local, md5) + self.persist() } - defer f.Close() - io.Copy(h, f) - return fmt.Sprintf("%x", h.Sum(nil)) + return md5 +} + +func (self CachedMd5Comparer) cacheAdd(lf *drive.LocalFile, md5 string) { + self.cache[lf.AbsPath()] = &CachedFileInfo{ + Size: lf.Size(), + Modified: lf.Modified().UnixNano(), + Md5: md5, + } +} + +func (self CachedMd5Comparer) persist() { + writeJson(self.path, self.cache) } diff --git a/handlers_drive.go b/handlers_drive.go index 029b47e..9de27cc 100644 --- a/handlers_drive.go +++ b/handlers_drive.go @@ -5,6 +5,7 @@ import ( "os" "io" "io/ioutil" + "path/filepath" "./cli" "./auth" "./drive" @@ -13,6 +14,7 @@ import ( const ClientId = "367116221053-7n0vf5akeru7on6o2fjinrecpdoe99eg.apps.googleusercontent.com" const ClientSecret = "1qsNodXNaWq1mQuBjUjmvhoO" const TokenFilename = "token_v2.json" +const DefaultCacheFileName = "file_cache.json" func listHandler(ctx cli.Context) { @@ -58,6 +60,7 @@ func downloadHandler(ctx cli.Context) { func downloadSyncHandler(ctx cli.Context) { args := ctx.Args() + cachePath := filepath.Join(args.String("configDir"), DefaultCacheFileName) err := newDrive(args).DownloadSync(drive.DownloadSyncArgs{ Out: os.Stdout, Progress: progressWriter(args.Bool("noProgress")), @@ -65,7 +68,7 @@ func downloadSyncHandler(ctx cli.Context) { RootId: args.String("id"), DryRun: args.Bool("dryRun"), DeleteExtraneous: args.Bool("deleteExtraneous"), - Comparer: Md5Comparer{}, + Comparer: NewCachedMd5Comparer(cachePath), }) checkErr(err) } @@ -115,6 +118,7 @@ func uploadStdinHandler(ctx cli.Context) { func uploadSyncHandler(ctx cli.Context) { args := ctx.Args() + cachePath := filepath.Join(args.String("configDir"), DefaultCacheFileName) err := newDrive(args).UploadSync(drive.UploadSyncArgs{ Out: os.Stdout, Progress: progressWriter(args.Bool("noProgress")), @@ -123,7 +127,7 @@ func uploadSyncHandler(ctx cli.Context) { DryRun: args.Bool("dryRun"), DeleteExtraneous: args.Bool("deleteExtraneous"), ChunkSize: args.Int64("chunksize"), - Comparer: Md5Comparer{}, + Comparer: NewCachedMd5Comparer(cachePath), }) checkErr(err) } @@ -4,7 +4,10 @@ import ( "runtime" "path/filepath" "fmt" + "encoding/json" "os" + "io" + "crypto/md5" ) func GetDefaultConfigDir() string { @@ -56,3 +59,32 @@ func checkErr(err error) { os.Exit(1) } } + +func writeJson(path string, data interface{}) error { + tmpFile := path + ".tmp" + f, err := os.Create(tmpFile) + if err != nil { + return err + } + + err = json.NewEncoder(f).Encode(data) + f.Close() + if err != nil { + os.Remove(tmpFile) + return err + } + + return os.Rename(tmpFile, path) +} + +func md5sum(path string) string { + h := md5.New() + f, err := os.Open(path) + if err != nil { + return "" + } + defer f.Close() + + io.Copy(h, f) + return fmt.Sprintf("%x", h.Sum(nil)) +} |
