rc: Add GetFsNamedFileOK to get an fs which could also be a file

This commit is contained in:
Nick Craig-Wood 2024-01-19 10:35:02 +00:00
parent 5994fcfed8
commit 0b8689dc28
2 changed files with 92 additions and 6 deletions

View File

@ -5,27 +5,71 @@ package rc
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/cache" "github.com/rclone/rclone/fs/cache"
"github.com/rclone/rclone/fs/config/configmap" "github.com/rclone/rclone/fs/config/configmap"
"github.com/rclone/rclone/fs/filter"
"github.com/rclone/rclone/fs/fspath"
) )
// GetFsNamed gets an fs.Fs named fsName either from the cache or creates it afresh // getFsName gets an fs name from fsName either from the cache or direct
func GetFsNamed(ctx context.Context, in Params, fsName string) (f fs.Fs, err error) { func getFsName(in Params, fsName string) (fsString string, err error) {
fsString, err := in.GetString(fsName) fsString, err = in.GetString(fsName)
if err != nil { if err != nil {
if !IsErrParamInvalid(err) { if !IsErrParamInvalid(err) {
return nil, err return fsString, err
} }
fsString, err = getConfigMap(in, fsName) fsString, err = getConfigMap(in, fsName)
if err != nil {
return fsString, err
}
}
return fsString, err
}
// GetFsNamed gets an fs.Fs named fsName either from the cache or creates it afresh
func GetFsNamed(ctx context.Context, in Params, fsName string) (f fs.Fs, err error) {
fsString, err := getFsName(in, fsName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
return cache.Get(ctx, fsString) return cache.Get(ctx, fsString)
} }
// GetFsNamedFileOK gets an fs.Fs named fsName either from the cache or creates it afresh
//
// If the fs.Fs points to a single file then it returns a new ctx with
// filters applied to make the listings return only that file.
func GetFsNamedFileOK(ctx context.Context, in Params, fsName string) (newCtx context.Context, f fs.Fs, err error) {
fsString, err := getFsName(in, fsName)
if err != nil {
return ctx, nil, err
}
f, err = cache.Get(ctx, fsString)
if err == nil {
return ctx, f, nil
} else if !errors.Is(err, fs.ErrorIsFile) {
return ctx, nil, err
}
// f points to the directory above the file so find the remote name
_, fileName, err := fspath.Split(fsString)
if err != nil {
return ctx, f, err
}
ctx, fi := filter.AddConfig(ctx)
if !fi.InActive() {
return ctx, f, fmt.Errorf("can't limit to single files when using filters: %q", fileName)
}
// Limit transfers to this file
err = fi.AddFile(fileName)
if err != nil {
return ctx, f, fmt.Errorf("failed to limit to single file: %w", err)
}
return ctx, f, nil
}
// getConfigMap gets the config as a map from in and converts it to a // getConfigMap gets the config as a map from in and converts it to a
// config string // config string
// //

View File

@ -5,18 +5,26 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/cache" "github.com/rclone/rclone/fs/cache"
"github.com/rclone/rclone/fs/filter"
"github.com/rclone/rclone/fstest/mockfs" "github.com/rclone/rclone/fstest/mockfs"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func mockNewFs(t *testing.T) func() { func mockNewFs(t *testing.T) func() {
f, err := mockfs.NewFs(context.Background(), "mock", "mock", nil) ctx := context.Background()
f, err := mockfs.NewFs(ctx, "/", "", nil)
require.NoError(t, err) require.NoError(t, err)
cache.Put("/", f) cache.Put("/", f)
f, err = mockfs.NewFs(ctx, "mock", "/", nil)
require.NoError(t, err)
cache.Put("mock:/", f) cache.Put("mock:/", f)
cache.Put(":mock:/", f) cache.Put(":mock:/", f)
f, err = mockfs.NewFs(ctx, "mock", "dir/file.txt", nil)
require.NoError(t, err)
cache.PutErr("mock:dir/file.txt", f, fs.ErrorIsFile)
return func() { return func() {
cache.Clear() cache.Clear()
} }
@ -64,6 +72,40 @@ func TestGetFsNamedStruct(t *testing.T) {
assert.NotNil(t, f) assert.NotNil(t, f)
} }
func TestGetFsNamedFileOK(t *testing.T) {
defer mockNewFs(t)()
ctx := context.Background()
in := Params{
"potato": "/",
}
newCtx, f, err := GetFsNamedFileOK(ctx, in, "potato")
require.NoError(t, err)
assert.NotNil(t, f)
assert.Equal(t, ctx, newCtx)
in = Params{
"sausage": "/",
}
newCtx, f, err = GetFsNamedFileOK(ctx, in, "potato")
require.Error(t, err)
assert.Nil(t, f)
assert.Equal(t, ctx, newCtx)
in = Params{
"potato": "mock:dir/file.txt",
}
newCtx, f, err = GetFsNamedFileOK(ctx, in, "potato")
assert.Nil(t, err)
assert.NotNil(t, f)
assert.NotEqual(t, ctx, newCtx)
fi := filter.GetConfig(newCtx)
assert.False(t, fi.InActive())
assert.True(t, fi.IncludeRemote("file.txt"))
assert.False(t, fi.IncludeRemote("other.txt"))
}
func TestGetConfigMap(t *testing.T) { func TestGetConfigMap(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
in Params in Params