mirror of
https://github.com/rclone/rclone.git
synced 2026-01-30 00:03:34 +00:00
Compare commits
57 Commits
v1.71.2
...
fix-8401-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f499c625bc | ||
|
|
c5a3e86df8 | ||
|
|
4026e8db20 | ||
|
|
c9ce686231 | ||
|
|
b085598cbc | ||
|
|
bb47dccdeb | ||
|
|
7a279d2789 | ||
|
|
9bd5df658a | ||
|
|
d512e4d566 | ||
|
|
3dd68c824a | ||
|
|
fbe73c993b | ||
|
|
d915f75edf | ||
|
|
26b629f42f | ||
|
|
ceaac2194c | ||
|
|
1f14b6aa35 | ||
|
|
dd75af6a18 | ||
|
|
99e8a63df2 | ||
|
|
0019e18ac3 | ||
|
|
218c3bf6e9 | ||
|
|
8f9702583d | ||
|
|
e6578fb5a1 | ||
|
|
fa1d7da272 | ||
|
|
813708c24d | ||
|
|
fee4716343 | ||
|
|
6e9a675b3f | ||
|
|
7f5a444350 | ||
|
|
d2916ac5c7 | ||
|
|
3369a15285 | ||
|
|
58aee30de7 | ||
|
|
ef919241a6 | ||
|
|
d5386bb9a7 | ||
|
|
bf46ea5611 | ||
|
|
b8a379c9c9 | ||
|
|
8c37a9c2ef | ||
|
|
963a72ce01 | ||
|
|
a4962e21d1 | ||
|
|
9e200531b1 | ||
|
|
04683f2032 | ||
|
|
b41f7994da | ||
|
|
13a5ffe391 | ||
|
|
85deea82e4 | ||
|
|
89a8ea7a91 | ||
|
|
c8912eb6a0 | ||
|
|
01674949a1 | ||
|
|
98e1d3ee73 | ||
|
|
50d7a80331 | ||
|
|
bc3e8e1abd | ||
|
|
30e80d0716 | ||
|
|
f288920696 | ||
|
|
fa2bbd705c | ||
|
|
43a794860f | ||
|
|
adfe6b3bad | ||
|
|
091ccb649c | ||
|
|
2e02d49578 | ||
|
|
514535ad46 | ||
|
|
b010591c96 | ||
|
|
1aaee9edce |
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -100,7 +100,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
check-latest: true
|
||||
@@ -222,7 +222,7 @@ jobs:
|
||||
|
||||
- name: Install Go
|
||||
id: setup-go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '>=1.24.0-rc.1'
|
||||
check-latest: true
|
||||
@@ -311,7 +311,7 @@ jobs:
|
||||
|
||||
# Upgrade together with NDK version
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '>=1.25.0-rc.1'
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
# There's no way around this, because "ImageOS" is only available to
|
||||
# processes, but the setup-go action uses it in its key.
|
||||
id: imageos
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
|
||||
@@ -628,7 +628,7 @@ You'll need to modify the following files
|
||||
- `backend/s3/s3.go`
|
||||
- Add the provider to `providerOption` at the top of the file
|
||||
- Add endpoints and other config for your provider gated on the provider in `fs.RegInfo`.
|
||||
- Exclude your provider from generic config questions (eg `region` and `endpoint`).
|
||||
- Exclude your provider from generic config questions (eg `region` and `endpoint).
|
||||
- Add the provider to the `setQuirks` function - see the documentation there.
|
||||
- `docs/content/s3.md`
|
||||
- Add the provider at the top of the page.
|
||||
|
||||
8410
MANUAL.html
generated
8410
MANUAL.html
generated
File diff suppressed because it is too large
Load Diff
2248
MANUAL.txt
generated
2248
MANUAL.txt
generated
File diff suppressed because it is too large
Load Diff
2
Makefile
2
Makefile
@@ -100,6 +100,7 @@ compiletest:
|
||||
check: rclone
|
||||
@echo "-- START CODE QUALITY REPORT -------------------------------"
|
||||
@golangci-lint run $(LINTTAGS) ./...
|
||||
@bin/markdown-lint
|
||||
@echo "-- END CODE QUALITY REPORT ---------------------------------"
|
||||
|
||||
# Get the build dependencies
|
||||
@@ -148,6 +149,7 @@ commanddocs: rclone
|
||||
-@rmdir -p '$$HOME/.config/rclone'
|
||||
XDG_CACHE_HOME="" XDG_CONFIG_HOME="" HOME="\$$HOME" USER="\$$USER" rclone gendocs --config=/notfound docs/content/
|
||||
@[ ! -e '$$HOME' ] || (echo 'Error: created unwanted directory named $$HOME' && exit 1)
|
||||
go run bin/make_bisync_docs.go ./docs/content/
|
||||
|
||||
backenddocs: rclone bin/make_backend_docs.py
|
||||
-@rmdir -p '$$HOME/.config/rclone'
|
||||
|
||||
@@ -59,6 +59,7 @@ directories to and from different cloud storage providers.
|
||||
- Internet Archive [:page_facing_up:](https://rclone.org/internetarchive/)
|
||||
- Jottacloud [:page_facing_up:](https://rclone.org/jottacloud/)
|
||||
- IBM COS S3 [:page_facing_up:](https://rclone.org/s3/#ibm-cos-s3)
|
||||
- Intercolo Object Storage [:page_facing_up:](https://rclone.org/s3/#intercolo)
|
||||
- IONOS Cloud [:page_facing_up:](https://rclone.org/s3/#ionos)
|
||||
- Koofr [:page_facing_up:](https://rclone.org/koofr/)
|
||||
- Leviia Object Storage [:page_facing_up:](https://rclone.org/s3/#leviia)
|
||||
|
||||
@@ -1338,9 +1338,9 @@ func (f *Fs) containerOK(container string) bool {
|
||||
}
|
||||
|
||||
// listDir lists a single directory
|
||||
func (f *Fs) listDir(ctx context.Context, containerName, directory, prefix string, addContainer bool) (entries fs.DirEntries, err error) {
|
||||
func (f *Fs) listDir(ctx context.Context, containerName, directory, prefix string, addContainer bool, callback func(fs.DirEntry) error) (err error) {
|
||||
if !f.containerOK(containerName) {
|
||||
return nil, fs.ErrorDirNotFound
|
||||
return fs.ErrorDirNotFound
|
||||
}
|
||||
err = f.list(ctx, containerName, directory, prefix, addContainer, false, int32(f.opt.ListChunkSize), func(remote string, object *container.BlobItem, isDirectory bool) error {
|
||||
entry, err := f.itemToDirEntry(ctx, remote, object, isDirectory)
|
||||
@@ -1348,16 +1348,16 @@ func (f *Fs) listDir(ctx context.Context, containerName, directory, prefix strin
|
||||
return err
|
||||
}
|
||||
if entry != nil {
|
||||
entries = append(entries, entry)
|
||||
return callback(entry)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// container must be present if listing succeeded
|
||||
f.cache.MarkOK(containerName)
|
||||
return entries, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// listContainers returns all the containers to out
|
||||
@@ -1393,14 +1393,47 @@ func (f *Fs) listContainers(ctx context.Context) (entries fs.DirEntries, err err
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
|
||||
return list.WithListP(ctx, dir, f)
|
||||
}
|
||||
|
||||
// ListP lists the objects and directories of the Fs starting
|
||||
// from dir non recursively into out.
|
||||
//
|
||||
// dir should be "" to start from the root, and should not
|
||||
// have trailing slashes.
|
||||
//
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
//
|
||||
// It should call callback for each tranche of entries read.
|
||||
// These need not be returned in any particular order. If
|
||||
// callback returns an error then the listing will stop
|
||||
// immediately.
|
||||
func (f *Fs) ListP(ctx context.Context, dir string, callback fs.ListRCallback) error {
|
||||
list := list.NewHelper(callback)
|
||||
container, directory := f.split(dir)
|
||||
if container == "" {
|
||||
if directory != "" {
|
||||
return nil, fs.ErrorListBucketRequired
|
||||
return fs.ErrorListBucketRequired
|
||||
}
|
||||
return f.listContainers(ctx)
|
||||
entries, err := f.listContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
err = list.Add(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := f.listDir(ctx, container, directory, f.rootDirectory, f.rootContainer == "", list.Add)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return f.listDir(ctx, container, directory, f.rootDirectory, f.rootContainer == "")
|
||||
return list.Flush()
|
||||
}
|
||||
|
||||
// ListR lists the objects and directories of the Fs starting
|
||||
@@ -2765,6 +2798,8 @@ func (o *Object) clearUncommittedBlocks(ctx context.Context) (err error) {
|
||||
blockList blockblob.GetBlockListResponse
|
||||
properties *blob.GetPropertiesResponse
|
||||
options *blockblob.CommitBlockListOptions
|
||||
// Use temporary pacer as this can be called recursively which can cause a deadlock with --max-connections
|
||||
pacer = fs.NewPacer(ctx, pacer.NewS3(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant)))
|
||||
)
|
||||
|
||||
properties, err = o.readMetaDataAlways(ctx)
|
||||
@@ -2776,7 +2811,7 @@ func (o *Object) clearUncommittedBlocks(ctx context.Context) (err error) {
|
||||
|
||||
if objectExists {
|
||||
// Get the committed block list
|
||||
err = o.fs.pacer.Call(func() (bool, error) {
|
||||
err = pacer.Call(func() (bool, error) {
|
||||
blockList, err = blockBlobSVC.GetBlockList(ctx, blockblob.BlockListTypeAll, nil)
|
||||
return o.fs.shouldRetry(ctx, err)
|
||||
})
|
||||
@@ -2818,7 +2853,7 @@ func (o *Object) clearUncommittedBlocks(ctx context.Context) (err error) {
|
||||
|
||||
// Commit only the committed blocks
|
||||
fs.Debugf(o, "Committing %d blocks to remove uncommitted blocks", len(blockIDs))
|
||||
err = o.fs.pacer.Call(func() (bool, error) {
|
||||
err = pacer.Call(func() (bool, error) {
|
||||
_, err := blockBlobSVC.CommitBlockList(ctx, blockIDs, options)
|
||||
return o.fs.shouldRetry(ctx, err)
|
||||
})
|
||||
@@ -3154,6 +3189,7 @@ var (
|
||||
_ fs.PutStreamer = &Fs{}
|
||||
_ fs.Purger = &Fs{}
|
||||
_ fs.ListRer = &Fs{}
|
||||
_ fs.ListPer = &Fs{}
|
||||
_ fs.OpenChunkWriter = &Fs{}
|
||||
_ fs.Object = &Object{}
|
||||
_ fs.MimeTyper = &Object{}
|
||||
|
||||
@@ -1313,29 +1313,10 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object,
|
||||
}
|
||||
srcURL := srcObj.fileClient().URL()
|
||||
fc := f.fileClient(remote)
|
||||
startCopy, err := fc.StartCopyFromURL(ctx, srcURL, &opt)
|
||||
_, err = fc.StartCopyFromURL(ctx, srcURL, &opt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Copy failed: %w", err)
|
||||
}
|
||||
|
||||
// Poll for completion if necessary
|
||||
//
|
||||
// The for loop is never executed for same storage account copies.
|
||||
copyStatus := startCopy.CopyStatus
|
||||
var properties file.GetPropertiesResponse
|
||||
pollTime := 100 * time.Millisecond
|
||||
|
||||
for copyStatus != nil && string(*copyStatus) == string(file.CopyStatusTypePending) {
|
||||
time.Sleep(pollTime)
|
||||
|
||||
properties, err = fc.GetProperties(ctx, &file.GetPropertiesOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copyStatus = properties.CopyStatus
|
||||
pollTime = min(2*pollTime, time.Second)
|
||||
}
|
||||
|
||||
dstObj, err := f.NewObject(ctx, remote)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Copy: NewObject failed: %w", err)
|
||||
|
||||
@@ -847,7 +847,7 @@ func (f *Fs) itemToDirEntry(ctx context.Context, remote string, object *api.File
|
||||
}
|
||||
|
||||
// listDir lists a single directory
|
||||
func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addBucket bool) (entries fs.DirEntries, err error) {
|
||||
func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addBucket bool, callback func(fs.DirEntry) error) (err error) {
|
||||
last := ""
|
||||
err = f.list(ctx, bucket, directory, prefix, f.rootBucket == "", false, 0, f.opt.Versions, false, func(remote string, object *api.File, isDirectory bool) error {
|
||||
entry, err := f.itemToDirEntry(ctx, remote, object, isDirectory, &last)
|
||||
@@ -855,16 +855,16 @@ func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addB
|
||||
return err
|
||||
}
|
||||
if entry != nil {
|
||||
entries = append(entries, entry)
|
||||
return callback(entry)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// bucket must be present if listing succeeded
|
||||
f.cache.MarkOK(bucket)
|
||||
return entries, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// listBuckets returns all the buckets to out
|
||||
@@ -890,14 +890,46 @@ func (f *Fs) listBuckets(ctx context.Context) (entries fs.DirEntries, err error)
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
|
||||
return list.WithListP(ctx, dir, f)
|
||||
}
|
||||
|
||||
// ListP lists the objects and directories of the Fs starting
|
||||
// from dir non recursively into out.
|
||||
//
|
||||
// dir should be "" to start from the root, and should not
|
||||
// have trailing slashes.
|
||||
//
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
//
|
||||
// It should call callback for each tranche of entries read.
|
||||
// These need not be returned in any particular order. If
|
||||
// callback returns an error then the listing will stop
|
||||
// immediately.
|
||||
func (f *Fs) ListP(ctx context.Context, dir string, callback fs.ListRCallback) error {
|
||||
list := list.NewHelper(callback)
|
||||
bucket, directory := f.split(dir)
|
||||
if bucket == "" {
|
||||
if directory != "" {
|
||||
return nil, fs.ErrorListBucketRequired
|
||||
return fs.ErrorListBucketRequired
|
||||
}
|
||||
entries, err := f.listBuckets(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
err = list.Add(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := f.listDir(ctx, bucket, directory, f.rootDirectory, f.rootBucket == "", list.Add)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.listBuckets(ctx)
|
||||
}
|
||||
return f.listDir(ctx, bucket, directory, f.rootDirectory, f.rootBucket == "")
|
||||
return list.Flush()
|
||||
}
|
||||
|
||||
// ListR lists the objects and directories of the Fs starting
|
||||
@@ -2192,17 +2224,13 @@ func (f *Fs) OpenChunkWriter(ctx context.Context, remote string, src fs.ObjectIn
|
||||
return info, nil, err
|
||||
}
|
||||
|
||||
up, err := f.newLargeUpload(ctx, o, nil, src, f.opt.ChunkSize, false, nil, options...)
|
||||
if err != nil {
|
||||
return info, nil, err
|
||||
}
|
||||
|
||||
info = fs.ChunkWriterInfo{
|
||||
ChunkSize: up.chunkSize,
|
||||
ChunkSize: int64(f.opt.ChunkSize),
|
||||
Concurrency: o.fs.opt.UploadConcurrency,
|
||||
//LeavePartsOnError: o.fs.opt.LeavePartsOnError,
|
||||
}
|
||||
return info, up, nil
|
||||
up, err := f.newLargeUpload(ctx, o, nil, src, f.opt.ChunkSize, false, nil, options...)
|
||||
return info, up, err
|
||||
}
|
||||
|
||||
// Remove an object
|
||||
@@ -2432,6 +2460,7 @@ var (
|
||||
_ fs.PutStreamer = &Fs{}
|
||||
_ fs.CleanUpper = &Fs{}
|
||||
_ fs.ListRer = &Fs{}
|
||||
_ fs.ListPer = &Fs{}
|
||||
_ fs.PublicLinker = &Fs{}
|
||||
_ fs.OpenChunkWriter = &Fs{}
|
||||
_ fs.Commander = &Fs{}
|
||||
|
||||
@@ -252,9 +252,6 @@ Docs: https://cloud.google.com/storage/docs/bucket-policy-only
|
||||
}, {
|
||||
Value: "us-east4",
|
||||
Help: "Northern Virginia",
|
||||
}, {
|
||||
Value: "us-east5",
|
||||
Help: "Ohio",
|
||||
}, {
|
||||
Value: "us-west1",
|
||||
Help: "Oregon",
|
||||
@@ -763,7 +760,7 @@ func (f *Fs) itemToDirEntry(ctx context.Context, remote string, object *storage.
|
||||
}
|
||||
|
||||
// listDir lists a single directory
|
||||
func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addBucket bool) (entries fs.DirEntries, err error) {
|
||||
func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addBucket bool, callback func(fs.DirEntry) error) (err error) {
|
||||
// List the objects
|
||||
err = f.list(ctx, bucket, directory, prefix, addBucket, false, func(remote string, object *storage.Object, isDirectory bool) error {
|
||||
entry, err := f.itemToDirEntry(ctx, remote, object, isDirectory)
|
||||
@@ -771,16 +768,16 @@ func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addB
|
||||
return err
|
||||
}
|
||||
if entry != nil {
|
||||
entries = append(entries, entry)
|
||||
return callback(entry)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// bucket must be present if listing succeeded
|
||||
f.cache.MarkOK(bucket)
|
||||
return entries, err
|
||||
return err
|
||||
}
|
||||
|
||||
// listBuckets lists the buckets
|
||||
@@ -823,14 +820,46 @@ func (f *Fs) listBuckets(ctx context.Context) (entries fs.DirEntries, err error)
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
|
||||
return list.WithListP(ctx, dir, f)
|
||||
}
|
||||
|
||||
// ListP lists the objects and directories of the Fs starting
|
||||
// from dir non recursively into out.
|
||||
//
|
||||
// dir should be "" to start from the root, and should not
|
||||
// have trailing slashes.
|
||||
//
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
//
|
||||
// It should call callback for each tranche of entries read.
|
||||
// These need not be returned in any particular order. If
|
||||
// callback returns an error then the listing will stop
|
||||
// immediately.
|
||||
func (f *Fs) ListP(ctx context.Context, dir string, callback fs.ListRCallback) error {
|
||||
list := list.NewHelper(callback)
|
||||
bucket, directory := f.split(dir)
|
||||
if bucket == "" {
|
||||
if directory != "" {
|
||||
return nil, fs.ErrorListBucketRequired
|
||||
return fs.ErrorListBucketRequired
|
||||
}
|
||||
entries, err := f.listBuckets(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
err = list.Add(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := f.listDir(ctx, bucket, directory, f.rootDirectory, f.rootBucket == "", list.Add)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.listBuckets(ctx)
|
||||
}
|
||||
return f.listDir(ctx, bucket, directory, f.rootDirectory, f.rootBucket == "")
|
||||
return list.Flush()
|
||||
}
|
||||
|
||||
// ListR lists the objects and directories of the Fs starting
|
||||
@@ -1465,6 +1494,7 @@ var (
|
||||
_ fs.Copier = &Fs{}
|
||||
_ fs.PutStreamer = &Fs{}
|
||||
_ fs.ListRer = &Fs{}
|
||||
_ fs.ListPer = &Fs{}
|
||||
_ fs.Object = &Object{}
|
||||
_ fs.MimeTyper = &Object{}
|
||||
)
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
iofs "io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -842,13 +841,7 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error {
|
||||
} else if !fi.IsDir() {
|
||||
return fs.ErrorIsFile
|
||||
}
|
||||
err := os.Remove(localPath)
|
||||
if runtime.GOOS == "windows" && errors.Is(err, iofs.ErrPermission) { // https://github.com/golang/go/issues/26295
|
||||
if os.Chmod(localPath, 0o600) == nil {
|
||||
err = os.Remove(localPath)
|
||||
}
|
||||
}
|
||||
return err
|
||||
return os.Remove(localPath)
|
||||
}
|
||||
|
||||
// Precision of the file system
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/fs/operations"
|
||||
"github.com/rclone/rclone/fstest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestRmdirWindows tests that FILE_ATTRIBUTE_READONLY does not block Rmdir on windows.
|
||||
// Microsoft docs indicate that "This attribute is not honored on directories."
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants#file_attribute_readonly
|
||||
// and https://github.com/golang/go/issues/26295
|
||||
func TestRmdirWindows(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skipf("windows only")
|
||||
}
|
||||
r := fstest.NewRun(t)
|
||||
defer r.Finalise()
|
||||
|
||||
err := operations.Mkdir(context.Background(), r.Flocal, "testdir")
|
||||
require.NoError(t, err)
|
||||
|
||||
ptr, err := syscall.UTF16PtrFromString(filepath.Join(r.Flocal.Root(), "testdir"))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = syscall.SetFileAttributes(ptr, uint32(syscall.FILE_ATTRIBUTE_DIRECTORY+syscall.FILE_ATTRIBUTE_READONLY))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = operations.Rmdir(context.Background(), r.Flocal, "testdir")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -325,13 +325,12 @@ func (f *Fs) list(ctx context.Context, bucket, directory, prefix string, addBuck
|
||||
}
|
||||
|
||||
// listDir lists the bucket to the entries
|
||||
func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addBucket bool) (entries fs.DirEntries, err error) {
|
||||
func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addBucket bool, callback func(fs.DirEntry) error) (err error) {
|
||||
// List the objects and directories
|
||||
err = f.list(ctx, bucket, directory, prefix, addBucket, false, func(remote string, entry fs.DirEntry, isDirectory bool) error {
|
||||
entries = append(entries, entry)
|
||||
return nil
|
||||
return callback(entry)
|
||||
})
|
||||
return entries, err
|
||||
return err
|
||||
}
|
||||
|
||||
// listBuckets lists the buckets to entries
|
||||
@@ -354,15 +353,46 @@ func (f *Fs) listBuckets(ctx context.Context) (entries fs.DirEntries, err error)
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
|
||||
// defer fslog.Trace(dir, "")("entries = %q, err = %v", &entries, &err)
|
||||
return list.WithListP(ctx, dir, f)
|
||||
}
|
||||
|
||||
// ListP lists the objects and directories of the Fs starting
|
||||
// from dir non recursively into out.
|
||||
//
|
||||
// dir should be "" to start from the root, and should not
|
||||
// have trailing slashes.
|
||||
//
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
//
|
||||
// It should call callback for each tranche of entries read.
|
||||
// These need not be returned in any particular order. If
|
||||
// callback returns an error then the listing will stop
|
||||
// immediately.
|
||||
func (f *Fs) ListP(ctx context.Context, dir string, callback fs.ListRCallback) error {
|
||||
list := list.NewHelper(callback)
|
||||
bucket, directory := f.split(dir)
|
||||
if bucket == "" {
|
||||
if directory != "" {
|
||||
return nil, fs.ErrorListBucketRequired
|
||||
return fs.ErrorListBucketRequired
|
||||
}
|
||||
entries, err := f.listBuckets(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
err = list.Add(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := f.listDir(ctx, bucket, directory, f.rootDirectory, f.rootBucket == "", list.Add)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.listBuckets(ctx)
|
||||
}
|
||||
return f.listDir(ctx, bucket, directory, f.rootDirectory, f.rootBucket == "")
|
||||
return list.Flush()
|
||||
}
|
||||
|
||||
// ListR lists the objects and directories of the Fs starting
|
||||
@@ -629,6 +659,7 @@ var (
|
||||
_ fs.Copier = &Fs{}
|
||||
_ fs.PutStreamer = &Fs{}
|
||||
_ fs.ListRer = &Fs{}
|
||||
_ fs.ListPer = &Fs{}
|
||||
_ fs.Object = &Object{}
|
||||
_ fs.MimeTyper = &Object{}
|
||||
)
|
||||
|
||||
@@ -254,15 +254,47 @@ func (f *Fs) split(rootRelativePath string) (bucketName, bucketPath string) {
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
|
||||
return list.WithListP(ctx, dir, f)
|
||||
}
|
||||
|
||||
// ListP lists the objects and directories of the Fs starting
|
||||
// from dir non recursively into out.
|
||||
//
|
||||
// dir should be "" to start from the root, and should not
|
||||
// have trailing slashes.
|
||||
//
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
//
|
||||
// It should call callback for each tranche of entries read.
|
||||
// These need not be returned in any particular order. If
|
||||
// callback returns an error then the listing will stop
|
||||
// immediately.
|
||||
func (f *Fs) ListP(ctx context.Context, dir string, callback fs.ListRCallback) error {
|
||||
list := list.NewHelper(callback)
|
||||
bucketName, directory := f.split(dir)
|
||||
fs.Debugf(f, "listing: bucket : %v, directory: %v", bucketName, dir)
|
||||
if bucketName == "" {
|
||||
if directory != "" {
|
||||
return nil, fs.ErrorListBucketRequired
|
||||
return fs.ErrorListBucketRequired
|
||||
}
|
||||
entries, err := f.listBuckets(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
err = list.Add(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := f.listDir(ctx, bucketName, directory, f.rootDirectory, f.rootBucket == "", list.Add)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.listBuckets(ctx)
|
||||
}
|
||||
return f.listDir(ctx, bucketName, directory, f.rootDirectory, f.rootBucket == "")
|
||||
return list.Flush()
|
||||
}
|
||||
|
||||
// listFn is called from list to handle an object.
|
||||
@@ -411,24 +443,24 @@ func (f *Fs) itemToDirEntry(ctx context.Context, remote string, object *objectst
|
||||
}
|
||||
|
||||
// listDir lists a single directory
|
||||
func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addBucket bool) (entries fs.DirEntries, err error) {
|
||||
func (f *Fs) listDir(ctx context.Context, bucket, directory, prefix string, addBucket bool, callback func(fs.DirEntry) error) (err error) {
|
||||
fn := func(remote string, object *objectstorage.ObjectSummary, isDirectory bool) error {
|
||||
entry, err := f.itemToDirEntry(ctx, remote, object, isDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if entry != nil {
|
||||
entries = append(entries, entry)
|
||||
return callback(entry)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = f.list(ctx, bucket, directory, prefix, addBucket, false, 0, fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// bucket must be present if listing succeeded
|
||||
f.cache.MarkOK(bucket)
|
||||
return entries, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// listBuckets returns all the buckets to out
|
||||
@@ -765,6 +797,7 @@ var (
|
||||
_ fs.Copier = &Fs{}
|
||||
_ fs.PutStreamer = &Fs{}
|
||||
_ fs.ListRer = &Fs{}
|
||||
_ fs.ListPer = &Fs{}
|
||||
_ fs.Commander = &Fs{}
|
||||
_ fs.CleanUpper = &Fs{}
|
||||
_ fs.OpenChunkWriter = &Fs{}
|
||||
|
||||
@@ -5,7 +5,6 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -137,25 +136,8 @@ type Link struct {
|
||||
}
|
||||
|
||||
// Valid reports whether l is non-nil, has an URL, and is not expired.
|
||||
// It primarily checks the URL's expire query parameter, falling back to the Expire field.
|
||||
func (l *Link) Valid() bool {
|
||||
if l == nil || l.URL == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Primary validation: check URL's expire query parameter
|
||||
if u, err := url.Parse(l.URL); err == nil {
|
||||
if expireStr := u.Query().Get("expire"); expireStr != "" {
|
||||
// Try parsing as Unix timestamp (seconds)
|
||||
if expireInt, err := strconv.ParseInt(expireStr, 10, 64); err == nil {
|
||||
expireTime := time.Unix(expireInt, 0)
|
||||
return time.Now().Add(10 * time.Second).Before(expireTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback validation: use the Expire field if URL parsing didn't work
|
||||
return time.Now().Add(10 * time.Second).Before(time.Time(l.Expire))
|
||||
return l != nil && l.URL != "" && time.Now().Add(10*time.Second).Before(time.Time(l.Expire))
|
||||
}
|
||||
|
||||
// URL is a basic form of URL
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestLinkValid tests the Link.Valid method for various scenarios
|
||||
func TestLinkValid(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
link *Link
|
||||
expected bool
|
||||
desc string
|
||||
}{
|
||||
{
|
||||
name: "nil link",
|
||||
link: nil,
|
||||
expected: false,
|
||||
desc: "nil link should be invalid",
|
||||
},
|
||||
{
|
||||
name: "empty URL",
|
||||
link: &Link{URL: ""},
|
||||
expected: false,
|
||||
desc: "empty URL should be invalid",
|
||||
},
|
||||
{
|
||||
name: "valid URL with future expire parameter",
|
||||
link: &Link{
|
||||
URL: fmt.Sprintf("https://example.com/file?expire=%d", time.Now().Add(time.Hour).Unix()),
|
||||
},
|
||||
expected: true,
|
||||
desc: "URL with future expire parameter should be valid",
|
||||
},
|
||||
{
|
||||
name: "expired URL with past expire parameter",
|
||||
link: &Link{
|
||||
URL: fmt.Sprintf("https://example.com/file?expire=%d", time.Now().Add(-time.Hour).Unix()),
|
||||
},
|
||||
expected: false,
|
||||
desc: "URL with past expire parameter should be invalid",
|
||||
},
|
||||
{
|
||||
name: "URL expire parameter takes precedence over Expire field",
|
||||
link: &Link{
|
||||
URL: fmt.Sprintf("https://example.com/file?expire=%d", time.Now().Add(time.Hour).Unix()),
|
||||
Expire: Time(time.Now().Add(-time.Hour)), // Fallback is expired
|
||||
},
|
||||
expected: true,
|
||||
desc: "URL expire parameter should take precedence over Expire field",
|
||||
},
|
||||
{
|
||||
name: "URL expire parameter within 10 second buffer should be invalid",
|
||||
link: &Link{
|
||||
URL: fmt.Sprintf("https://example.com/file?expire=%d", time.Now().Add(5*time.Second).Unix()),
|
||||
},
|
||||
expected: false,
|
||||
desc: "URL expire parameter within 10 second buffer should be invalid",
|
||||
},
|
||||
{
|
||||
name: "fallback to Expire field when no URL expire parameter",
|
||||
link: &Link{
|
||||
URL: "https://example.com/file",
|
||||
Expire: Time(time.Now().Add(time.Hour)),
|
||||
},
|
||||
expected: true,
|
||||
desc: "should fallback to Expire field when URL has no expire parameter",
|
||||
},
|
||||
{
|
||||
name: "fallback to Expire field when URL expire parameter is invalid",
|
||||
link: &Link{
|
||||
URL: "https://example.com/file?expire=invalid",
|
||||
Expire: Time(time.Now().Add(time.Hour)),
|
||||
},
|
||||
expected: true,
|
||||
desc: "should fallback to Expire field when URL expire parameter is unparseable",
|
||||
},
|
||||
{
|
||||
name: "invalid when both URL expire and Expire field are expired",
|
||||
link: &Link{
|
||||
URL: fmt.Sprintf("https://example.com/file?expire=%d", time.Now().Add(-time.Hour).Unix()),
|
||||
Expire: Time(time.Now().Add(-time.Hour)),
|
||||
},
|
||||
expected: false,
|
||||
desc: "should be invalid when both URL expire and Expire field are expired",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.link.Valid()
|
||||
if result != tt.expected {
|
||||
t.Errorf("Link.Valid() = %v, expected %v. %s", result, tt.expected, tt.desc)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,9 @@ var providerOption = fs.Option{
|
||||
}, {
|
||||
Value: "IDrive",
|
||||
Help: "IDrive e2",
|
||||
}, {
|
||||
Value: "Intercolo",
|
||||
Help: "Intercolo Object Storage",
|
||||
}, {
|
||||
Value: "IONOS",
|
||||
Help: "IONOS Cloud",
|
||||
@@ -504,6 +507,14 @@ func init() {
|
||||
Value: "us-east-1",
|
||||
Help: "Indore, Madhya Pradesh, India",
|
||||
}},
|
||||
}, {
|
||||
Name: "region",
|
||||
Help: "Region where your bucket will be created and your data stored.\n",
|
||||
Provider: "Intercolo",
|
||||
Examples: []fs.OptionExample{{
|
||||
Value: "de-fra",
|
||||
Help: "Frankfurt, Germany",
|
||||
}},
|
||||
}, {
|
||||
Name: "region",
|
||||
Help: "Region where your bucket will be created and your data stored.\n",
|
||||
@@ -643,7 +654,7 @@ func init() {
|
||||
}, {
|
||||
Name: "region",
|
||||
Help: "Region to connect to.\n\nLeave blank if you are using an S3 clone and you don't have a region.",
|
||||
Provider: "!AWS,Alibaba,ArvanCloud,ChinaMobile,Cloudflare,FlashBlade,IONOS,Petabox,Liara,Linode,Magalu,OVHcloud,Qiniu,RackCorp,Scaleway,Selectel,Storj,Synology,TencentCOS,HuaweiOBS,IDrive,Mega,Zata",
|
||||
Provider: "!AWS,Alibaba,ArvanCloud,ChinaMobile,Cloudflare,FlashBlade,Intercolo,IONOS,Petabox,Liara,Linode,Magalu,OVHcloud,Qiniu,RackCorp,Scaleway,Selectel,Storj,Synology,TencentCOS,HuaweiOBS,IDrive,Mega,Zata",
|
||||
Examples: []fs.OptionExample{{
|
||||
Value: "",
|
||||
Help: "Use this if unsure.\nWill use v4 signatures and an empty region.",
|
||||
@@ -954,6 +965,14 @@ func init() {
|
||||
Value: "s3.private.sng01.cloud-object-storage.appdomain.cloud",
|
||||
Help: "Singapore Single Site Private Endpoint",
|
||||
}},
|
||||
}, {
|
||||
Name: "endpoint",
|
||||
Help: "Endpoint for Intercolo Object Storage.",
|
||||
Provider: "Intercolo",
|
||||
Examples: []fs.OptionExample{{
|
||||
Value: "de-fra.i3storage.com",
|
||||
Help: "Frankfurt, Germany",
|
||||
}},
|
||||
}, {
|
||||
Name: "endpoint",
|
||||
Help: "Endpoint for IONOS S3 Object Storage.\n\nSpecify the endpoint from the same region.",
|
||||
@@ -1532,7 +1551,7 @@ func init() {
|
||||
}, {
|
||||
Name: "endpoint",
|
||||
Help: "Endpoint for S3 API.\n\nRequired when using an S3 clone.",
|
||||
Provider: "!AWS,ArvanCloud,IBMCOS,IDrive,IONOS,TencentCOS,HuaweiOBS,Alibaba,ChinaMobile,GCS,Liara,Linode,LyveCloud,Magalu,OVHcloud,Scaleway,Selectel,StackPath,Storj,Synology,RackCorp,Qiniu,Petabox,Zata",
|
||||
Provider: "!AWS,ArvanCloud,IBMCOS,IDrive,Intercolo,IONOS,TencentCOS,HuaweiOBS,Alibaba,ChinaMobile,GCS,Liara,Linode,LyveCloud,Magalu,OVHcloud,Scaleway,Selectel,StackPath,Storj,Synology,RackCorp,Qiniu,Petabox,Zata",
|
||||
Examples: []fs.OptionExample{{
|
||||
Value: "objects-us-east-1.dream.io",
|
||||
Help: "Dream Objects endpoint",
|
||||
@@ -2067,7 +2086,7 @@ func init() {
|
||||
}, {
|
||||
Name: "location_constraint",
|
||||
Help: "Location constraint - must be set to match the Region.\n\nLeave blank if not sure. Used when creating buckets only.",
|
||||
Provider: "!AWS,Alibaba,ArvanCloud,HuaweiOBS,ChinaMobile,Cloudflare,FlashBlade,IBMCOS,IDrive,IONOS,Leviia,Liara,Linode,Magalu,Outscale,OVHcloud,Qiniu,RackCorp,Scaleway,Selectel,StackPath,Storj,TencentCOS,Petabox,Mega",
|
||||
Provider: "!AWS,Alibaba,ArvanCloud,HuaweiOBS,ChinaMobile,Cloudflare,FlashBlade,IBMCOS,IDrive,Intercolo,IONOS,Leviia,Liara,Linode,Magalu,Outscale,OVHcloud,Qiniu,RackCorp,Scaleway,Selectel,StackPath,Storj,TencentCOS,Petabox,Mega",
|
||||
}, {
|
||||
Name: "acl",
|
||||
Help: `Canned ACL used when creating buckets and storing or copying objects.
|
||||
@@ -3677,6 +3696,9 @@ func setQuirks(opt *Options) {
|
||||
case "IDrive":
|
||||
virtualHostStyle = false
|
||||
useAlreadyExists = false // untested
|
||||
case "Intercolo":
|
||||
// no quirks
|
||||
useUnsignedPayload = false // Intercolo has trailer support
|
||||
case "IONOS":
|
||||
// listObjectsV2 supported - https://api.ionos.com/docs/s3/#Basic-Operations-get-Bucket-list-type-2
|
||||
virtualHostStyle = false
|
||||
|
||||
@@ -773,21 +773,20 @@ func (f *Fs) list(ctx context.Context, container, directory, prefix string, addC
|
||||
}
|
||||
|
||||
// listDir lists a single directory
|
||||
func (f *Fs) listDir(ctx context.Context, container, directory, prefix string, addContainer bool) (entries fs.DirEntries, err error) {
|
||||
func (f *Fs) listDir(ctx context.Context, container, directory, prefix string, addContainer bool, callback func(fs.DirEntry) error) (err error) {
|
||||
if container == "" {
|
||||
return nil, fs.ErrorListBucketRequired
|
||||
return fs.ErrorListBucketRequired
|
||||
}
|
||||
// List the objects
|
||||
err = f.list(ctx, container, directory, prefix, addContainer, false, false, func(entry fs.DirEntry) error {
|
||||
entries = append(entries, entry)
|
||||
return nil
|
||||
return callback(entry)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// container must be present if listing succeeded
|
||||
f.cache.MarkOK(container)
|
||||
return entries, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// listContainers lists the containers
|
||||
@@ -818,14 +817,46 @@ func (f *Fs) listContainers(ctx context.Context) (entries fs.DirEntries, err err
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
|
||||
return list.WithListP(ctx, dir, f)
|
||||
}
|
||||
|
||||
// ListP lists the objects and directories of the Fs starting
|
||||
// from dir non recursively into out.
|
||||
//
|
||||
// dir should be "" to start from the root, and should not
|
||||
// have trailing slashes.
|
||||
//
|
||||
// This should return ErrDirNotFound if the directory isn't
|
||||
// found.
|
||||
//
|
||||
// It should call callback for each tranche of entries read.
|
||||
// These need not be returned in any particular order. If
|
||||
// callback returns an error then the listing will stop
|
||||
// immediately.
|
||||
func (f *Fs) ListP(ctx context.Context, dir string, callback fs.ListRCallback) error {
|
||||
list := list.NewHelper(callback)
|
||||
container, directory := f.split(dir)
|
||||
if container == "" {
|
||||
if directory != "" {
|
||||
return nil, fs.ErrorListBucketRequired
|
||||
return fs.ErrorListBucketRequired
|
||||
}
|
||||
entries, err := f.listContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
err = list.Add(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := f.listDir(ctx, container, directory, f.rootDirectory, f.rootContainer == "", list.Add)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.listContainers(ctx)
|
||||
}
|
||||
return f.listDir(ctx, container, directory, f.rootDirectory, f.rootContainer == "")
|
||||
return list.Flush()
|
||||
}
|
||||
|
||||
// ListR lists the objects and directories of the Fs starting
|
||||
@@ -1650,6 +1681,7 @@ var (
|
||||
_ fs.PutStreamer = &Fs{}
|
||||
_ fs.Copier = &Fs{}
|
||||
_ fs.ListRer = &Fs{}
|
||||
_ fs.ListPer = &Fs{}
|
||||
_ fs.Object = &Object{}
|
||||
_ fs.MimeTyper = &Object{}
|
||||
)
|
||||
|
||||
159
bin/make_bisync_docs.go
Normal file
159
bin/make_bisync_docs.go
Normal file
@@ -0,0 +1,159 @@
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/operations"
|
||||
"github.com/rclone/rclone/fstest/runs"
|
||||
"github.com/stretchr/testify/assert/yaml"
|
||||
)
|
||||
|
||||
var path = flag.String("path", "./docs/content/", "root path")
|
||||
|
||||
const (
|
||||
configFile = "fstest/test_all/config.yaml"
|
||||
startListIgnores = "<!--- start list_ignores - DO NOT EDIT THIS SECTION - use make commanddocs --->"
|
||||
endListIgnores = "<!--- end list_ignores - DO NOT EDIT THIS SECTION - use make commanddocs --->"
|
||||
startListFailures = "<!--- start list_failures - DO NOT EDIT THIS SECTION - use make commanddocs --->"
|
||||
endListFailures = "<!--- end list_failures - DO NOT EDIT THIS SECTION - use make commanddocs --->"
|
||||
integrationTestsJSONURL = "https://pub.rclone.org/integration-tests/current/index.json"
|
||||
integrationTestsHTMLURL = "https://pub.rclone.org/integration-tests/current/"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := replaceBetween(*path, startListIgnores, endListIgnores, getIgnores)
|
||||
if err != nil {
|
||||
fs.Errorf(*path, "error replacing ignores: %v", err)
|
||||
}
|
||||
err = replaceBetween(*path, startListFailures, endListFailures, getFailures)
|
||||
if err != nil {
|
||||
fs.Errorf(*path, "error replacing failures: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// replaceBetween replaces the text between startSep and endSep with fn()
|
||||
func replaceBetween(path, startSep, endSep string, fn func() (string, error)) error {
|
||||
b, err := os.ReadFile(filepath.Join(path, "bisync.md"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
doc := string(b)
|
||||
|
||||
before, after, found := strings.Cut(doc, startSep)
|
||||
if !found {
|
||||
return fmt.Errorf("could not find: %v", startSep)
|
||||
}
|
||||
_, after, found = strings.Cut(after, endSep)
|
||||
if !found {
|
||||
return fmt.Errorf("could not find: %v", endSep)
|
||||
}
|
||||
|
||||
replaceSection, err := fn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newDoc := before + startSep + "\n" + strings.TrimSpace(replaceSection) + "\n" + endSep + after
|
||||
|
||||
err = os.WriteFile(filepath.Join(path, "bisync.md"), []byte(newDoc), 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getIgnores updates the list of ignores from config.yaml
|
||||
func getIgnores() (string, error) {
|
||||
config, err := parseConfig()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse config: %v", err)
|
||||
}
|
||||
s := ""
|
||||
slices.SortFunc(config.Backends, func(a, b runs.Backend) int {
|
||||
return cmp.Compare(a.Remote, b.Remote)
|
||||
})
|
||||
for _, backend := range config.Backends {
|
||||
include := false
|
||||
|
||||
if slices.Contains(backend.IgnoreTests, "cmd/bisync") {
|
||||
include = true
|
||||
s += fmt.Sprintf("- `%s` (`%s`)\n", strings.TrimSuffix(backend.Remote, ":"), backend.Backend)
|
||||
}
|
||||
|
||||
for _, ignore := range backend.Ignore {
|
||||
if strings.Contains(strings.ToLower(ignore), "bisync") {
|
||||
if !include { // don't have header row yet
|
||||
s += fmt.Sprintf("- `%s` (`%s`)\n", strings.TrimSuffix(backend.Remote, ":"), backend.Backend)
|
||||
}
|
||||
include = true
|
||||
s += fmt.Sprintf(" - `%s`\n", ignore)
|
||||
// TODO: might be neat to add a "reason" param displaying the reason the test is ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// getFailures updates the list of currently failing tests from the integration tests server
|
||||
func getFailures() (string, error) {
|
||||
var buf bytes.Buffer
|
||||
err := operations.CopyURLToWriter(context.Background(), integrationTestsJSONURL, &buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
r := runs.Report{}
|
||||
err = json.Unmarshal(buf.Bytes(), &r)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal json: %v", err)
|
||||
}
|
||||
|
||||
s := ""
|
||||
for _, run := range r.Failed {
|
||||
for i, t := range run.FailedTests {
|
||||
if strings.Contains(strings.ToLower(t), "bisync") {
|
||||
|
||||
if i == 0 { // don't have header row yet
|
||||
s += fmt.Sprintf("- `%s` (`%s`)\n", strings.TrimSuffix(run.Remote, ":"), run.Backend)
|
||||
}
|
||||
|
||||
url := integrationTestsHTMLURL + run.TrialName
|
||||
url = url[:len(url)-5] + "1.txt" // numbers higher than 1 could change from night to night
|
||||
s += fmt.Sprintf(" - [`%s`](%v)\n", t, url)
|
||||
|
||||
if i == 4 && len(run.FailedTests) > 5 { // stop after 5
|
||||
s += fmt.Sprintf(" - [%v more](%v)\n", len(run.FailedTests)-5, integrationTestsHTMLURL)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s += fmt.Sprintf("- Updated: %v", r.DateTime)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// parseConfig reads and parses the config.yaml file
|
||||
func parseConfig() (*runs.Config, error) {
|
||||
d, err := os.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
config := &runs.Config{}
|
||||
err = yaml.Unmarshal(d, &config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config file: %w", err)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
17
bin/markdown-lint
Executable file
17
bin/markdown-lint
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Run markdown linting locally
|
||||
set -e
|
||||
|
||||
# Workflow
|
||||
build=.github/workflows/build.yml
|
||||
|
||||
# Globs read from from $build
|
||||
globs=$(awk '/- name: Check Markdown format/{f=1;next} f && /globs:/{f=2;next} f==2 && NF{if($1=="-"){exit} print $0}' $build)
|
||||
|
||||
if [ -z "$globs" ]; then
|
||||
echo "Error: No globs found in Check Markdown step in $build" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker run -v $PWD:/workdir --user $(id -u):$(id -g) davidanson/markdownlint-cli2 $globs
|
||||
@@ -23,15 +23,15 @@ func init() {
|
||||
}
|
||||
|
||||
var commandDefinition = &cobra.Command{
|
||||
Use: "authorize <backendname> [base64_json_blob | client_id client_secret]",
|
||||
Use: "authorize <fs name> [base64_json_blob | client_id client_secret]",
|
||||
Short: `Remote authorization.`,
|
||||
Long: `Remote authorization. Used to authorize a remote or headless
|
||||
rclone from a machine with a browser. Use as instructed by rclone config.
|
||||
See also the [remote setup documentation](/remote_setup).
|
||||
rclone from a machine with a browser - use as instructed by
|
||||
rclone config.
|
||||
|
||||
The command requires 1-3 arguments:
|
||||
|
||||
- Name of a backend (e.g. "drive", "s3")
|
||||
- fs name (e.g., "drive", "s3", etc.)
|
||||
- Either a base64 encoded JSON blob obtained from a previous rclone config session
|
||||
- Or a client_id and client_secret pair obtained from the remote service
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
func TestAuthorizeCommand(t *testing.T) {
|
||||
// Test that the Use string is correctly formatted
|
||||
if commandDefinition.Use != "authorize <backendname> [base64_json_blob | client_id client_secret]" {
|
||||
if commandDefinition.Use != "authorize <fs name> [base64_json_blob | client_id client_secret]" {
|
||||
t.Errorf("Command Use string doesn't match expected format: %s", commandDefinition.Use)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestAuthorizeCommand(t *testing.T) {
|
||||
}
|
||||
|
||||
helpOutput := buf.String()
|
||||
if !strings.Contains(helpOutput, "authorize <backendname>") {
|
||||
if !strings.Contains(helpOutput, "authorize <fs name>") {
|
||||
t.Errorf("Help output doesn't contain correct usage information")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,19 +4,15 @@ package bilib
|
||||
import (
|
||||
"bytes"
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
"github.com/rclone/rclone/fs/log"
|
||||
)
|
||||
|
||||
// CaptureOutput runs a function capturing its output at log level INFO.
|
||||
func CaptureOutput(fun func()) []byte {
|
||||
var mu sync.Mutex
|
||||
buf := &bytes.Buffer{}
|
||||
oldLevel := log.Handler.SetLevel(slog.LevelInfo)
|
||||
log.Handler.SetOutput(func(level slog.Level, text string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
buf.WriteString(text)
|
||||
})
|
||||
defer func() {
|
||||
@@ -24,7 +20,5 @@ func CaptureOutput(fun func()) []byte {
|
||||
log.Handler.SetLevel(oldLevel)
|
||||
}()
|
||||
fun()
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ var (
|
||||
// "src and dst identical but can't set mod time without deleting and re-uploading"
|
||||
argRefreshTimes = flag.Bool("refresh-times", false, "Force refreshing the target modtime, useful for Dropbox (default: false)")
|
||||
ignoreLogs = flag.Bool("ignore-logs", false, "skip comparing log lines but still compare listings")
|
||||
argPCount = flag.Int("pcount", 2, "number of parallel subtests to run for TestBisyncConcurrent") // go test ./cmd/bisync -race -pcount 10
|
||||
)
|
||||
|
||||
// bisyncTest keeps all test data in a single place
|
||||
@@ -284,6 +285,15 @@ func TestBisyncConcurrent(t *testing.T) {
|
||||
if !isLocal(*fstest.RemoteName) {
|
||||
t.Skip("TestBisyncConcurrent is skipped on non-local")
|
||||
}
|
||||
if *argTestCase != "" && *argTestCase != "basic" {
|
||||
t.Skip("TestBisyncConcurrent only tests 'basic'")
|
||||
}
|
||||
if *argPCount < 2 {
|
||||
t.Skip("TestBisyncConcurrent is pointless with -pcount < 2")
|
||||
}
|
||||
if *argGolden {
|
||||
t.Skip("skip TestBisyncConcurrent when goldenizing")
|
||||
}
|
||||
oldArgTestCase := argTestCase
|
||||
*argTestCase = "basic"
|
||||
*ignoreLogs = true // not useful to compare logs here because both runs will be logging at once
|
||||
@@ -292,8 +302,9 @@ func TestBisyncConcurrent(t *testing.T) {
|
||||
*ignoreLogs = false
|
||||
})
|
||||
|
||||
t.Run("test1", testParallel)
|
||||
t.Run("test2", testParallel)
|
||||
for i := 0; i < *argPCount; i++ {
|
||||
t.Run(fmt.Sprintf("test%v", i), testParallel)
|
||||
}
|
||||
}
|
||||
|
||||
func testParallel(t *testing.T) {
|
||||
@@ -465,6 +476,7 @@ func (b *bisyncTest) runTestCase(ctx context.Context, t *testing.T, testCase str
|
||||
|
||||
// Prepare initial content
|
||||
b.cleanupCase(ctx)
|
||||
ctx = accounting.WithStatsGroup(ctx, random.String(8))
|
||||
fstest.CheckListingWithPrecision(b.t, b.fs1, []fstest.Item{}, []string{}, b.fs1.Precision()) // verify starting from empty
|
||||
fstest.CheckListingWithPrecision(b.t, b.fs2, []fstest.Item{}, []string{}, b.fs2.Precision())
|
||||
initFs, err := cache.Get(ctx, b.initDir)
|
||||
@@ -641,12 +653,11 @@ func (b *bisyncTest) cleanupCase(ctx context.Context) {
|
||||
_ = operations.Purge(ctx, b.fs1, "")
|
||||
_ = operations.Purge(ctx, b.fs2, "")
|
||||
_ = os.RemoveAll(b.workDir)
|
||||
accounting.Stats(ctx).ResetCounters()
|
||||
}
|
||||
|
||||
func (b *bisyncTest) runTestStep(ctx context.Context, line string) (err error) {
|
||||
var fsrc, fdst fs.Fs
|
||||
accounting.Stats(ctx).ResetErrors()
|
||||
ctx = accounting.WithStatsGroup(ctx, random.String(8))
|
||||
b.logPrintf("%s %s", color(terminal.CyanFg, b.stepStr), color(terminal.BlueFg, line))
|
||||
|
||||
ci := fs.GetConfig(ctx)
|
||||
@@ -1007,6 +1018,7 @@ func (b *bisyncTest) checkPreReqs(ctx context.Context, opt *bisync.Options) (con
|
||||
}
|
||||
// test if modtimes are writeable
|
||||
testSetModtime := func(f fs.Fs) {
|
||||
ctx := accounting.WithStatsGroup(ctx, random.String(8)) // keep stats separate
|
||||
in := bytes.NewBufferString("modtime_write_test")
|
||||
objinfo := object.NewStaticObjectInfo("modtime_write_test", initDate, int64(len("modtime_write_test")), true, nil, nil)
|
||||
obj, err := f.Put(ctx, in, objinfo)
|
||||
@@ -1018,6 +1030,11 @@ func (b *bisyncTest) checkPreReqs(ctx context.Context, opt *bisync.Options) (con
|
||||
if err == fs.ErrorCantSetModTime {
|
||||
b.t.Skip("skipping test as at least one remote does not support setting modtime")
|
||||
}
|
||||
if err == fs.ErrorCantSetModTimeWithoutDelete { // transfers stats expected to differ on this backend
|
||||
logReplacements = append(logReplacements, `^.*There was nothing to transfer.*$`, dropMe)
|
||||
} else {
|
||||
require.NoError(b.t, err)
|
||||
}
|
||||
if !f.Features().IsLocal {
|
||||
time.Sleep(time.Second) // avoid GoogleCloudStorage Error 429 rateLimitExceeded
|
||||
}
|
||||
@@ -1619,6 +1636,14 @@ func (b *bisyncTest) mangleResult(dir, file string, golden bool) string {
|
||||
`^.*not equal on recheck.*$`, dropMe,
|
||||
)
|
||||
}
|
||||
if b.ignoreBlankHash || !b.fs1.Hashes().Contains(hash.MD5) || !b.fs2.Hashes().Contains(hash.MD5) {
|
||||
// if either side lacks support for md5, need to ignore the "nothing to transfer" log,
|
||||
// as sync may in fact need to transfer, where it would otherwise skip based on hash or just update modtime.
|
||||
// transfer stats will also differ in fs.ErrorCantSetModTimeWithoutDelete scenario, and where --download-hash is needed.
|
||||
logReplacements = append(logReplacements,
|
||||
`^.*There was nothing to transfer.*$`, dropMe,
|
||||
)
|
||||
}
|
||||
rep := logReplacements
|
||||
if b.testCase == "dry_run" {
|
||||
rep = append(rep, dryrunReplacements...)
|
||||
|
||||
@@ -434,6 +434,7 @@ func (b *bisyncRun) listDirsOnly(listingNum int) (*fileList, error) {
|
||||
}
|
||||
|
||||
fulllisting, err = b.loadListingNum(listingNum)
|
||||
|
||||
if err != nil {
|
||||
b.critical = true
|
||||
b.retryable = true
|
||||
@@ -609,11 +610,6 @@ func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, res
|
||||
}
|
||||
}
|
||||
if srcNewName != "" { // if it was renamed and not deleted
|
||||
if new == nil { // should not happen. log error and debug info
|
||||
b.handleErr(b.renames, "internal error", fmt.Errorf("missing info for %q. Please report a bug at https://github.com/rclone/rclone/issues", srcNewName), true, true)
|
||||
fs.PrettyPrint(srcList, "srcList for debugging", fs.LogLevelNotice)
|
||||
continue
|
||||
}
|
||||
srcList.put(srcNewName, new.size, new.time, new.hash, new.id, new.flags)
|
||||
dstList.put(srcNewName, new.size, new.time, new.hash, new.id, new.flags)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -59,6 +61,7 @@ INFO : - [36mPath1[0m [35m[32mQueue copy to[0m Path2[0m - [36m{
|
||||
INFO : - [36mPath1[0m [35m[32mQueue copy to[0m Path2[0m - [36m{path2/}file1.txt[0m
|
||||
INFO : - [36mPath1[0m [35m[32mQueue copy to[0m Path2[0m - [36m{path2/}subdir/file20.txt[0m
|
||||
INFO : - [36mPath1[0m [35mDo queued copies to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -133,6 +136,7 @@ INFO : - [36mPath1[0m [35m[32mQueue copy to[0m Path2[0m - [36m{
|
||||
INFO : - [36mPath1[0m [35m[32mQueue copy to[0m Path2[0m - [36m{path2/}file1.txt[0m
|
||||
INFO : - [36mPath1[0m [35m[32mQueue copy to[0m Path2[0m - [36m{path2/}subdir/file20.txt[0m
|
||||
INFO : - [36mPath1[0m [35mDo queued copies to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -87,6 +89,7 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
|
||||
@@ -21,7 +21,9 @@ INFO : Using filters file {workdir/}exclude-other-filtersfile.txt
|
||||
INFO : Storing filters file hash to {workdir/}exclude-other-filtersfile.txt.{hashtype}
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -136,7 +138,9 @@ INFO : Using filters file {workdir/}include-other-filtersfile.txt
|
||||
INFO : Storing filters file hash to {workdir/}include-other-filtersfile.txt.{hashtype}
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -90,7 +92,9 @@ INFO : Copying Path2 files to Path1
|
||||
INFO : Checking access health
|
||||
INFO : Found 2 matching ".chk_file" files on both paths
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -102,7 +104,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -15,7 +15,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -15,7 +15,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -23,7 +23,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -80,7 +82,7 @@ INFO : Path2 checking for diffs
|
||||
INFO : Applying changes
|
||||
INFO : - [36mPath1[0m [35m[32mQueue copy to[0m Path2[0m - [36m{path2/}subdir[0m
|
||||
INFO : - [36mPath1[0m [35mDo queued copies to[0m - [36mPath2[0m
|
||||
INFO : subdir: Making directory
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -124,6 +126,7 @@ INFO : Path2: 1 changes: [32m 0 new[0m, [33m 0 modified[0m, [31m
|
||||
INFO : Applying changes
|
||||
INFO : - [34mPath2[0m [35m[31mQueue delete[0m[0m - [36m{path2/}RCLONE_TEST[0m
|
||||
INFO : - [36mPath1[0m [35mDo queued copies to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -148,7 +151,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -188,6 +193,7 @@ INFO : Path2 checking for diffs
|
||||
INFO : Applying changes
|
||||
INFO : - [34mPath2[0m [35m[31mQueue delete[0m[0m - [36m{path2/}subdir[0m
|
||||
INFO : - [36mPath1[0m [35mDo queued copies to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : subdir: Removing directory
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -27,7 +27,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}測試Русский ěáñ/" with Path2 "{path2/}測試Русский ěáñ/"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}測試Русский ěáñ/" vs Path2 "{path2/}測試Русский ěáñ/"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -84,7 +86,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -174,7 +178,9 @@ INFO : Using filters file {workdir/}測試_filtersfile.txt
|
||||
INFO : Storing filters file hash to {workdir/}測試_filtersfile.txt.{hashtype}
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -20,7 +20,9 @@ INFO : Using filters file {workdir/}filtersfile.flt
|
||||
INFO : Storing filters file hash to {workdir/}filtersfile.flt.{hashtype}
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -81,7 +83,9 @@ INFO : Using filters file {workdir/}filtersfile.txt
|
||||
INFO : Storing filters file hash to {workdir/}filtersfile.txt.{hashtype}
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -146,7 +150,9 @@ INFO : Using filters file {workdir/}filtersfile.txt
|
||||
INFO : Skipped storing filters file hash to {workdir/}filtersfile.txt.{hashtype} as --dry-run is set
|
||||
INFO : Copying Path2 files to Path1
|
||||
NOTICE: - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
NOTICE: - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -33,7 +35,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -84,6 +86,7 @@ INFO : - [34mPath2[0m [35m[31mQueue delete[0m[0m - [36m{
|
||||
INFO : - [34mPath2[0m [35m[31mQueue delete[0m[0m - [36m{path2/}file4.txt[0m
|
||||
INFO : - [34mPath2[0m [35m[31mQueue delete[0m[0m - [36m{path2/}file5.txt[0m
|
||||
INFO : - [36mPath1[0m [35mDo queued copies to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -84,6 +86,7 @@ INFO : - [36mPath1[0m [35m[31mQueue delete[0m[0m - [36m{
|
||||
INFO : - [36mPath1[0m [35m[31mQueue delete[0m[0m - [36m{path1/}file4.txt[0m
|
||||
INFO : - [36mPath1[0m [35m[31mQueue delete[0m[0m - [36m{path1/}file5.txt[0m
|
||||
INFO : - [34mPath2[0m [35mDo queued copies to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -15,7 +15,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -17,7 +17,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -115,7 +117,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -154,6 +158,7 @@ INFO : Applying changes
|
||||
INFO : - [34mPath2[0m [35m[32mQueue copy to[0m Path1[0m - [36m{path1/}file2.txt[0m
|
||||
INFO : - [34mPath2[0m [35m[32mQueue copy to[0m Path1[0m - [36m{path1/}subdir/file21.txt[0m
|
||||
INFO : - [34mPath2[0m [35mDo queued copies to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -171,6 +176,7 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -39,6 +39,7 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
|
||||
@@ -22,6 +22,7 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
@@ -129,6 +130,7 @@ INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : file1.txt: Path1 is smaller. Path1: 33, Path2: 42, Difference: 9
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : file1.txt: Path1 is smaller. Path1: 33, Path2: 42, Difference: 9
|
||||
INFO : Resync updating listings
|
||||
@@ -158,6 +160,7 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
|
||||
@@ -16,7 +16,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
@@ -45,6 +47,7 @@ INFO : Path2 checking for diffs
|
||||
INFO : Applying changes
|
||||
INFO : - [34mPath2[0m [35m[31mQueue delete[0m[0m - [36m{path2/}subdir/file20.txt[0m
|
||||
INFO : - [36mPath1[0m [35mDo queued copies to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -15,7 +15,9 @@ INFO : Bisyncing with Comparison Settings:
|
||||
INFO : Synching Path1 "{path1/}" with Path2 "{path2/}"
|
||||
INFO : Copying Path2 files to Path1
|
||||
INFO : - [34mPath2[0m [35mResync is copying files to[0m - [36mPath1[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : - [36mPath1[0m [35mResync is copying files to[0m - [36mPath2[0m
|
||||
INFO : There was nothing to transfer
|
||||
INFO : Resync updating listings
|
||||
INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
|
||||
INFO : [32mBisync successful[0m
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
@@ -91,7 +92,7 @@ rclone.org website.`,
|
||||
Aliases []string
|
||||
Annotations map[string]string
|
||||
}
|
||||
var commands = map[string]commandDetails{}
|
||||
commands := map[string]commandDetails{}
|
||||
var addCommandDetails func(root *cobra.Command, parentAliases []string)
|
||||
addCommandDetails = func(root *cobra.Command, parentAliases []string) {
|
||||
name := strings.ReplaceAll(root.CommandPath(), " ", "_") + ".md"
|
||||
@@ -158,7 +159,7 @@ rclone.org website.`,
|
||||
return err
|
||||
}
|
||||
|
||||
var outdentTitle = regexp.MustCompile(`(?m)^#(#+)`)
|
||||
outdentTitle := regexp.MustCompile(`(?m)^#(#+)`)
|
||||
|
||||
// Munge the files to add a link to the global flags page
|
||||
err = filepath.Walk(out, func(path string, info os.FileInfo, err error) error {
|
||||
@@ -169,6 +170,20 @@ rclone.org website.`,
|
||||
name := filepath.Base(path)
|
||||
cmd, ok := commands[name]
|
||||
if !ok {
|
||||
switch name {
|
||||
case "rclone_mount.md":
|
||||
switch runtime.GOOS {
|
||||
case "darwin", "windows":
|
||||
fs.Logf(nil, "Skipping docs for command not available without the cmount build tag: %v", name)
|
||||
return nil
|
||||
}
|
||||
case "rclone_nfsmount.md", "rclone_serve_nfs.md":
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
fs.Logf(nil, "Skipping docs for command not supported on %v: %v", runtime.GOOS, name)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("didn't find command for %q", name)
|
||||
}
|
||||
b, err := os.ReadFile(path)
|
||||
|
||||
@@ -33,7 +33,7 @@ func init() {
|
||||
cmd.Root.AddCommand(commandDefinition)
|
||||
cmdFlags := commandDefinition.Flags()
|
||||
flags.StringVarP(cmdFlags, &format, "format", "F", "p", "Output format - see help for details", "")
|
||||
flags.StringVarP(cmdFlags, &timeFormat, "time-format", "t", "", "Specify a custom time format, or 'max' for max precision supported by remote (default: 2006-01-02 15:04:05)", "")
|
||||
flags.StringVarP(cmdFlags, &timeFormat, "time-format", "t", "", "Specify a custom time format - see docs for details (default: 2006-01-02 15:04:05)", "")
|
||||
flags.StringVarP(cmdFlags, &separator, "separator", "s", ";", "Separator for the items in the format", "")
|
||||
flags.BoolVarP(cmdFlags, &dirSlash, "dir-slash", "d", true, "Append a slash to directory names", "")
|
||||
flags.FVarP(cmdFlags, &hashType, "hash", "", "Use this hash when `h` is used in the format MD5|SHA-1|DropboxHash", "")
|
||||
@@ -169,6 +169,8 @@ rclone lsf remote:path --format pt --time-format '2006-01-02T15:04:05.999999999Z
|
||||
rclone lsf remote:path --format pt --time-format RFC3339
|
||||
rclone lsf remote:path --format pt --time-format DateOnly
|
||||
rclone lsf remote:path --format pt --time-format max
|
||||
rclone lsf remote:path --format pt --time-format unix
|
||||
rclone lsf remote:path --format pt --time-format unixnano
|
||||
` + "```" + `
|
||||
|
||||
` + "`--time-format max`" + ` will automatically truncate ` + "`2006-01-02 15:04:05.000000000`" + `
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -112,6 +113,7 @@ func (vol *Volume) applyOptions(volOpt VolOpts) error {
|
||||
}
|
||||
mntMap := configmap.Simple{}
|
||||
vfsMap := configmap.Simple{}
|
||||
globalMap := configmap.Simple{}
|
||||
for key := range opt {
|
||||
var ok bool
|
||||
var err error
|
||||
@@ -144,6 +146,13 @@ func (vol *Volume) applyOptions(volOpt VolOpts) error {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
// try as a global option in globalMap
|
||||
if fs.ConfigOptionsInfo.Get(underscoreKey) != nil {
|
||||
globalMap[underscoreKey] = vol.Options[key]
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
// try as a backend option in fsOpt (backends use "_" instead of "-")
|
||||
@@ -172,6 +181,20 @@ func (vol *Volume) applyOptions(volOpt VolOpts) error {
|
||||
return fmt.Errorf("cannot parse mount options: %w", err)
|
||||
}
|
||||
|
||||
// Parse Global options
|
||||
if len(globalMap) > 0 {
|
||||
ctx := context.Background()
|
||||
ci := fs.GetConfig(ctx)
|
||||
err = configstruct.Set(globalMap, ci)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse global options: %w", err)
|
||||
}
|
||||
err = ci.Reload(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to reload global options: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// build remote string from fsName, fsType, fsOpt, fsPath
|
||||
colon := ":"
|
||||
comma := ","
|
||||
|
||||
@@ -208,7 +208,6 @@ func newServer(ctx context.Context, f fs.Fs, opt *Options, vfsOpt *vfscommon.Opt
|
||||
// Serve HTTP until the server is shutdown
|
||||
func (s *HTTP) Serve() error {
|
||||
s.server.Serve()
|
||||
fs.Logf(s.f, "HTTP Server started on %s", s.server.URLs())
|
||||
s.server.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -61,15 +61,18 @@ func init() {
|
||||
test.Command.AddCommand(makefileCmd)
|
||||
makefileFlags := makefileCmd.Flags()
|
||||
|
||||
// Common flags to makefiles and makefile
|
||||
for _, f := range []*pflag.FlagSet{makefilesFlags, makefileFlags} {
|
||||
flags.Int64VarP(f, &seed, "seed", "", seed, "Seed for the random number generator (0 for random)", "")
|
||||
flags.BoolVarP(f, &zero, "zero", "", zero, "Fill files with ASCII 0x00", "")
|
||||
flags.BoolVarP(f, &sparse, "sparse", "", sparse, "Make the files sparse (appear to be filled with ASCII 0x00)", "")
|
||||
flags.BoolVarP(f, &ascii, "ascii", "", ascii, "Fill files with random ASCII printable bytes only", "")
|
||||
flags.BoolVarP(f, &pattern, "pattern", "", pattern, "Fill files with a periodic pattern", "")
|
||||
flags.BoolVarP(f, &chargen, "chargen", "", chargen, "Fill files with a ASCII chargen pattern", "")
|
||||
}
|
||||
addCommonFlags(makefilesFlags)
|
||||
addCommonFlags(makefileFlags)
|
||||
}
|
||||
|
||||
// Common flags for makefiles and makefile
|
||||
func addCommonFlags(f *pflag.FlagSet) {
|
||||
flags.Int64VarP(f, &seed, "seed", "", seed, "Seed for the random number generator (0 for random)", "")
|
||||
flags.BoolVarP(f, &zero, "zero", "", zero, "Fill files with ASCII 0x00", "")
|
||||
flags.BoolVarP(f, &sparse, "sparse", "", sparse, "Make the files sparse (appear to be filled with ASCII 0x00)", "")
|
||||
flags.BoolVarP(f, &ascii, "ascii", "", ascii, "Fill files with random ASCII printable bytes only", "")
|
||||
flags.BoolVarP(f, &pattern, "pattern", "", pattern, "Fill files with a periodic pattern", "")
|
||||
flags.BoolVarP(f, &chargen, "chargen", "", chargen, "Fill files with a ASCII chargen pattern", "")
|
||||
}
|
||||
|
||||
var makefilesCmd = &cobra.Command{
|
||||
@@ -123,20 +126,24 @@ var makefileCmd = &cobra.Command{
|
||||
if err != nil {
|
||||
fs.Fatalf(nil, "Failed to parse size %q: %v", args[0], err)
|
||||
}
|
||||
start := time.Now()
|
||||
fs.Logf(nil, "Creating %d files of size %v.", len(args[1:]), size)
|
||||
totalBytes := int64(0)
|
||||
for _, filePath := range args[1:] {
|
||||
dir := filepath.Dir(filePath)
|
||||
name := filepath.Base(filePath)
|
||||
writeFile(dir, name, int64(size))
|
||||
totalBytes += int64(size)
|
||||
}
|
||||
dt := time.Since(start)
|
||||
fs.Logf(nil, "Written %vB in %v at %vB/s.", fs.SizeSuffix(totalBytes), dt.Round(time.Millisecond), fs.SizeSuffix((totalBytes*int64(time.Second))/int64(dt)))
|
||||
makefiles(size, args[1:])
|
||||
},
|
||||
}
|
||||
|
||||
func makefiles(size fs.SizeSuffix, files []string) {
|
||||
start := time.Now()
|
||||
fs.Logf(nil, "Creating %d files of size %v.", len(files), size)
|
||||
totalBytes := int64(0)
|
||||
for _, filePath := range files {
|
||||
dir := filepath.Dir(filePath)
|
||||
name := filepath.Base(filePath)
|
||||
writeFile(dir, name, int64(size))
|
||||
totalBytes += int64(size)
|
||||
}
|
||||
dt := time.Since(start)
|
||||
fs.Logf(nil, "Written %vB in %v at %vB/s.", fs.SizeSuffix(totalBytes), dt.Round(time.Millisecond), fs.SizeSuffix((totalBytes*int64(time.Second))/int64(dt)))
|
||||
}
|
||||
|
||||
func bool2int(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
|
||||
235
cmd/test/makefiles/speed.go
Normal file
235
cmd/test/makefiles/speed.go
Normal file
@@ -0,0 +1,235 @@
|
||||
package makefiles
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/cmd"
|
||||
"github.com/rclone/rclone/cmd/test"
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/cache"
|
||||
"github.com/rclone/rclone/fs/config/flags"
|
||||
"github.com/rclone/rclone/fs/operations"
|
||||
"github.com/rclone/rclone/fs/sync"
|
||||
"github.com/rclone/rclone/lib/atexit"
|
||||
"github.com/rclone/rclone/lib/random"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Flags
|
||||
testTime = fs.Duration(15 * time.Second)
|
||||
fcap = 100
|
||||
small = fs.SizeSuffix(1024)
|
||||
medium = fs.SizeSuffix(10 * 1024 * 1024)
|
||||
large = fs.SizeSuffix(1024 * 1024 * 1024)
|
||||
useJSON = false
|
||||
)
|
||||
|
||||
func init() {
|
||||
test.Command.AddCommand(speedCmd)
|
||||
|
||||
speedFlags := speedCmd.Flags()
|
||||
flags.FVarP(speedFlags, &testTime, "test-time", "", "Length for each test to run", "")
|
||||
flags.IntVarP(speedFlags, &fcap, "file-cap", "", fcap, "Maximum number of files to use in each test", "")
|
||||
flags.FVarP(speedFlags, &small, "small", "", "Size of small files", "")
|
||||
flags.FVarP(speedFlags, &medium, "medium", "", "Size of medium files", "")
|
||||
flags.FVarP(speedFlags, &large, "large", "", "Size of large files", "")
|
||||
flags.BoolVarP(speedFlags, &useJSON, "json", "", useJSON, "Output only results in JSON format", "")
|
||||
|
||||
addCommonFlags(speedFlags)
|
||||
}
|
||||
|
||||
func logf(text string, args ...any) {
|
||||
if !useJSON {
|
||||
fmt.Printf(text, args...)
|
||||
}
|
||||
}
|
||||
|
||||
var speedCmd = &cobra.Command{
|
||||
Use: "speed <remote> [flags]",
|
||||
Short: `Run a speed test to the remote`,
|
||||
Long: `Run a speed test to the remote.
|
||||
|
||||
This command runs a series of uploads and downloads to the remote, measuring
|
||||
and printing the speed of each test using varying file sizes and numbers of
|
||||
files.
|
||||
|
||||
Test time can be innaccurate with small file caps and large files. As it
|
||||
uses the results of an initial test to determine how many files to use in
|
||||
each subsequent test.
|
||||
|
||||
It is recommended to use -q flag for a simpler output. e.g.:
|
||||
|
||||
rlone test speed remote: -q
|
||||
|
||||
**NB** This command will create and delete files on the remote in a randomly
|
||||
named directory which should be tidied up after.
|
||||
|
||||
You can use the --json flag to only print the results in JSON format.`,
|
||||
Annotations: map[string]string{
|
||||
"versionIntroduced": "v1.72",
|
||||
},
|
||||
RunE: func(command *cobra.Command, args []string) error {
|
||||
ctx := command.Context()
|
||||
cmd.CheckArgs(1, 1, command, args)
|
||||
commonInit()
|
||||
|
||||
// initial test
|
||||
size := fs.SizeSuffix(1024 * 1024)
|
||||
logf("Running initial test for 4 files of size %v\n", size)
|
||||
stats, err := speedTest(ctx, 4, size, args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("speed test failed: %w", err)
|
||||
}
|
||||
|
||||
var results []*Stats
|
||||
|
||||
// main tests
|
||||
logf("\nTest Time: %v, File cap: %d\n", testTime, fcap)
|
||||
for _, size := range []fs.SizeSuffix{small, medium, large} {
|
||||
numberOfFilesUpload := int((float64(stats.Upload.Speed) * time.Duration(testTime).Seconds()) / float64(size))
|
||||
numberOfFilesDownload := int((float64(stats.Download.Speed) * time.Duration(testTime).Seconds()) / float64(size))
|
||||
numberOfFiles := min(numberOfFilesUpload, numberOfFilesDownload)
|
||||
|
||||
logf("\nNumber of files for upload and download: %v\n", numberOfFiles)
|
||||
if numberOfFiles < 1 {
|
||||
logf("Skipping test for file size %v as calculated number of files is 0\n", size)
|
||||
continue
|
||||
} else if numberOfFiles > fcap {
|
||||
numberOfFiles = fcap
|
||||
logf("Capping test for file size %v to %v files\n", size, fcap)
|
||||
}
|
||||
|
||||
logf("Running test for %d files of size %v\n", numberOfFiles, size)
|
||||
s, err := speedTest(ctx, numberOfFiles, size, args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("speed test failed: %w", err)
|
||||
}
|
||||
results = append(results, s)
|
||||
|
||||
}
|
||||
|
||||
if useJSON {
|
||||
b, err := json.MarshalIndent(results, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal results to JSON: %w", err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Stats of a speed test
|
||||
type Stats struct {
|
||||
Size fs.SizeSuffix
|
||||
NumberOfFiles int
|
||||
Upload TestResult
|
||||
Download TestResult
|
||||
}
|
||||
|
||||
// TestResult of a speed test operation
|
||||
type TestResult struct {
|
||||
Bytes int64
|
||||
Duration time.Duration
|
||||
Speed fs.SizeSuffix
|
||||
}
|
||||
|
||||
// measures stats for speedTest operations
|
||||
func measure(desc string, f func() error, size fs.SizeSuffix, numberOfFiles int, tr *TestResult) error {
|
||||
start := time.Now()
|
||||
err := f()
|
||||
dt := time.Since(start)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tr.Duration = dt
|
||||
tr.Bytes = int64(size) * int64(numberOfFiles)
|
||||
tr.Speed = fs.SizeSuffix(float64(tr.Bytes) / dt.Seconds())
|
||||
logf("%-20s: %vB in %v at %vB/s\n", desc, tr.Bytes, dt.Round(time.Millisecond), tr.Speed)
|
||||
return err
|
||||
}
|
||||
|
||||
func speedTest(ctx context.Context, numberOfFiles int, size fs.SizeSuffix, remote string) (*Stats, error) {
|
||||
stats := Stats{
|
||||
Size: size,
|
||||
NumberOfFiles: numberOfFiles,
|
||||
}
|
||||
|
||||
tempDirName := "rclone-speed-test-" + random.String(8)
|
||||
tempDirPath := path.Join(remote, tempDirName)
|
||||
fremote := cmd.NewFsDir([]string{tempDirPath})
|
||||
aErr := io.EOF
|
||||
defer atexit.OnError(&aErr, func() {
|
||||
err := operations.Purge(ctx, fremote, "")
|
||||
if err != nil {
|
||||
fs.Debugf(fremote, "Failed to remove temp dir %q: %v", tempDirPath, err)
|
||||
}
|
||||
})()
|
||||
|
||||
flocalDir, err := os.MkdirTemp("", "rclone-speedtest-local-")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create local temp dir: %w", err)
|
||||
}
|
||||
defer atexit.OnError(&aErr, func() { _ = os.RemoveAll(flocalDir) })()
|
||||
|
||||
flocal, err := cache.Get(ctx, flocalDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create local fs: %w", err)
|
||||
}
|
||||
|
||||
fdownloadDir, err := os.MkdirTemp("", "rclone-speedtest-download-")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create download temp dir: %w", err)
|
||||
}
|
||||
defer atexit.OnError(&aErr, func() { _ = os.RemoveAll(fdownloadDir) })()
|
||||
|
||||
fdownload, err := cache.Get(ctx, fdownloadDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create download fs: %w", err)
|
||||
}
|
||||
|
||||
// make the largest amount of files we will need
|
||||
files := make([]string, numberOfFiles)
|
||||
for i := range files {
|
||||
files[i] = path.Join(flocalDir, fmt.Sprintf("file%03d-%v.bin", i, size))
|
||||
}
|
||||
makefiles(size, files)
|
||||
|
||||
// upload files
|
||||
err = measure("Upload", func() error {
|
||||
return sync.CopyDir(ctx, fremote, flocal, false)
|
||||
}, size, numberOfFiles, &stats.Upload)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to Copy to remote: %w", err)
|
||||
}
|
||||
|
||||
// download files
|
||||
err = measure("Download", func() error {
|
||||
return sync.CopyDir(ctx, fdownload, fremote, false)
|
||||
}, size, numberOfFiles, &stats.Download)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to Copy from remote: %w", err)
|
||||
}
|
||||
|
||||
// check files
|
||||
opt := operations.CheckOpt{
|
||||
Fsrc: flocal,
|
||||
Fdst: fdownload,
|
||||
OneWay: false,
|
||||
}
|
||||
logf("Checking file integrity\n")
|
||||
err = operations.CheckDownload(ctx, &opt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check redownloaded files were identical: %w", err)
|
||||
}
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
@@ -136,13 +136,13 @@ WebDAV or S3, that work out of the box.)
|
||||
{{< provider name="Hetzner Storage Box" home="https://www.hetzner.com/storage/storage-box" config="/sftp/#hetzner-storage-box" >}}
|
||||
{{< provider name="HiDrive" home="https://www.strato.de/cloud-speicher/" config="/hidrive/" >}}
|
||||
{{< provider name="HTTP" home="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol" config="/http/" >}}
|
||||
{{< provider name="Huawei OBS" home="https://www.huaweicloud.com/intl/en-us/product/obs.html" config="/s3/#huawei-obs" >}}
|
||||
{{< provider name="iCloud Drive" home="https://icloud.com/" config="/iclouddrive/" >}}
|
||||
{{< provider name="ImageKit" home="https://imagekit.io" config="/imagekit/" >}}
|
||||
{{< provider name="Internet Archive" home="https://archive.org/" config="/internetarchive/" >}}
|
||||
{{< provider name="Jottacloud" home="https://www.jottacloud.com/en/" config="/jottacloud/" >}}
|
||||
{{< provider name="IBM COS S3" home="http://www.ibm.com/cloud/object-storage" config="/s3/#ibm-cos-s3" >}}
|
||||
{{< provider name="IDrive e2" home="https://www.idrive.com/e2/?refer=rclone" config="/s3/#idrive-e2" >}}
|
||||
{{< provider name="Intercolo Object Storage" home="https://intercolo.de/object-storage" config="/s3/#intercolo" >}}
|
||||
{{< provider name="IONOS Cloud" home="https://cloud.ionos.com/storage/object-storage" config="/s3/#ionos" >}}
|
||||
{{< provider name="Koofr" home="https://koofr.eu/" config="/koofr/" >}}
|
||||
{{< provider name="Leviia Object Storage" home="https://www.leviia.com/object-storage" config="/s3/#leviia" >}}
|
||||
@@ -179,9 +179,7 @@ WebDAV or S3, that work out of the box.)
|
||||
{{< provider name="QingStor" home="https://www.qingcloud.com/products/storage" config="/qingstor/" >}}
|
||||
{{< provider name="Qiniu Cloud Object Storage (Kodo)" home="https://www.qiniu.com/en/products/kodo" config="/s3/#qiniu" >}}
|
||||
{{< provider name="Quatrix by Maytech" home="https://www.maytech.net/products/quatrix-business" config="/quatrix/" >}}
|
||||
{{< provider name="RackCorp Object Storage" home="https://www.rackcorp.com/" config="/s3/#RackCorp" >}}
|
||||
{{< provider name="Rackspace Cloud Files" home="https://www.rackspace.com/cloud/files" config="/swift/" >}}
|
||||
{{< provider name="Rclone Serve S3" home="/commands/rclone_serve_s3/" config="/s3/#rclone" >}}
|
||||
{{< provider name="rsync.net" home="https://rsync.net/products/rclone.html" config="/sftp/#rsync-net" >}}
|
||||
{{< provider name="Scaleway" home="https://www.scaleway.com/object-storage/" config="/s3/#scaleway" >}}
|
||||
{{< provider name="Seafile" home="https://www.seafile.com/" config="/seafile/" >}}
|
||||
|
||||
@@ -1004,3 +1004,10 @@ put them back in again.` >}}
|
||||
- Lucas Bremgartner <breml@users.noreply.github.com>
|
||||
- Binbin Qian <qianbinbin@hotmail.com>
|
||||
- cui <523516579@qq.com>
|
||||
- Tilman Vogel <tilman.vogel@web.de>
|
||||
- skbeh <60107333+skbeh@users.noreply.github.com>
|
||||
- Claudius Ellsel <claudius.ellsel@live.de>
|
||||
- Motte <37443982+dmotte@users.noreply.github.com>
|
||||
- dougal <dougal.craigwood@gmail.com> <147946567+roucc@users.noreply.github.com>
|
||||
- anon-pradip <pradipsubedi360@gmail.com>
|
||||
- Robin Rolf <imer@imer.cc>
|
||||
|
||||
@@ -1046,7 +1046,7 @@ encodings.)
|
||||
|
||||
The following backends have known issues that need more investigation:
|
||||
|
||||
<!--- start list_failures - DO NOT EDIT THIS SECTION - use rclone gendocs --->
|
||||
<!--- start list_failures - DO NOT EDIT THIS SECTION - use make commanddocs --->
|
||||
- `TestGoFile` (`gofile`)
|
||||
- [`TestBisyncRemoteLocal/all_changed`](https://pub.rclone.org/integration-tests/current/gofile-cmd.bisync-TestGoFile-1.txt)
|
||||
- [`TestBisyncRemoteLocal/backupdir`](https://pub.rclone.org/integration-tests/current/gofile-cmd.bisync-TestGoFile-1.txt)
|
||||
@@ -1055,12 +1055,12 @@ The following backends have known issues that need more investigation:
|
||||
- [`TestBisyncRemoteLocal/check_access`](https://pub.rclone.org/integration-tests/current/gofile-cmd.bisync-TestGoFile-1.txt)
|
||||
- [78 more](https://pub.rclone.org/integration-tests/current/)
|
||||
- Updated: 2025-08-21-010015
|
||||
<!--- end list_failures - DO NOT EDIT THIS SECTION - use rclone gendocs --->
|
||||
<!--- end list_failures - DO NOT EDIT THIS SECTION - use make commanddocs --->
|
||||
|
||||
The following backends either have not been tested recently or have known issues
|
||||
that are deemed unfixable for the time being:
|
||||
|
||||
<!--- start list_ignores - DO NOT EDIT THIS SECTION - use rclone gendocs --->
|
||||
<!--- start list_ignores - DO NOT EDIT THIS SECTION - use make commanddocs --->
|
||||
- `TestCache` (`cache`)
|
||||
- `TestFileLu` (`filelu`)
|
||||
- `TestFilesCom` (`filescom`)
|
||||
@@ -1085,7 +1085,7 @@ that are deemed unfixable for the time being:
|
||||
- `TestWebdavNextcloud` (`webdav`)
|
||||
- `TestWebdavOwncloud` (`webdav`)
|
||||
- `TestnStorage` (`netstorage`)
|
||||
<!--- end list_ignores - DO NOT EDIT THIS SECTION - use rclone gendocs --->
|
||||
<!--- end list_ignores - DO NOT EDIT THIS SECTION - use make commanddocs --->
|
||||
([more info](https://github.com/rclone/rclone/blob/master/fstest/test_all/config.yaml))
|
||||
|
||||
The above lists are updated for each stable release of rclone. For test results
|
||||
|
||||
@@ -84,7 +84,7 @@ y/e/d> y
|
||||
```
|
||||
|
||||
See the [remote setup docs](/remote_setup/) for how to set it up on a
|
||||
machine without an internet-connected web browser available.
|
||||
machine with no Internet browser available.
|
||||
|
||||
Note that rclone runs a webserver on your local machine to collect the
|
||||
token as returned from Box. This only runs from the moment it opens
|
||||
|
||||
@@ -6,54 +6,6 @@ description: "Rclone Changelog"
|
||||
|
||||
# Changelog
|
||||
|
||||
## v1.71.2 - 2025-10-20
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.71.1...v1.71.2)
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- update Go to 1.25.3
|
||||
- Update Docker image Alpine version to fix CVE-2025-9230
|
||||
- bisync: Fix race when CaptureOutput is used concurrently (Nick Craig-Wood)
|
||||
- doc fixes (albertony, dougal, iTrooz, Matt LaPaglia, Nick Craig-Wood)
|
||||
- index: Add missing providers (dougal)
|
||||
- serve http: Fix: logging URL on start (dougal)
|
||||
- Azurefiles
|
||||
- Fix server side copy not waiting for completion (Vikas Bhansali)
|
||||
- B2
|
||||
- Fix 1TB+ uploads (dougal)
|
||||
- Google Cloud Storage
|
||||
- Add region us-east5 (Dulani Woods)
|
||||
- Mega
|
||||
- Fix 402 payment required errors (Nick Craig-Wood)
|
||||
- Pikpak
|
||||
- Fix unnecessary retries by using URL expire parameter (Youfu Zhang)
|
||||
|
||||
## v1.71.1 - 2025-09-24
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.71.0...v1.71.1)
|
||||
|
||||
- Bug Fixes
|
||||
- bisync: Fix error handling for renamed conflicts (nielash)
|
||||
- march: Fix deadlock when using --fast-list on syncs (Nick Craig-Wood)
|
||||
- operations: Fix partial name collisions for non --inplace copies (Nick Craig-Wood)
|
||||
- pacer: Fix deadlock with --max-connections (Nick Craig-Wood)
|
||||
- doc fixes (albertony, anon-pradip, Claudius Ellsel, dougal, Jean-Christophe Cura, Nick Craig-Wood, nielash)
|
||||
- Mount
|
||||
- Do not log successful unmount as an error (Tilman Vogel)
|
||||
- VFS
|
||||
- Fix SIGHUP killing serve instead of flushing directory caches (dougal)
|
||||
- Local
|
||||
- Fix rmdir "Access is denied" on windows (nielash)
|
||||
- Box
|
||||
- Fix about after change in API return (Nick Craig-Wood)
|
||||
- Combine
|
||||
- Propagate SlowHash feature (skbeh)
|
||||
- Drive
|
||||
- Update making your own client ID instructions (Ed Craig-Wood)
|
||||
- Internet Archive
|
||||
- Fix server side copy files with spaces (Nick Craig-Wood)
|
||||
|
||||
## v1.71.0 - 2025-08-22
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.70.0...v1.71.0)
|
||||
|
||||
@@ -15,6 +15,8 @@ mounting them, listing them in lots of different ways.
|
||||
See the home page (https://rclone.org/) for installation, usage,
|
||||
documentation, changelog and configuration walkthroughs.
|
||||
|
||||
|
||||
|
||||
```
|
||||
rclone [flags]
|
||||
```
|
||||
@@ -1013,7 +1015,7 @@ rclone [flags]
|
||||
--use-json-log Use json log format
|
||||
--use-mmap Use mmap allocator (see docs)
|
||||
--use-server-modtime Use server modified time instead of object metadata
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.71.2")
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.71.0")
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
-V, --version Print the version number
|
||||
--webdav-auth-redirect Preserve authentication on redirect
|
||||
@@ -1055,9 +1057,6 @@ rclone [flags]
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone about](/commands/rclone_about/) - Get quota information from the remote.
|
||||
* [rclone authorize](/commands/rclone_authorize/) - Remote authorization.
|
||||
* [rclone backend](/commands/rclone_backend/) - Run a backend-specific command.
|
||||
@@ -1112,5 +1111,3 @@ rclone [flags]
|
||||
* [rclone tree](/commands/rclone_tree/) - List the contents of the remote in a tree like fashion.
|
||||
* [rclone version](/commands/rclone_version/) - Show the version number.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -15,46 +15,40 @@ output. The output is typically used, free, quota and trash contents.
|
||||
|
||||
E.g. Typical output from `rclone about remote:` is:
|
||||
|
||||
```text
|
||||
Total: 17 GiB
|
||||
Used: 7.444 GiB
|
||||
Free: 1.315 GiB
|
||||
Trashed: 100.000 MiB
|
||||
Other: 8.241 GiB
|
||||
```
|
||||
Total: 17 GiB
|
||||
Used: 7.444 GiB
|
||||
Free: 1.315 GiB
|
||||
Trashed: 100.000 MiB
|
||||
Other: 8.241 GiB
|
||||
|
||||
Where the fields are:
|
||||
|
||||
- Total: Total size available.
|
||||
- Used: Total size used.
|
||||
- Free: Total space available to this user.
|
||||
- Trashed: Total space used by trash.
|
||||
- Other: Total amount in other storage (e.g. Gmail, Google Photos).
|
||||
- Objects: Total number of objects in the storage.
|
||||
* Total: Total size available.
|
||||
* Used: Total size used.
|
||||
* Free: Total space available to this user.
|
||||
* Trashed: Total space used by trash.
|
||||
* Other: Total amount in other storage (e.g. Gmail, Google Photos).
|
||||
* Objects: Total number of objects in the storage.
|
||||
|
||||
All sizes are in number of bytes.
|
||||
|
||||
Applying a `--full` flag to the command prints the bytes in full, e.g.
|
||||
|
||||
```text
|
||||
Total: 18253611008
|
||||
Used: 7993453766
|
||||
Free: 1411001220
|
||||
Trashed: 104857602
|
||||
Other: 8849156022
|
||||
```
|
||||
Total: 18253611008
|
||||
Used: 7993453766
|
||||
Free: 1411001220
|
||||
Trashed: 104857602
|
||||
Other: 8849156022
|
||||
|
||||
A `--json` flag generates conveniently machine-readable output, e.g.
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 18253611008,
|
||||
"used": 7993453766,
|
||||
"trashed": 104857602,
|
||||
"other": 8849156022,
|
||||
"free": 1411001220
|
||||
}
|
||||
```
|
||||
{
|
||||
"total": 18253611008,
|
||||
"used": 7993453766,
|
||||
"trashed": 104857602,
|
||||
"other": 8849156022,
|
||||
"free": 1411001220
|
||||
}
|
||||
|
||||
Not all backends print all fields. Information is not included if it is not
|
||||
provided by a backend. Where the value is unlimited it is omitted.
|
||||
@@ -62,6 +56,7 @@ provided by a backend. Where the value is unlimited it is omitted.
|
||||
Some backends does not support the `rclone about` command at all,
|
||||
see complete list in [documentation](https://rclone.org/overview/#optional-features).
|
||||
|
||||
|
||||
```
|
||||
rclone about remote: [flags]
|
||||
```
|
||||
@@ -78,10 +73,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -11,23 +11,21 @@ Remote authorization.
|
||||
## Synopsis
|
||||
|
||||
Remote authorization. Used to authorize a remote or headless
|
||||
rclone from a machine with a browser. Use as instructed by rclone config.
|
||||
See also the [remote setup documentation](/remote_setup).
|
||||
rclone from a machine with a browser - use as instructed by
|
||||
rclone config.
|
||||
|
||||
The command requires 1-3 arguments:
|
||||
|
||||
- Name of a backend (e.g. "drive", "s3")
|
||||
- Either a base64 encoded JSON blob obtained from a previous rclone config session
|
||||
- Or a client_id and client_secret pair obtained from the remote service
|
||||
- fs name (e.g., "drive", "s3", etc.)
|
||||
- Either a base64 encoded JSON blob obtained from a previous rclone config session
|
||||
- Or a client_id and client_secret pair obtained from the remote service
|
||||
|
||||
Use --auth-no-open-browser to prevent rclone to open auth
|
||||
link in default browser automatically.
|
||||
|
||||
Use --template to generate HTML output via a custom Go template. If a blank
|
||||
string is provided as an argument to this flag, the default template is used.
|
||||
Use --template to generate HTML output via a custom Go template. If a blank string is provided as an argument to this flag, the default template is used.
|
||||
|
||||
```
|
||||
rclone authorize <backendname> [base64_json_blob | client_id client_secret] [flags]
|
||||
rclone authorize <fs name> [base64_json_blob | client_id client_secret] [flags]
|
||||
```
|
||||
|
||||
## Options
|
||||
@@ -42,10 +40,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -16,34 +16,27 @@ see the backend docs for definitions.
|
||||
|
||||
You can discover what commands a backend implements by using
|
||||
|
||||
```sh
|
||||
rclone backend help remote:
|
||||
rclone backend help <backendname>
|
||||
```
|
||||
rclone backend help remote:
|
||||
rclone backend help <backendname>
|
||||
|
||||
You can also discover information about the backend using (see
|
||||
[operations/fsinfo](/rc/#operations-fsinfo) in the remote control docs
|
||||
for more info).
|
||||
|
||||
```sh
|
||||
rclone backend features remote:
|
||||
```
|
||||
rclone backend features remote:
|
||||
|
||||
Pass options to the backend command with -o. This should be key=value or key, e.g.:
|
||||
|
||||
```sh
|
||||
rclone backend stats remote:path stats -o format=json -o long
|
||||
```
|
||||
rclone backend stats remote:path stats -o format=json -o long
|
||||
|
||||
Pass arguments to the backend by placing them on the end of the line
|
||||
|
||||
```sh
|
||||
rclone backend cleanup remote:path file1 file2 file3
|
||||
```
|
||||
rclone backend cleanup remote:path file1 file2 file3
|
||||
|
||||
Note to run these commands on a running backend then see
|
||||
[backend/command](/rc/#backend-command) in the rc docs.
|
||||
|
||||
|
||||
```
|
||||
rclone backend <command> remote:path [opts] <args> [flags]
|
||||
```
|
||||
@@ -63,7 +56,7 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
Important flags useful for most commands
|
||||
|
||||
```text
|
||||
```
|
||||
-n, --dry-run Do a trial run with no permanent changes
|
||||
-i, --interactive Enable interactive mode
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
@@ -71,10 +64,5 @@ Important flags useful for most commands
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -16,19 +16,18 @@ Perform bidirectional synchronization between two paths.
|
||||
bidirectional cloud sync solution in rclone.
|
||||
It retains the Path1 and Path2 filesystem listings from the prior run.
|
||||
On each successive run it will:
|
||||
|
||||
- list files on Path1 and Path2, and check for changes on each side.
|
||||
Changes include `New`, `Newer`, `Older`, and `Deleted` files.
|
||||
- Propagate changes on Path1 to Path2, and vice-versa.
|
||||
|
||||
Bisync is considered an **advanced command**, so use with care.
|
||||
Make sure you have read and understood the entire [manual](https://rclone.org/bisync)
|
||||
(especially the [Limitations](https://rclone.org/bisync/#limitations) section)
|
||||
before using, or data loss can result. Questions can be asked in the
|
||||
[Rclone Forum](https://forum.rclone.org/).
|
||||
(especially the [Limitations](https://rclone.org/bisync/#limitations) section) before using,
|
||||
or data loss can result. Questions can be asked in the [Rclone Forum](https://forum.rclone.org/).
|
||||
|
||||
See [full bisync description](https://rclone.org/bisync/) for details.
|
||||
|
||||
|
||||
```
|
||||
rclone bisync remote1:path1 remote2:path2 [flags]
|
||||
```
|
||||
@@ -70,7 +69,7 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
Flags for anything which can copy a file
|
||||
|
||||
```text
|
||||
```
|
||||
--check-first Do all the checks before starting transfers
|
||||
-c, --checksum Check for changes with size & checksum (if available, or fallback to size only)
|
||||
--compare-dest stringArray Include additional server-side paths during comparison
|
||||
@@ -111,7 +110,7 @@ Flags for anything which can copy a file
|
||||
|
||||
Important flags useful for most commands
|
||||
|
||||
```text
|
||||
```
|
||||
-n, --dry-run Do a trial run with no permanent changes
|
||||
-i, --interactive Enable interactive mode
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
@@ -121,7 +120,7 @@ Important flags useful for most commands
|
||||
|
||||
Flags for filtering directory listings
|
||||
|
||||
```text
|
||||
```
|
||||
--delete-excluded Delete files on dest excluded from sync
|
||||
--exclude stringArray Exclude files matching pattern
|
||||
--exclude-from stringArray Read file exclude patterns from file (use - to read from stdin)
|
||||
@@ -149,10 +148,5 @@ Flags for filtering directory listings
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -14,21 +14,15 @@ Sends any files to standard output.
|
||||
|
||||
You can use it like this to output a single file
|
||||
|
||||
```sh
|
||||
rclone cat remote:path/to/file
|
||||
```
|
||||
rclone cat remote:path/to/file
|
||||
|
||||
Or like this to output any file in dir or its subdirectories.
|
||||
|
||||
```sh
|
||||
rclone cat remote:path/to/dir
|
||||
```
|
||||
rclone cat remote:path/to/dir
|
||||
|
||||
Or like this to output any .txt files in dir or its subdirectories.
|
||||
|
||||
```sh
|
||||
rclone --include "*.txt" cat remote:path/to/dir
|
||||
```
|
||||
rclone --include "*.txt" cat remote:path/to/dir
|
||||
|
||||
Use the `--head` flag to print characters only at the start, `--tail` for
|
||||
the end and `--offset` and `--count` to print a section in the middle.
|
||||
@@ -39,17 +33,14 @@ Use the `--separator` flag to print a separator value between files. Be sure to
|
||||
shell-escape special characters. For example, to print a newline between
|
||||
files, use:
|
||||
|
||||
- bash:
|
||||
* bash:
|
||||
|
||||
```sh
|
||||
rclone --include "*.txt" --separator $'\n' cat remote:path/to/dir
|
||||
```
|
||||
rclone --include "*.txt" --separator $'\n' cat remote:path/to/dir
|
||||
|
||||
- powershell:
|
||||
* powershell:
|
||||
|
||||
rclone --include "*.txt" --separator "`n" cat remote:path/to/dir
|
||||
|
||||
```powershell
|
||||
rclone --include "*.txt" --separator "`n" cat remote:path/to/dir
|
||||
```
|
||||
|
||||
```
|
||||
rclone cat remote:path [flags]
|
||||
@@ -74,7 +65,7 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
Flags for filtering directory listings
|
||||
|
||||
```text
|
||||
```
|
||||
--delete-excluded Delete files on dest excluded from sync
|
||||
--exclude stringArray Exclude files matching pattern
|
||||
--exclude-from stringArray Read file exclude patterns from file (use - to read from stdin)
|
||||
@@ -104,17 +95,12 @@ Flags for filtering directory listings
|
||||
|
||||
Flags for listing directories
|
||||
|
||||
```text
|
||||
```
|
||||
--default-time Time Time to show if modtime is unknown for files and directories (default 2000-01-01T00:00:00Z)
|
||||
--fast-list Use recursive list if available; uses more memory but fewer transactions
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -52,6 +52,7 @@ you what happened to it. These are reminiscent of diff files.
|
||||
The default number of parallel checks is 8. See the [--checkers](/docs/#checkers-int)
|
||||
option for more information.
|
||||
|
||||
|
||||
```
|
||||
rclone check source:path dest:path [flags]
|
||||
```
|
||||
@@ -78,7 +79,7 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
Flags used for check commands
|
||||
|
||||
```text
|
||||
```
|
||||
--max-backlog int Maximum number of objects in sync or check backlog (default 10000)
|
||||
```
|
||||
|
||||
@@ -86,7 +87,7 @@ Flags used for check commands
|
||||
|
||||
Flags for filtering directory listings
|
||||
|
||||
```text
|
||||
```
|
||||
--delete-excluded Delete files on dest excluded from sync
|
||||
--exclude stringArray Exclude files matching pattern
|
||||
--exclude-from stringArray Read file exclude patterns from file (use - to read from stdin)
|
||||
@@ -116,17 +117,12 @@ Flags for filtering directory listings
|
||||
|
||||
Flags for listing directories
|
||||
|
||||
```text
|
||||
```
|
||||
--default-time Time Time to show if modtime is unknown for files and directories (default 2000-01-01T00:00:00Z)
|
||||
--fast-list Use recursive list if available; uses more memory but fewer transactions
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -47,6 +47,7 @@ you what happened to it. These are reminiscent of diff files.
|
||||
The default number of parallel checks is 8. See the [--checkers](/docs/#checkers-int)
|
||||
option for more information.
|
||||
|
||||
|
||||
```
|
||||
rclone checksum <hash> sumfile dst:path [flags]
|
||||
```
|
||||
@@ -72,7 +73,7 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
Flags for filtering directory listings
|
||||
|
||||
```text
|
||||
```
|
||||
--delete-excluded Delete files on dest excluded from sync
|
||||
--exclude stringArray Exclude files matching pattern
|
||||
--exclude-from stringArray Read file exclude patterns from file (use - to read from stdin)
|
||||
@@ -102,17 +103,12 @@ Flags for filtering directory listings
|
||||
|
||||
Flags for listing directories
|
||||
|
||||
```text
|
||||
```
|
||||
--default-time Time Time to show if modtime is unknown for files and directories (default 2000-01-01T00:00:00Z)
|
||||
--fast-list Use recursive list if available; uses more memory but fewer transactions
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -13,6 +13,7 @@ Clean up the remote if possible.
|
||||
Clean up the remote if possible. Empty the trash or delete old file
|
||||
versions. Not supported by all remotes.
|
||||
|
||||
|
||||
```
|
||||
rclone cleanup remote:path [flags]
|
||||
```
|
||||
@@ -30,7 +31,7 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
Important flags useful for most commands
|
||||
|
||||
```text
|
||||
```
|
||||
-n, --dry-run Do a trial run with no permanent changes
|
||||
-i, --interactive Enable interactive mode
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
@@ -38,10 +39,5 @@ Important flags useful for most commands
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -15,6 +15,7 @@ Output completion script for a given shell.
|
||||
Generates a shell completion script for rclone.
|
||||
Run with `--help` to list the supported shells.
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
```
|
||||
@@ -25,14 +26,9 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
* [rclone completion bash](/commands/rclone_completion_bash/) - Output bash completion script for rclone.
|
||||
* [rclone completion fish](/commands/rclone_completion_fish/) - Output fish completion script for rclone.
|
||||
* [rclone completion powershell](/commands/rclone_completion_powershell/) - Output powershell completion script for rclone.
|
||||
* [rclone completion zsh](/commands/rclone_completion_zsh/) - Output zsh completion script for rclone.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -13,21 +13,17 @@ Output bash completion script for rclone.
|
||||
|
||||
Generates a bash shell autocompletion script for rclone.
|
||||
|
||||
By default, when run without any arguments,
|
||||
By default, when run without any arguments,
|
||||
|
||||
```sh
|
||||
rclone completion bash
|
||||
```
|
||||
rclone completion bash
|
||||
|
||||
the generated script will be written to
|
||||
|
||||
```sh
|
||||
/etc/bash_completion.d/rclone
|
||||
```
|
||||
/etc/bash_completion.d/rclone
|
||||
|
||||
and so rclone will probably need to be run as root, or with sudo.
|
||||
|
||||
If you supply a path to a file as the command line argument, then
|
||||
If you supply a path to a file as the command line argument, then
|
||||
the generated script will be written to that file, in which case
|
||||
you should not need root privileges.
|
||||
|
||||
@@ -38,13 +34,12 @@ can logout and login again to use the autocompletion script.
|
||||
|
||||
Alternatively, you can source the script directly
|
||||
|
||||
```sh
|
||||
. /path/to/my_bash_completion_scripts/rclone
|
||||
```
|
||||
. /path/to/my_bash_completion_scripts/rclone
|
||||
|
||||
and the autocompletion functionality will be added to your
|
||||
current shell.
|
||||
|
||||
|
||||
```
|
||||
rclone completion bash [output_file] [flags]
|
||||
```
|
||||
@@ -59,10 +54,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone completion](/commands/rclone_completion/) - Output completion script for a given shell.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -16,22 +16,19 @@ Generates a fish autocompletion script for rclone.
|
||||
This writes to /etc/fish/completions/rclone.fish by default so will
|
||||
probably need to be run with sudo or as root, e.g.
|
||||
|
||||
```sh
|
||||
sudo rclone completion fish
|
||||
```
|
||||
sudo rclone completion fish
|
||||
|
||||
Logout and login again to use the autocompletion scripts, or source
|
||||
them directly
|
||||
|
||||
```sh
|
||||
. /etc/fish/completions/rclone.fish
|
||||
```
|
||||
. /etc/fish/completions/rclone.fish
|
||||
|
||||
If you supply a command line argument the script will be written
|
||||
there.
|
||||
|
||||
If output_file is "-", then the output will be written to stdout.
|
||||
|
||||
|
||||
```
|
||||
rclone completion fish [output_file] [flags]
|
||||
```
|
||||
@@ -46,10 +43,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone completion](/commands/rclone_completion/) - Output completion script for a given shell.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -15,15 +15,14 @@ Generate the autocompletion script for powershell.
|
||||
|
||||
To load completions in your current shell session:
|
||||
|
||||
```sh
|
||||
rclone completion powershell | Out-String | Invoke-Expression
|
||||
```
|
||||
rclone completion powershell | Out-String | Invoke-Expression
|
||||
|
||||
To load completions for every new session, add the output of the above command
|
||||
to your powershell profile.
|
||||
|
||||
If output_file is "-" or missing, then the output will be written to stdout.
|
||||
|
||||
|
||||
```
|
||||
rclone completion powershell [output_file] [flags]
|
||||
```
|
||||
@@ -38,10 +37,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone completion](/commands/rclone_completion/) - Output completion script for a given shell.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -16,22 +16,19 @@ Generates a zsh autocompletion script for rclone.
|
||||
This writes to /usr/share/zsh/vendor-completions/_rclone by default so will
|
||||
probably need to be run with sudo or as root, e.g.
|
||||
|
||||
```sh
|
||||
sudo rclone completion zsh
|
||||
```
|
||||
sudo rclone completion zsh
|
||||
|
||||
Logout and login again to use the autocompletion scripts, or source
|
||||
them directly
|
||||
|
||||
```sh
|
||||
autoload -U compinit && compinit
|
||||
```
|
||||
autoload -U compinit && compinit
|
||||
|
||||
If you supply a command line argument the script will be written
|
||||
there.
|
||||
|
||||
If output_file is "-", then the output will be written to stdout.
|
||||
|
||||
|
||||
```
|
||||
rclone completion zsh [output_file] [flags]
|
||||
```
|
||||
@@ -46,10 +43,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone completion](/commands/rclone_completion/) - Output completion script for a given shell.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -14,6 +14,7 @@ Enter an interactive configuration session where you can setup new
|
||||
remotes and manage existing ones. You may also set or remove a
|
||||
password to protect your configuration.
|
||||
|
||||
|
||||
```
|
||||
rclone config [flags]
|
||||
```
|
||||
@@ -28,9 +29,6 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
* [rclone config create](/commands/rclone_config_create/) - Create a new remote with name, type and options.
|
||||
* [rclone config delete](/commands/rclone_config_delete/) - Delete an existing remote.
|
||||
@@ -49,5 +47,3 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
* [rclone config update](/commands/rclone_config_update/) - Update options in an existing remote.
|
||||
* [rclone config userinfo](/commands/rclone_config_userinfo/) - Prints info about logged in user of remote.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -16,17 +16,13 @@ should be passed in pairs of `key` `value` or as `key=value`.
|
||||
For example, to make a swift remote of name myremote using auto config
|
||||
you would do:
|
||||
|
||||
```sh
|
||||
rclone config create myremote swift env_auth true
|
||||
rclone config create myremote swift env_auth=true
|
||||
```
|
||||
rclone config create myremote swift env_auth true
|
||||
rclone config create myremote swift env_auth=true
|
||||
|
||||
So for example if you wanted to configure a Google Drive remote but
|
||||
using remote authorization you would do this:
|
||||
|
||||
```sh
|
||||
rclone config create mydrive drive config_is_local=false
|
||||
```
|
||||
rclone config create mydrive drive config_is_local=false
|
||||
|
||||
Note that if the config process would normally ask a question the
|
||||
default is taken (unless `--non-interactive` is used). Each time
|
||||
@@ -54,29 +50,29 @@ it.
|
||||
|
||||
This will look something like (some irrelevant detail removed):
|
||||
|
||||
```json
|
||||
```
|
||||
{
|
||||
"State": "*oauth-islocal,teamdrive,,",
|
||||
"Option": {
|
||||
"Name": "config_is_local",
|
||||
"Help": "Use web browser to automatically authenticate rclone with remote?\n * Say Y if the machine running rclone has a web browser you can use\n * Say N if running rclone on a (remote) machine without web browser access\nIf not sure try Y. If Y failed, try N.\n",
|
||||
"Default": true,
|
||||
"Examples": [
|
||||
{
|
||||
"Value": "true",
|
||||
"Help": "Yes"
|
||||
},
|
||||
{
|
||||
"Value": "false",
|
||||
"Help": "No"
|
||||
}
|
||||
],
|
||||
"Required": false,
|
||||
"IsPassword": false,
|
||||
"Type": "bool",
|
||||
"Exclusive": true,
|
||||
},
|
||||
"Error": "",
|
||||
"State": "*oauth-islocal,teamdrive,,",
|
||||
"Option": {
|
||||
"Name": "config_is_local",
|
||||
"Help": "Use web browser to automatically authenticate rclone with remote?\n * Say Y if the machine running rclone has a web browser you can use\n * Say N if running rclone on a (remote) machine without web browser access\nIf not sure try Y. If Y failed, try N.\n",
|
||||
"Default": true,
|
||||
"Examples": [
|
||||
{
|
||||
"Value": "true",
|
||||
"Help": "Yes"
|
||||
},
|
||||
{
|
||||
"Value": "false",
|
||||
"Help": "No"
|
||||
}
|
||||
],
|
||||
"Required": false,
|
||||
"IsPassword": false,
|
||||
"Type": "bool",
|
||||
"Exclusive": true,
|
||||
},
|
||||
"Error": "",
|
||||
}
|
||||
```
|
||||
|
||||
@@ -99,9 +95,7 @@ The keys of `Option` are used as follows:
|
||||
If `Error` is set then it should be shown to the user at the same
|
||||
time as the question.
|
||||
|
||||
```sh
|
||||
rclone config update name --continue --state "*oauth-islocal,teamdrive,," --result "true"
|
||||
```
|
||||
rclone config update name --continue --state "*oauth-islocal,teamdrive,," --result "true"
|
||||
|
||||
Note that when using `--continue` all passwords should be passed in
|
||||
the clear (not obscured). Any default config values should be passed
|
||||
@@ -117,6 +111,7 @@ defaults for questions as usual.
|
||||
Note that `bin/config.py` in the rclone source implements this protocol
|
||||
as a readable demonstration.
|
||||
|
||||
|
||||
```
|
||||
rclone config create name type [key value]* [flags]
|
||||
```
|
||||
@@ -139,10 +134,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -22,10 +22,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -15,6 +15,7 @@ This normally means revoking the oauth token.
|
||||
|
||||
To reconnect use "rclone config reconnect".
|
||||
|
||||
|
||||
```
|
||||
rclone config disconnect remote: [flags]
|
||||
```
|
||||
@@ -29,10 +30,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -22,10 +22,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -14,6 +14,7 @@ Enter an interactive configuration session where you can setup new
|
||||
remotes and manage existing ones. You may also set or remove a
|
||||
password to protect your configuration.
|
||||
|
||||
|
||||
```
|
||||
rclone config edit [flags]
|
||||
```
|
||||
@@ -28,10 +29,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -12,6 +12,7 @@ set, remove and check the encryption for the config file
|
||||
This command sets, clears and checks the encryption for the config file using
|
||||
the subcommands below.
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
```
|
||||
@@ -22,13 +23,8 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
* [rclone config encryption check](/commands/rclone_config_encryption_check/) - Check that the config file is encrypted
|
||||
* [rclone config encryption remove](/commands/rclone_config_encryption_remove/) - Remove the config file encryption password
|
||||
* [rclone config encryption set](/commands/rclone_config_encryption_set/) - Set or change the config file encryption password
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -18,6 +18,7 @@ If decryption fails it will return a non-zero exit code if using
|
||||
|
||||
If the config file is not encrypted it will return a non zero exit code.
|
||||
|
||||
|
||||
```
|
||||
rclone config encryption check [flags]
|
||||
```
|
||||
@@ -32,10 +33,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config encryption](/commands/rclone_config_encryption/) - set, remove and check the encryption for the config file
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -19,6 +19,7 @@ password.
|
||||
If the config was not encrypted then no error will be returned and
|
||||
this command will do nothing.
|
||||
|
||||
|
||||
```
|
||||
rclone config encryption remove [flags]
|
||||
```
|
||||
@@ -33,10 +34,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config encryption](/commands/rclone_config_encryption/) - set, remove and check the encryption for the config file
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -29,6 +29,7 @@ encryption remove`), then set it again with this command which may be
|
||||
easier if you don't mind the unencrypted config file being on the disk
|
||||
briefly.
|
||||
|
||||
|
||||
```
|
||||
rclone config encryption set [flags]
|
||||
```
|
||||
@@ -43,10 +44,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config encryption](/commands/rclone_config_encryption/) - set, remove and check the encryption for the config file
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -22,10 +22,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -16,14 +16,13 @@ The `password` should be passed in in clear (unobscured).
|
||||
|
||||
For example, to set password of a remote of name myremote you would do:
|
||||
|
||||
```sh
|
||||
rclone config password myremote fieldname mypassword
|
||||
rclone config password myremote fieldname=mypassword
|
||||
```
|
||||
rclone config password myremote fieldname mypassword
|
||||
rclone config password myremote fieldname=mypassword
|
||||
|
||||
This command is obsolete now that "config update" and "config create"
|
||||
both support obscuring passwords directly.
|
||||
|
||||
|
||||
```
|
||||
rclone config password name [key value]+ [flags]
|
||||
```
|
||||
@@ -38,10 +37,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -22,10 +22,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -22,10 +22,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -15,6 +15,7 @@ To disconnect the remote use "rclone config disconnect".
|
||||
|
||||
This normally means going through the interactive oauth flow again.
|
||||
|
||||
|
||||
```
|
||||
rclone config reconnect remote: [flags]
|
||||
```
|
||||
@@ -29,10 +30,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -20,6 +20,8 @@ This makes the config file suitable for posting online for support.
|
||||
|
||||
It should be double checked before posting as the redaction may not be perfect.
|
||||
|
||||
|
||||
|
||||
```
|
||||
rclone config redacted [<remote>] [flags]
|
||||
```
|
||||
@@ -34,10 +36,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -22,10 +22,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -22,10 +22,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -16,17 +16,13 @@ pairs of `key` `value` or as `key=value`.
|
||||
For example, to update the env_auth field of a remote of name myremote
|
||||
you would do:
|
||||
|
||||
```sh
|
||||
rclone config update myremote env_auth true
|
||||
rclone config update myremote env_auth=true
|
||||
```
|
||||
rclone config update myremote env_auth true
|
||||
rclone config update myremote env_auth=true
|
||||
|
||||
If the remote uses OAuth the token will be updated, if you don't
|
||||
require this add an extra parameter thus:
|
||||
|
||||
```sh
|
||||
rclone config update myremote env_auth=true config_refresh_token=false
|
||||
```
|
||||
rclone config update myremote env_auth=true config_refresh_token=false
|
||||
|
||||
Note that if the config process would normally ask a question the
|
||||
default is taken (unless `--non-interactive` is used). Each time
|
||||
@@ -54,29 +50,29 @@ it.
|
||||
|
||||
This will look something like (some irrelevant detail removed):
|
||||
|
||||
```json
|
||||
```
|
||||
{
|
||||
"State": "*oauth-islocal,teamdrive,,",
|
||||
"Option": {
|
||||
"Name": "config_is_local",
|
||||
"Help": "Use web browser to automatically authenticate rclone with remote?\n * Say Y if the machine running rclone has a web browser you can use\n * Say N if running rclone on a (remote) machine without web browser access\nIf not sure try Y. If Y failed, try N.\n",
|
||||
"Default": true,
|
||||
"Examples": [
|
||||
{
|
||||
"Value": "true",
|
||||
"Help": "Yes"
|
||||
},
|
||||
{
|
||||
"Value": "false",
|
||||
"Help": "No"
|
||||
}
|
||||
],
|
||||
"Required": false,
|
||||
"IsPassword": false,
|
||||
"Type": "bool",
|
||||
"Exclusive": true,
|
||||
},
|
||||
"Error": "",
|
||||
"State": "*oauth-islocal,teamdrive,,",
|
||||
"Option": {
|
||||
"Name": "config_is_local",
|
||||
"Help": "Use web browser to automatically authenticate rclone with remote?\n * Say Y if the machine running rclone has a web browser you can use\n * Say N if running rclone on a (remote) machine without web browser access\nIf not sure try Y. If Y failed, try N.\n",
|
||||
"Default": true,
|
||||
"Examples": [
|
||||
{
|
||||
"Value": "true",
|
||||
"Help": "Yes"
|
||||
},
|
||||
{
|
||||
"Value": "false",
|
||||
"Help": "No"
|
||||
}
|
||||
],
|
||||
"Required": false,
|
||||
"IsPassword": false,
|
||||
"Type": "bool",
|
||||
"Exclusive": true,
|
||||
},
|
||||
"Error": "",
|
||||
}
|
||||
```
|
||||
|
||||
@@ -99,9 +95,7 @@ The keys of `Option` are used as follows:
|
||||
If `Error` is set then it should be shown to the user at the same
|
||||
time as the question.
|
||||
|
||||
```sh
|
||||
rclone config update name --continue --state "*oauth-islocal,teamdrive,," --result "true"
|
||||
```
|
||||
rclone config update name --continue --state "*oauth-islocal,teamdrive,," --result "true"
|
||||
|
||||
Note that when using `--continue` all passwords should be passed in
|
||||
the clear (not obscured). Any default config values should be passed
|
||||
@@ -117,6 +111,7 @@ defaults for questions as usual.
|
||||
Note that `bin/config.py` in the rclone source implements this protocol
|
||||
as a readable demonstration.
|
||||
|
||||
|
||||
```
|
||||
rclone config update name [key value]+ [flags]
|
||||
```
|
||||
@@ -139,10 +134,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -12,6 +12,7 @@ Prints info about logged in user of remote.
|
||||
This prints the details of the person logged in to the cloud storage
|
||||
system.
|
||||
|
||||
|
||||
```
|
||||
rclone config userinfo remote: [flags]
|
||||
```
|
||||
@@ -27,10 +28,5 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone config](/commands/rclone_config/) - Enter an interactive configuration session.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
@@ -10,8 +10,8 @@ Convert file and directory names in place.
|
||||
|
||||
## Synopsis
|
||||
|
||||
convmv supports advanced path name transformations for converting and renaming
|
||||
files and directories by applying prefixes, suffixes, and other alterations.
|
||||
|
||||
convmv supports advanced path name transformations for converting and renaming files and directories by applying prefixes, suffixes, and other alterations.
|
||||
|
||||
| Command | Description |
|
||||
|------|------|
|
||||
@@ -20,13 +20,10 @@ files and directories by applying prefixes, suffixes, and other alterations.
|
||||
| `--name-transform suffix_keep_extension=XXXX` | Appends XXXX to the file name while preserving the original file extension. |
|
||||
| `--name-transform trimprefix=XXXX` | Removes XXXX if it appears at the start of the file name. |
|
||||
| `--name-transform trimsuffix=XXXX` | Removes XXXX if it appears at the end of the file name. |
|
||||
| `--name-transform regex=pattern/replacement` | Applies a regex-based transformation. |
|
||||
| `--name-transform regex=/pattern/replacement/` | Applies a regex-based transformation. |
|
||||
| `--name-transform replace=old:new` | Replaces occurrences of old with new in the file name. |
|
||||
| `--name-transform date={YYYYMMDD}` | Appends or prefixes the specified date format. |
|
||||
| `--name-transform truncate=N` | Truncates the file name to a maximum of N characters. |
|
||||
| `--name-transform truncate_keep_extension=N` | Truncates the file name to a maximum of N characters while preserving the original file extension. |
|
||||
| `--name-transform truncate_bytes=N` | Truncates the file name to a maximum of N bytes (not characters). |
|
||||
| `--name-transform truncate_bytes_keep_extension=N` | Truncates the file name to a maximum of N bytes (not characters) while preserving the original file extension. |
|
||||
| `--name-transform base64encode` | Encodes the file name in Base64. |
|
||||
| `--name-transform base64decode` | Decodes a Base64-encoded file name. |
|
||||
| `--name-transform encoder=ENCODING` | Converts the file name to the specified encoding (e.g., ISO-8859-1, Windows-1252, Macintosh). |
|
||||
@@ -41,227 +38,211 @@ files and directories by applying prefixes, suffixes, and other alterations.
|
||||
| `--name-transform nfd` | Converts the file name to NFD Unicode normalization form. |
|
||||
| `--name-transform nfkc` | Converts the file name to NFKC Unicode normalization form. |
|
||||
| `--name-transform nfkd` | Converts the file name to NFKD Unicode normalization form. |
|
||||
| `--name-transform command=/path/to/my/programfile names.` | Executes an external program to transform. |
|
||||
| `--name-transform command=/path/to/my/programfile names.` | Executes an external program to transform |
|
||||
|
||||
Conversion modes:
|
||||
|
||||
```text
|
||||
none
|
||||
nfc
|
||||
nfd
|
||||
nfkc
|
||||
nfkd
|
||||
replace
|
||||
prefix
|
||||
suffix
|
||||
suffix_keep_extension
|
||||
trimprefix
|
||||
trimsuffix
|
||||
index
|
||||
date
|
||||
truncate
|
||||
truncate_keep_extension
|
||||
truncate_bytes
|
||||
truncate_bytes_keep_extension
|
||||
base64encode
|
||||
base64decode
|
||||
encoder
|
||||
decoder
|
||||
ISO-8859-1
|
||||
Windows-1252
|
||||
Macintosh
|
||||
charmap
|
||||
lowercase
|
||||
uppercase
|
||||
titlecase
|
||||
ascii
|
||||
url
|
||||
regex
|
||||
command
|
||||
Conversion modes:
|
||||
```
|
||||
|
||||
Char maps:
|
||||
|
||||
```text
|
||||
IBM-Code-Page-037
|
||||
IBM-Code-Page-437
|
||||
IBM-Code-Page-850
|
||||
IBM-Code-Page-852
|
||||
IBM-Code-Page-855
|
||||
Windows-Code-Page-858
|
||||
IBM-Code-Page-860
|
||||
IBM-Code-Page-862
|
||||
IBM-Code-Page-863
|
||||
IBM-Code-Page-865
|
||||
IBM-Code-Page-866
|
||||
IBM-Code-Page-1047
|
||||
IBM-Code-Page-1140
|
||||
ISO-8859-1
|
||||
ISO-8859-2
|
||||
ISO-8859-3
|
||||
ISO-8859-4
|
||||
ISO-8859-5
|
||||
ISO-8859-6
|
||||
ISO-8859-7
|
||||
ISO-8859-8
|
||||
ISO-8859-9
|
||||
ISO-8859-10
|
||||
ISO-8859-13
|
||||
ISO-8859-14
|
||||
ISO-8859-15
|
||||
ISO-8859-16
|
||||
KOI8-R
|
||||
KOI8-U
|
||||
Macintosh
|
||||
Macintosh-Cyrillic
|
||||
Windows-874
|
||||
Windows-1250
|
||||
Windows-1251
|
||||
Windows-1252
|
||||
Windows-1253
|
||||
Windows-1254
|
||||
Windows-1255
|
||||
Windows-1256
|
||||
Windows-1257
|
||||
Windows-1258
|
||||
X-User-Defined
|
||||
none
|
||||
nfc
|
||||
nfd
|
||||
nfkc
|
||||
nfkd
|
||||
replace
|
||||
prefix
|
||||
suffix
|
||||
suffix_keep_extension
|
||||
trimprefix
|
||||
trimsuffix
|
||||
index
|
||||
date
|
||||
truncate
|
||||
base64encode
|
||||
base64decode
|
||||
encoder
|
||||
decoder
|
||||
ISO-8859-1
|
||||
Windows-1252
|
||||
Macintosh
|
||||
charmap
|
||||
lowercase
|
||||
uppercase
|
||||
titlecase
|
||||
ascii
|
||||
url
|
||||
regex
|
||||
command
|
||||
```
|
||||
|
||||
Encoding masks:
|
||||
|
||||
```text
|
||||
Asterisk
|
||||
BackQuote
|
||||
BackSlash
|
||||
Colon
|
||||
CrLf
|
||||
Ctl
|
||||
Del
|
||||
Dollar
|
||||
Dot
|
||||
DoubleQuote
|
||||
Exclamation
|
||||
Hash
|
||||
InvalidUtf8
|
||||
LeftCrLfHtVt
|
||||
LeftPeriod
|
||||
LeftSpace
|
||||
LeftTilde
|
||||
LtGt
|
||||
None
|
||||
Percent
|
||||
Pipe
|
||||
Question
|
||||
Raw
|
||||
RightCrLfHtVt
|
||||
RightPeriod
|
||||
RightSpace
|
||||
Semicolon
|
||||
SingleQuote
|
||||
Slash
|
||||
SquareBracket
|
||||
Char maps:
|
||||
```
|
||||
|
||||
IBM-Code-Page-037
|
||||
IBM-Code-Page-437
|
||||
IBM-Code-Page-850
|
||||
IBM-Code-Page-852
|
||||
IBM-Code-Page-855
|
||||
Windows-Code-Page-858
|
||||
IBM-Code-Page-860
|
||||
IBM-Code-Page-862
|
||||
IBM-Code-Page-863
|
||||
IBM-Code-Page-865
|
||||
IBM-Code-Page-866
|
||||
IBM-Code-Page-1047
|
||||
IBM-Code-Page-1140
|
||||
ISO-8859-1
|
||||
ISO-8859-2
|
||||
ISO-8859-3
|
||||
ISO-8859-4
|
||||
ISO-8859-5
|
||||
ISO-8859-6
|
||||
ISO-8859-7
|
||||
ISO-8859-8
|
||||
ISO-8859-9
|
||||
ISO-8859-10
|
||||
ISO-8859-13
|
||||
ISO-8859-14
|
||||
ISO-8859-15
|
||||
ISO-8859-16
|
||||
KOI8-R
|
||||
KOI8-U
|
||||
Macintosh
|
||||
Macintosh-Cyrillic
|
||||
Windows-874
|
||||
Windows-1250
|
||||
Windows-1251
|
||||
Windows-1252
|
||||
Windows-1253
|
||||
Windows-1254
|
||||
Windows-1255
|
||||
Windows-1256
|
||||
Windows-1257
|
||||
Windows-1258
|
||||
X-User-Defined
|
||||
```
|
||||
Encoding masks:
|
||||
```
|
||||
Asterisk
|
||||
BackQuote
|
||||
BackSlash
|
||||
Colon
|
||||
CrLf
|
||||
Ctl
|
||||
Del
|
||||
Dollar
|
||||
Dot
|
||||
DoubleQuote
|
||||
Exclamation
|
||||
Hash
|
||||
InvalidUtf8
|
||||
LeftCrLfHtVt
|
||||
LeftPeriod
|
||||
LeftSpace
|
||||
LeftTilde
|
||||
LtGt
|
||||
None
|
||||
Percent
|
||||
Pipe
|
||||
Question
|
||||
Raw
|
||||
RightCrLfHtVt
|
||||
RightPeriod
|
||||
RightSpace
|
||||
Semicolon
|
||||
SingleQuote
|
||||
Slash
|
||||
SquareBracket
|
||||
```
|
||||
Examples:
|
||||
|
||||
Examples:
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,uppercase"
|
||||
// Output: STORIES/THE QUICK BROWN FOX!.TXT
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,replace=Fox:Turtle" --name-transform "all,replace=Quick:Slow"
|
||||
// Output: stories/The Slow Brown Turtle!.txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,base64encode"
|
||||
// Output: c3Rvcmllcw==/VGhlIFF1aWNrIEJyb3duIEZveCEudHh0
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "c3Rvcmllcw==/VGhlIFF1aWNrIEJyb3duIEZveCEudHh0" --name-transform "all,base64decode"
|
||||
// Output: stories/The Quick Brown Fox!.txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown 🦊 Fox Went to the Café!.txt" --name-transform "all,nfc"
|
||||
// Output: stories/The Quick Brown 🦊 Fox Went to the Café!.txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown 🦊 Fox Went to the Café!.txt" --name-transform "all,nfd"
|
||||
// Output: stories/The Quick Brown 🦊 Fox Went to the Café!.txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown 🦊 Fox!.txt" --name-transform "all,ascii"
|
||||
// Output: stories/The Quick Brown Fox!.txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,trimsuffix=.txt"
|
||||
// Output: stories/The Quick Brown Fox!
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,prefix=OLD_"
|
||||
// Output: OLD_stories/OLD_The Quick Brown Fox!.txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown 🦊 Fox Went to the Café!.txt" --name-transform "all,charmap=ISO-8859-7"
|
||||
// Output: stories/The Quick Brown _ Fox Went to the Caf_!.txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox: A Memoir [draft].txt" --name-transform "all,encoder=Colon,SquareBracket"
|
||||
// Output: stories/The Quick Brown Fox: A Memoir [draft].txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown 🦊 Fox Went to the Café!.txt" --name-transform "all,truncate=21"
|
||||
// Output: stories/The Quick Brown 🦊 Fox
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,command=echo"
|
||||
// Output: stories/The Quick Brown Fox!.txt
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{YYYYMMDD}"
|
||||
// Output: stories/The Quick Brown Fox!-20251020
|
||||
// Output: stories/The Quick Brown Fox!-20250618
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{macfriendlytime}"
|
||||
// Output: stories/The Quick Brown Fox!-2025-10-20 1251PM
|
||||
// Output: stories/The Quick Brown Fox!-2025-06-18 0148PM
|
||||
```
|
||||
|
||||
```sh
|
||||
```
|
||||
rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,regex=[\\.\\w]/ab"
|
||||
// Output: ababababababab/ababab ababababab ababababab ababab!abababab
|
||||
```
|
||||
|
||||
The regex command generally accepts Perl-style regular expressions, the exact
|
||||
syntax is defined in the [Go regular expression reference](https://golang.org/pkg/regexp/syntax/).
|
||||
The replacement string may contain capturing group variables, referencing
|
||||
capturing groups using the syntax `$name` or `${name}`, where the name can
|
||||
refer to a named capturing group or it can simply be the index as a number.
|
||||
To insert a literal $, use $$.
|
||||
|
||||
Multiple transformations can be used in sequence, applied
|
||||
in the order they are specified on the command line.
|
||||
Multiple transformations can be used in sequence, applied in the order they are specified on the command line.
|
||||
|
||||
The `--name-transform` flag is also available in `sync`, `copy`, and `move`.
|
||||
|
||||
## Files vs Directories
|
||||
# Files vs Directories
|
||||
|
||||
By default `--name-transform` will only apply to file names. The means only the
|
||||
leaf file name will be transformed. However some of the transforms would be
|
||||
better applied to the whole path or just directories. To choose which which
|
||||
part of the file path is affected some tags can be added to the `--name-transform`.
|
||||
By default `--name-transform` will only apply to file names. The means only the leaf file name will be transformed.
|
||||
However some of the transforms would be better applied to the whole path or just directories.
|
||||
To choose which which part of the file path is affected some tags can be added to the `--name-transform`.
|
||||
|
||||
| Tag | Effect |
|
||||
|------|------|
|
||||
@@ -269,58 +250,42 @@ part of the file path is affected some tags can be added to the `--name-transfor
|
||||
| `dir` | Only transform name of directories - these may appear anywhere in the path |
|
||||
| `all` | Transform the entire path for files and directories |
|
||||
|
||||
This is used by adding the tag into the transform name like this:
|
||||
`--name-transform file,prefix=ABC` or `--name-transform dir,prefix=DEF`.
|
||||
This is used by adding the tag into the transform name like this: `--name-transform file,prefix=ABC` or `--name-transform dir,prefix=DEF`.
|
||||
|
||||
For some conversions using all is more likely to be useful, for example
|
||||
`--name-transform all,nfc`.
|
||||
For some conversions using all is more likely to be useful, for example `--name-transform all,nfc`.
|
||||
|
||||
Note that `--name-transform` may not add path separators `/` to the name.
|
||||
This will cause an error.
|
||||
Note that `--name-transform` may not add path separators `/` to the name. This will cause an error.
|
||||
|
||||
## Ordering and Conflicts
|
||||
# Ordering and Conflicts
|
||||
|
||||
- Transformations will be applied in the order specified by the user.
|
||||
- If the `file` tag is in use (the default) then only the leaf name of files
|
||||
will be transformed.
|
||||
- If the `dir` tag is in use then directories anywhere in the path will be
|
||||
transformed
|
||||
- If the `all` tag is in use then directories and files anywhere in the path
|
||||
will be transformed
|
||||
- Each transformation will be run one path segment at a time.
|
||||
- If a transformation adds a `/` or ends up with an empty path segment then
|
||||
that will be an error.
|
||||
- It is up to the user to put the transformations in a sensible order.
|
||||
- Conflicting transformations, such as `prefix` followed by `trimprefix` or
|
||||
`nfc` followed by `nfd`, are possible.
|
||||
- Instead of enforcing mutual exclusivity, transformations are applied in
|
||||
sequence as specified by the user, allowing for intentional use cases
|
||||
(e.g., trimming one prefix before adding another).
|
||||
- Users should be aware that certain combinations may lead to unexpected
|
||||
results and should verify transformations using `--dry-run` before execution.
|
||||
* Transformations will be applied in the order specified by the user.
|
||||
* If the `file` tag is in use (the default) then only the leaf name of files will be transformed.
|
||||
* If the `dir` tag is in use then directories anywhere in the path will be transformed
|
||||
* If the `all` tag is in use then directories and files anywhere in the path will be transformed
|
||||
* Each transformation will be run one path segment at a time.
|
||||
* If a transformation adds a `/` or ends up with an empty path segment then that will be an error.
|
||||
* It is up to the user to put the transformations in a sensible order.
|
||||
* Conflicting transformations, such as `prefix` followed by `trimprefix` or `nfc` followed by `nfd`, are possible.
|
||||
* Instead of enforcing mutual exclusivity, transformations are applied in sequence as specified by the
|
||||
user, allowing for intentional use cases (e.g., trimming one prefix before adding another).
|
||||
* Users should be aware that certain combinations may lead to unexpected results and should verify
|
||||
transformations using `--dry-run` before execution.
|
||||
|
||||
## Race Conditions and Non-Deterministic Behavior
|
||||
# Race Conditions and Non-Deterministic Behavior
|
||||
|
||||
Some transformations, such as `replace=old:new`, may introduce conflicts where
|
||||
multiple source files map to the same destination name. This can lead to race
|
||||
conditions when performing concurrent transfers. It is up to the user to
|
||||
anticipate these.
|
||||
|
||||
- If two files from the source are transformed into the same name at the
|
||||
destination, the final state may be non-deterministic.
|
||||
- Running rclone check after a sync using such transformations may erroneously
|
||||
report missing or differing files due to overwritten results.
|
||||
Some transformations, such as `replace=old:new`, may introduce conflicts where multiple source files map to the same destination name.
|
||||
This can lead to race conditions when performing concurrent transfers. It is up to the user to anticipate these.
|
||||
* If two files from the source are transformed into the same name at the destination, the final state may be non-deterministic.
|
||||
* Running rclone check after a sync using such transformations may erroneously report missing or differing files due to overwritten results.
|
||||
|
||||
To minimize risks, users should:
|
||||
* Carefully review transformations that may introduce conflicts.
|
||||
* Use `--dry-run` to inspect changes before executing a sync (but keep in mind that it won't show the effect of non-deterministic transformations).
|
||||
* Avoid transformations that cause multiple distinct source files to map to the same destination name.
|
||||
* Consider disabling concurrency with `--transfers=1` if necessary.
|
||||
* Certain transformations (e.g. `prefix`) will have a multiplying effect every time they are used. Avoid these when using `bisync`.
|
||||
|
||||
- Carefully review transformations that may introduce conflicts.
|
||||
- Use `--dry-run` to inspect changes before executing a sync (but keep in mind
|
||||
that it won't show the effect of non-deterministic transformations).
|
||||
- Avoid transformations that cause multiple distinct source files to map to the
|
||||
same destination name.
|
||||
- Consider disabling concurrency with `--transfers=1` if necessary.
|
||||
- Certain transformations (e.g. `prefix`) will have a multiplying effect every
|
||||
time they are used. Avoid these when using `bisync`.
|
||||
|
||||
|
||||
```
|
||||
rclone convmv dest:path --name-transform XXX [flags]
|
||||
@@ -341,7 +306,7 @@ See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
Flags for anything which can copy a file
|
||||
|
||||
```text
|
||||
```
|
||||
--check-first Do all the checks before starting transfers
|
||||
-c, --checksum Check for changes with size & checksum (if available, or fallback to size only)
|
||||
--compare-dest stringArray Include additional server-side paths during comparison
|
||||
@@ -382,7 +347,7 @@ Flags for anything which can copy a file
|
||||
|
||||
Important flags useful for most commands
|
||||
|
||||
```text
|
||||
```
|
||||
-n, --dry-run Do a trial run with no permanent changes
|
||||
-i, --interactive Enable interactive mode
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
@@ -392,7 +357,7 @@ Important flags useful for most commands
|
||||
|
||||
Flags for filtering directory listings
|
||||
|
||||
```text
|
||||
```
|
||||
--delete-excluded Delete files on dest excluded from sync
|
||||
--exclude stringArray Exclude files matching pattern
|
||||
--exclude-from stringArray Read file exclude patterns from file (use - to read from stdin)
|
||||
@@ -422,17 +387,12 @@ Flags for filtering directory listings
|
||||
|
||||
Flags for listing directories
|
||||
|
||||
```text
|
||||
```
|
||||
--default-time Time Time to show if modtime is unknown for files and directories (default 2000-01-01T00:00:00Z)
|
||||
--fast-list Use recursive list if available; uses more memory but fewer transactions
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable ul-style line-length -->
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user