From c3b2b89473d0054602d25b05051a72b659d63028 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 24 Jan 2017 11:00:05 +0000 Subject: [PATCH] Add ListDirSorted function to list a directory * fix error return of readFilesFn also --- fs/operations.go | 67 ++++++++++++++++++++++++++++++++++++++++++- fs/operations_test.go | 58 +++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/fs/operations.go b/fs/operations.go index 1bcee69e9..f95e9d594 100644 --- a/fs/operations.go +++ b/fs/operations.go @@ -504,7 +504,72 @@ func readFilesFn(fs Fs, includeAll bool, dir string, add func(Object) error) (er Debug(o, "Excluded from sync (and deletion)") } } - return nil + return list.Error() +} + +// DirEntries is a slice of Object or *Dir +type DirEntries []BasicInfo + +// Len is part of sort.Interface. +func (ds DirEntries) Len() int { + return len(ds) +} + +// Swap is part of sort.Interface. +func (ds DirEntries) Swap(i, j int) { + ds[i], ds[j] = ds[j], ds[i] +} + +// Less is part of sort.Interface. +func (ds DirEntries) Less(i, j int) bool { + return ds[i].Remote() < ds[j].Remote() +} + +// FIXME can use this in Mount + +// ListDirSorted reads Object and *Dir into entries for the given Fs. +// +// dir is the start directory, "" for root +// +// If includeAll is specified all files will be added, otherwise only +// files passing the filter will be added. +// +// Files will be returned in sorted order +func ListDirSorted(fs Fs, includeAll bool, dir string) (entries DirEntries, err error) { + list := NewLister().SetLevel(1) + if !includeAll { + list.SetFilter(Config.Filter) + } + list.Start(fs, dir) + for { + o, dir, err := list.Get() + if err != nil { + return nil, err + } else if o != nil { + // Make sure we don't delete excluded files if not required + if includeAll || Config.Filter.IncludeObject(o) { + entries = append(entries, o) + } else { + Debug(o, "Excluded from sync (and deletion)") + } + } else if dir != nil { + if includeAll || Config.Filter.IncludeDirectory(dir.Remote()) { + entries = append(entries, dir) + } else { + Debug(dir, "Excluded from sync (and deletion)") + } + } else { + // finishd since err, o, dir == nil + break + } + } + err = list.Error() + if err != nil { + return nil, err + } + // sort the directory entries by Remote + sort.Sort(entries) + return entries, nil } // Read a map of Object.Remote to Object for the given Fs. diff --git a/fs/operations_test.go b/fs/operations_test.go index 9d659b2a2..43710f81c 100644 --- a/fs/operations_test.go +++ b/fs/operations_test.go @@ -883,3 +883,61 @@ func TestOverlapping(t *testing.T) { assert.Equal(t, test.expected, actual, what) } } + +func TestListDirSorted(t *testing.T) { + r := NewRun(t) + defer r.Finalise() + + fs.Config.Filter.MaxSize = 10 + defer func() { + fs.Config.Filter.MaxSize = -1 + }() + + r.WriteObject("a.txt", "hello world", t1) + r.WriteObject("zend.txt", "hello", t1) + r.WriteObject("sub dir/hello world", "hello world", t1) + r.WriteObject("sub dir/hello world2", "hello world", t1) + r.WriteObject("sub dir/sub sub dir/hello world3", "hello world", t1) + var items fs.DirEntries + var err error + + // Turn the BasicInfo into a name, ending with a / if it is a + // dir + str := func(i int) string { + item := items[i] + name := item.Remote() + switch item.(type) { + case fs.Object: + case *fs.Dir: + name += "/" + default: + t.Fatalf("Unknown type %+v", item) + } + return name + } + + items, err = fs.ListDirSorted(r.fremote, true, "") + require.NoError(t, err) + require.Len(t, items, 3) + assert.Equal(t, "a.txt", str(0)) + assert.Equal(t, "sub dir/", str(1)) + assert.Equal(t, "zend.txt", str(2)) + + items, err = fs.ListDirSorted(r.fremote, false, "") + require.NoError(t, err) + require.Len(t, items, 2) + assert.Equal(t, "sub dir/", str(0)) + assert.Equal(t, "zend.txt", str(1)) + + items, err = fs.ListDirSorted(r.fremote, true, "sub dir") + require.NoError(t, err) + require.Len(t, items, 3) + assert.Equal(t, "sub dir/hello world", str(0)) + assert.Equal(t, "sub dir/hello world2", str(1)) + assert.Equal(t, "sub dir/sub sub dir/", str(2)) + + items, err = fs.ListDirSorted(r.fremote, false, "sub dir") + require.NoError(t, err) + require.Len(t, items, 1) + assert.Equal(t, "sub dir/sub sub dir/", str(0)) +}