aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetter Rasmussen2016-02-06 19:33:42 +0100
committerPetter Rasmussen2016-02-06 21:34:35 +0100
commit69fb273d2f99604aa3fb80e88fb58f48fc1998c0 (patch)
tree1579e3ca79517c5c92e619e22f21a0eedc23eb4b
parentb7e45b080ffe13d286be65ce396da47b36a16944 (diff)
downloadgdrive-69fb273d2f99604aa3fb80e88fb58f48fc1998c0.tar.bz2
CachedMd5Comparer
-rw-r--r--compare.go67
-rw-r--r--handlers_drive.go8
-rw-r--r--util.go32
3 files changed, 95 insertions, 12 deletions
diff --git a/compare.go b/compare.go
index 7275a38..10cab3c 100644
--- a/compare.go
+++ b/compare.go
@@ -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)
}
diff --git a/util.go b/util.go
index d40d33e..041daed 100644
--- a/util.go
+++ b/util.go
@@ -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))
+}