drive: added moveid function to backend

This commit is contained in:
Spencer McCullough 2024-11-20 13:35:16 -07:00
parent d8bc542ffc
commit 6b1bf5fbc0
3 changed files with 566 additions and 439 deletions

View File

@ -3559,6 +3559,41 @@ func (f *Fs) copyID(ctx context.Context, id, dest string) (err error) {
return nil return nil
} }
// move file with id to dest (original file is deleted, unlike with copy)
func (f *Fs) moveID(ctx context.Context, id, dest string) (err error) {
info, err := f.getFile(ctx, id, f.getFileFields(ctx))
if err != nil {
return fmt.Errorf("couldn't find id: %w", err)
}
if info.MimeType == driveFolderType {
return fmt.Errorf("can't copy directory use: rclone copy --drive-root-folder-id %s %s %s", id, fs.ConfigString(f), dest)
}
info.Name = f.opt.Enc.ToStandardName(info.Name)
o, err := f.newObjectWithInfo(ctx, info.Name, info)
if err != nil {
return err
}
destDir, destLeaf, err := fspath.Split(dest)
if err != nil {
return err
}
if destLeaf == "" {
destLeaf = path.Base(o.Remote())
}
if destDir == "" {
destDir = "."
}
dstFs, err := cache.Get(ctx, destDir)
if err != nil {
return err
}
_, err = operations.Move(ctx, dstFs, nil, destLeaf, o)
if err != nil {
return fmt.Errorf("move failed: %w", err)
}
return nil
}
// Run the drive query calling fn on each entry found // Run the drive query calling fn on each entry found
func (f *Fs) queryFn(ctx context.Context, query string, fn func(*drive.File)) (err error) { func (f *Fs) queryFn(ctx context.Context, query string, fn func(*drive.File)) (err error) {
list := f.svc.Files.List() list := f.svc.Files.List()
@ -3789,6 +3824,29 @@ component will be used as the file name.
If the destination is a drive backend then server-side copying will be If the destination is a drive backend then server-side copying will be
attempted if possible. attempted if possible.
Use the --interactive/-i or --dry-run flag to see what would be copied before copying.
`,
}, {
Name: "moveid",
Short: "Move files by ID",
Long: `This command copies files by ID
Usage:
rclone backend moveid drive: ID path
rclone backend moveid drive: ID1 path1 ID2 path2
It moves the drive file with ID given to the path (an rclone path which
will be passed internally to rclone copyto). The ID and path pairs can be
repeated.
The path should end with a / to indicate copy the file as named to
this directory. If it doesn't end with a / then the last path
component will be used as the file name.
If the destination is a drive backend then server-side copying will be
attempted if possible.
Use the --interactive/-i or --dry-run flag to see what would be copied before copying. Use the --interactive/-i or --dry-run flag to see what would be copied before copying.
`, `,
}, { }, {
@ -3982,6 +4040,19 @@ func (f *Fs) Command(ctx context.Context, name string, arg []string, opt map[str
} }
} }
return nil, nil return nil, nil
case "moveid":
if len(arg)%2 != 0 {
return nil, errors.New("need an even number of arguments")
}
for len(arg) > 0 {
id, dest := arg[0], arg[1]
arg = arg[2:]
err = f.moveID(ctx, id, dest)
if err != nil {
return nil, fmt.Errorf("failed moving %q to %q: %w", id, dest, err)
}
}
return nil, nil
case "exportformats": case "exportformats":
return f.exportFormats(ctx), nil return f.exportFormats(ctx), nil
case "importformats": case "importformats":

View File

@ -524,6 +524,51 @@ func (f *Fs) InternalTestCopyID(t *testing.T) {
}) })
} }
// TestIntegration/FsMkdir/FsPutFiles/Internal/MoveID
func (f *Fs) InternalTestMoveID(t *testing.T) {
ctx := context.Background()
obj, err := f.NewObject(ctx, existingFile)
require.NoError(t, err)
o := obj.(*Object)
dir := t.TempDir()
checkFile := func(name string) {
filePath := filepath.Join(dir, name)
fi, err := os.Stat(filePath)
require.NoError(t, err)
assert.Equal(t, int64(100), fi.Size())
err = os.Remove(filePath)
require.NoError(t, err)
}
t.Run("BadID", func(t *testing.T) {
err = f.moveID(ctx, "ID-NOT-FOUND", dir+"/")
require.Error(t, err)
assert.Contains(t, err.Error(), "couldn't find id")
})
t.Run("Directory", func(t *testing.T) {
rootID, err := f.dirCache.RootID(ctx, false)
require.NoError(t, err)
err = f.moveID(ctx, rootID, dir+"/")
require.Error(t, err)
assert.Contains(t, err.Error(), "can't copy directory")
})
t.Run("WithoutDestName", func(t *testing.T) {
err = f.moveID(ctx, o.id, dir+"/")
require.NoError(t, err)
checkFile(path.Base(existingFile))
})
t.Run("WithDestName", func(t *testing.T) {
err = f.moveID(ctx, o.id, dir+"/potato.txt")
require.NoError(t, err)
checkFile("potato.txt")
})
}
// TestIntegration/FsMkdir/FsPutFiles/Internal/Query // TestIntegration/FsMkdir/FsPutFiles/Internal/Query
func (f *Fs) InternalTestQuery(t *testing.T) { func (f *Fs) InternalTestQuery(t *testing.T) {
ctx := context.Background() ctx := context.Background()
@ -648,6 +693,7 @@ func (f *Fs) InternalTest(t *testing.T) {
t.Run("Shortcuts", f.InternalTestShortcuts) t.Run("Shortcuts", f.InternalTestShortcuts)
t.Run("UnTrash", f.InternalTestUnTrash) t.Run("UnTrash", f.InternalTestUnTrash)
t.Run("CopyID", f.InternalTestCopyID) t.Run("CopyID", f.InternalTestCopyID)
t.Run("MoveID", f.InternalTestMoveID)
t.Run("Query", f.InternalTestQuery) t.Run("Query", f.InternalTestQuery)
t.Run("AgeQuery", f.InternalTestAgeQuery) t.Run("AgeQuery", f.InternalTestAgeQuery)
t.Run("ShouldRetry", f.InternalTestShouldRetry) t.Run("ShouldRetry", f.InternalTestShouldRetry)

File diff suppressed because it is too large Load Diff