fs: add Fingerprint to detect changes in an object
This commit is contained in:
parent
25662b9e05
commit
79f5d940cf
2 changed files with 97 additions and 0 deletions
54
fs/fingerprint.go
Normal file
54
fs/fingerprint.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/rclone/rclone/fs/hash"
|
||||
)
|
||||
|
||||
// Fingerprint produces a unique-ish string for an object.
|
||||
//
|
||||
// This is for detecting whether an object has changed since we last
|
||||
// saw it, not for checking object identity between two different
|
||||
// remotes - operations.Equal should be used for that.
|
||||
//
|
||||
// If fast is set then Fingerprint will only include attributes where
|
||||
// usually another operation is not required to fetch them. For
|
||||
// example if fast is set then this won't include hashes on the local
|
||||
// backend.
|
||||
func Fingerprint(ctx context.Context, o ObjectInfo, fast bool) string {
|
||||
var (
|
||||
out strings.Builder
|
||||
f = o.Fs()
|
||||
features = f.Features()
|
||||
)
|
||||
fmt.Fprintf(&out, "%d", o.Size())
|
||||
// Whether we want to do a slow operation or not
|
||||
//
|
||||
// fast true false true false
|
||||
// opIsSlow true true false false
|
||||
// do Op false true true true
|
||||
//
|
||||
// If !fast (slow) do the operation or if !OpIsSlow ==
|
||||
// OpIsFast do the operation.
|
||||
//
|
||||
// Eg don't do this for S3 where modtimes are expensive
|
||||
if !fast || !features.SlowModTime {
|
||||
if f.Precision() != ModTimeNotSupported {
|
||||
fmt.Fprintf(&out, ",%v", o.ModTime(ctx).UTC())
|
||||
}
|
||||
}
|
||||
// Eg don't do this for SFTP/local where hashes are expensive?
|
||||
if !fast || !features.SlowHash {
|
||||
hashType := f.Hashes().GetOne()
|
||||
if hashType != hash.None {
|
||||
hash, err := o.Hash(ctx, hashType)
|
||||
if err == nil {
|
||||
fmt.Fprintf(&out, ",%v", hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out.String()
|
||||
}
|
43
fs/fingerprint_test.go
Normal file
43
fs/fingerprint_test.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package fs_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/hash"
|
||||
"github.com/rclone/rclone/fstest/mockfs"
|
||||
"github.com/rclone/rclone/fstest/mockobject"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFingerprint(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := mockfs.NewFs("test", "root")
|
||||
f.SetHashes(hash.NewHashSet(hash.MD5))
|
||||
|
||||
for i, test := range []struct {
|
||||
fast bool
|
||||
slowModTime bool
|
||||
slowHash bool
|
||||
want string
|
||||
}{
|
||||
{fast: false, slowModTime: false, slowHash: false, want: "4,0001-01-01 00:00:00 +0000 UTC,8d777f385d3dfec8815d20f7496026dc"},
|
||||
{fast: false, slowModTime: false, slowHash: true, want: "4,0001-01-01 00:00:00 +0000 UTC,8d777f385d3dfec8815d20f7496026dc"},
|
||||
{fast: false, slowModTime: true, slowHash: false, want: "4,0001-01-01 00:00:00 +0000 UTC,8d777f385d3dfec8815d20f7496026dc"},
|
||||
{fast: false, slowModTime: true, slowHash: true, want: "4,0001-01-01 00:00:00 +0000 UTC,8d777f385d3dfec8815d20f7496026dc"},
|
||||
{fast: true, slowModTime: false, slowHash: false, want: "4,0001-01-01 00:00:00 +0000 UTC,8d777f385d3dfec8815d20f7496026dc"},
|
||||
{fast: true, slowModTime: false, slowHash: true, want: "4,0001-01-01 00:00:00 +0000 UTC"},
|
||||
{fast: true, slowModTime: true, slowHash: false, want: "4,8d777f385d3dfec8815d20f7496026dc"},
|
||||
{fast: true, slowModTime: true, slowHash: true, want: "4"},
|
||||
} {
|
||||
what := fmt.Sprintf("#%d fast=%v,slowModTime=%v,slowHash=%v", i, test.fast, test.slowModTime, test.slowHash)
|
||||
o := mockobject.New("potato").WithContent([]byte("data"), mockobject.SeekModeRegular)
|
||||
o.SetFs(f)
|
||||
f.Features().SlowModTime = test.slowModTime
|
||||
f.Features().SlowHash = test.slowHash
|
||||
got := fs.Fingerprint(ctx, o, test.fast)
|
||||
assert.Equal(t, test.want, got, what)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue