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)

View File

@ -278,20 +278,16 @@ y/n> # Auto config, n
##### 4. Verify that it's working ##### 4. Verify that it's working
- `rclone -v --drive-impersonate foo@example.com lsf gdrive:backup` - `rclone -v --drive-impersonate foo@example.com lsf gdrive:backup`
- The arguments do: - The arguments do: - `-v` - verbose logging - `--drive-impersonate foo@example.com` - this is what does
- `-v` - verbose logging the magic, pretending to be user foo. - `lsf` - list files in a parsing friendly way - `gdrive:backup` - use the remote called gdrive, work in
- `--drive-impersonate foo@example.com` - this is what does
the magic, pretending to be user foo.
- `lsf` - list files in a parsing friendly way
- `gdrive:backup` - use the remote called gdrive, work in
the folder named backup. the folder named backup.
Note: in case you configured a specific root folder on gdrive and rclone is unable to access the contents of that folder when using `--drive-impersonate`, do this instead: Note: in case you configured a specific root folder on gdrive and rclone is unable to access the contents of that folder when using `--drive-impersonate`, do this instead:
- in the gdrive web interface, share your root folder with the user/email of the new Service Account you created/selected at step 1 - in the gdrive web interface, share your root folder with the user/email of the new Service Account you created/selected at step 1
- use rclone without specifying the `--drive-impersonate` option, like this: - use rclone without specifying the `--drive-impersonate` option, like this:
`rclone -v lsf gdrive:backup` `rclone -v lsf gdrive:backup`
### Shared drives (team drives) ### Shared drives (team drives)
If you want to configure the remote to point to a Google Shared Drive If you want to configure the remote to point to a Google Shared Drive
@ -342,12 +338,15 @@ It does this by combining multiple `list` calls into a single API request.
This works by combining many `'%s' in parents` filters into one expression. This works by combining many `'%s' in parents` filters into one expression.
To list the contents of directories a, b and c, the following requests will be send by the regular `List` function: To list the contents of directories a, b and c, the following requests will be send by the regular `List` function:
``` ```
trashed=false and 'a' in parents trashed=false and 'a' in parents
trashed=false and 'b' in parents trashed=false and 'b' in parents
trashed=false and 'c' in parents trashed=false and 'c' in parents
``` ```
These can now be combined into a single request: These can now be combined into a single request:
``` ```
trashed=false and ('a' in parents or 'b' in parents or 'c' in parents) trashed=false and ('a' in parents or 'b' in parents or 'c' in parents)
``` ```
@ -357,6 +356,7 @@ It will use the `--checkers` value to specify the number of requests to run in
In tests, these batch requests were up to 20x faster than the regular method. In tests, these batch requests were up to 20x faster than the regular method.
Running the following command against different sized folders gives: Running the following command against different sized folders gives:
``` ```
rclone lsjson -vv -R --checkers=6 gdrive:folder rclone lsjson -vv -R --checkers=6 gdrive:folder
``` ```
@ -396,8 +396,8 @@ revision of that file.
Revisions follow the standard google policy which at time of writing Revisions follow the standard google policy which at time of writing
was was
* They are deleted after 30 days or 100 revisions (whatever comes first). - They are deleted after 30 days or 100 revisions (whatever comes first).
* They do not count towards a user storage quota. - They do not count towards a user storage quota.
### Deleting files ### Deleting files
@ -527,7 +527,7 @@ This list can be changed by Google Drive at any time and might not
represent the currently available conversions. represent the currently available conversions.
| Extension | Mime Type | Description | | Extension | Mime Type | Description |
| --------- |-----------| ------------| | --------- | ------------------------------------------------------------------------- | ---------------------------------------- |
| bmp | image/bmp | Windows Bitmap format | | bmp | image/bmp | Windows Bitmap format |
| csv | text/csv | Standard CSV format for Spreadsheets | | csv | text/csv | Standard CSV format for Spreadsheets |
| doc | application/msword | Classic Word file | | doc | application/msword | Classic Word file |
@ -561,13 +561,14 @@ when opened. The link file extension has to be specified as a
Google Documents. Google Documents.
| Extension | Description | OS Support | | Extension | Description | OS Support |
| --------- | ----------- | ---------- | | --------- | --------------------------------------- | -------------- |
| desktop | freedesktop.org specified desktop entry | Linux | | desktop | freedesktop.org specified desktop entry | Linux |
| link.html | An HTML Document with a redirect | All | | link.html | An HTML Document with a redirect | All |
| url | INI style link file | macOS, Windows | | url | INI style link file | macOS, Windows |
| webloc | macOS specific XML format | macOS | | webloc | macOS specific XML format | macOS |
{{< rem autogenerated options start" - DO NOT EDIT - instead edit fs.RegInfo in backend/drive/drive.go then run make backenddocs" >}} {{< rem autogenerated options start" - DO NOT EDIT - instead edit fs.RegInfo in backend/drive/drive.go then run make backenddocs" >}}
### Standard options ### Standard options
Here are the Standard options specific to drive (Google Drive). Here are the Standard options specific to drive (Google Drive).
@ -701,7 +702,6 @@ Leave blank normally.
Fill in to access "Computers" folders (see docs), or for rclone to use Fill in to access "Computers" folders (see docs), or for rclone to use
a non root folder as its starting point. a non root folder as its starting point.
Properties: Properties:
- Config: root_folder_id - Config: root_folder_id
@ -806,7 +806,6 @@ in this mode.
Do **not** use this flag when trying to download Google Docs - rclone Do **not** use this flag when trying to download Google Docs - rclone
will fail to download them. will fail to download them.
Properties: Properties:
- Config: show_all_gdocs - Config: show_all_gdocs
@ -1137,8 +1136,6 @@ be removed.
See: https://github.com/rclone/rclone/issues/3631 See: https://github.com/rclone/rclone/issues/3631
Properties: Properties:
- Config: disable_http2 - Config: disable_http2
@ -1161,7 +1158,6 @@ Google don't document so it may break in the future.
See: https://github.com/rclone/rclone/issues/3857 See: https://github.com/rclone/rclone/issues/3857
Properties: Properties:
- Config: stop_on_upload_limit - Config: stop_on_upload_limit
@ -1182,7 +1178,6 @@ the in-progress sync.
Note that this detection is relying on error message strings which Note that this detection is relying on error message strings which
Google don't document so it may break in the future. Google don't document so it may break in the future.
Properties: Properties:
- Config: stop_on_download_limit - Config: stop_on_download_limit
@ -1198,7 +1193,6 @@ Normally rclone dereferences shortcut files making them appear as if
they are the original file (see [the shortcuts section](#shortcuts)). they are the original file (see [the shortcuts section](#shortcuts)).
If this flag is set then rclone will ignore shortcut files completely. If this flag is set then rclone will ignore shortcut files completely.
Properties: Properties:
- Config: skip_shortcuts - Config: skip_shortcuts
@ -1212,7 +1206,6 @@ If set skip dangling shortcut files.
If this is set then rclone will not show any dangling shortcuts in listings. If this is set then rclone will not show any dangling shortcuts in listings.
Properties: Properties:
- Config: skip_dangling_shortcuts - Config: skip_dangling_shortcuts
@ -1240,7 +1233,6 @@ Note also that opening the folder once in the web interface (with the
user you've authenticated rclone with) seems to be enough so that the user you've authenticated rclone with) seems to be enough so that the
resource key is not needed. resource key is not needed.
Properties: Properties:
- Config: resource_key - Config: resource_key
@ -1268,7 +1260,6 @@ This flag allows the work-around to be disabled. This is **not**
recommended in normal use - only if you have a particular case you are recommended in normal use - only if you have a particular case you are
having trouble with like many empty directories. having trouble with like many empty directories.
Properties: Properties:
- Config: fast_list_bug_fix - Config: fast_list_bug_fix
@ -1288,7 +1279,6 @@ ownership will generate an email to the new owner (this can't be
disabled), and you can't transfer ownership to someone outside your disabled), and you can't transfer ownership to someone outside your
organization. organization.
Properties: Properties:
- Config: metadata_owner - Config: metadata_owner
@ -1318,7 +1308,6 @@ Note that rclone drops any inherited permissions on Shared Drives and
any owner permission on My Drives as these are duplicated in the owner any owner permission on My Drives as these are duplicated in the owner
metadata. metadata.
Properties: Properties:
- Config: metadata_permissions - Config: metadata_permissions
@ -1355,7 +1344,6 @@ from two different accounts you will have to create the labels in
advance and use the metadata mapper to translate the IDs between the advance and use the metadata mapper to translate the IDs between the
two accounts. two accounts.
Properties: Properties:
- Config: metadata_labels - Config: metadata_labels
@ -1425,7 +1413,7 @@ Metadata is supported on files and directories.
Here are the possible system metadata items for the drive backend. Here are the possible system metadata items for the drive backend.
| Name | Help | Type | Example | Read Only | | Name | Help | Type | Example | Read Only |
|------|------|------|---------|-----------| | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ----------------------------- | --------- |
| btime | Time of file birth (creation) with mS accuracy. Note that this is only writable on fresh uploads - it can't be written for updates. | RFC 3339 | 2006-01-02T15:04:05.999Z07:00 | N | | btime | Time of file birth (creation) with mS accuracy. Note that this is only writable on fresh uploads - it can't be written for updates. | RFC 3339 | 2006-01-02T15:04:05.999Z07:00 | N |
| content-type | The MIME type of the file. | string | text/plain | N | | content-type | The MIME type of the file. | string | text/plain | N |
| copy-requires-writer-permission | Whether the options to copy, print, or download this file, should be disabled for readers and commenters. | boolean | true | N | | copy-requires-writer-permission | Whether the options to copy, print, or download this file, should be disabled for readers and commenters. | boolean | true | N |
@ -1470,7 +1458,6 @@ Usage Examples:
rclone backend get drive: [-o service_account_file] [-o chunk_size] rclone backend get drive: [-o service_account_file] [-o chunk_size]
rclone rc backend/command command=get fs=drive: [-o service_account_file] [-o chunk_size] rclone rc backend/command command=get fs=drive: [-o service_account_file] [-o chunk_size]
Options: Options:
- "chunk_size": show the current upload chunk size - "chunk_size": show the current upload chunk size
@ -1489,7 +1476,6 @@ Usage Examples:
rclone backend set drive: [-o service_account_file=sa.json] [-o chunk_size=67108864] rclone backend set drive: [-o service_account_file=sa.json] [-o chunk_size=67108864]
rclone rc backend/command command=set fs=drive: [-o service_account_file=sa.json] [-o chunk_size=67108864] rclone rc backend/command command=set fs=drive: [-o service_account_file=sa.json] [-o chunk_size=67108864]
Options: Options:
- "chunk_size": update the current upload chunk size - "chunk_size": update the current upload chunk size
@ -1518,7 +1504,6 @@ relative to "drive:" to the "destination_shortcut" relative to
"drive2:". This may fail with a permission error if the user "drive2:". This may fail with a permission error if the user
authenticated with "drive2:" can't read files from "drive:". authenticated with "drive2:" can't read files from "drive:".
Options: Options:
- "target": optional target remote for the shortcut destination - "target": optional target remote for the shortcut destination
@ -1569,11 +1554,10 @@ drives found and a combined drive.
Adding this to the rclone config file will cause those team drives to Adding this to the rclone config file will cause those team drives to
be accessible with the aliases shown. Any illegal characters will be be accessible with the aliases shown. Any illegal characters will be
substituted with "_" and duplicate names will have numbers suffixed. substituted with "\_" and duplicate names will have numbers suffixed.
It will also add a remote called AllDrives which shows all the shared It will also add a remote called AllDrives which shows all the shared
drives combined into one directory tree. drives combined into one directory tree.
### untrash ### untrash
Untrash files and directories Untrash files and directories
@ -1600,7 +1584,6 @@ Result:
"Errors": 0 "Errors": 0
} }
### copyid ### copyid
Copy files by ID Copy files by ID
@ -1627,6 +1610,31 @@ 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.
### moveid
Move files by ID
rclone backend moveid remote: [options] [<arguments>+]
This command moves 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 moving will be
attempted if possible.
Use the --interactive/-i or --dry-run flag to see what would be moved before moving.
### exportformats ### exportformats
@ -1788,11 +1796,13 @@ and click on "CREATE"; on the next screen, enter an "Application name"
enter "Developer Contact Email" (your own email is OK); then click on enter "Developer Contact Email" (your own email is OK); then click on
"Save" (all other data is optional). You will also have to add [some scopes](https://developers.google.com/drive/api/guides/api-specific-auth), "Save" (all other data is optional). You will also have to add [some scopes](https://developers.google.com/drive/api/guides/api-specific-auth),
including including
- `https://www.googleapis.com/auth/docs` - `https://www.googleapis.com/auth/docs`
- `https://www.googleapis.com/auth/drive` in order to be able to edit, - `https://www.googleapis.com/auth/drive` in order to be able to edit,
create and delete files with RClone. create and delete files with RClone.
- `https://www.googleapis.com/auth/drive.metadata.readonly` which you may also want to add. - `https://www.googleapis.com/auth/drive.metadata.readonly` which you may also want to add.
- If you want to add all at once, comma separated it would be `https://www.googleapis.com/auth/docs,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/drive.metadata.readonly`. - If you want to add all at once, comma separated it would be `https://www.googleapis.com/auth/docs,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/drive.metadata.readonly`.
6. After adding scopes, click 6. After adding scopes, click
"Save and continue" to add test users. Be sure to add your own account to "Save and continue" to add test users. Be sure to add your own account to
the test users. Once you've added yourself as a test user and saved the the test users. Once you've added yourself as a test user and saved the