Merge branch 'rclone:master' into mct-install-set-modes-mac
This commit is contained in:
commit
eab83baf6d
30 changed files with 194 additions and 103 deletions
8
Makefile
8
Makefile
|
@ -245,18 +245,18 @@ retag:
|
|||
startdev:
|
||||
@echo "Version is $(VERSION)"
|
||||
@echo "Next version is $(NEXT_VERSION)"
|
||||
echo -e "package fs\n\n// Version of rclone\nvar Version = \"$(NEXT_VERSION)-DEV\"\n" | gofmt > fs/version.go
|
||||
echo -e "package fs\n\n// VersionTag of rclone\nvar VersionTag = \"$(NEXT_VERSION)\"\n" | gofmt > fs/versiontag.go
|
||||
echo -n "$(NEXT_VERSION)" > docs/layouts/partials/version.html
|
||||
echo "$(NEXT_VERSION)" > VERSION
|
||||
git commit -m "Start $(NEXT_VERSION)-DEV development" fs/version.go VERSION docs/layouts/partials/version.html
|
||||
git commit -m "Start $(NEXT_VERSION)-DEV development" fs/versiontag.go VERSION docs/layouts/partials/version.html
|
||||
|
||||
startstable:
|
||||
@echo "Version is $(VERSION)"
|
||||
@echo "Next stable version is $(NEXT_PATCH_VERSION)"
|
||||
echo -e "package fs\n\n// Version of rclone\nvar Version = \"$(NEXT_PATCH_VERSION)-DEV\"\n" | gofmt > fs/version.go
|
||||
echo -e "package fs\n\n// VersionTag of rclone\nvar VersionTag = \"$(NEXT_PATCH_VERSION)\"\n" | gofmt > fs/versiontag.go
|
||||
echo -n "$(NEXT_PATCH_VERSION)" > docs/layouts/partials/version.html
|
||||
echo "$(NEXT_PATCH_VERSION)" > VERSION
|
||||
git commit -m "Start $(NEXT_PATCH_VERSION)-DEV development" fs/version.go VERSION docs/layouts/partials/version.html
|
||||
git commit -m "Start $(NEXT_PATCH_VERSION)-DEV development" fs/versiontag.go VERSION docs/layouts/partials/version.html
|
||||
|
||||
winzip:
|
||||
zip -9 rclone-$(TAG).zip rclone.exe
|
||||
|
|
|
@ -515,7 +515,7 @@ func (f *Fs) setChunkNameFormat(pattern string) error {
|
|||
|
||||
strRegex := regexp.QuoteMeta(pattern)
|
||||
strRegex = reHashes.ReplaceAllLiteralString(strRegex, reDataOrCtrl)
|
||||
strRegex = strings.Replace(strRegex, "\\*", mainNameRegStr, -1)
|
||||
strRegex = strings.ReplaceAll(strRegex, "\\*", mainNameRegStr)
|
||||
strRegex = fmt.Sprintf("^%s(?:%s|%s)?$", strRegex, tempSuffixRegStr, tempSuffixRegOld)
|
||||
f.nameRegexp = regexp.MustCompile(strRegex)
|
||||
|
||||
|
@ -524,7 +524,7 @@ func (f *Fs) setChunkNameFormat(pattern string) error {
|
|||
if numDigits > 1 {
|
||||
fmtDigits = fmt.Sprintf("%%0%dd", numDigits)
|
||||
}
|
||||
strFmt := strings.Replace(pattern, "%", "%%", -1)
|
||||
strFmt := strings.ReplaceAll(pattern, "%", "%%")
|
||||
strFmt = strings.Replace(strFmt, "*", "%s", 1)
|
||||
f.dataNameFmt = reHashes.ReplaceAllLiteralString(strFmt, fmtDigits)
|
||||
f.ctrlNameFmt = reHashes.ReplaceAllLiteralString(strFmt, "_%s")
|
||||
|
|
|
@ -70,7 +70,7 @@ const (
|
|||
// 1<<18 is the minimum size supported by the Google uploader, and there is no maximum.
|
||||
minChunkSize = fs.SizeSuffix(googleapi.MinUploadChunkSize)
|
||||
defaultChunkSize = 8 * fs.Mebi
|
||||
partialFields = "id,name,size,md5Checksum,trashed,explicitlyTrashed,modifiedTime,createdTime,mimeType,parents,webViewLink,shortcutDetails,exportLinks"
|
||||
partialFields = "id,name,size,md5Checksum,trashed,explicitlyTrashed,modifiedTime,createdTime,mimeType,parents,webViewLink,shortcutDetails,exportLinks,resourceKey"
|
||||
listRGrouping = 50 // number of IDs to search at once when using ListR
|
||||
listRInputBuffer = 1000 // size of input buffer when using ListR
|
||||
defaultXDGIcon = "text-html"
|
||||
|
@ -660,6 +660,7 @@ type baseObject struct {
|
|||
mimeType string // The object MIME type
|
||||
bytes int64 // size of the object
|
||||
parents []string // IDs of the parent directories
|
||||
resourceKey *string // resourceKey is needed for link shared objects
|
||||
}
|
||||
type documentObject struct {
|
||||
baseObject
|
||||
|
@ -829,8 +830,8 @@ func (f *Fs) list(ctx context.Context, dirIDs []string, title string, directorie
|
|||
if title != "" {
|
||||
searchTitle := f.opt.Enc.FromStandardName(title)
|
||||
// Escaping the backslash isn't documented but seems to work
|
||||
searchTitle = strings.Replace(searchTitle, `\`, `\\`, -1)
|
||||
searchTitle = strings.Replace(searchTitle, `'`, `\'`, -1)
|
||||
searchTitle = strings.ReplaceAll(searchTitle, `\`, `\\`)
|
||||
searchTitle = strings.ReplaceAll(searchTitle, `'`, `\'`)
|
||||
|
||||
var titleQuery bytes.Buffer
|
||||
_, _ = fmt.Fprintf(&titleQuery, "(name='%s'", searchTitle)
|
||||
|
@ -1319,12 +1320,16 @@ func (f *Fs) newRegularObject(remote string, info *drive.File) fs.Object {
|
|||
}
|
||||
}
|
||||
}
|
||||
return &Object{
|
||||
o := &Object{
|
||||
baseObject: f.newBaseObject(remote, info),
|
||||
url: fmt.Sprintf("%sfiles/%s?alt=media", f.svc.BasePath, actualID(info.Id)),
|
||||
md5sum: strings.ToLower(info.Md5Checksum),
|
||||
v2Download: f.opt.V2DownloadMinSize != -1 && info.Size >= int64(f.opt.V2DownloadMinSize),
|
||||
}
|
||||
if info.ResourceKey != "" {
|
||||
o.resourceKey = &info.ResourceKey
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// newDocumentObject creates an fs.Object for a google docs drive.File
|
||||
|
@ -2429,11 +2434,12 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object,
|
|||
|
||||
var info *drive.File
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
info, err = f.svc.Files.Copy(id, createInfo).
|
||||
copy := f.svc.Files.Copy(id, createInfo).
|
||||
Fields(partialFields).
|
||||
SupportsAllDrives(true).
|
||||
KeepRevisionForever(f.opt.KeepRevisionForever).
|
||||
Context(ctx).Do()
|
||||
KeepRevisionForever(f.opt.KeepRevisionForever)
|
||||
srcObj.addResourceKey(copy.Header())
|
||||
info, err = copy.Context(ctx).Do()
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -3530,6 +3536,14 @@ func (o *baseObject) Storable() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// addResourceKey adds a X-Goog-Drive-Resource-Keys header for this
|
||||
// object if required.
|
||||
func (o *baseObject) addResourceKey(header http.Header) {
|
||||
if o.resourceKey != nil {
|
||||
header.Add("X-Goog-Drive-Resource-Keys", fmt.Sprintf("%s/%s", o.id, *o.resourceKey))
|
||||
}
|
||||
}
|
||||
|
||||
// httpResponse gets an http.Response object for the object
|
||||
// using the url and method passed in
|
||||
func (o *baseObject) httpResponse(ctx context.Context, url, method string, options []fs.OpenOption) (req *http.Request, res *http.Response, err error) {
|
||||
|
@ -3545,6 +3559,7 @@ func (o *baseObject) httpResponse(ctx context.Context, url, method string, optio
|
|||
// Don't supply range requests for 0 length objects as they always fail
|
||||
delete(req.Header, "Range")
|
||||
}
|
||||
o.addResourceKey(req.Header)
|
||||
err = o.fs.pacer.Call(func() (bool, error) {
|
||||
res, err = o.fs.client.Do(req)
|
||||
if err == nil {
|
||||
|
|
|
@ -562,7 +562,7 @@ func (f *Fs) list(ctx context.Context, filter api.SearchFilter, fn listFn) (err
|
|||
for i := range items {
|
||||
item := &result.MediaItems[i]
|
||||
remote := item.Filename
|
||||
remote = strings.Replace(remote, "/", "/", -1)
|
||||
remote = strings.ReplaceAll(remote, "/", "/")
|
||||
err = fn(remote, item, false)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -119,7 +119,7 @@ func (f *Fs) getCredentials(ctx context.Context) (err error) {
|
|||
defer fs.CheckClose(resp.Body, &err)
|
||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
bodyStr := strings.TrimSpace(strings.Replace(string(body), "\n", " ", -1))
|
||||
bodyStr := strings.TrimSpace(strings.ReplaceAll(string(body), "\n", " "))
|
||||
return fmt.Errorf("failed to get credentials: %s: %s", resp.Status, bodyStr)
|
||||
}
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
|
|
|
@ -191,7 +191,7 @@ machines.`)
|
|||
m.Set("auth_code", "")
|
||||
return fs.ConfigGoto("legacy_do_auth")
|
||||
case "legacy_auth_code":
|
||||
authCode := strings.Replace(config.Result, "-", "", -1) // remove any "-" contained in the code so we have a 6 digit number
|
||||
authCode := strings.ReplaceAll(config.Result, "-", "") // remove any "-" contained in the code so we have a 6 digit number
|
||||
m.Set("auth_code", authCode)
|
||||
return fs.ConfigGoto("legacy_do_auth")
|
||||
case "legacy_do_auth":
|
||||
|
@ -649,7 +649,7 @@ func errorHandler(resp *http.Response) error {
|
|||
|
||||
// Jottacloud wants '+' to be URL encoded even though the RFC states it's not reserved
|
||||
func urlPathEscape(in string) string {
|
||||
return strings.Replace(rest.URLPathEscape(in), "+", "%2B", -1)
|
||||
return strings.ReplaceAll(rest.URLPathEscape(in), "+", "%2B")
|
||||
}
|
||||
|
||||
// filePathRaw returns an unescaped file path (f.root, file)
|
||||
|
|
|
@ -1294,7 +1294,7 @@ For more info visit https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview
|
|||
|
||||
Note that this ACL is applied when server-side copying objects as S3
|
||||
doesn't copy the ACL from the source but rather writes a fresh one.`,
|
||||
Provider: "!Storj",
|
||||
Provider: "!Storj,Cloudflare",
|
||||
Examples: []fs.OptionExample{{
|
||||
Value: "default",
|
||||
Help: "Owner gets Full_CONTROL.\nNo one else has access rights (default).",
|
||||
|
@ -2966,7 +2966,7 @@ func (f *Fs) Precision() time.Duration {
|
|||
// pathEscape escapes s as for a URL path. It uses rest.URLPathEscape
|
||||
// but also escapes '+' for S3 and Digital Ocean spaces compatibility
|
||||
func pathEscape(s string) string {
|
||||
return strings.Replace(rest.URLPathEscape(s), "+", "%2B", -1)
|
||||
return strings.ReplaceAll(rest.URLPathEscape(s), "+", "%2B")
|
||||
}
|
||||
|
||||
// copy does a server-side copy
|
||||
|
|
|
@ -1311,7 +1311,7 @@ var shellEscapeRegex = regexp.MustCompile("[^A-Za-z0-9_.,:/\\@\u0080-\uFFFFFFFF\
|
|||
// when sending it to a shell.
|
||||
func shellEscape(str string) string {
|
||||
safe := shellEscapeRegex.ReplaceAllString(str, `\$0`)
|
||||
return strings.Replace(safe, "\n", "'\n'", -1)
|
||||
return strings.ReplaceAll(safe, "\n", "'\n'")
|
||||
}
|
||||
|
||||
// Converts a byte array from the SSH session returned by
|
||||
|
|
|
@ -173,8 +173,8 @@ func buildZip(dir string) string {
|
|||
func buildDebAndRpm(dir, version, goarch string) []string {
|
||||
// Make internal version number acceptable to .deb and .rpm
|
||||
pkgVersion := version[1:]
|
||||
pkgVersion = strings.Replace(pkgVersion, "β", "-beta", -1)
|
||||
pkgVersion = strings.Replace(pkgVersion, "-", ".", -1)
|
||||
pkgVersion = strings.ReplaceAll(pkgVersion, "β", "-beta")
|
||||
pkgVersion = strings.ReplaceAll(pkgVersion, "-", ".")
|
||||
nfpmArch, ok := goarchToNfpm[goarch]
|
||||
if !ok {
|
||||
nfpmArch = goarch
|
||||
|
|
|
@ -79,7 +79,7 @@ rclone.org website.`,
|
|||
var description = map[string]string{}
|
||||
var addDescription func(root *cobra.Command)
|
||||
addDescription = func(root *cobra.Command) {
|
||||
name := strings.Replace(root.CommandPath(), " ", "_", -1) + ".md"
|
||||
name := strings.ReplaceAll(root.CommandPath(), " ", "_") + ".md"
|
||||
description[name] = root.Short
|
||||
for _, c := range root.Commands() {
|
||||
addDescription(c)
|
||||
|
@ -93,11 +93,11 @@ rclone.org website.`,
|
|||
base := strings.TrimSuffix(name, path.Ext(name))
|
||||
data := frontmatter{
|
||||
Date: now,
|
||||
Title: strings.Replace(base, "_", " ", -1),
|
||||
Title: strings.ReplaceAll(base, "_", " "),
|
||||
Description: description[name],
|
||||
Slug: base,
|
||||
URL: "/commands/" + strings.ToLower(base) + "/",
|
||||
Source: strings.Replace(strings.Replace(base, "rclone", "cmd", -1), "_", "/", -1) + "/",
|
||||
Source: strings.ReplaceAll(strings.ReplaceAll(base, "rclone", "cmd"), "_", "/") + "/",
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err := frontmatterTemplate.Execute(&buf, data)
|
||||
|
|
|
@ -290,7 +290,7 @@ func list(ctx context.Context) error {
|
|||
if !ok {
|
||||
return errors.New("bad JSON")
|
||||
}
|
||||
fmt.Printf("### %s: %s {#%s}\n\n", info["Path"], info["Title"], strings.Replace(info["Path"].(string), "/", "-", -1))
|
||||
fmt.Printf("### %s: %s {#%s}\n\n", info["Path"], info["Title"], strings.ReplaceAll(info["Path"].(string), "/", "-"))
|
||||
fmt.Printf("%s\n\n", info["Help"])
|
||||
if authRequired := info["AuthRequired"]; authRequired != nil {
|
||||
if authRequired.(bool) {
|
||||
|
|
|
@ -43,7 +43,7 @@ var shellUnEscapeRegex = regexp.MustCompile(`\\(.)`)
|
|||
|
||||
// Unescape a string that was escaped by rclone
|
||||
func shellUnEscape(str string) string {
|
||||
str = strings.Replace(str, "'\n'", "\n", -1)
|
||||
str = strings.ReplaceAll(str, "'\n'", "\n")
|
||||
str = shellUnEscapeRegex.ReplaceAllString(str, `$1`)
|
||||
return str
|
||||
}
|
||||
|
|
|
@ -593,3 +593,6 @@ put them back in again.` >}}
|
|||
* Kaspian <34658474+KaspianDev@users.noreply.github.com>
|
||||
* Werner <EvilOlaf@users.noreply.github.com>
|
||||
* Hugal31 <hugo.laloge@gmail.com>
|
||||
* Christian Galo <36752715+cgalo5758@users.noreply.github.com>
|
||||
* Erik van Velzen <erik@evanv.nl>
|
||||
* Derek Battams <derek@battams.ca>
|
||||
|
|
|
@ -3,11 +3,11 @@ title: "Install"
|
|||
description: "Rclone Installation"
|
||||
---
|
||||
|
||||
# Install #
|
||||
# Install
|
||||
|
||||
Rclone is a Go program and comes as a single binary file.
|
||||
|
||||
## Quickstart ##
|
||||
## Quickstart
|
||||
|
||||
* [Download](/downloads/) the relevant binary.
|
||||
* Extract the `rclone` executable, `rclone.exe` on Windows, from the archive.
|
||||
|
@ -22,7 +22,7 @@ run `rclone -h`.
|
|||
Already installed rclone can be easily updated to the latest version
|
||||
using the [rclone selfupdate](/commands/rclone_selfupdate/) command.
|
||||
|
||||
## Script installation ##
|
||||
## Script installation
|
||||
|
||||
To install rclone on Linux/macOS/BSD systems, run:
|
||||
|
||||
|
@ -35,7 +35,7 @@ For beta installation, run:
|
|||
Note that this script checks the version of rclone installed first and
|
||||
won't re-download if not needed.
|
||||
|
||||
## Linux installation from precompiled binary ##
|
||||
## Linux installation from precompiled binary
|
||||
|
||||
Fetch and unpack
|
||||
|
||||
|
@ -59,7 +59,7 @@ Run `rclone config` to setup. See [rclone config docs](/docs/) for more details.
|
|||
|
||||
rclone config
|
||||
|
||||
## macOS installation with brew ##
|
||||
## macOS installation with brew
|
||||
|
||||
brew install rclone
|
||||
|
||||
|
@ -68,7 +68,7 @@ NOTE: This version of rclone will not support `mount` any more (see
|
|||
on macOS, either install a precompiled binary or enable the relevant option
|
||||
when [installing from source](#install-from-source).
|
||||
|
||||
## macOS installation from precompiled binary, using curl ##
|
||||
## macOS installation from precompiled binary, using curl
|
||||
|
||||
To avoid problems with macOS gatekeeper enforcing the binary to be signed and
|
||||
notarized it is enough to download with `curl`.
|
||||
|
@ -96,20 +96,20 @@ Run `rclone config` to setup. See [rclone config docs](/docs/) for more details.
|
|||
|
||||
rclone config
|
||||
|
||||
## macOS installation from precompiled binary, using a web browser ##
|
||||
## macOS installation from precompiled binary, using a web browser
|
||||
|
||||
When downloading a binary with a web browser, the browser will set the macOS
|
||||
gatekeeper quarantine attribute. Starting from Catalina, when attempting to run
|
||||
`rclone`, a pop-up will appear saying:
|
||||
|
||||
“rclone” cannot be opened because the developer cannot be verified.
|
||||
"rclone" cannot be opened because the developer cannot be verified.
|
||||
macOS cannot verify that this app is free from malware.
|
||||
|
||||
The simplest fix is to run
|
||||
|
||||
xattr -d com.apple.quarantine rclone
|
||||
|
||||
## Install with docker ##
|
||||
## Install with docker
|
||||
|
||||
The rclone maintains a [docker image for rclone](https://hub.docker.com/r/rclone/rclone).
|
||||
These images are autobuilt by docker hub from the rclone source based
|
||||
|
@ -188,39 +188,93 @@ ls ~/data/mount
|
|||
kill %1
|
||||
```
|
||||
|
||||
## Install from source ##
|
||||
## Install from source
|
||||
|
||||
Make sure you have at least [Go](https://golang.org/) go1.16
|
||||
installed. [Download go](https://golang.org/dl/) if necessary. The
|
||||
latest release is recommended. Then
|
||||
Make sure you have git and [Go](https://golang.org/) installed.
|
||||
Go version 1.16 or newer is required, latest release is recommended.
|
||||
You can get it from your package manager, or download it from
|
||||
[golang.org/dl](https://golang.org/dl/). Then you can run the following:
|
||||
|
||||
```sh
|
||||
```
|
||||
git clone https://github.com/rclone/rclone.git
|
||||
cd rclone
|
||||
go build
|
||||
# If on macOS and mount is wanted, instead run: make GOTAGS=cmount
|
||||
./rclone version
|
||||
```
|
||||
|
||||
This will leave you a checked out version of rclone you can modify and
|
||||
send pull requests with. If you use `make` instead of `go build` then
|
||||
the rclone build will have the correct version information in it.
|
||||
This will check out the rclone source in subfolder rclone, which you can later
|
||||
modify and send pull requests with. Then it will build the rclone executable
|
||||
in the same folder. As an initial check you can now run `./rclone version`
|
||||
(`.\rclone version` on Windows).
|
||||
|
||||
You can also build the latest stable rclone with:
|
||||
Note that on macOS and Windows the [mount](https://rclone.org/commands/rclone_mount/)
|
||||
command will not be available unless you specify additional build tag `cmount`.
|
||||
|
||||
go get github.com/rclone/rclone
|
||||
```
|
||||
go build -tags cmount
|
||||
```
|
||||
|
||||
or the latest version (equivalent to the beta) with
|
||||
This assumes you have a GCC compatible C compiler (GCC or Clang) in your PATH,
|
||||
as it uses [cgo](https://pkg.go.dev/cmd/cgo). But on Windows, the
|
||||
[cgofuse](https://github.com/winfsp/cgofuse) library that the cmount
|
||||
implementation is based on, also supports building
|
||||
[without cgo](https://github.com/golang/go/wiki/WindowsDLLs), i.e. by setting
|
||||
environment variable CGO_ENABLED to value 0 (static linking). This is how the
|
||||
official Windows release of rclone is being built, starting with version 1.59.
|
||||
It is still possible to build with cgo on Windows as well, by using the MinGW
|
||||
port of GCC, e.g. by installing it in a [MSYS2](https://www.msys2.org)
|
||||
distribution (make sure you install it in the classic mingw64 subsystem, the
|
||||
ucrt64 version is not compatible).
|
||||
|
||||
go get github.com/rclone/rclone@master
|
||||
Additionally, on Windows, you must install the third party utility
|
||||
[WinFsp](http://www.secfs.net/winfsp/), with the "Developer" feature selected.
|
||||
If building with cgo, you must also set environment variable CPATH pointing to
|
||||
the fuse include directory within the WinFsp installation
|
||||
(normally `C:\Program Files (x86)\WinFsp\inc\fuse`).
|
||||
|
||||
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 dependencies that rclone uses and sometimes these
|
||||
don't work with the current version of rclone.
|
||||
You may also add arguments `-ldflags -s` (with or without `-tags cmount`),
|
||||
to omit symbol table and debug information, making the executable file smaller,
|
||||
and `-trimpath` to remove references to local file system paths. This is how
|
||||
the official rclone releases are built.
|
||||
|
||||
## Installation with Ansible ##
|
||||
```
|
||||
go build -trimpath -ldflags -s -tags cmount
|
||||
```
|
||||
|
||||
Instead of executing the `go build` command directly, you can run it via the
|
||||
Makefile, which also sets version information and copies the resulting rclone
|
||||
executable into your GOPATH bin folder (`$(go env GOPATH)/bin`, which
|
||||
corresponds to `~/go/bin/rclone` by default).
|
||||
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
To include mount command on macOS and Windows with Makefile build:
|
||||
|
||||
```
|
||||
make GOTAGS=cmount
|
||||
```
|
||||
|
||||
As an alternative you can download the source, build and install rclone in one
|
||||
operation, as a regular Go package. The source will be stored it in the Go
|
||||
module cache, and the resulting executable will be in your GOPATH bin folder
|
||||
(`$(go env GOPATH)/bin`, which corresponds to `~/go/bin/rclone` by default).
|
||||
|
||||
With Go version 1.17 or newer:
|
||||
|
||||
```
|
||||
go install github.com/rclone/rclone@latest
|
||||
```
|
||||
|
||||
With Go versions older than 1.17 (do **not** use the `-u` flag, it causes Go to
|
||||
try to update the dependencies that rclone uses and sometimes these don't work
|
||||
with the current version):
|
||||
|
||||
```
|
||||
go get github.com/rclone/rclone
|
||||
```
|
||||
|
||||
## Installation with Ansible
|
||||
|
||||
This can be done with [Stefan Weichinger's ansible
|
||||
role](https://github.com/stefangweichinger/ansible-rclone).
|
||||
|
@ -236,7 +290,7 @@ Instructions
|
|||
- rclone
|
||||
```
|
||||
|
||||
## Portable installation ##
|
||||
## Portable installation
|
||||
|
||||
As mentioned [above](https://rclone.org/install/#quickstart), rclone is single
|
||||
executable (`rclone`, or `rclone.exe` on Windows) that you can download as a
|
||||
|
@ -314,7 +368,7 @@ the [PsExec](https://docs.microsoft.com/en-us/sysinternals/downloads/psexec)
|
|||
utility from Microsoft's Sysinternals suite, which takes option `-s` to
|
||||
execute commands as the `SYSTEM` user.
|
||||
|
||||
#### Start from Startup folder ###
|
||||
#### Start from Startup folder
|
||||
|
||||
To quickly execute an rclone command you can simply create a standard
|
||||
Windows Explorer shortcut for the complete rclone command you want to run. If you
|
||||
|
@ -329,7 +383,7 @@ functionality to set it to run as different user, or to set conditions or
|
|||
actions on certain events. Setting up a scheduled task as described below
|
||||
will often give you better results.
|
||||
|
||||
#### Start from Task Scheduler ###
|
||||
#### Start from Task Scheduler
|
||||
|
||||
Task Scheduler is an administrative tool built into Windows, and it can be used to
|
||||
configure rclone to be started automatically in a highly configurable way, e.g.
|
||||
|
@ -339,14 +393,14 @@ be available to all users it can run as the `SYSTEM` user.
|
|||
For technical information, see
|
||||
https://docs.microsoft.com/windows/win32/taskschd/task-scheduler-start-page.
|
||||
|
||||
#### Run as service ###
|
||||
#### Run as service
|
||||
|
||||
For running rclone at system startup, you can create a Windows service that executes
|
||||
your rclone command, as an alternative to scheduled task configured to run at startup.
|
||||
|
||||
##### Mount command built-in service integration ####
|
||||
##### Mount command built-in service integration
|
||||
|
||||
For mount commands, Rclone has a built-in Windows service integration via the third-party
|
||||
For mount commands, rclone has a built-in Windows service integration via the third-party
|
||||
WinFsp library it uses. Registering as a regular Windows service easy, as you just have to
|
||||
execute the built-in PowerShell command `New-Service` (requires administrative privileges).
|
||||
|
||||
|
@ -366,7 +420,7 @@ Windows standard methods for managing network drives. This is currently not
|
|||
officially supported by Rclone, but with WinFsp version 2019.3 B2 / v1.5B2 or later
|
||||
it should be possible through path rewriting as described [here](https://github.com/rclone/rclone/issues/3340).
|
||||
|
||||
##### Third-party service integration #####
|
||||
##### Third-party service integration
|
||||
|
||||
To Windows service running any rclone command, the excellent third-party utility
|
||||
[NSSM](http://nssm.cc), the "Non-Sucking Service Manager", can be used.
|
||||
|
|
|
@ -150,6 +150,16 @@ use these methods. The alternative is to use `--rc-user` and
|
|||
|
||||
Default Off.
|
||||
|
||||
### --rc-baseurl
|
||||
|
||||
Prefix for URLs.
|
||||
|
||||
Default is root
|
||||
|
||||
### --rc-template
|
||||
|
||||
User-specified template.
|
||||
|
||||
## Accessing the remote control via the rclone rc command {#api-rc}
|
||||
|
||||
Rclone itself implements the remote control protocol in its `rclone
|
||||
|
|
|
@ -2575,6 +2575,10 @@ Here is an example of making a Cloudflare R2 configuration. First run:
|
|||
|
||||
This will guide you through an interactive setup process.
|
||||
|
||||
Note that all buckets are private, and all are stored in the same
|
||||
"auto" region. It is necessary to use Cloudflare workers to share the
|
||||
content of a bucket publicly.
|
||||
|
||||
```
|
||||
No remotes found, make a new one?
|
||||
n) New remote
|
||||
|
@ -2631,19 +2635,6 @@ Endpoint for S3 API.
|
|||
Required when using an S3 clone.
|
||||
Enter a value. Press Enter to leave empty.
|
||||
endpoint> https://ACCOUNT_ID.r2.cloudflarestorage.com
|
||||
Option acl.
|
||||
Canned ACL used when creating buckets and storing or copying objects.
|
||||
This ACL is used for creating objects and if bucket_acl isn't set, for creating buckets too.
|
||||
For more info visit https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl
|
||||
Note that this ACL is applied when server-side copying objects as S3
|
||||
doesn't copy the ACL from the source but rather writes a fresh one.
|
||||
Choose a number from below, or type in your own value.
|
||||
Press Enter to leave empty.
|
||||
/ Owner gets FULL_CONTROL.
|
||||
1 | No one else has access rights (default).
|
||||
\ (private)
|
||||
...
|
||||
acl> 1
|
||||
Edit advanced config?
|
||||
y) Yes
|
||||
n) No (default)
|
||||
|
|
|
@ -230,7 +230,7 @@ func ConfigChoose(state string, name string, help string, n int, getItem func(i
|
|||
// StatePush pushes a new values onto the front of the config string
|
||||
func StatePush(state string, values ...string) string {
|
||||
for i := range values {
|
||||
values[i] = strings.Replace(values[i], ",", ",", -1) // replace comma with unicode wide version
|
||||
values[i] = strings.ReplaceAll(values[i], ",", ",") // replace comma with unicode wide version
|
||||
}
|
||||
if state != "" {
|
||||
values = append(values[:len(values):len(values)], state)
|
||||
|
@ -262,7 +262,7 @@ func StatePop(state string) (newState string, value string) {
|
|||
return "", state
|
||||
}
|
||||
value, newState = state[:comma], state[comma+1:]
|
||||
value = strings.Replace(value, ",", ",", -1) // replace unicode wide comma with comma
|
||||
value = strings.ReplaceAll(value, ",", ",") // replace unicode wide comma with comma
|
||||
return newState, value
|
||||
}
|
||||
|
||||
|
|
|
@ -248,11 +248,11 @@ func AddConfig(ctx context.Context) (context.Context, *ConfigInfo) {
|
|||
// "ignore-size") into an environment name
|
||||
// "RCLONE_CONFIG_MY-REMOTE_IGNORE_SIZE"
|
||||
func ConfigToEnv(section, name string) string {
|
||||
return "RCLONE_CONFIG_" + strings.ToUpper(section+"_"+strings.Replace(name, "-", "_", -1))
|
||||
return "RCLONE_CONFIG_" + strings.ToUpper(section+"_"+strings.ReplaceAll(name, "-", "_"))
|
||||
}
|
||||
|
||||
// OptionToEnv converts an option name, e.g. "ignore-size" into an
|
||||
// environment name "RCLONE_IGNORE_SIZE"
|
||||
func OptionToEnv(name string) string {
|
||||
return "RCLONE_" + strings.ToUpper(strings.Replace(name, "-", "_", -1))
|
||||
return "RCLONE_" + strings.ToUpper(strings.ReplaceAll(name, "-", "_"))
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func setConfigFile(t *testing.T, data string) func() {
|
|||
// toUnix converts \r\n to \n in buf
|
||||
func toUnix(buf string) string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return strings.Replace(buf, "\r\n", "\n", -1)
|
||||
return strings.ReplaceAll(buf, "\r\n", "\n")
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
|
|
@ -417,7 +417,7 @@ func ChooseOption(o *fs.Option, name string) string {
|
|||
fmt.Printf("Option %s.\n", o.Name)
|
||||
if o.Help != "" {
|
||||
// Show help string without empty lines.
|
||||
help := strings.Replace(strings.TrimSpace(o.Help), "\n\n", "\n", -1)
|
||||
help := strings.ReplaceAll(strings.TrimSpace(o.Help), "\n\n", "\n")
|
||||
fmt.Println(help)
|
||||
}
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ loop:
|
|||
value := path[prev : i-1]
|
||||
// replace any doubled quotes if there were any
|
||||
if doubled {
|
||||
value = strings.Replace(value, string(quote)+string(quote), string(quote), -1)
|
||||
value = strings.ReplaceAll(value, string(quote)+string(quote), string(quote))
|
||||
}
|
||||
prev = i + 1
|
||||
parsed.Config[param] = value
|
||||
|
|
|
@ -1407,7 +1407,7 @@ func TestDirMove(t *testing.T) {
|
|||
require.NoError(t, operations.DirMove(ctx, r.Fremote, "A1", "A2"))
|
||||
|
||||
for i := range files {
|
||||
files[i].Path = strings.Replace(files[i].Path, "A1/", "A2/", -1)
|
||||
files[i].Path = strings.ReplaceAll(files[i].Path, "A1/", "A2/")
|
||||
}
|
||||
|
||||
fstest.CheckListingWithPrecision(
|
||||
|
@ -1432,7 +1432,7 @@ func TestDirMove(t *testing.T) {
|
|||
require.NoError(t, operations.DirMove(ctx, r.Fremote, "A2", "A3"))
|
||||
|
||||
for i := range files {
|
||||
files[i].Path = strings.Replace(files[i].Path, "A2/", "A3/", -1)
|
||||
files[i].Path = strings.ReplaceAll(files[i].Path, "A2/", "A3/")
|
||||
}
|
||||
|
||||
fstest.CheckListingWithPrecision(
|
||||
|
|
|
@ -44,7 +44,7 @@ type RegInfo struct {
|
|||
|
||||
// FileName returns the on disk file name for this backend
|
||||
func (ri *RegInfo) FileName() string {
|
||||
return strings.Replace(ri.Name, " ", "", -1)
|
||||
return strings.ReplaceAll(ri.Name, " ", "")
|
||||
}
|
||||
|
||||
// Options is a slice of configuration Option for a backend
|
||||
|
@ -210,7 +210,7 @@ func (o *Option) Type() string {
|
|||
|
||||
// FlagName for the option
|
||||
func (o *Option) FlagName(prefix string) string {
|
||||
name := strings.Replace(o.Name, "_", "-", -1) // convert snake_case to kebab-case
|
||||
name := strings.ReplaceAll(o.Name, "_", "-") // convert snake_case to kebab-case
|
||||
if !o.NoPrefix {
|
||||
name = prefix + "-" + name
|
||||
}
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
package fs
|
||||
|
||||
// Version of rclone
|
||||
var Version = "v1.59.0-DEV"
|
||||
// Version of rclone containing the complete version string
|
||||
var Version string
|
||||
|
||||
func init() {
|
||||
if Version == "" {
|
||||
if VersionSuffix == "" {
|
||||
Version = VersionTag
|
||||
} else {
|
||||
Version = VersionTag + "-" + VersionSuffix
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
fs/versionsuffix.go
Normal file
4
fs/versionsuffix.go
Normal file
|
@ -0,0 +1,4 @@
|
|||
package fs
|
||||
|
||||
// VersionSuffix of rclone containing the pre-release label if any
|
||||
var VersionSuffix = "DEV"
|
4
fs/versiontag.go
Normal file
4
fs/versiontag.go
Normal file
|
@ -0,0 +1,4 @@
|
|||
package fs
|
||||
|
||||
// VersionTag of rclone
|
||||
var VersionTag = "v1.59.0"
|
|
@ -317,7 +317,7 @@ func (r *Run) RemoveTestBinary() {
|
|||
func (r *Run) Name() string {
|
||||
ns := []string{
|
||||
r.Backend,
|
||||
strings.Replace(r.Path, "/", ".", -1),
|
||||
strings.ReplaceAll(r.Path, "/", "."),
|
||||
r.Remote,
|
||||
}
|
||||
if r.FastList {
|
||||
|
@ -325,7 +325,7 @@ func (r *Run) Name() string {
|
|||
}
|
||||
ns = append(ns, fmt.Sprintf("%d", r.Try))
|
||||
s := strings.Join(ns, "-")
|
||||
s = strings.Replace(s, ":", "", -1)
|
||||
s = strings.ReplaceAll(s, ":", "")
|
||||
return s
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ func Add(fileName string, t time.Time) string {
|
|||
base, ext := splitExt(fileName)
|
||||
s := t.Format(versionFormat)
|
||||
// Replace the '.' with a '-'
|
||||
s = strings.Replace(s, ".", "-", -1)
|
||||
s = strings.ReplaceAll(s, ".", "-")
|
||||
return base + s + ext
|
||||
}
|
||||
|
||||
|
|
|
@ -365,32 +365,32 @@ func rename(osOldPath, osNewPath string) error {
|
|||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Failed to stat source: %s: %w", osOldPath, err)
|
||||
return fmt.Errorf("failed to stat source: %s: %w", osOldPath, err)
|
||||
}
|
||||
if !sfi.Mode().IsRegular() {
|
||||
// cannot copy non-regular files (e.g., directories, symlinks, devices, etc.)
|
||||
return fmt.Errorf("Non-regular source file: %s (%q)", sfi.Name(), sfi.Mode().String())
|
||||
return fmt.Errorf("non-regular source file: %s (%q)", sfi.Name(), sfi.Mode().String())
|
||||
}
|
||||
dfi, err := os.Stat(osNewPath)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return fmt.Errorf("Failed to stat destination: %s: %w", osNewPath, err)
|
||||
return fmt.Errorf("failed to stat destination: %s: %w", osNewPath, err)
|
||||
}
|
||||
parent := vfscommon.OsFindParent(osNewPath)
|
||||
parent := vfscommon.OSFindParent(osNewPath)
|
||||
err = createDir(parent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create parent dir: %s: %w", parent, err)
|
||||
return fmt.Errorf("failed to create parent dir: %s: %w", parent, err)
|
||||
}
|
||||
} else {
|
||||
if !(dfi.Mode().IsRegular()) {
|
||||
return fmt.Errorf("Non-regular destination file: %s (%q)", dfi.Name(), dfi.Mode().String())
|
||||
return fmt.Errorf("non-regular destination file: %s (%q)", dfi.Name(), dfi.Mode().String())
|
||||
}
|
||||
if os.SameFile(sfi, dfi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if err = os.Rename(osOldPath, osNewPath); err != nil {
|
||||
return fmt.Errorf("Failed to rename in cache: %s to %s: %w", osOldPath, osNewPath, err)
|
||||
return fmt.Errorf("failed to rename in cache: %s to %s: %w", osOldPath, osNewPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ import (
|
|||
"path/filepath"
|
||||
)
|
||||
|
||||
// OsFindParent returns the parent directory of name, or "" for the
|
||||
// OSFindParent returns the parent directory of name, or "" for the
|
||||
// root for OS native paths.
|
||||
func OsFindParent(name string) string {
|
||||
func OSFindParent(name string) string {
|
||||
parent := filepath.Dir(name)
|
||||
if parent == "." || parent == "/" {
|
||||
if parent == "." || (len(parent) == 1 && parent[0] == filepath.Separator) {
|
||||
parent = ""
|
||||
}
|
||||
return parent
|
||||
|
|
Loading…
Add table
Reference in a new issue