mirror of
https://github.com/rclone/rclone.git
synced 2025-12-22 03:03:20 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
729799af7c | ||
|
|
029f817ebc | ||
|
|
073e996cc2 | ||
|
|
fb2a4edd6f | ||
|
|
f949856170 | ||
|
|
c0e9584403 | ||
|
|
ace56b6e0f | ||
|
|
1d45c6eaaa | ||
|
|
e8222bbc95 | ||
|
|
815643264b | ||
|
|
4f8472664f | ||
|
|
3278b297cf | ||
|
|
5c0af62d0a | ||
|
|
6760ab6bb3 | ||
|
|
a9ffa1178c | ||
|
|
687865f760 | ||
|
|
d745bc1baa | ||
|
|
1f279f0419 | ||
|
|
d805e63f7d |
3732
MANUAL.html
generated
3732
MANUAL.html
generated
File diff suppressed because it is too large
Load Diff
90
MANUAL.md
generated
90
MANUAL.md
generated
@@ -1,6 +1,6 @@
|
|||||||
% rclone(1) User Manual
|
% rclone(1) User Manual
|
||||||
% Nick Craig-Wood
|
% Nick Craig-Wood
|
||||||
% Jun 24, 2020
|
% Aug 07, 2020
|
||||||
|
|
||||||
# Rclone syncs your files to cloud storage
|
# Rclone syncs your files to cloud storage
|
||||||
|
|
||||||
@@ -330,7 +330,7 @@ kill %1
|
|||||||
|
|
||||||
## Install from source ##
|
## Install from source ##
|
||||||
|
|
||||||
Make sure you have at least [Go](https://golang.org/) 1.7
|
Make sure you have at least [Go](https://golang.org/) 1.10
|
||||||
installed. [Download go](https://golang.org/dl/) if necessary. The
|
installed. [Download go](https://golang.org/dl/) if necessary. The
|
||||||
latest release is recommended. Then
|
latest release is recommended. Then
|
||||||
|
|
||||||
@@ -339,16 +339,23 @@ latest release is recommended. Then
|
|||||||
go build
|
go build
|
||||||
./rclone version
|
./rclone version
|
||||||
|
|
||||||
You can also build and install rclone in the
|
This will leave you a checked out version of rclone you can modify and
|
||||||
[GOPATH](https://github.com/golang/go/wiki/GOPATH) (which defaults to
|
send pull requests with. If you use `make` instead of `go build` then
|
||||||
`~/go`) with:
|
the rclone build will have the correct version information in it.
|
||||||
|
|
||||||
go get -u -v github.com/rclone/rclone
|
You can also build the latest stable rclone with:
|
||||||
|
|
||||||
and this will build the binary in `$GOPATH/bin` (`~/go/bin/rclone` by
|
go get github.com/rclone/rclone
|
||||||
default) after downloading the source to
|
|
||||||
`$GOPATH/src/github.com/rclone/rclone` (`~/go/src/github.com/rclone/rclone`
|
or the latest version (equivalent to the beta) with
|
||||||
by default).
|
|
||||||
|
go get github.com/rclone/rclone@master
|
||||||
|
|
||||||
|
These will build the binary in `$(go env GOPATH)/bin`
|
||||||
|
(`~/go/bin/rclone` by default) after downloading the source to the go
|
||||||
|
module cache. Note - do **not** use the `-u` flag here. This causes go
|
||||||
|
to try to update the depencencies that rclone uses and sometimes these
|
||||||
|
don't work with the current version of rclone.
|
||||||
|
|
||||||
## Installation with Ansible ##
|
## Installation with Ansible ##
|
||||||
|
|
||||||
@@ -9683,7 +9690,7 @@ These flags are available for every command.
|
|||||||
--use-json-log Use json log format.
|
--use-json-log Use json log format.
|
||||||
--use-mmap Use mmap allocator (see docs).
|
--use-mmap Use mmap allocator (see docs).
|
||||||
--use-server-modtime Use server modified time instead of object metadata
|
--use-server-modtime Use server modified time instead of object metadata
|
||||||
--user-agent string Set the user-agent to a specified string. The default is rclone/ version (default "rclone/v1.52.2")
|
--user-agent string Set the user-agent to a specified string. The default is rclone/ version (default "rclone/v1.52.3")
|
||||||
-v, --verbose count Print lots more stuff (repeat for more)
|
-v, --verbose count Print lots more stuff (repeat for more)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -9893,6 +9900,7 @@ and may be set in the config file.
|
|||||||
--pcloud-client-id string Pcloud App Client Id
|
--pcloud-client-id string Pcloud App Client Id
|
||||||
--pcloud-client-secret string Pcloud App Client Secret
|
--pcloud-client-secret string Pcloud App Client Secret
|
||||||
--pcloud-encoding MultiEncoder This sets the encoding for the backend. (default Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
--pcloud-encoding MultiEncoder This sets the encoding for the backend. (default Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
||||||
|
--pcloud-hostname string Hostname to connect to. (default "api.pcloud.com")
|
||||||
--pcloud-root-folder-id string Fill in for rclone to use a non root folder as its starting point. (default "d0")
|
--pcloud-root-folder-id string Fill in for rclone to use a non root folder as its starting point. (default "d0")
|
||||||
--premiumizeme-encoding MultiEncoder This sets the encoding for the backend. (default Slash,DoubleQuote,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
--premiumizeme-encoding MultiEncoder This sets the encoding for the backend. (default Slash,DoubleQuote,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
||||||
--putio-encoding MultiEncoder This sets the encoding for the backend. (default Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
--putio-encoding MultiEncoder This sets the encoding for the backend. (default Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
||||||
@@ -15337,6 +15345,10 @@ FTP is the File Transfer Protocol. FTP support is provided using the
|
|||||||
[github.com/jlaffaye/ftp](https://godoc.org/github.com/jlaffaye/ftp)
|
[github.com/jlaffaye/ftp](https://godoc.org/github.com/jlaffaye/ftp)
|
||||||
package.
|
package.
|
||||||
|
|
||||||
|
Paths are specified as `remote:path`. If the path does not begin with
|
||||||
|
a `/` it is relative to the home directory of the user. An empty path
|
||||||
|
`remote:` refers to the user's home directory.
|
||||||
|
|
||||||
Here is an example of making an FTP configuration. First run
|
Here is an example of making an FTP configuration. First run
|
||||||
|
|
||||||
rclone config
|
rclone config
|
||||||
@@ -16624,9 +16636,6 @@ Leave blank normally.
|
|||||||
Fill in to access "Computers" folders (see docs), or for rclone to use
|
Fill in to access "Computers" folders (see docs), or for rclone to use
|
||||||
a non root folder as its starting point.
|
a non root folder as its starting point.
|
||||||
|
|
||||||
Note that if this is blank, the first time rclone runs it will fill it
|
|
||||||
in with the ID of the root folder.
|
|
||||||
|
|
||||||
|
|
||||||
- Config: root_folder_id
|
- Config: root_folder_id
|
||||||
- Env Var: RCLONE_DRIVE_ROOT_FOLDER_ID
|
- Env Var: RCLONE_DRIVE_ROOT_FOLDER_ID
|
||||||
@@ -16833,9 +16842,6 @@ Size of listing chunk 100-1000. 0 to disable.
|
|||||||
|
|
||||||
Impersonate this user when using a service account.
|
Impersonate this user when using a service account.
|
||||||
|
|
||||||
Note that if this is used then "root_folder_id" will be ignored.
|
|
||||||
|
|
||||||
|
|
||||||
- Config: impersonate
|
- Config: impersonate
|
||||||
- Env Var: RCLONE_DRIVE_IMPERSONATE
|
- Env Var: RCLONE_DRIVE_IMPERSONATE
|
||||||
- Type: string
|
- Type: string
|
||||||
@@ -17232,6 +17238,13 @@ the remote configuration, it's not such a big deal).
|
|||||||
|
|
||||||
(Thanks to @balazer on github for these instructions.)
|
(Thanks to @balazer on github for these instructions.)
|
||||||
|
|
||||||
|
Sometimes, creation of an OAuth consent in Google API Console fails due to an error message
|
||||||
|
“The request failed because changes to one of the field of the resource is not supported”.
|
||||||
|
As a convenient workaround, the necessary Google Drive API key can be created on the
|
||||||
|
[Python Quickstart](https://developers.google.com/drive/api/v3/quickstart/python) page.
|
||||||
|
Just push the Enable the Drive API button to receive the Client ID and Secret.
|
||||||
|
Note that it will automatically create a new project in the API Console.
|
||||||
|
|
||||||
Google Photos
|
Google Photos
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
@@ -19449,7 +19462,7 @@ requests.
|
|||||||
If you are having problems with them (E.g., seeing a lot of throttling), you can get your own
|
If you are having problems with them (E.g., seeing a lot of throttling), you can get your own
|
||||||
Client ID and Key by following the steps below:
|
Client ID and Key by following the steps below:
|
||||||
|
|
||||||
1. Open https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade, then click `New registration`.
|
1. Open https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade and then click `New registration`.
|
||||||
2. Enter a name for your app, choose account type `Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)`, select `Web` in `Redirect URI` Enter `http://localhost:53682/` and click Register. Copy and keep the `Application (client) ID` under the app name for later use.
|
2. Enter a name for your app, choose account type `Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)`, select `Web` in `Redirect URI` Enter `http://localhost:53682/` and click Register. Copy and keep the `Application (client) ID` under the app name for later use.
|
||||||
3. Under `manage` select `Certificates & secrets`, click `New client secret`. Copy and keep that secret for later use.
|
3. Under `manage` select `Certificates & secrets`, click `New client secret`. Copy and keep that secret for later use.
|
||||||
4. Under `manage` select `API permissions`, click `Add a permission` and select `Microsoft Graph` then select `delegated permissions`.
|
4. Under `manage` select `API permissions`, click `Add a permission` and select `Microsoft Graph` then select `delegated permissions`.
|
||||||
@@ -20869,6 +20882,17 @@ Fill in for rclone to use a non root folder as its starting point.
|
|||||||
- Type: string
|
- Type: string
|
||||||
- Default: "d0"
|
- Default: "d0"
|
||||||
|
|
||||||
|
#### --pcloud-hostname
|
||||||
|
|
||||||
|
Hostname to connect to.
|
||||||
|
|
||||||
|
This is normally set when rclone initially does the oauth connection.
|
||||||
|
|
||||||
|
- Config: hostname
|
||||||
|
- Env Var: RCLONE_PCLOUD_HOSTNAME
|
||||||
|
- Type: string
|
||||||
|
- Default: "api.pcloud.com"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
premiumize.me
|
premiumize.me
|
||||||
@@ -23638,6 +23662,36 @@ Options:
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.52.3 - 2020-08-07
|
||||||
|
|
||||||
|
[See commits](https://github.com/rclone/rclone/compare/v1.52.2...v1.52.3)
|
||||||
|
|
||||||
|
* Bug Fixes
|
||||||
|
* docs
|
||||||
|
* Disable smart typography (eg en-dash) in MANUAL.* and man page (Nick Craig-Wood)
|
||||||
|
* Update install.md to reflect minimum Go version (Evan Harris)
|
||||||
|
* Update install from source instructions (Nick Craig-Wood)
|
||||||
|
* make_manual: Support SOURCE_DATE_EPOCH (Morten Linderud)
|
||||||
|
* log: Fix --use-json-log going to stderr not --log-file on Windows (Nick Craig-Wood)
|
||||||
|
* serve dlna: Fix file list on Samsung Series 6+ TVs (Matteo Pietro Dazzi)
|
||||||
|
* sync: Fix deadlock with --track-renames-strategy modtime (Nick Craig-Wood)
|
||||||
|
* Cache
|
||||||
|
* Fix moveto/copyto remote:file remote:file2 (Nick Craig-Wood)
|
||||||
|
* Drive
|
||||||
|
* Stop using root_folder_id as a cache (Nick Craig-Wood)
|
||||||
|
* Make dangling shortcuts appear in listings (Nick Craig-Wood)
|
||||||
|
* Drop "Disabling ListR" messages down to debug (Nick Craig-Wood)
|
||||||
|
* Workaround and policy for Google Drive API (Dmitry Ustalov)
|
||||||
|
* FTP
|
||||||
|
* Add note to docs about home vs root directory selection (Nick Craig-Wood)
|
||||||
|
* Onedrive
|
||||||
|
* Fix reverting to Copy when Move would have worked (Nick Craig-Wood)
|
||||||
|
* Avoid comma rendered in URL in onedrive.md (Kevin)
|
||||||
|
* Pcloud
|
||||||
|
* Fix oauth on European region "eapi.pcloud.com" (Nick Craig-Wood)
|
||||||
|
* S3
|
||||||
|
* Fix bucket Region auto detection when Region unset in config (Nick Craig-Wood)
|
||||||
|
|
||||||
## v1.52.2 - 2020-06-24
|
## v1.52.2 - 2020-06-24
|
||||||
|
|
||||||
[See commits](https://github.com/rclone/rclone/compare/v1.52.1...v1.52.2)
|
[See commits](https://github.com/rclone/rclone/compare/v1.52.1...v1.52.2)
|
||||||
|
|||||||
4376
MANUAL.txt
generated
4376
MANUAL.txt
generated
File diff suppressed because it is too large
Load Diff
6
Makefile
6
Makefile
@@ -105,16 +105,16 @@ tidy:
|
|||||||
doc: rclone.1 MANUAL.html MANUAL.txt rcdocs commanddocs
|
doc: rclone.1 MANUAL.html MANUAL.txt rcdocs commanddocs
|
||||||
|
|
||||||
rclone.1: MANUAL.md
|
rclone.1: MANUAL.md
|
||||||
pandoc -s --from markdown --to man MANUAL.md -o rclone.1
|
pandoc -s --from markdown-smart --to man MANUAL.md -o rclone.1
|
||||||
|
|
||||||
MANUAL.md: bin/make_manual.py docs/content/*.md commanddocs backenddocs
|
MANUAL.md: bin/make_manual.py docs/content/*.md commanddocs backenddocs
|
||||||
./bin/make_manual.py
|
./bin/make_manual.py
|
||||||
|
|
||||||
MANUAL.html: MANUAL.md
|
MANUAL.html: MANUAL.md
|
||||||
pandoc -s --from markdown --to html MANUAL.md -o MANUAL.html
|
pandoc -s --from markdown-smart --to html MANUAL.md -o MANUAL.html
|
||||||
|
|
||||||
MANUAL.txt: MANUAL.md
|
MANUAL.txt: MANUAL.md
|
||||||
pandoc -s --from markdown --to plain MANUAL.md -o MANUAL.txt
|
pandoc -s --from markdown-smart --to plain MANUAL.md -o MANUAL.txt
|
||||||
|
|
||||||
commanddocs: rclone
|
commanddocs: rclone
|
||||||
XDG_CACHE_HOME="" XDG_CONFIG_HOME="" HOME="\$$HOME" USER="\$$USER" rclone gendocs docs/content/
|
XDG_CACHE_HOME="" XDG_CONFIG_HOME="" HOME="\$$HOME" USER="\$$USER" rclone gendocs docs/content/
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ const (
|
|||||||
rcloneEncryptedClientSecret = "eX8GpZTVx3vxMWVkuuBdDWmAUE6rGhTwVrvG9GhllYccSdj2-mvHVg"
|
rcloneEncryptedClientSecret = "eX8GpZTVx3vxMWVkuuBdDWmAUE6rGhTwVrvG9GhllYccSdj2-mvHVg"
|
||||||
driveFolderType = "application/vnd.google-apps.folder"
|
driveFolderType = "application/vnd.google-apps.folder"
|
||||||
shortcutMimeType = "application/vnd.google-apps.shortcut"
|
shortcutMimeType = "application/vnd.google-apps.shortcut"
|
||||||
|
shortcutMimeTypeDangling = "application/vnd.google-apps.shortcut.dangling" // synthetic mime type for internal use
|
||||||
timeFormatIn = time.RFC3339
|
timeFormatIn = time.RFC3339
|
||||||
timeFormatOut = "2006-01-02T15:04:05.000000000Z07:00"
|
timeFormatOut = "2006-01-02T15:04:05.000000000Z07:00"
|
||||||
defaultMinSleep = fs.Duration(100 * time.Millisecond)
|
defaultMinSleep = fs.Duration(100 * time.Millisecond)
|
||||||
@@ -223,9 +224,6 @@ Leave blank normally.
|
|||||||
|
|
||||||
Fill in to access "Computers" folders (see docs), or for rclone to use
|
Fill in to access "Computers" folders (see docs), or for rclone to use
|
||||||
a non root folder as its starting point.
|
a non root folder as its starting point.
|
||||||
|
|
||||||
Note that if this is blank, the first time rclone runs it will fill it
|
|
||||||
in with the ID of the root folder.
|
|
||||||
`,
|
`,
|
||||||
}, {
|
}, {
|
||||||
Name: "service_account_file",
|
Name: "service_account_file",
|
||||||
@@ -349,12 +347,9 @@ date is used.`,
|
|||||||
Help: "Size of listing chunk 100-1000. 0 to disable.",
|
Help: "Size of listing chunk 100-1000. 0 to disable.",
|
||||||
Advanced: true,
|
Advanced: true,
|
||||||
}, {
|
}, {
|
||||||
Name: "impersonate",
|
Name: "impersonate",
|
||||||
Default: "",
|
Default: "",
|
||||||
Help: `Impersonate this user when using a service account.
|
Help: `Impersonate this user when using a service account.`,
|
||||||
|
|
||||||
Note that if this is used then "root_folder_id" will be ignored.
|
|
||||||
`,
|
|
||||||
Advanced: true,
|
Advanced: true,
|
||||||
}, {
|
}, {
|
||||||
Name: "alternate_export",
|
Name: "alternate_export",
|
||||||
@@ -1121,25 +1116,15 @@ func NewFs(name, path string, m configmap.Mapper) (fs.Fs, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If impersonating warn about root_folder_id if set and unset it
|
// Set the root folder ID
|
||||||
//
|
|
||||||
// This is because rclone v1.51 and v1.52 cached root_folder_id when
|
|
||||||
// using impersonate which they shouldn't have done. It is possible
|
|
||||||
// someone is using impersonate and root_folder_id in which case this
|
|
||||||
// breaks their workflow. There isn't an easy way around that.
|
|
||||||
if opt.RootFolderID != "" && opt.Impersonate != "" {
|
|
||||||
fs.Logf(f, "Ignoring cached root_folder_id when using --drive-impersonate")
|
|
||||||
opt.RootFolderID = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// set root folder for a team drive or query the user root folder
|
|
||||||
if opt.RootFolderID != "" {
|
if opt.RootFolderID != "" {
|
||||||
// override root folder if set or cached in the config and not impersonating
|
// use root_folder ID if set
|
||||||
f.rootFolderID = opt.RootFolderID
|
f.rootFolderID = opt.RootFolderID
|
||||||
} else if f.isTeamDrive {
|
} else if f.isTeamDrive {
|
||||||
|
// otherwise use team_drive if set
|
||||||
f.rootFolderID = f.opt.TeamDriveID
|
f.rootFolderID = f.opt.TeamDriveID
|
||||||
} else {
|
} else {
|
||||||
// Look up the root ID and cache it in the config
|
// otherwise look up the actual root ID
|
||||||
rootID, err := f.getRootID()
|
rootID, err := f.getRootID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if gerr, ok := errors.Cause(err).(*googleapi.Error); ok && gerr.Code == 404 {
|
if gerr, ok := errors.Cause(err).(*googleapi.Error); ok && gerr.Code == 404 {
|
||||||
@@ -1151,10 +1136,7 @@ func NewFs(name, path string, m configmap.Mapper) (fs.Fs, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.rootFolderID = rootID
|
f.rootFolderID = rootID
|
||||||
// Don't cache the root folder ID if impersonating
|
fs.Debugf(f, "root_folder_id = %q - save this in the config to speed up startup", rootID)
|
||||||
if opt.Impersonate == "" {
|
|
||||||
m.Set("root_folder_id", rootID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.dirCache = dircache.New(root, f.rootFolderID, f)
|
f.dirCache = dircache.New(root, f.rootFolderID, f)
|
||||||
@@ -1356,6 +1338,10 @@ func (f *Fs) newObjectWithExportInfo(
|
|||||||
// and not from a listing. This is unlikely.
|
// and not from a listing. This is unlikely.
|
||||||
fs.Debugf(remote, "Ignoring shortcut as skip shortcuts is set")
|
fs.Debugf(remote, "Ignoring shortcut as skip shortcuts is set")
|
||||||
return nil, fs.ErrorObjectNotFound
|
return nil, fs.ErrorObjectNotFound
|
||||||
|
case info.MimeType == shortcutMimeTypeDangling:
|
||||||
|
// Pretend a dangling shortcut is a regular object
|
||||||
|
// It will error if used, but appear in listings so it can be deleted
|
||||||
|
return f.newRegularObject(remote, info), nil
|
||||||
case info.Md5Checksum != "" || info.Size > 0:
|
case info.Md5Checksum != "" || info.Size > 0:
|
||||||
// If item has MD5 sum or a length it is a file stored on drive
|
// If item has MD5 sum or a length it is a file stored on drive
|
||||||
return f.newRegularObject(remote, info), nil
|
return f.newRegularObject(remote, info), nil
|
||||||
@@ -1740,7 +1726,7 @@ func (f *Fs) listRRunner(ctx context.Context, wg *sync.WaitGroup, in chan listRE
|
|||||||
// https://issuetracker.google.com/issues/149522397
|
// https://issuetracker.google.com/issues/149522397
|
||||||
if len(dirs) > 1 && !foundItems {
|
if len(dirs) > 1 && !foundItems {
|
||||||
if atomic.SwapInt32(&f.grouping, 1) != 1 {
|
if atomic.SwapInt32(&f.grouping, 1) != 1 {
|
||||||
fs.Logf(f, "Disabling ListR to work around bug in drive as multi listing (%d) returned no entries", len(dirs))
|
fs.Debugf(f, "Disabling ListR to work around bug in drive as multi listing (%d) returned no entries", len(dirs))
|
||||||
}
|
}
|
||||||
var recycled = make([]listREntry, len(dirs))
|
var recycled = make([]listREntry, len(dirs))
|
||||||
f.listRmu.Lock()
|
f.listRmu.Lock()
|
||||||
@@ -1773,7 +1759,7 @@ func (f *Fs) listRRunner(ctx context.Context, wg *sync.WaitGroup, in chan listRE
|
|||||||
// empty so must have made a mistake
|
// empty so must have made a mistake
|
||||||
if len(f.listRempties) == 0 {
|
if len(f.listRempties) == 0 {
|
||||||
if atomic.SwapInt32(&f.grouping, listRGrouping) != listRGrouping {
|
if atomic.SwapInt32(&f.grouping, listRGrouping) != listRGrouping {
|
||||||
fs.Logf(f, "Re-enabling ListR as previous detection was in error")
|
fs.Debugf(f, "Re-enabling ListR as previous detection was in error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1988,6 +1974,12 @@ func (f *Fs) resolveShortcut(item *drive.File) (newItem *drive.File, err error)
|
|||||||
}
|
}
|
||||||
newItem, err = f.getFile(item.ShortcutDetails.TargetId, f.fileFields)
|
newItem, err = f.getFile(item.ShortcutDetails.TargetId, f.fileFields)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if gerr, ok := errors.Cause(err).(*googleapi.Error); ok && gerr.Code == 404 {
|
||||||
|
// 404 means dangling shortcut, so just return the shortcut with the mime type mangled
|
||||||
|
fs.Logf(nil, "Dangling shortcut %q detected", item.Name)
|
||||||
|
item.MimeType = shortcutMimeTypeDangling
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
return nil, errors.Wrap(err, "failed to resolve shortcut")
|
return nil, errors.Wrap(err, "failed to resolve shortcut")
|
||||||
}
|
}
|
||||||
// make sure we use the Name, Parents and Trashed from the original item
|
// make sure we use the Name, Parents and Trashed from the original item
|
||||||
@@ -3296,6 +3288,9 @@ func (o *baseObject) open(ctx context.Context, url string, options ...fs.OpenOpt
|
|||||||
|
|
||||||
// Open an object for read
|
// Open an object for read
|
||||||
func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.ReadCloser, err error) {
|
func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.ReadCloser, err error) {
|
||||||
|
if o.mimeType == shortcutMimeTypeDangling {
|
||||||
|
return nil, errors.New("can't read dangling shortcut")
|
||||||
|
}
|
||||||
if o.v2Download {
|
if o.v2Download {
|
||||||
var v2File *drive_v2.File
|
var v2File *drive_v2.File
|
||||||
err = o.fs.pacer.Call(func() (bool, error) {
|
err = o.fs.pacer.Call(func() (bool, error) {
|
||||||
|
|||||||
@@ -1121,9 +1121,10 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object,
|
|||||||
id, dstDriveID, _ := parseNormalizedID(directoryID)
|
id, dstDriveID, _ := parseNormalizedID(directoryID)
|
||||||
_, srcObjDriveID, _ := parseNormalizedID(srcObj.id)
|
_, srcObjDriveID, _ := parseNormalizedID(srcObj.id)
|
||||||
|
|
||||||
if dstDriveID != srcObjDriveID {
|
if f.canonicalDriveID(dstDriveID) != srcObj.fs.canonicalDriveID(srcObjDriveID) {
|
||||||
// https://docs.microsoft.com/en-us/graph/api/driveitem-move?view=graph-rest-1.0
|
// https://docs.microsoft.com/en-us/graph/api/driveitem-move?view=graph-rest-1.0
|
||||||
// "Items cannot be moved between Drives using this request."
|
// "Items cannot be moved between Drives using this request."
|
||||||
|
fs.Debugf(f, "Can't move files between drives (%q != %q)", dstDriveID, srcObjDriveID)
|
||||||
return nil, fs.ErrorCantMove
|
return nil, fs.ErrorCantMove
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1219,9 +1220,10 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string
|
|||||||
}
|
}
|
||||||
_, srcDriveID, _ := parseNormalizedID(srcID)
|
_, srcDriveID, _ := parseNormalizedID(srcID)
|
||||||
|
|
||||||
if dstDriveID != srcDriveID {
|
if f.canonicalDriveID(dstDriveID) != srcFs.canonicalDriveID(srcDriveID) {
|
||||||
// https://docs.microsoft.com/en-us/graph/api/driveitem-move?view=graph-rest-1.0
|
// https://docs.microsoft.com/en-us/graph/api/driveitem-move?view=graph-rest-1.0
|
||||||
// "Items cannot be moved between Drives using this request."
|
// "Items cannot be moved between Drives using this request."
|
||||||
|
fs.Debugf(f, "Can't move directories between drives (%q != %q)", dstDriveID, srcDriveID)
|
||||||
return fs.ErrorCantDirMove
|
return fs.ErrorCantDirMove
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1869,6 +1871,17 @@ func parseNormalizedID(ID string) (string, string, string) {
|
|||||||
return ID, "", ""
|
return ID, "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the canonical form of the driveID
|
||||||
|
func (f *Fs) canonicalDriveID(driveID string) (canonicalDriveID string) {
|
||||||
|
if driveID == "" {
|
||||||
|
canonicalDriveID = f.opt.DriveID
|
||||||
|
} else {
|
||||||
|
canonicalDriveID = driveID
|
||||||
|
}
|
||||||
|
canonicalDriveID = strings.ToLower(canonicalDriveID)
|
||||||
|
return canonicalDriveID
|
||||||
|
}
|
||||||
|
|
||||||
// getRelativePathInsideBase checks if `target` is inside `base`. If so, it
|
// getRelativePathInsideBase checks if `target` is inside `base`. If so, it
|
||||||
// returns a relative path for `target` based on `base` and a boolean `true`.
|
// returns a relative path for `target` based on `base` and a boolean `true`.
|
||||||
// Otherwise returns "", false.
|
// Otherwise returns "", false.
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const (
|
|||||||
minSleep = 10 * time.Millisecond
|
minSleep = 10 * time.Millisecond
|
||||||
maxSleep = 2 * time.Second
|
maxSleep = 2 * time.Second
|
||||||
decayConstant = 2 // bigger for slower decay, exponential
|
decayConstant = 2 // bigger for slower decay, exponential
|
||||||
rootURL = "https://api.pcloud.com"
|
defaultHostname = "api.pcloud.com"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Globals
|
// Globals
|
||||||
@@ -51,8 +51,8 @@ var (
|
|||||||
oauthConfig = &oauth2.Config{
|
oauthConfig = &oauth2.Config{
|
||||||
Scopes: nil,
|
Scopes: nil,
|
||||||
Endpoint: oauth2.Endpoint{
|
Endpoint: oauth2.Endpoint{
|
||||||
AuthURL: "https://my.pcloud.com/oauth2/authorize",
|
AuthURL: "https://my.pcloud.com/oauth2/authorize",
|
||||||
TokenURL: "https://api.pcloud.com/oauth2_token",
|
// TokenURL: "https://api.pcloud.com/oauth2_token", set by updateTokenURL
|
||||||
},
|
},
|
||||||
ClientID: rcloneClientID,
|
ClientID: rcloneClientID,
|
||||||
ClientSecret: obscure.MustReveal(rcloneEncryptedClientSecret),
|
ClientSecret: obscure.MustReveal(rcloneEncryptedClientSecret),
|
||||||
@@ -60,17 +60,45 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Update the TokenURL with the actual hostname
|
||||||
|
func updateTokenURL(oauthConfig *oauth2.Config, hostname string) {
|
||||||
|
oauthConfig.Endpoint.TokenURL = "https://" + hostname + "/oauth2_token"
|
||||||
|
}
|
||||||
|
|
||||||
// Register with Fs
|
// Register with Fs
|
||||||
func init() {
|
func init() {
|
||||||
|
updateTokenURL(oauthConfig, defaultHostname)
|
||||||
fs.Register(&fs.RegInfo{
|
fs.Register(&fs.RegInfo{
|
||||||
Name: "pcloud",
|
Name: "pcloud",
|
||||||
Description: "Pcloud",
|
Description: "Pcloud",
|
||||||
NewFs: NewFs,
|
NewFs: NewFs,
|
||||||
Config: func(name string, m configmap.Mapper) {
|
Config: func(name string, m configmap.Mapper) {
|
||||||
|
optc := new(Options)
|
||||||
|
err := configstruct.Set(m, optc)
|
||||||
|
if err != nil {
|
||||||
|
fs.Errorf(nil, "Failed to read config: %v", err)
|
||||||
|
}
|
||||||
|
updateTokenURL(oauthConfig, optc.Hostname)
|
||||||
|
checkAuth := func(oauthConfig *oauth2.Config, auth *oauthutil.AuthResult) error {
|
||||||
|
if auth == nil || auth.Form == nil {
|
||||||
|
return errors.New("form not found in response")
|
||||||
|
}
|
||||||
|
hostname := auth.Form.Get("hostname")
|
||||||
|
if hostname == "" {
|
||||||
|
hostname = defaultHostname
|
||||||
|
}
|
||||||
|
// Save the hostname in the config
|
||||||
|
m.Set("hostname", hostname)
|
||||||
|
// Update the token URL
|
||||||
|
updateTokenURL(oauthConfig, hostname)
|
||||||
|
fs.Debugf(nil, "pcloud: got hostname %q", hostname)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
opt := oauthutil.Options{
|
opt := oauthutil.Options{
|
||||||
|
CheckAuth: checkAuth,
|
||||||
StateBlankOK: true, // pCloud seems to drop the state parameter now - see #4210
|
StateBlankOK: true, // pCloud seems to drop the state parameter now - see #4210
|
||||||
}
|
}
|
||||||
err := oauthutil.Config("pcloud", name, m, oauthConfig, &opt)
|
err = oauthutil.Config("pcloud", name, m, oauthConfig, &opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to configure token: %v", err)
|
log.Fatalf("Failed to configure token: %v", err)
|
||||||
}
|
}
|
||||||
@@ -96,6 +124,13 @@ func init() {
|
|||||||
Help: "Fill in for rclone to use a non root folder as its starting point.",
|
Help: "Fill in for rclone to use a non root folder as its starting point.",
|
||||||
Default: "d0",
|
Default: "d0",
|
||||||
Advanced: true,
|
Advanced: true,
|
||||||
|
}, {
|
||||||
|
Name: "hostname",
|
||||||
|
Help: `Hostname to connect to.
|
||||||
|
|
||||||
|
This is normally set when rclone initially does the oauth connection.`,
|
||||||
|
Default: defaultHostname,
|
||||||
|
Advanced: true,
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -104,6 +139,7 @@ func init() {
|
|||||||
type Options struct {
|
type Options struct {
|
||||||
Enc encoder.MultiEncoder `config:"encoding"`
|
Enc encoder.MultiEncoder `config:"encoding"`
|
||||||
RootFolderID string `config:"root_folder_id"`
|
RootFolderID string `config:"root_folder_id"`
|
||||||
|
Hostname string `config:"hostname"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fs represents a remote pcloud
|
// Fs represents a remote pcloud
|
||||||
@@ -253,12 +289,13 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to configure Pcloud")
|
return nil, errors.Wrap(err, "failed to configure Pcloud")
|
||||||
}
|
}
|
||||||
|
updateTokenURL(oauthConfig, opt.Hostname)
|
||||||
|
|
||||||
f := &Fs{
|
f := &Fs{
|
||||||
name: name,
|
name: name,
|
||||||
root: root,
|
root: root,
|
||||||
opt: *opt,
|
opt: *opt,
|
||||||
srv: rest.NewClient(oAuthClient).SetRoot(rootURL),
|
srv: rest.NewClient(oAuthClient).SetRoot("https://" + opt.Hostname),
|
||||||
pacer: fs.NewPacer(pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant))),
|
pacer: fs.NewPacer(pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant))),
|
||||||
}
|
}
|
||||||
f.features = (&fs.Features{
|
f.features = (&fs.Features{
|
||||||
|
|||||||
@@ -1127,9 +1127,6 @@ func s3Connection(opt *Options) (*s3.S3, *session.Session, error) {
|
|||||||
return nil, nil, errors.New("secret_access_key not found")
|
return nil, nil, errors.New("secret_access_key not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.Region == "" && opt.Endpoint == "" {
|
|
||||||
opt.Endpoint = "https://s3.amazonaws.com/"
|
|
||||||
}
|
|
||||||
if opt.Region == "" {
|
if opt.Region == "" {
|
||||||
opt.Region = "us-east-1"
|
opt.Region = "us-east-1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ conversion into man pages etc.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
docpath = "docs/content"
|
docpath = "docs/content"
|
||||||
@@ -160,13 +161,15 @@ def read_commands(docpath):
|
|||||||
def main():
|
def main():
|
||||||
check_docs(docpath)
|
check_docs(docpath)
|
||||||
command_docs = read_commands(docpath).replace("\\", "\\\\") # escape \ so we can use command_docs in re.sub
|
command_docs = read_commands(docpath).replace("\\", "\\\\") # escape \ so we can use command_docs in re.sub
|
||||||
|
build_date = datetime.utcfromtimestamp(
|
||||||
|
int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
|
||||||
with open(outfile, "w") as out:
|
with open(outfile, "w") as out:
|
||||||
out.write("""\
|
out.write("""\
|
||||||
%% rclone(1) User Manual
|
%% rclone(1) User Manual
|
||||||
%% Nick Craig-Wood
|
%% Nick Craig-Wood
|
||||||
%% %s
|
%% %s
|
||||||
|
|
||||||
""" % datetime.now().strftime("%b %d, %Y"))
|
""" % build_date.strftime("%b %d, %Y"))
|
||||||
for doc in docs:
|
for doc in docs:
|
||||||
contents = read_doc(doc)
|
contents = read_doc(doc)
|
||||||
# Substitute the commands into doc.md
|
# Substitute the commands into doc.md
|
||||||
|
|||||||
@@ -77,10 +77,12 @@ func (cds *contentDirectoryService) cdsObjectToUpnpavObject(cdsObject object, fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fileInfo.IsDir() {
|
if fileInfo.IsDir() {
|
||||||
|
defaultChildCount := 1
|
||||||
obj.Class = "object.container.storageFolder"
|
obj.Class = "object.container.storageFolder"
|
||||||
obj.Title = fileInfo.Name()
|
obj.Title = fileInfo.Name()
|
||||||
return upnpav.Container{
|
return upnpav.Container{
|
||||||
Object: obj,
|
Object: obj,
|
||||||
|
ChildCount: &defaultChildCount,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,36 @@ description: "Rclone Changelog"
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.52.3 - 2020-08-07
|
||||||
|
|
||||||
|
[See commits](https://github.com/rclone/rclone/compare/v1.52.2...v1.52.3)
|
||||||
|
|
||||||
|
* Bug Fixes
|
||||||
|
* docs
|
||||||
|
* Disable smart typography (eg en-dash) in MANUAL.* and man page (Nick Craig-Wood)
|
||||||
|
* Update install.md to reflect minimum Go version (Evan Harris)
|
||||||
|
* Update install from source instructions (Nick Craig-Wood)
|
||||||
|
* make_manual: Support SOURCE_DATE_EPOCH (Morten Linderud)
|
||||||
|
* log: Fix --use-json-log going to stderr not --log-file on Windows (Nick Craig-Wood)
|
||||||
|
* serve dlna: Fix file list on Samsung Series 6+ TVs (Matteo Pietro Dazzi)
|
||||||
|
* sync: Fix deadlock with --track-renames-strategy modtime (Nick Craig-Wood)
|
||||||
|
* Cache
|
||||||
|
* Fix moveto/copyto remote:file remote:file2 (Nick Craig-Wood)
|
||||||
|
* Drive
|
||||||
|
* Stop using root_folder_id as a cache (Nick Craig-Wood)
|
||||||
|
* Make dangling shortcuts appear in listings (Nick Craig-Wood)
|
||||||
|
* Drop "Disabling ListR" messages down to debug (Nick Craig-Wood)
|
||||||
|
* Workaround and policy for Google Drive API (Dmitry Ustalov)
|
||||||
|
* FTP
|
||||||
|
* Add note to docs about home vs root directory selection (Nick Craig-Wood)
|
||||||
|
* Onedrive
|
||||||
|
* Fix reverting to Copy when Move would have worked (Nick Craig-Wood)
|
||||||
|
* Avoid comma rendered in URL in onedrive.md (Kevin)
|
||||||
|
* Pcloud
|
||||||
|
* Fix oauth on European region "eapi.pcloud.com" (Nick Craig-Wood)
|
||||||
|
* S3
|
||||||
|
* Fix bucket Region auto detection when Region unset in config (Nick Craig-Wood)
|
||||||
|
|
||||||
## v1.52.2 - 2020-06-24
|
## v1.52.2 - 2020-06-24
|
||||||
|
|
||||||
[See commits](https://github.com/rclone/rclone/compare/v1.52.1...v1.52.2)
|
[See commits](https://github.com/rclone/rclone/compare/v1.52.1...v1.52.2)
|
||||||
|
|||||||
@@ -593,9 +593,6 @@ Leave blank normally.
|
|||||||
Fill in to access "Computers" folders (see docs), or for rclone to use
|
Fill in to access "Computers" folders (see docs), or for rclone to use
|
||||||
a non root folder as its starting point.
|
a non root folder as its starting point.
|
||||||
|
|
||||||
Note that if this is blank, the first time rclone runs it will fill it
|
|
||||||
in with the ID of the root folder.
|
|
||||||
|
|
||||||
|
|
||||||
- Config: root_folder_id
|
- Config: root_folder_id
|
||||||
- Env Var: RCLONE_DRIVE_ROOT_FOLDER_ID
|
- Env Var: RCLONE_DRIVE_ROOT_FOLDER_ID
|
||||||
@@ -802,9 +799,6 @@ Size of listing chunk 100-1000. 0 to disable.
|
|||||||
|
|
||||||
Impersonate this user when using a service account.
|
Impersonate this user when using a service account.
|
||||||
|
|
||||||
Note that if this is used then "root_folder_id" will be ignored.
|
|
||||||
|
|
||||||
|
|
||||||
- Config: impersonate
|
- Config: impersonate
|
||||||
- Env Var: RCLONE_DRIVE_IMPERSONATE
|
- Env Var: RCLONE_DRIVE_IMPERSONATE
|
||||||
- Type: string
|
- Type: string
|
||||||
@@ -1200,3 +1194,10 @@ for rclone to be able to get its token-id (but as this only happens during
|
|||||||
the remote configuration, it's not such a big deal).
|
the remote configuration, it's not such a big deal).
|
||||||
|
|
||||||
(Thanks to @balazer on github for these instructions.)
|
(Thanks to @balazer on github for these instructions.)
|
||||||
|
|
||||||
|
Sometimes, creation of an OAuth consent in Google API Console fails due to an error message
|
||||||
|
“The request failed because changes to one of the field of the resource is not supported”.
|
||||||
|
As a convenient workaround, the necessary Google Drive API key can be created on the
|
||||||
|
[Python Quickstart](https://developers.google.com/drive/api/v3/quickstart/python) page.
|
||||||
|
Just push the Enable the Drive API button to receive the Client ID and Secret.
|
||||||
|
Note that it will automatically create a new project in the API Console.
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ These flags are available for every command.
|
|||||||
--use-json-log Use json log format.
|
--use-json-log Use json log format.
|
||||||
--use-mmap Use mmap allocator (see docs).
|
--use-mmap Use mmap allocator (see docs).
|
||||||
--use-server-modtime Use server modified time instead of object metadata
|
--use-server-modtime Use server modified time instead of object metadata
|
||||||
--user-agent string Set the user-agent to a specified string. The default is rclone/ version (default "rclone/v1.52.2")
|
--user-agent string Set the user-agent to a specified string. The default is rclone/ version (default "rclone/v1.52.3")
|
||||||
-v, --verbose count Print lots more stuff (repeat for more)
|
-v, --verbose count Print lots more stuff (repeat for more)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -354,6 +354,7 @@ and may be set in the config file.
|
|||||||
--pcloud-client-id string Pcloud App Client Id
|
--pcloud-client-id string Pcloud App Client Id
|
||||||
--pcloud-client-secret string Pcloud App Client Secret
|
--pcloud-client-secret string Pcloud App Client Secret
|
||||||
--pcloud-encoding MultiEncoder This sets the encoding for the backend. (default Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
--pcloud-encoding MultiEncoder This sets the encoding for the backend. (default Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
||||||
|
--pcloud-hostname string Hostname to connect to. (default "api.pcloud.com")
|
||||||
--pcloud-root-folder-id string Fill in for rclone to use a non root folder as its starting point. (default "d0")
|
--pcloud-root-folder-id string Fill in for rclone to use a non root folder as its starting point. (default "d0")
|
||||||
--premiumizeme-encoding MultiEncoder This sets the encoding for the backend. (default Slash,DoubleQuote,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
--premiumizeme-encoding MultiEncoder This sets the encoding for the backend. (default Slash,DoubleQuote,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
||||||
--putio-encoding MultiEncoder This sets the encoding for the backend. (default Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
--putio-encoding MultiEncoder This sets the encoding for the backend. (default Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot)
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ FTP is the File Transfer Protocol. FTP support is provided using the
|
|||||||
[github.com/jlaffaye/ftp](https://godoc.org/github.com/jlaffaye/ftp)
|
[github.com/jlaffaye/ftp](https://godoc.org/github.com/jlaffaye/ftp)
|
||||||
package.
|
package.
|
||||||
|
|
||||||
|
Paths are specified as `remote:path`. If the path does not begin with
|
||||||
|
a `/` it is relative to the home directory of the user. An empty path
|
||||||
|
`remote:` refers to the user's home directory.
|
||||||
|
|
||||||
Here is an example of making an FTP configuration. First run
|
Here is an example of making an FTP configuration. First run
|
||||||
|
|
||||||
rclone config
|
rclone config
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ kill %1
|
|||||||
|
|
||||||
## Install from source ##
|
## Install from source ##
|
||||||
|
|
||||||
Make sure you have at least [Go](https://golang.org/) 1.7
|
Make sure you have at least [Go](https://golang.org/) 1.10
|
||||||
installed. [Download go](https://golang.org/dl/) if necessary. The
|
installed. [Download go](https://golang.org/dl/) if necessary. The
|
||||||
latest release is recommended. Then
|
latest release is recommended. Then
|
||||||
|
|
||||||
@@ -183,16 +183,23 @@ latest release is recommended. Then
|
|||||||
go build
|
go build
|
||||||
./rclone version
|
./rclone version
|
||||||
|
|
||||||
You can also build and install rclone in the
|
This will leave you a checked out version of rclone you can modify and
|
||||||
[GOPATH](https://github.com/golang/go/wiki/GOPATH) (which defaults to
|
send pull requests with. If you use `make` instead of `go build` then
|
||||||
`~/go`) with:
|
the rclone build will have the correct version information in it.
|
||||||
|
|
||||||
go get -u -v github.com/rclone/rclone
|
You can also build the latest stable rclone with:
|
||||||
|
|
||||||
and this will build the binary in `$GOPATH/bin` (`~/go/bin/rclone` by
|
go get github.com/rclone/rclone
|
||||||
default) after downloading the source to
|
|
||||||
`$GOPATH/src/github.com/rclone/rclone` (`~/go/src/github.com/rclone/rclone`
|
or the latest version (equivalent to the beta) with
|
||||||
by default).
|
|
||||||
|
go get github.com/rclone/rclone@master
|
||||||
|
|
||||||
|
These will build the binary in `$(go env GOPATH)/bin`
|
||||||
|
(`~/go/bin/rclone` by default) after downloading the source to the go
|
||||||
|
module cache. Note - do **not** use the `-u` flag here. This causes go
|
||||||
|
to try to update the depencencies that rclone uses and sometimes these
|
||||||
|
don't work with the current version of rclone.
|
||||||
|
|
||||||
## Installation with Ansible ##
|
## Installation with Ansible ##
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ requests.
|
|||||||
If you are having problems with them (E.g., seeing a lot of throttling), you can get your own
|
If you are having problems with them (E.g., seeing a lot of throttling), you can get your own
|
||||||
Client ID and Key by following the steps below:
|
Client ID and Key by following the steps below:
|
||||||
|
|
||||||
1. Open https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade, then click `New registration`.
|
1. Open https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade and then click `New registration`.
|
||||||
2. Enter a name for your app, choose account type `Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)`, select `Web` in `Redirect URI` Enter `http://localhost:53682/` and click Register. Copy and keep the `Application (client) ID` under the app name for later use.
|
2. Enter a name for your app, choose account type `Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)`, select `Web` in `Redirect URI` Enter `http://localhost:53682/` and click Register. Copy and keep the `Application (client) ID` under the app name for later use.
|
||||||
3. Under `manage` select `Certificates & secrets`, click `New client secret`. Copy and keep that secret for later use.
|
3. Under `manage` select `Certificates & secrets`, click `New client secret`. Copy and keep that secret for later use.
|
||||||
4. Under `manage` select `API permissions`, click `Add a permission` and select `Microsoft Graph` then select `delegated permissions`.
|
4. Under `manage` select `API permissions`, click `Add a permission` and select `Microsoft Graph` then select `delegated permissions`.
|
||||||
|
|||||||
@@ -182,4 +182,15 @@ Fill in for rclone to use a non root folder as its starting point.
|
|||||||
- Type: string
|
- Type: string
|
||||||
- Default: "d0"
|
- Default: "d0"
|
||||||
|
|
||||||
|
#### --pcloud-hostname
|
||||||
|
|
||||||
|
Hostname to connect to.
|
||||||
|
|
||||||
|
This is normally set when rclone initially does the oauth connection.
|
||||||
|
|
||||||
|
- Config: hostname
|
||||||
|
- Env Var: RCLONE_PCLOUD_HOSTNAME
|
||||||
|
- Type: string
|
||||||
|
- Default: "api.pcloud.com"
|
||||||
|
|
||||||
{{< rem autogenerated options stop >}}
|
{{< rem autogenerated options stop >}}
|
||||||
|
|||||||
@@ -53,6 +53,14 @@ Users are advised to use social media platforms wisely and communicate / engage
|
|||||||
|
|
||||||
This website may use social sharing buttons which help share web content directly from web pages to the social media platform in question. Users are advised before using such social sharing buttons that they do so at their own discretion and note that the social media platform may track and save your request to share a web page respectively through your social media platform account.
|
This website may use social sharing buttons which help share web content directly from web pages to the social media platform in question. Users are advised before using such social sharing buttons that they do so at their own discretion and note that the social media platform may track and save your request to share a web page respectively through your social media platform account.
|
||||||
|
|
||||||
|
## Use of Cloud API User Data ##
|
||||||
|
|
||||||
|
Rclone is a command line program to manage files on cloud storage. Its sole purpose is to access and manipulate user content in the [supported](/overview/) cloud storage systems from a local machine of the end user. For accessing the user content via the cloud provider API, Rclone uses authentication mechanisms, such as OAuth or HTTP Cookies, depending on the particular cloud provider offerings. Use of these authentication mechanisms and user data is governed by the privacy policies mentioned in the [Resources & Further Information](/privacy/#resources-further-information) section and followed by the privacy policy of Rclone.
|
||||||
|
|
||||||
|
* Rclone provides the end user with access to their files available in a storage system associated by the authentication credentials via the publicly exposed API of the storage system.
|
||||||
|
* Rclone allows storing the authentication credentials on the user machine in the local configuration file.
|
||||||
|
* Rclone does not share any user data with third parties.
|
||||||
|
|
||||||
## Resources & Further Information ##
|
## Resources & Further Information ##
|
||||||
|
|
||||||
* [Data Protection Act 1998](http://www.legislation.gov.uk/ukpga/1998/29/contents)
|
* [Data Protection Act 1998](http://www.legislation.gov.uk/ukpga/1998/29/contents)
|
||||||
@@ -61,4 +69,5 @@ This website may use social sharing buttons which help share web content directl
|
|||||||
* [Twitter Privacy Policy](https://twitter.com/privacy)
|
* [Twitter Privacy Policy](https://twitter.com/privacy)
|
||||||
* [Facebook Privacy Policy](https://www.facebook.com/about/privacy/)
|
* [Facebook Privacy Policy](https://www.facebook.com/about/privacy/)
|
||||||
* [Google Privacy Policy](https://www.google.com/privacy.html)
|
* [Google Privacy Policy](https://www.google.com/privacy.html)
|
||||||
|
* [Google API Services User Data Policy](https://developers.google.com/terms/api-services-user-data-policy)
|
||||||
* [Sample Website Privacy Policy](http://www.jamieking.co.uk/resources/free_sample_privacy_policy.html)
|
* [Sample Website Privacy Policy](http://www.jamieking.co.uk/resources/free_sample_privacy_policy.html)
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
v1.52.2
|
v1.52.3
|
||||||
18
fs/cache/cache.go
vendored
18
fs/cache/cache.go
vendored
@@ -56,12 +56,20 @@ func GetFn(fsString string, create func(fsString string) (fs.Fs, error)) (f fs.F
|
|||||||
if created {
|
if created {
|
||||||
canonicalName := fs.ConfigString(f)
|
canonicalName := fs.ConfigString(f)
|
||||||
if canonicalName != fsString {
|
if canonicalName != fsString {
|
||||||
fs.Debugf(nil, "fs cache: renaming cache item %q to be canonical %q", fsString, canonicalName)
|
// Note that if err == fs.ErrorIsFile at this moment
|
||||||
value, found := c.Rename(fsString, canonicalName)
|
// then we can't rename the remote as it will have the
|
||||||
if found {
|
// wrong error status, we need to add a new one.
|
||||||
f = value.(fs.Fs)
|
if err == nil {
|
||||||
|
fs.Debugf(nil, "fs cache: renaming cache item %q to be canonical %q", fsString, canonicalName)
|
||||||
|
value, found := c.Rename(fsString, canonicalName)
|
||||||
|
if found {
|
||||||
|
f = value.(fs.Fs)
|
||||||
|
}
|
||||||
|
addMapping(fsString, canonicalName)
|
||||||
|
} else {
|
||||||
|
fs.Debugf(nil, "fs cache: adding new entry for parent of %q, %q", fsString, canonicalName)
|
||||||
|
Put(canonicalName, f)
|
||||||
}
|
}
|
||||||
addMapping(fsString, canonicalName)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return f, err
|
return f, err
|
||||||
|
|||||||
37
fs/cache/cache_test.go
vendored
37
fs/cache/cache_test.go
vendored
@@ -23,7 +23,7 @@ func mockNewFs(t *testing.T) (func(), func(path string) (fs.Fs, error)) {
|
|||||||
switch path {
|
switch path {
|
||||||
case "mock:/":
|
case "mock:/":
|
||||||
return mockfs.NewFs("mock", "/"), nil
|
return mockfs.NewFs("mock", "/"), nil
|
||||||
case "mock:/file.txt":
|
case "mock:/file.txt", "mock:file.txt":
|
||||||
return mockfs.NewFs("mock", "/"), fs.ErrorIsFile
|
return mockfs.NewFs("mock", "/"), fs.ErrorIsFile
|
||||||
case "mock:/error":
|
case "mock:/error":
|
||||||
return nil, errSentinel
|
return nil, errSentinel
|
||||||
@@ -64,13 +64,46 @@ func TestGetFile(t *testing.T) {
|
|||||||
require.Equal(t, fs.ErrorIsFile, err)
|
require.Equal(t, fs.ErrorIsFile, err)
|
||||||
require.NotNil(t, f)
|
require.NotNil(t, f)
|
||||||
|
|
||||||
assert.Equal(t, 1, c.Entries())
|
assert.Equal(t, 2, c.Entries())
|
||||||
|
|
||||||
f2, err := GetFn("mock:/file.txt", create)
|
f2, err := GetFn("mock:/file.txt", create)
|
||||||
require.Equal(t, fs.ErrorIsFile, err)
|
require.Equal(t, fs.ErrorIsFile, err)
|
||||||
require.NotNil(t, f2)
|
require.NotNil(t, f2)
|
||||||
|
|
||||||
assert.Equal(t, f, f2)
|
assert.Equal(t, f, f2)
|
||||||
|
|
||||||
|
// check parent is there too
|
||||||
|
f2, err = GetFn("mock:/", create)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.NotNil(t, f2)
|
||||||
|
|
||||||
|
assert.Equal(t, f, f2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFile2(t *testing.T) {
|
||||||
|
cleanup, create := mockNewFs(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
assert.Equal(t, 0, c.Entries())
|
||||||
|
|
||||||
|
f, err := GetFn("mock:file.txt", create)
|
||||||
|
require.Equal(t, fs.ErrorIsFile, err)
|
||||||
|
require.NotNil(t, f)
|
||||||
|
|
||||||
|
assert.Equal(t, 2, c.Entries())
|
||||||
|
|
||||||
|
f2, err := GetFn("mock:file.txt", create)
|
||||||
|
require.Equal(t, fs.ErrorIsFile, err)
|
||||||
|
require.NotNil(t, f2)
|
||||||
|
|
||||||
|
assert.Equal(t, f, f2)
|
||||||
|
|
||||||
|
// check parent is there too
|
||||||
|
f2, err = GetFn("mock:/", create)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.NotNil(t, f2)
|
||||||
|
|
||||||
|
assert.Equal(t, f, f2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetError(t *testing.T) {
|
func TestGetError(t *testing.T) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options contains options for the remote control server
|
// Options contains options for the remote control server
|
||||||
@@ -120,6 +121,7 @@ func InitLogging() {
|
|||||||
fs.Errorf(nil, "Failed to seek log file to end: %v", err)
|
fs.Errorf(nil, "Failed to seek log file to end: %v", err)
|
||||||
}
|
}
|
||||||
log.SetOutput(f)
|
log.SetOutput(f)
|
||||||
|
logrus.SetOutput(f)
|
||||||
redirectStderr(f)
|
redirectStderr(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -658,6 +658,7 @@ func (s *syncCopyMove) pushRenameMap(hash string, obj fs.Object) {
|
|||||||
// renameMap or returns nil if not found.
|
// renameMap or returns nil if not found.
|
||||||
func (s *syncCopyMove) popRenameMap(hash string, src fs.Object) (dst fs.Object) {
|
func (s *syncCopyMove) popRenameMap(hash string, src fs.Object) (dst fs.Object) {
|
||||||
s.renameMapMu.Lock()
|
s.renameMapMu.Lock()
|
||||||
|
defer s.renameMapMu.Unlock()
|
||||||
dsts, ok := s.renameMap[hash]
|
dsts, ok := s.renameMap[hash]
|
||||||
if ok && len(dsts) > 0 {
|
if ok && len(dsts) > 0 {
|
||||||
// Element to remove
|
// Element to remove
|
||||||
@@ -690,7 +691,6 @@ func (s *syncCopyMove) popRenameMap(hash string, src fs.Object) (dst fs.Object)
|
|||||||
delete(s.renameMap, hash)
|
delete(s.renameMap, hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.renameMapMu.Unlock()
|
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
// Version of rclone
|
// Version of rclone
|
||||||
var Version = "v1.52.2"
|
var Version = "v1.52.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user