mirror of
https://github.com/rclone/rclone.git
synced 2026-01-31 08:43:29 +00:00
Compare commits
24 Commits
feat-webda
...
v1.55-stab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
825dd65e1d | ||
|
|
96cdbc5eaa | ||
|
|
baf626c1d0 | ||
|
|
e8be37bebc | ||
|
|
e67ac64f51 | ||
|
|
c86fc6e05d | ||
|
|
a6cab5d0e9 | ||
|
|
0d8c69b4ea | ||
|
|
07f4b9832d | ||
|
|
c764ab2751 | ||
|
|
563c4f76c6 | ||
|
|
2f6afe6005 | ||
|
|
b30d7a026f | ||
|
|
1a5e67fe98 | ||
|
|
2d210c2729 | ||
|
|
5603983a5d | ||
|
|
501475a3a3 | ||
|
|
958f5297fe | ||
|
|
572c6ad601 | ||
|
|
9e2e2bb5fc | ||
|
|
12d039261f | ||
|
|
74be50ae92 | ||
|
|
b0608d6f25 | ||
|
|
b60838221b |
33
.github/ISSUE_TEMPLATE/Bug.md
vendored
33
.github/ISSUE_TEMPLATE/Bug.md
vendored
@@ -5,31 +5,19 @@ about: Report a problem with rclone
|
||||
|
||||
<!--
|
||||
|
||||
We understand you are having a problem with rclone; we want to help you with that!
|
||||
Welcome :-) We understand you are having a problem with rclone; we want to help you with that!
|
||||
|
||||
**STOP and READ**
|
||||
**YOUR POST WILL BE REMOVED IF IT IS LOW QUALITY**:
|
||||
Please show the effort you've put in to solving the problem and please be specific.
|
||||
People are volunteering their time to help! Low effort posts are not likely to get good answers!
|
||||
|
||||
If you think you might have found a bug, try to replicate it with the latest beta (or stable).
|
||||
The update instructions are available at https://rclone.org/commands/rclone_selfupdate/
|
||||
|
||||
If you can still replicate it or just got a question then please use the rclone forum:
|
||||
If you've just got a question or aren't sure if you've found a bug then please use the rclone forum:
|
||||
|
||||
https://forum.rclone.org/
|
||||
|
||||
for a quick response instead of filing an issue on this repo.
|
||||
instead of filing an issue for a quick response.
|
||||
|
||||
If nothing else helps, then please fill in the info below which helps us help you.
|
||||
If you think you might have found a bug, please can you try to replicate it with the latest beta?
|
||||
|
||||
**DO NOT REDACT** any information except passwords/keys/personal info.
|
||||
|
||||
You should use 3 backticks to begin and end your paste to make it readable.
|
||||
|
||||
Make sure to include a log obtained with '-vv'.
|
||||
|
||||
You can also use '-vv --log-file bug.log' and a service such as https://pastebin.com or https://gist.github.com/
|
||||
https://beta.rclone.org/
|
||||
|
||||
If you can still replicate it with the latest beta, then please fill in the info below which makes our lives much easier. A log with -vv will make our day :-)
|
||||
|
||||
Thank you
|
||||
|
||||
@@ -37,11 +25,6 @@ The Rclone Developers
|
||||
|
||||
-->
|
||||
|
||||
|
||||
#### The associated forum post URL from `https://forum.rclone.org`
|
||||
|
||||
|
||||
|
||||
#### What is the problem you are having with rclone?
|
||||
|
||||
|
||||
@@ -54,7 +37,7 @@ The Rclone Developers
|
||||
|
||||
|
||||
|
||||
#### Which cloud storage system are you using? (e.g. Google Drive)
|
||||
#### Which cloud storage system are you using? (e.g. Google Drive)
|
||||
|
||||
|
||||
|
||||
|
||||
16
.github/ISSUE_TEMPLATE/Feature.md
vendored
16
.github/ISSUE_TEMPLATE/Feature.md
vendored
@@ -7,16 +7,12 @@ about: Suggest a new feature or enhancement for rclone
|
||||
|
||||
Welcome :-)
|
||||
|
||||
So you've got an idea to improve rclone? We love that!
|
||||
You'll be glad to hear we've incorporated hundreds of ideas from contributors already.
|
||||
So you've got an idea to improve rclone? We love that! You'll be glad to hear we've incorporated hundreds of ideas from contributors already.
|
||||
|
||||
Probably the latest beta (or stable) release has your feature, so try to update your rclone.
|
||||
The update instructions are available at https://rclone.org/commands/rclone_selfupdate/
|
||||
Here is a checklist of things to do:
|
||||
|
||||
If it still isn't there, here is a checklist of things to do:
|
||||
|
||||
1. Search the old issues for your idea and +1 or comment on an existing issue if possible.
|
||||
2. Discuss on the forum: https://forum.rclone.org/
|
||||
1. Please search the old issues first for your idea and +1 or comment on an existing issue if possible.
|
||||
2. Discuss on the forum first: https://forum.rclone.org/
|
||||
3. Make a feature request issue (this is the right place!).
|
||||
4. Be prepared to get involved making the feature :-)
|
||||
|
||||
@@ -27,10 +23,6 @@ The Rclone Developers
|
||||
-->
|
||||
|
||||
|
||||
#### The associated forum post URL from `https://forum.rclone.org`
|
||||
|
||||
|
||||
|
||||
#### What is your current rclone version (output from `rclone version`)?
|
||||
|
||||
|
||||
|
||||
79
MANUAL.html
generated
79
MANUAL.html
generated
@@ -17,7 +17,7 @@
|
||||
<header id="title-block-header">
|
||||
<h1 class="title">rclone(1) User Manual</h1>
|
||||
<p class="author">Nick Craig-Wood</p>
|
||||
<p class="date">Mar 31, 2021</p>
|
||||
<p class="date">Apr 26, 2021</p>
|
||||
</header>
|
||||
<h1 id="rclone-syncs-your-files-to-cloud-storage">Rclone syncs your files to cloud storage</h1>
|
||||
<p><img width="50%" src="https://rclone.org/img/logo_on_light__horizontal_color.svg" alt="rclone logo" style="float:right; padding: 5px;" ></p>
|
||||
@@ -774,8 +774,8 @@ two-3.txt: renamed from: two.txt</code></pre>
|
||||
<h1 id="rclone-about">rclone about</h1>
|
||||
<p>Get quota information from the remote.</p>
|
||||
<h2 id="synopsis-16">Synopsis</h2>
|
||||
<p><code>rclone about</code>prints quota information about a remote to standard output. The output is typically used, free, quota and trash contents.</p>
|
||||
<p>E.g. Typical output from<code>rclone about remote:</code>is:</p>
|
||||
<p><code>rclone about</code> prints quota information about a remote to standard output. The output is typically used, free, quota and trash contents.</p>
|
||||
<p>E.g. Typical output from <code>rclone about remote:</code> is:</p>
|
||||
<pre><code>Total: 17G
|
||||
Used: 7.444G
|
||||
Free: 1.315G
|
||||
@@ -797,7 +797,7 @@ Used: 7993453766
|
||||
Free: 1411001220
|
||||
Trashed: 104857602
|
||||
Other: 8849156022</code></pre>
|
||||
<p>A <code>--json</code>flag generates conveniently computer readable output, e.g.</p>
|
||||
<p>A <code>--json</code> flag generates conveniently computer readable output, e.g.</p>
|
||||
<pre><code>{
|
||||
"total": 18253611008,
|
||||
"used": 7993453766,
|
||||
@@ -1066,7 +1066,7 @@ if src is directory
|
||||
<p>Copy url content to dest.</p>
|
||||
<h2 id="synopsis-28">Synopsis</h2>
|
||||
<p>Download a URL's content and copy it to the destination without saving it in temporary storage.</p>
|
||||
<p>Setting <code>--auto-filename</code>will cause the file name to be retrieved from the from URL (after any redirections) and used in the destination path. With <code>--print-filename</code> in addition, the resuling file name will be printed.</p>
|
||||
<p>Setting <code>--auto-filename</code> will cause the file name to be retrieved from the from URL (after any redirections) and used in the destination path. With <code>--print-filename</code> in addition, the resuling file name will be printed.</p>
|
||||
<p>Setting <code>--no-clobber</code> will prevent overwriting file on the destination if there is one with the same name.</p>
|
||||
<p>Setting <code>--stdout</code> or making the output file name <code>-</code> will cause the output to be written to standard output.</p>
|
||||
<pre><code>rclone copyurl https://example.com dest:path [flags]</code></pre>
|
||||
@@ -1475,7 +1475,7 @@ rclone mount remote:path/to/files * --volname \\cloud\remote</code></pre>
|
||||
<p>The permissions on each entry will be set according to <a href="#options">options</a> <code>--dir-perms</code> and <code>--file-perms</code>, which takes a value in traditional <a href="https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation">numeric notation</a>, where the default corresponds to <code>--file-perms 0666 --dir-perms 0777</code>.</p>
|
||||
<p>Note that the mapping of permissions is not always trivial, and the result you see in Windows Explorer may not be exactly like you expected. For example, when setting a value that includes write access, this will be mapped to individual permissions "write attributes", "write data" and "append data", but not "write extended attributes". Windows will then show this as basic permission "Special" instead of "Write", because "Write" includes the "write extended attributes" permission.</p>
|
||||
<p>If you set POSIX permissions for only allowing access to the owner, using <code>--file-perms 0600 --dir-perms 0700</code>, the user group and the built-in "Everyone" group will still be given some special permissions, such as "read attributes" and "read permissions", in Windows. This is done for compatibility reasons, e.g. to allow users without additional permissions to be able to read basic metadata about files like in UNIX. One case that may arise is that other programs (incorrectly) interprets this as the file being accessible by everyone. For example an SSH client may warn about "unprotected private key file".</p>
|
||||
<p>WinFsp 2021 (version 1.9, still in beta) introduces a new FUSE option "FileSecurity", that allows the complete specification of file security descriptors using <a href="https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format">SDDL</a>. With this you can work around issues such as the mentioned "unprotected private key file" by specifying <code>-o FileSecurity="D:P(A;;FA;;;OW)"</code>, for file all access (FA) to the owner (OW).</p>
|
||||
<p>WinFsp 2021 (version 1.9) introduces a new FUSE option "FileSecurity", that allows the complete specification of file security descriptors using <a href="https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format">SDDL</a>. With this you can work around issues such as the mentioned "unprotected private key file" by specifying <code>-o FileSecurity="D:P(A;;FA;;;OW)"</code>, for file all access (FA) to the owner (OW).</p>
|
||||
<h3 id="windows-caveats">Windows caveats</h3>
|
||||
<p>Note that drives created as Administrator are not visible by other accounts (including the account that was elevated as Administrator). So if you start a Windows drive from an Administrative Command Prompt and then try to access the same drive from Explorer (which does not run as Administrator), you will not be able to see the new drive.</p>
|
||||
<p>The easiest way around this is to start the drive from a normal command prompt. It is also possible to start a drive from the SYSTEM account (using <a href="https://github.com/billziss-gh/winfsp/wiki/WinFsp-Service-Architecture">the WinFsp.Launcher infrastructure</a>) which creates drives accessible for everyone on the system or alternatively using <a href="https://nssm.cc/usage">the nssm service manager</a>.</p>
|
||||
@@ -1805,7 +1805,7 @@ ffmpeg - | rclone rcat remote:path/to/file</code></pre>
|
||||
<p>This command downloads the latest release of rclone and replaces the currently running binary. The download is verified with a hashsum and cryptographically signed signature.</p>
|
||||
<p>If used without flags (or with implied <code>--stable</code> flag), this command will install the latest stable release. However, some issues may be fixed (or features added) only in the latest beta release. In such cases you should run the command with the <code>--beta</code> flag, i.e. <code>rclone selfupdate --beta</code>. You can check in advance what version would be installed by adding the <code>--check</code> flag, then repeat the command without it when you are satisfied.</p>
|
||||
<p>Sometimes the rclone team may recommend you a concrete beta or stable rclone release to troubleshoot your issue or add a bleeding edge feature. The <code>--version VER</code> flag, if given, will update to the concrete version instead of the latest one. If you omit micro version from <code>VER</code> (for example <code>1.53</code>), the latest matching micro version will be used.</p>
|
||||
<p>Upon successful update rclone will print a message that contains a previous version number. You will need it if you later decide to revert your update for some reason. Then you'll have to note the previous version and run the following command: <code>rclone selfupdate [--beta] OLDVER</code>. If the old version contains only dots and digits (for example <code>v1.54.0</code>) then it's a stable release so you won't need the <code>--beta</code> flag. Beta releases have an additional information similar to <code>v1.54.0-beta.5111.06f1c0c61</code>. (if you are a developer and use a locally built rclone, the version number will end with <code>-DEV</code>, you will have to rebuild it as it obvisously can't be distributed).</p>
|
||||
<p>Upon successful update rclone will print a message that contains a previous version number. You will need it if you later decide to revert your update for some reason. Then you'll have to note the previous version and run the following command: <code>rclone selfupdate [--beta] OLDVER</code>. If the old version contains only dots and digits (for example <code>v1.54.0</code>) then it's a stable release so you won't need the <code>--beta</code> flag. Beta releases have an additional information similar to <code>v1.54.0-beta.5111.06f1c0c61</code>. (if you are a developer and use a locally built rclone, the version number will end with <code>-DEV</code>, you will have to rebuild it as it obviously can't be distributed).</p>
|
||||
<p>If you previously installed rclone via a package manager, the package may include local documentation or configure services. You may wish to update with the flag <code>--package deb</code> or <code>--package rpm</code> (whichever is correct for your OS) to update these too. This command with the default <code>--package zip</code> will update only the rclone executable so the local manual may become inaccurate after it.</p>
|
||||
<p>The <code>rclone mount</code> command (https://rclone.org/commands/rclone_mount/) may or may not support extended FUSE options depending on the build and OS. <code>selfupdate</code> will refuse to update if the capability would be discarded.</p>
|
||||
<p>Note: Windows forbids deletion of a currently running executable so this command will rename the old executable to 'rclone.old.exe' upon success.</p>
|
||||
@@ -3378,7 +3378,7 @@ rclone sync -i /path/to/files remote:current-backup</code></pre>
|
||||
<p>Normally the config file is in your home directory as a file called <code>.config/rclone/rclone.conf</code> (or <code>.rclone.conf</code> if created with an older version). If <code>$XDG_CONFIG_HOME</code> is set it will be at <code>$XDG_CONFIG_HOME/rclone/rclone.conf</code>.</p>
|
||||
<p>If there is a file <code>rclone.conf</code> in the same directory as the rclone executable it will be preferred. This file must be created manually for Rclone to use it, it will never be created automatically.</p>
|
||||
<p>If you run <code>rclone config file</code> you will see where the default location is for you.</p>
|
||||
<p>Use this flag to override the config location, e.g. <code>rclone --config=".myconfig" .config</code>.</p>
|
||||
<p>Use this flag to override the config location, e.g. <code>rclone --config=".myconfig" config</code>.</p>
|
||||
<p>If the location is set to empty string <code>""</code> or the special value <code>/notfound</code>, or the os null device represented by value <code>NUL</code> on Windows and <code>/dev/null</code> on Unix systems, then rclone will keep the config file in memory only.</p>
|
||||
<p>The file format is basic <a href="https://en.wikipedia.org/wiki/INI_file#Format">INI</a>: Sections of text, led by a <code>[section]</code> header and followed by <code>key=value</code> entries on separate lines. In rclone each remote is represented by its own section, where the section name defines the name of the remote. Options are specified as the <code>key=value</code> entries, where the key is the option name without the <code>--backend-</code> prefix, in lowercase and with <code>_</code> instead of <code>-</code>. E.g. option <code>--mega-hard-delete</code> corresponds to key <code>hard_delete</code>. Only backend options can be specified. A special, and required, key <code>type</code> identifies the <a href="https://rclone.org/overview/">storage system</a>, where the value is the internal lowercase name as returned by command <code>rclone help backends</code>. Comments are indicated by <code>;</code> or <code>#</code> at the beginning of a line.</p>
|
||||
<p>Example:</p>
|
||||
@@ -3929,7 +3929,7 @@ $ rclone lsd MYS3:
|
||||
$ rclone listremotes | grep mys3
|
||||
mys3:</code></pre>
|
||||
<p>Note that if you want to create a remote using environment variables you must create the <code>..._TYPE</code> variable as above.</p>
|
||||
<p>Note also that now rclone has <a href="#connection-strings">connectionstrings</a>, it is probably easier to use those instead which makes the above example</p>
|
||||
<p>Note also that now rclone has <a href="#connection-strings">connection strings</a>, it is probably easier to use those instead which makes the above example</p>
|
||||
<pre><code>rclone lsd :s3,access_key_id=XXX,secret_access_key=XXX:</code></pre>
|
||||
<h3 id="precedence">Precedence</h3>
|
||||
<p>The various different methods of backend configuration are read in this order and the first one with a value is used.</p>
|
||||
@@ -6806,7 +6806,7 @@ Showing nodes accounting for 1537.03kB, 100% of 1537.03kB total
|
||||
--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. The default is rclone/ version (default "rclone/v1.55.0")
|
||||
--user-agent string Set the user-agent to a specified string. The default is rclone/ version (default "rclone/v1.55.1")
|
||||
-v, --verbose count Print lots more stuff (repeat for more)</code></pre>
|
||||
<h2 id="backend-flags">Backend Flags</h2>
|
||||
<p>These flags are available for every command. They control the backends and may be set in the config file.</p>
|
||||
@@ -20355,6 +20355,65 @@ $ tree /tmp/b
|
||||
<li>"error": return an error based on option value</li>
|
||||
</ul>
|
||||
<h1 id="changelog">Changelog</h1>
|
||||
<h2 id="v1.55.1---2021-04-26">v1.55.1 - 2021-04-26</h2>
|
||||
<p><a href="https://github.com/rclone/rclone/compare/v1.55.0...v1.55.1">See commits</a></p>
|
||||
<ul>
|
||||
<li>Bug Fixes
|
||||
<ul>
|
||||
<li>selfupdate
|
||||
<ul>
|
||||
<li>Dont detect FUSE if build is static (Ivan Andreev)</li>
|
||||
<li>Add build tag noselfupdate (Ivan Andreev)</li>
|
||||
</ul></li>
|
||||
<li>sync: Fix incorrect error reported by graceful cutoff (Nick Craig-Wood)</li>
|
||||
<li>install.sh: fix macOS arm64 download (Nick Craig-Wood)</li>
|
||||
<li>build: Fix version numbers in android branch builds (Nick Craig-Wood)</li>
|
||||
<li>docs
|
||||
<ul>
|
||||
<li>Contributing.md: update setup instructions for go1.16 (Nick Gaya)</li>
|
||||
<li>WinFsp 2021 is out of beta (albertony)</li>
|
||||
<li>Minor cleanup of space around code section (albertony)</li>
|
||||
<li>Fixed some typos (albertony)</li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
<li>VFS
|
||||
<ul>
|
||||
<li>Fix a code path which allows dirty data to be removed causing data loss (Nick Craig-Wood)</li>
|
||||
</ul></li>
|
||||
<li>Compress
|
||||
<ul>
|
||||
<li>Fix compressed name regexp (buengese)</li>
|
||||
</ul></li>
|
||||
<li>Drive
|
||||
<ul>
|
||||
<li>Fix backend copyid of google doc to directory (Nick Craig-Wood)</li>
|
||||
<li>Don't open browser when service account... (Ansh Mittal)</li>
|
||||
</ul></li>
|
||||
<li>Dropbox
|
||||
<ul>
|
||||
<li>Add missing team_data.member scope for use with --impersonate (Nick Craig-Wood)</li>
|
||||
<li>Fix About after scopes changes - rclone config reconnect needed (Nick Craig-Wood)</li>
|
||||
<li>Fix Unable to decrypt returned paths from changeNotify (Nick Craig-Wood)</li>
|
||||
</ul></li>
|
||||
<li>FTP
|
||||
<ul>
|
||||
<li>Fix implicit TLS (Ivan Andreev)</li>
|
||||
</ul></li>
|
||||
<li>Onedrive
|
||||
<ul>
|
||||
<li>Work around for random "Unable to initialize RPS" errors (OleFrost)</li>
|
||||
</ul></li>
|
||||
<li>SFTP
|
||||
<ul>
|
||||
<li>Revert sftp library to v1.12.0 from v1.13.0 to fix performance regression (Nick Craig-Wood)</li>
|
||||
<li>Fix Update ReadFrom failed: failed to send packet: EOF errors (Nick Craig-Wood)</li>
|
||||
</ul></li>
|
||||
<li>Zoho
|
||||
<ul>
|
||||
<li>Fix error when region isn't set (buengese)</li>
|
||||
<li>Do not ask for mountpoint twice when using headless setup (buengese)</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<h2 id="v1.55.0---2021-03-31">v1.55.0 - 2021-03-31</h2>
|
||||
<p><a href="https://github.com/rclone/rclone/compare/v1.54.0...v1.55.0">See commits</a></p>
|
||||
<ul>
|
||||
|
||||
58
MANUAL.md
generated
58
MANUAL.md
generated
@@ -1,6 +1,6 @@
|
||||
% rclone(1) User Manual
|
||||
% Nick Craig-Wood
|
||||
% Mar 31, 2021
|
||||
% Apr 26, 2021
|
||||
|
||||
# Rclone syncs your files to cloud storage
|
||||
|
||||
@@ -1395,10 +1395,10 @@ Get quota information from the remote.
|
||||
## Synopsis
|
||||
|
||||
|
||||
`rclone about`prints quota information about a remote to standard
|
||||
`rclone about` prints quota information about a remote to standard
|
||||
output. The output is typically used, free, quota and trash contents.
|
||||
|
||||
E.g. Typical output from`rclone about remote:`is:
|
||||
E.g. Typical output from `rclone about remote:` is:
|
||||
|
||||
Total: 17G
|
||||
Used: 7.444G
|
||||
@@ -1426,7 +1426,7 @@ Applying a `--full` flag to the command prints the bytes in full, e.g.
|
||||
Trashed: 104857602
|
||||
Other: 8849156022
|
||||
|
||||
A `--json`flag generates conveniently computer readable output, e.g.
|
||||
A `--json` flag generates conveniently computer readable output, e.g.
|
||||
|
||||
{
|
||||
"total": 18253611008,
|
||||
@@ -2009,7 +2009,7 @@ Copy url content to dest.
|
||||
Download a URL's content and copy it to the destination without saving
|
||||
it in temporary storage.
|
||||
|
||||
Setting `--auto-filename`will cause the file name to be retrieved from
|
||||
Setting `--auto-filename` will cause the file name to be retrieved from
|
||||
the from URL (after any redirections) and used in the destination
|
||||
path. With `--print-filename` in addition, the resuling file name will
|
||||
be printed.
|
||||
@@ -2931,7 +2931,7 @@ metadata about files like in UNIX. One case that may arise is that other program
|
||||
(incorrectly) interprets this as the file being accessible by everyone. For example
|
||||
an SSH client may warn about "unprotected private key file".
|
||||
|
||||
WinFsp 2021 (version 1.9, still in beta) introduces a new FUSE option "FileSecurity",
|
||||
WinFsp 2021 (version 1.9) introduces a new FUSE option "FileSecurity",
|
||||
that allows the complete specification of file security descriptors using
|
||||
[SDDL](https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format).
|
||||
With this you can work around issues such as the mentioned "unprotected private key file"
|
||||
@@ -3751,7 +3751,7 @@ If the old version contains only dots and digits (for example `v1.54.0`)
|
||||
then it's a stable release so you won't need the `--beta` flag. Beta releases
|
||||
have an additional information similar to `v1.54.0-beta.5111.06f1c0c61`.
|
||||
(if you are a developer and use a locally built rclone, the version number
|
||||
will end with `-DEV`, you will have to rebuild it as it obvisously can't
|
||||
will end with `-DEV`, you will have to rebuild it as it obviously can't
|
||||
be distributed).
|
||||
|
||||
If you previously installed rclone via a package manager, the package may
|
||||
@@ -6977,7 +6977,7 @@ If you run `rclone config file` you will see where the default
|
||||
location is for you.
|
||||
|
||||
Use this flag to override the config location, e.g. `rclone
|
||||
--config=".myconfig" .config`.
|
||||
--config=".myconfig" config`.
|
||||
|
||||
If the location is set to empty string `""` or the special value
|
||||
`/notfound`, or the os null device represented by value `NUL` on
|
||||
@@ -8442,7 +8442,7 @@ mys3:
|
||||
Note that if you want to create a remote using environment variables
|
||||
you must create the `..._TYPE` variable as above.
|
||||
|
||||
Note also that now rclone has [connectionstrings](#connection-strings),
|
||||
Note also that now rclone has [connection strings](#connection-strings),
|
||||
it is probably easier to use those instead which makes the above example
|
||||
|
||||
rclone lsd :s3,access_key_id=XXX,secret_access_key=XXX:
|
||||
@@ -11750,7 +11750,7 @@ These flags are available for every command.
|
||||
--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. The default is rclone/ version (default "rclone/v1.55.0")
|
||||
--user-agent string Set the user-agent to a specified string. The default is rclone/ version (default "rclone/v1.55.1")
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
```
|
||||
|
||||
@@ -28837,6 +28837,44 @@ Options:
|
||||
|
||||
# Changelog
|
||||
|
||||
## v1.55.1 - 2021-04-26
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.55.0...v1.55.1)
|
||||
|
||||
* Bug Fixes
|
||||
* selfupdate
|
||||
* Dont detect FUSE if build is static (Ivan Andreev)
|
||||
* Add build tag noselfupdate (Ivan Andreev)
|
||||
* sync: Fix incorrect error reported by graceful cutoff (Nick Craig-Wood)
|
||||
* install.sh: fix macOS arm64 download (Nick Craig-Wood)
|
||||
* build: Fix version numbers in android branch builds (Nick Craig-Wood)
|
||||
* docs
|
||||
* Contributing.md: update setup instructions for go1.16 (Nick Gaya)
|
||||
* WinFsp 2021 is out of beta (albertony)
|
||||
* Minor cleanup of space around code section (albertony)
|
||||
* Fixed some typos (albertony)
|
||||
* VFS
|
||||
* Fix a code path which allows dirty data to be removed causing data loss (Nick Craig-Wood)
|
||||
* Compress
|
||||
* Fix compressed name regexp (buengese)
|
||||
* Drive
|
||||
* Fix backend copyid of google doc to directory (Nick Craig-Wood)
|
||||
* Don't open browser when service account... (Ansh Mittal)
|
||||
* Dropbox
|
||||
* Add missing team_data.member scope for use with --impersonate (Nick Craig-Wood)
|
||||
* Fix About after scopes changes - rclone config reconnect needed (Nick Craig-Wood)
|
||||
* Fix Unable to decrypt returned paths from changeNotify (Nick Craig-Wood)
|
||||
* FTP
|
||||
* Fix implicit TLS (Ivan Andreev)
|
||||
* Onedrive
|
||||
* Work around for random "Unable to initialize RPS" errors (OleFrost)
|
||||
* SFTP
|
||||
* Revert sftp library to v1.12.0 from v1.13.0 to fix performance regression (Nick Craig-Wood)
|
||||
* Fix Update ReadFrom failed: failed to send packet: EOF errors (Nick Craig-Wood)
|
||||
* Zoho
|
||||
* Fix error when region isn't set (buengese)
|
||||
* Do not ask for mountpoint twice when using headless setup (buengese)
|
||||
|
||||
## v1.55.0 - 2021-03-31
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.54.0...v1.55.0)
|
||||
|
||||
81
MANUAL.txt
generated
81
MANUAL.txt
generated
@@ -1,6 +1,6 @@
|
||||
rclone(1) User Manual
|
||||
Nick Craig-Wood
|
||||
Mar 31, 2021
|
||||
Apr 26, 2021
|
||||
|
||||
|
||||
|
||||
@@ -1419,10 +1419,10 @@ Get quota information from the remote.
|
||||
|
||||
Synopsis
|
||||
|
||||
rclone aboutprints quota information about a remote to standard output.
|
||||
rclone about prints quota information about a remote to standard output.
|
||||
The output is typically used, free, quota and trash contents.
|
||||
|
||||
E.g. Typical output fromrclone about remote:is:
|
||||
E.g. Typical output from rclone about remote: is:
|
||||
|
||||
Total: 17G
|
||||
Used: 7.444G
|
||||
@@ -1450,7 +1450,7 @@ Applying a --full flag to the command prints the bytes in full, e.g.
|
||||
Trashed: 104857602
|
||||
Other: 8849156022
|
||||
|
||||
A --jsonflag generates conveniently computer readable output, e.g.
|
||||
A --json flag generates conveniently computer readable output, e.g.
|
||||
|
||||
{
|
||||
"total": 18253611008,
|
||||
@@ -2036,9 +2036,10 @@ Synopsis
|
||||
Download a URL's content and copy it to the destination without saving
|
||||
it in temporary storage.
|
||||
|
||||
Setting --auto-filenamewill cause the file name to be retrieved from the
|
||||
from URL (after any redirections) and used in the destination path. With
|
||||
--print-filename in addition, the resuling file name will be printed.
|
||||
Setting --auto-filename will cause the file name to be retrieved from
|
||||
the from URL (after any redirections) and used in the destination path.
|
||||
With --print-filename in addition, the resuling file name will be
|
||||
printed.
|
||||
|
||||
Setting --no-clobber will prevent overwriting file on the destination if
|
||||
there is one with the same name.
|
||||
@@ -2968,10 +2969,10 @@ One case that may arise is that other programs (incorrectly) interprets
|
||||
this as the file being accessible by everyone. For example an SSH client
|
||||
may warn about "unprotected private key file".
|
||||
|
||||
WinFsp 2021 (version 1.9, still in beta) introduces a new FUSE option
|
||||
"FileSecurity", that allows the complete specification of file security
|
||||
descriptors using SDDL. With this you can work around issues such as the
|
||||
mentioned "unprotected private key file" by specifying
|
||||
WinFsp 2021 (version 1.9) introduces a new FUSE option "FileSecurity",
|
||||
that allows the complete specification of file security descriptors
|
||||
using SDDL. With this you can work around issues such as the mentioned
|
||||
"unprotected private key file" by specifying
|
||||
-o FileSecurity="D:P(A;;FA;;;OW)", for file all access (FA) to the owner
|
||||
(OW).
|
||||
|
||||
@@ -3797,7 +3798,7 @@ and digits (for example v1.54.0) then it's a stable release so you won't
|
||||
need the --beta flag. Beta releases have an additional information
|
||||
similar to v1.54.0-beta.5111.06f1c0c61. (if you are a developer and use
|
||||
a locally built rclone, the version number will end with -DEV, you will
|
||||
have to rebuild it as it obvisously can't be distributed).
|
||||
have to rebuild it as it obviously can't be distributed).
|
||||
|
||||
If you previously installed rclone via a package manager, the package
|
||||
may include local documentation or configure services. You may wish to
|
||||
@@ -7123,7 +7124,7 @@ If you run rclone config file you will see where the default location is
|
||||
for you.
|
||||
|
||||
Use this flag to override the config location, e.g.
|
||||
rclone --config=".myconfig" .config.
|
||||
rclone --config=".myconfig" config.
|
||||
|
||||
If the location is set to empty string "" or the special value
|
||||
/notfound, or the os null device represented by value NUL on Windows and
|
||||
@@ -8566,7 +8567,7 @@ For example, to configure an S3 remote named mys3: without a config file
|
||||
Note that if you want to create a remote using environment variables you
|
||||
must create the ..._TYPE variable as above.
|
||||
|
||||
Note also that now rclone has connectionstrings, it is probably easier
|
||||
Note also that now rclone has connection strings, it is probably easier
|
||||
to use those instead which makes the above example
|
||||
|
||||
rclone lsd :s3,access_key_id=XXX,secret_access_key=XXX:
|
||||
@@ -11862,7 +11863,7 @@ These flags are available for every command.
|
||||
--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. The default is rclone/ version (default "rclone/v1.55.0")
|
||||
--user-agent string Set the user-agent to a specified string. The default is rclone/ version (default "rclone/v1.55.1")
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
|
||||
|
||||
@@ -28814,6 +28815,56 @@ Options:
|
||||
CHANGELOG
|
||||
|
||||
|
||||
v1.55.1 - 2021-04-26
|
||||
|
||||
See commits
|
||||
|
||||
- Bug Fixes
|
||||
- selfupdate
|
||||
- Dont detect FUSE if build is static (Ivan Andreev)
|
||||
- Add build tag noselfupdate (Ivan Andreev)
|
||||
- sync: Fix incorrect error reported by graceful cutoff (Nick
|
||||
Craig-Wood)
|
||||
- install.sh: fix macOS arm64 download (Nick Craig-Wood)
|
||||
- build: Fix version numbers in android branch builds (Nick
|
||||
Craig-Wood)
|
||||
- docs
|
||||
- Contributing.md: update setup instructions for go1.16 (Nick
|
||||
Gaya)
|
||||
- WinFsp 2021 is out of beta (albertony)
|
||||
- Minor cleanup of space around code section (albertony)
|
||||
- Fixed some typos (albertony)
|
||||
- VFS
|
||||
- Fix a code path which allows dirty data to be removed causing
|
||||
data loss (Nick Craig-Wood)
|
||||
- Compress
|
||||
- Fix compressed name regexp (buengese)
|
||||
- Drive
|
||||
- Fix backend copyid of google doc to directory (Nick Craig-Wood)
|
||||
- Don't open browser when service account... (Ansh Mittal)
|
||||
- Dropbox
|
||||
- Add missing team_data.member scope for use with --impersonate
|
||||
(Nick Craig-Wood)
|
||||
- Fix About after scopes changes - rclone config reconnect needed
|
||||
(Nick Craig-Wood)
|
||||
- Fix Unable to decrypt returned paths from changeNotify (Nick
|
||||
Craig-Wood)
|
||||
- FTP
|
||||
- Fix implicit TLS (Ivan Andreev)
|
||||
- Onedrive
|
||||
- Work around for random "Unable to initialize RPS" errors
|
||||
(OleFrost)
|
||||
- SFTP
|
||||
- Revert sftp library to v1.12.0 from v1.13.0 to fix performance
|
||||
regression (Nick Craig-Wood)
|
||||
- Fix Update ReadFrom failed: failed to send packet: EOF errors
|
||||
(Nick Craig-Wood)
|
||||
- Zoho
|
||||
- Fix error when region isn't set (buengese)
|
||||
- Do not ask for mountpoint twice when using headless setup
|
||||
(buengese)
|
||||
|
||||
|
||||
v1.55.0 - 2021-03-31
|
||||
|
||||
See commits
|
||||
|
||||
@@ -41,7 +41,6 @@ import (
|
||||
_ "github.com/rclone/rclone/backend/swift"
|
||||
_ "github.com/rclone/rclone/backend/tardigrade"
|
||||
_ "github.com/rclone/rclone/backend/union"
|
||||
_ "github.com/rclone/rclone/backend/uptobox"
|
||||
_ "github.com/rclone/rclone/backend/webdav"
|
||||
_ "github.com/rclone/rclone/backend/yandex"
|
||||
_ "github.com/rclone/rclone/backend/zoho"
|
||||
|
||||
@@ -2,11 +2,12 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fs/fserrors"
|
||||
"github.com/rclone/rclone/lib/version"
|
||||
)
|
||||
|
||||
// Error describes a B2 error response
|
||||
@@ -62,17 +63,16 @@ func (t *Timestamp) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasVersion returns true if it looks like the passed filename has a timestamp on it.
|
||||
//
|
||||
// Note that the passed filename's timestamp may still be invalid even if this
|
||||
// function returns true.
|
||||
func HasVersion(remote string) bool {
|
||||
return version.Match(remote)
|
||||
}
|
||||
const versionFormat = "-v2006-01-02-150405.000"
|
||||
|
||||
// AddVersion adds the timestamp as a version string into the filename passed in.
|
||||
func (t Timestamp) AddVersion(remote string) string {
|
||||
return version.Add(remote, time.Time(t))
|
||||
ext := path.Ext(remote)
|
||||
base := remote[:len(remote)-len(ext)]
|
||||
s := time.Time(t).Format(versionFormat)
|
||||
// Replace the '.' with a '-'
|
||||
s = strings.Replace(s, ".", "-", -1)
|
||||
return base + s + ext
|
||||
}
|
||||
|
||||
// RemoveVersion removes the timestamp from a filename as a version string.
|
||||
@@ -80,9 +80,24 @@ func (t Timestamp) AddVersion(remote string) string {
|
||||
// It returns the new file name and a timestamp, or the old filename
|
||||
// and a zero timestamp.
|
||||
func RemoveVersion(remote string) (t Timestamp, newRemote string) {
|
||||
time, newRemote := version.Remove(remote)
|
||||
t = Timestamp(time)
|
||||
return
|
||||
newRemote = remote
|
||||
ext := path.Ext(remote)
|
||||
base := remote[:len(remote)-len(ext)]
|
||||
if len(base) < len(versionFormat) {
|
||||
return
|
||||
}
|
||||
versionStart := len(base) - len(versionFormat)
|
||||
// Check it ends in -xxx
|
||||
if base[len(base)-4] != '-' {
|
||||
return
|
||||
}
|
||||
// Replace with .xxx for parsing
|
||||
base = base[:len(base)-4] + "." + base[len(base)-3:]
|
||||
newT, err := time.Parse(versionFormat, base[versionStart:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return Timestamp(newT), base[:versionStart] + ext
|
||||
}
|
||||
|
||||
// IsZero returns true if the timestamp is uninitialized
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
var (
|
||||
emptyT api.Timestamp
|
||||
t0 = api.Timestamp(fstest.Time("1970-01-01T01:01:01.123456789Z"))
|
||||
t0r = api.Timestamp(fstest.Time("1970-01-01T01:01:01.123000000Z"))
|
||||
t1 = api.Timestamp(fstest.Time("2001-02-03T04:05:06.123000000Z"))
|
||||
)
|
||||
|
||||
@@ -35,6 +36,40 @@ func TestTimestampUnmarshalJSON(t *testing.T) {
|
||||
assert.Equal(t, (time.Time)(t1), (time.Time)(tActual))
|
||||
}
|
||||
|
||||
func TestTimestampAddVersion(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
t api.Timestamp
|
||||
in string
|
||||
expected string
|
||||
}{
|
||||
{t0, "potato.txt", "potato-v1970-01-01-010101-123.txt"},
|
||||
{t1, "potato", "potato-v2001-02-03-040506-123"},
|
||||
{t1, "", "-v2001-02-03-040506-123"},
|
||||
} {
|
||||
actual := test.t.AddVersion(test.in)
|
||||
assert.Equal(t, test.expected, actual, test.in)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestampRemoveVersion(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
expectedT api.Timestamp
|
||||
expectedRemote string
|
||||
}{
|
||||
{"potato.txt", emptyT, "potato.txt"},
|
||||
{"potato-v1970-01-01-010101-123.txt", t0r, "potato.txt"},
|
||||
{"potato-v2001-02-03-040506-123", t1, "potato"},
|
||||
{"-v2001-02-03-040506-123", t1, ""},
|
||||
{"potato-v2A01-02-03-040506-123", emptyT, "potato-v2A01-02-03-040506-123"},
|
||||
{"potato-v2001-02-03-040506=123", emptyT, "potato-v2001-02-03-040506=123"},
|
||||
} {
|
||||
actualT, actualRemote := api.RemoveVersion(test.in)
|
||||
assert.Equal(t, test.expectedT, actualT, test.in)
|
||||
assert.Equal(t, test.expectedRemote, actualRemote, test.in)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestampIsZero(t *testing.T) {
|
||||
assert.True(t, emptyT.IsZero())
|
||||
assert.False(t, t0.IsZero())
|
||||
|
||||
@@ -1353,7 +1353,7 @@ func (f *Fs) getDownloadAuthorization(ctx context.Context, bucket, remote string
|
||||
}
|
||||
var request = api.GetDownloadAuthorizationRequest{
|
||||
BucketID: bucketID,
|
||||
FileNamePrefix: f.opt.Enc.FromStandardPath(path.Join(f.rootDirectory, remote)),
|
||||
FileNamePrefix: f.opt.Enc.FromStandardPath(path.Join(f.root, remote)),
|
||||
ValidDurationInSeconds: validDurationInSeconds,
|
||||
}
|
||||
var response api.GetDownloadAuthorizationResponse
|
||||
|
||||
@@ -36,13 +36,13 @@ func (t *Time) UnmarshalJSON(data []byte) error {
|
||||
|
||||
// Error is returned from box when things go wrong
|
||||
type Error struct {
|
||||
Type string `json:"type"`
|
||||
Status int `json:"status"`
|
||||
Code string `json:"code"`
|
||||
ContextInfo json.RawMessage `json:"context_info"`
|
||||
HelpURL string `json:"help_url"`
|
||||
Message string `json:"message"`
|
||||
RequestID string `json:"request_id"`
|
||||
Type string `json:"type"`
|
||||
Status int `json:"status"`
|
||||
Code string `json:"code"`
|
||||
ContextInfo json.RawMessage
|
||||
HelpURL string `json:"help_url"`
|
||||
Message string `json:"message"`
|
||||
RequestID string `json:"request_id"`
|
||||
}
|
||||
|
||||
// Error returns a string for the error and satisfies the error interface
|
||||
@@ -132,38 +132,6 @@ type UploadFile struct {
|
||||
ContentModifiedAt Time `json:"content_modified_at"`
|
||||
}
|
||||
|
||||
// PreUploadCheck is the request for upload preflight check
|
||||
type PreUploadCheck struct {
|
||||
Name string `json:"name"`
|
||||
Parent Parent `json:"parent"`
|
||||
Size *int64 `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
// PreUploadCheckResponse is the response from upload preflight check
|
||||
// if successful
|
||||
type PreUploadCheckResponse struct {
|
||||
UploadToken string `json:"upload_token"`
|
||||
UploadURL string `json:"upload_url"`
|
||||
}
|
||||
|
||||
// PreUploadCheckConflict is returned in the ContextInfo error field
|
||||
// from PreUploadCheck when the error code is "item_name_in_use"
|
||||
type PreUploadCheckConflict struct {
|
||||
Conflicts struct {
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id"`
|
||||
FileVersion struct {
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Sha1 string `json:"sha1"`
|
||||
} `json:"file_version"`
|
||||
SequenceID string `json:"sequence_id"`
|
||||
Etag string `json:"etag"`
|
||||
Sha1 string `json:"sha1"`
|
||||
Name string `json:"name"`
|
||||
} `json:"conflicts"`
|
||||
}
|
||||
|
||||
// UpdateFileModTime is used in Update File Info
|
||||
type UpdateFileModTime struct {
|
||||
ContentModifiedAt Time `json:"content_modified_at"`
|
||||
|
||||
@@ -686,80 +686,22 @@ func (f *Fs) createObject(ctx context.Context, remote string, modTime time.Time,
|
||||
return o, leaf, directoryID, nil
|
||||
}
|
||||
|
||||
// preUploadCheck checks to see if a file can be uploaded
|
||||
//
|
||||
// It returns "", nil if the file is good to go
|
||||
// It returns "ID", nil if the file must be updated
|
||||
func (f *Fs) preUploadCheck(ctx context.Context, leaf, directoryID string, size int64) (ID string, err error) {
|
||||
check := api.PreUploadCheck{
|
||||
Name: f.opt.Enc.FromStandardName(leaf),
|
||||
Parent: api.Parent{
|
||||
ID: directoryID,
|
||||
},
|
||||
}
|
||||
if size >= 0 {
|
||||
check.Size = &size
|
||||
}
|
||||
opts := rest.Opts{
|
||||
Method: "OPTIONS",
|
||||
Path: "/files/content/",
|
||||
}
|
||||
var result api.PreUploadCheckResponse
|
||||
var resp *http.Response
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
resp, err = f.srv.CallJSON(ctx, &opts, &check, &result)
|
||||
return shouldRetry(ctx, resp, err)
|
||||
})
|
||||
if err != nil {
|
||||
if apiErr, ok := err.(*api.Error); ok && apiErr.Code == "item_name_in_use" {
|
||||
var conflict api.PreUploadCheckConflict
|
||||
err = json.Unmarshal(apiErr.ContextInfo, &conflict)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "pre-upload check: JSON decode failed")
|
||||
}
|
||||
if conflict.Conflicts.Type != api.ItemTypeFile {
|
||||
return "", errors.Wrap(err, "pre-upload check: can't overwrite non file with file")
|
||||
}
|
||||
return conflict.Conflicts.ID, nil
|
||||
}
|
||||
return "", errors.Wrap(err, "pre-upload check")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Put the object
|
||||
//
|
||||
// Copy the reader in to the new object which is returned
|
||||
//
|
||||
// The new object may have been created if an error is returned
|
||||
func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
|
||||
// If directory doesn't exist, file doesn't exist so can upload
|
||||
remote := src.Remote()
|
||||
leaf, directoryID, err := f.dirCache.FindPath(ctx, remote, false)
|
||||
if err != nil {
|
||||
if err == fs.ErrorDirNotFound {
|
||||
return f.PutUnchecked(ctx, in, src, options...)
|
||||
}
|
||||
existingObj, err := f.newObjectWithInfo(ctx, src.Remote(), nil)
|
||||
switch err {
|
||||
case nil:
|
||||
return existingObj, existingObj.Update(ctx, in, src, options...)
|
||||
case fs.ErrorObjectNotFound:
|
||||
// Not found so create it
|
||||
return f.PutUnchecked(ctx, in, src)
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Preflight check the upload, which returns the ID if the
|
||||
// object already exists
|
||||
ID, err := f.preUploadCheck(ctx, leaf, directoryID, src.Size())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ID == "" {
|
||||
return f.PutUnchecked(ctx, in, src, options...)
|
||||
}
|
||||
|
||||
// If object exists then create a skeleton one with just id
|
||||
o := &Object{
|
||||
fs: f,
|
||||
remote: remote,
|
||||
id: ID,
|
||||
}
|
||||
return o, o.Update(ctx, in, src, options...)
|
||||
}
|
||||
|
||||
// PutStream uploads to the remote path with the modTime given of indeterminate size
|
||||
|
||||
@@ -12,14 +12,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rclone/rclone/backend/crypt/pkcs7"
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/accounting"
|
||||
"github.com/rclone/rclone/lib/version"
|
||||
"github.com/rfjakob/eme"
|
||||
"golang.org/x/crypto/nacl/secretbox"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
@@ -444,32 +442,11 @@ func (c *Cipher) encryptFileName(in string) string {
|
||||
if !c.dirNameEncrypt && i != (len(segments)-1) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Strip version string so that only the non-versioned part
|
||||
// of the file name gets encrypted/obfuscated
|
||||
hasVersion := false
|
||||
var t time.Time
|
||||
if i == (len(segments)-1) && version.Match(segments[i]) {
|
||||
var s string
|
||||
t, s = version.Remove(segments[i])
|
||||
// version.Remove can fail, in which case it returns segments[i]
|
||||
if s != segments[i] {
|
||||
segments[i] = s
|
||||
hasVersion = true
|
||||
}
|
||||
}
|
||||
|
||||
if c.mode == NameEncryptionStandard {
|
||||
segments[i] = c.encryptSegment(segments[i])
|
||||
} else {
|
||||
segments[i] = c.obfuscateSegment(segments[i])
|
||||
}
|
||||
|
||||
// Add back a version to the encrypted/obfuscated
|
||||
// file name, if we stripped it off earlier
|
||||
if hasVersion {
|
||||
segments[i] = version.Add(segments[i], t)
|
||||
}
|
||||
}
|
||||
return strings.Join(segments, "/")
|
||||
}
|
||||
@@ -500,21 +477,6 @@ func (c *Cipher) decryptFileName(in string) (string, error) {
|
||||
if !c.dirNameEncrypt && i != (len(segments)-1) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Strip version string so that only the non-versioned part
|
||||
// of the file name gets decrypted/deobfuscated
|
||||
hasVersion := false
|
||||
var t time.Time
|
||||
if i == (len(segments)-1) && version.Match(segments[i]) {
|
||||
var s string
|
||||
t, s = version.Remove(segments[i])
|
||||
// version.Remove can fail, in which case it returns segments[i]
|
||||
if s != segments[i] {
|
||||
segments[i] = s
|
||||
hasVersion = true
|
||||
}
|
||||
}
|
||||
|
||||
if c.mode == NameEncryptionStandard {
|
||||
segments[i], err = c.decryptSegment(segments[i])
|
||||
} else {
|
||||
@@ -524,12 +486,6 @@ func (c *Cipher) decryptFileName(in string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Add back a version to the decrypted/deobfuscated
|
||||
// file name, if we stripped it off earlier
|
||||
if hasVersion {
|
||||
segments[i] = version.Add(segments[i], t)
|
||||
}
|
||||
}
|
||||
return strings.Join(segments, "/"), nil
|
||||
}
|
||||
@@ -538,18 +494,10 @@ func (c *Cipher) decryptFileName(in string) (string, error) {
|
||||
func (c *Cipher) DecryptFileName(in string) (string, error) {
|
||||
if c.mode == NameEncryptionOff {
|
||||
remainingLength := len(in) - len(encryptedSuffix)
|
||||
if remainingLength == 0 || !strings.HasSuffix(in, encryptedSuffix) {
|
||||
return "", ErrorNotAnEncryptedFile
|
||||
if remainingLength > 0 && strings.HasSuffix(in, encryptedSuffix) {
|
||||
return in[:remainingLength], nil
|
||||
}
|
||||
decrypted := in[:remainingLength]
|
||||
if version.Match(decrypted) {
|
||||
_, unversioned := version.Remove(decrypted)
|
||||
if unversioned == "" {
|
||||
return "", ErrorNotAnEncryptedFile
|
||||
}
|
||||
}
|
||||
// Leave the version string on, if it was there
|
||||
return decrypted, nil
|
||||
return "", ErrorNotAnEncryptedFile
|
||||
}
|
||||
return c.decryptFileName(in)
|
||||
}
|
||||
|
||||
@@ -160,29 +160,22 @@ func TestEncryptFileName(t *testing.T) {
|
||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s", c.EncryptFileName("1"))
|
||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", c.EncryptFileName("1/12"))
|
||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", c.EncryptFileName("1/12/123"))
|
||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s-v2001-02-03-040506-123", c.EncryptFileName("1-v2001-02-03-040506-123"))
|
||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng-v2001-02-03-040506-123", c.EncryptFileName("1/12-v2001-02-03-040506-123"))
|
||||
// Standard mode with directory name encryption off
|
||||
c, _ = newCipher(NameEncryptionStandard, "", "", false)
|
||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s", c.EncryptFileName("1"))
|
||||
assert.Equal(t, "1/l42g6771hnv3an9cgc8cr2n1ng", c.EncryptFileName("1/12"))
|
||||
assert.Equal(t, "1/12/qgm4avr35m5loi1th53ato71v0", c.EncryptFileName("1/12/123"))
|
||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s-v2001-02-03-040506-123", c.EncryptFileName("1-v2001-02-03-040506-123"))
|
||||
assert.Equal(t, "1/l42g6771hnv3an9cgc8cr2n1ng-v2001-02-03-040506-123", c.EncryptFileName("1/12-v2001-02-03-040506-123"))
|
||||
// Now off mode
|
||||
c, _ = newCipher(NameEncryptionOff, "", "", true)
|
||||
assert.Equal(t, "1/12/123.bin", c.EncryptFileName("1/12/123"))
|
||||
// Obfuscation mode
|
||||
c, _ = newCipher(NameEncryptionObfuscated, "", "", true)
|
||||
assert.Equal(t, "49.6/99.23/150.890/53.!!lipps", c.EncryptFileName("1/12/123/!hello"))
|
||||
assert.Equal(t, "49.6/99.23/150.890/53-v2001-02-03-040506-123.!!lipps", c.EncryptFileName("1/12/123/!hello-v2001-02-03-040506-123"))
|
||||
assert.Equal(t, "49.6/99.23/150.890/162.uryyB-v2001-02-03-040506-123.GKG", c.EncryptFileName("1/12/123/hello-v2001-02-03-040506-123.txt"))
|
||||
assert.Equal(t, "161.\u00e4", c.EncryptFileName("\u00a1"))
|
||||
assert.Equal(t, "160.\u03c2", c.EncryptFileName("\u03a0"))
|
||||
// Obfuscation mode with directory name encryption off
|
||||
c, _ = newCipher(NameEncryptionObfuscated, "", "", false)
|
||||
assert.Equal(t, "1/12/123/53.!!lipps", c.EncryptFileName("1/12/123/!hello"))
|
||||
assert.Equal(t, "1/12/123/53-v2001-02-03-040506-123.!!lipps", c.EncryptFileName("1/12/123/!hello-v2001-02-03-040506-123"))
|
||||
assert.Equal(t, "161.\u00e4", c.EncryptFileName("\u00a1"))
|
||||
assert.Equal(t, "160.\u03c2", c.EncryptFileName("\u03a0"))
|
||||
}
|
||||
@@ -201,19 +194,14 @@ func TestDecryptFileName(t *testing.T) {
|
||||
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", "1/12/123", nil},
|
||||
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1/qgm4avr35m5loi1th53ato71v0", "", ErrorNotAMultipleOfBlocksize},
|
||||
{NameEncryptionStandard, false, "1/12/qgm4avr35m5loi1th53ato71v0", "1/12/123", nil},
|
||||
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s-v2001-02-03-040506-123", "1-v2001-02-03-040506-123", nil},
|
||||
{NameEncryptionOff, true, "1/12/123.bin", "1/12/123", nil},
|
||||
{NameEncryptionOff, true, "1/12/123.bix", "", ErrorNotAnEncryptedFile},
|
||||
{NameEncryptionOff, true, ".bin", "", ErrorNotAnEncryptedFile},
|
||||
{NameEncryptionOff, true, "1/12/123-v2001-02-03-040506-123.bin", "1/12/123-v2001-02-03-040506-123", nil},
|
||||
{NameEncryptionOff, true, "1/12/123-v1970-01-01-010101-123-v2001-02-03-040506-123.bin", "1/12/123-v1970-01-01-010101-123-v2001-02-03-040506-123", nil},
|
||||
{NameEncryptionOff, true, "1/12/123-v1970-01-01-010101-123-v2001-02-03-040506-123.txt.bin", "1/12/123-v1970-01-01-010101-123-v2001-02-03-040506-123.txt", nil},
|
||||
{NameEncryptionObfuscated, true, "!.hello", "hello", nil},
|
||||
{NameEncryptionObfuscated, true, "hello", "", ErrorNotAnEncryptedFile},
|
||||
{NameEncryptionObfuscated, true, "161.\u00e4", "\u00a1", nil},
|
||||
{NameEncryptionObfuscated, true, "160.\u03c2", "\u03a0", nil},
|
||||
{NameEncryptionObfuscated, false, "1/12/123/53.!!lipps", "1/12/123/!hello", nil},
|
||||
{NameEncryptionObfuscated, false, "1/12/123/53-v2001-02-03-040506-123.!!lipps", "1/12/123/!hello-v2001-02-03-040506-123", nil},
|
||||
} {
|
||||
c, _ := newCipher(test.mode, "", "", test.dirNameEncrypt)
|
||||
actual, actualErr := c.DecryptFileName(test.in)
|
||||
|
||||
@@ -2959,12 +2959,12 @@ func (f *Fs) makeShortcut(ctx context.Context, srcPath string, dstFs *Fs, dstPat
|
||||
}
|
||||
|
||||
// List all team drives
|
||||
func (f *Fs) listTeamDrives(ctx context.Context) (drives []*drive.Drive, err error) {
|
||||
drives = []*drive.Drive{}
|
||||
listTeamDrives := f.svc.Drives.List().PageSize(100)
|
||||
func (f *Fs) listTeamDrives(ctx context.Context) (drives []*drive.TeamDrive, err error) {
|
||||
drives = []*drive.TeamDrive{}
|
||||
listTeamDrives := f.svc.Teamdrives.List().PageSize(100)
|
||||
var defaultFs Fs // default Fs with default Options
|
||||
for {
|
||||
var teamDrives *drive.DriveList
|
||||
var teamDrives *drive.TeamDriveList
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
teamDrives, err = listTeamDrives.Context(ctx).Do()
|
||||
return defaultFs.shouldRetry(ctx, err)
|
||||
@@ -2972,7 +2972,7 @@ func (f *Fs) listTeamDrives(ctx context.Context) (drives []*drive.Drive, err err
|
||||
if err != nil {
|
||||
return drives, errors.Wrap(err, "listing Team Drives failed")
|
||||
}
|
||||
drives = append(drives, teamDrives.Drives...)
|
||||
drives = append(drives, teamDrives.TeamDrives...)
|
||||
if teamDrives.NextPageToken == "" {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1086,30 +1086,13 @@ func (f *Fs) PublicLink(ctx context.Context, remote string, expire fs.Duration,
|
||||
fs.Debugf(f, "attempting to share '%s' (absolute path: %s)", remote, absPath)
|
||||
createArg := sharing.CreateSharedLinkWithSettingsArg{
|
||||
Path: absPath,
|
||||
Settings: &sharing.SharedLinkSettings{
|
||||
RequestedVisibility: &sharing.RequestedVisibility{
|
||||
Tagged: dropbox.Tagged{Tag: sharing.RequestedVisibilityPublic},
|
||||
},
|
||||
Audience: &sharing.LinkAudience{
|
||||
Tagged: dropbox.Tagged{Tag: sharing.LinkAudiencePublic},
|
||||
},
|
||||
Access: &sharing.RequestedLinkAccessLevel{
|
||||
Tagged: dropbox.Tagged{Tag: sharing.RequestedLinkAccessLevelViewer},
|
||||
},
|
||||
},
|
||||
// FIXME this gives settings_error/not_authorized/.. errors
|
||||
// and the expires setting isn't in the documentation so remove
|
||||
// for now.
|
||||
// Settings: &sharing.SharedLinkSettings{
|
||||
// Expires: time.Now().Add(time.Duration(expire)).UTC().Round(time.Second),
|
||||
// },
|
||||
}
|
||||
if expire < fs.DurationOff {
|
||||
expiryTime := time.Now().Add(time.Duration(expire)).UTC().Round(time.Second)
|
||||
createArg.Settings.Expires = expiryTime
|
||||
}
|
||||
// FIXME note we can't set Settings for non enterprise dropbox
|
||||
// because of https://github.com/dropbox/dropbox-sdk-go-unofficial/issues/75
|
||||
// however this only goes wrong when we set Expires, so as a
|
||||
// work-around remove Settings unless expire is set.
|
||||
if expire == fs.DurationOff {
|
||||
createArg.Settings = nil
|
||||
}
|
||||
|
||||
var linkRes sharing.IsSharedLinkMetadata
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
linkRes, err = f.sharing.CreateSharedLinkWithSettings(&createArg)
|
||||
|
||||
@@ -348,10 +348,8 @@ func (f *Fs) putUnchecked(ctx context.Context, in io.Reader, remote string, size
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(fileUploadResponse.Links) == 0 {
|
||||
return nil, errors.New("upload response not found")
|
||||
} else if len(fileUploadResponse.Links) > 1 {
|
||||
fs.Debugf(remote, "Multiple upload responses found, using the first")
|
||||
if len(fileUploadResponse.Links) != 1 {
|
||||
return nil, errors.New("unexpected amount of files")
|
||||
}
|
||||
|
||||
link := fileUploadResponse.Links[0]
|
||||
|
||||
@@ -361,11 +361,6 @@ This will only work if you are copying between two OneDrive *Personal* drives AN
|
||||
the files to copy are already shared between them. In other cases, rclone will
|
||||
fall back to normal copy (which will be slightly slower).`,
|
||||
Advanced: true,
|
||||
}, {
|
||||
Name: "list_chunk",
|
||||
Help: "Size of listing chunk.",
|
||||
Default: 1000,
|
||||
Advanced: true,
|
||||
}, {
|
||||
Name: "no_versions",
|
||||
Default: false,
|
||||
@@ -473,7 +468,6 @@ type Options struct {
|
||||
DriveType string `config:"drive_type"`
|
||||
ExposeOneNoteFiles bool `config:"expose_onenote_files"`
|
||||
ServerSideAcrossConfigs bool `config:"server_side_across_configs"`
|
||||
ListChunk int64 `config:"list_chunk"`
|
||||
NoVersions bool `config:"no_versions"`
|
||||
LinkScope string `config:"link_scope"`
|
||||
LinkType string `config:"link_type"`
|
||||
@@ -905,7 +899,7 @@ type listAllFn func(*api.Item) bool
|
||||
func (f *Fs) listAll(ctx context.Context, dirID string, directoriesOnly bool, filesOnly bool, fn listAllFn) (found bool, err error) {
|
||||
// Top parameter asks for bigger pages of data
|
||||
// https://dev.onedrive.com/odata/optional-query-parameters.htm
|
||||
opts := f.newOptsCall(dirID, "GET", fmt.Sprintf("/children?$top=%d", f.opt.ListChunk))
|
||||
opts := f.newOptsCall(dirID, "GET", "/children?$top=1000")
|
||||
OUTER:
|
||||
for {
|
||||
var result api.ListChildrenResponse
|
||||
@@ -1432,7 +1426,7 @@ func (f *Fs) PublicLink(ctx context.Context, remote string, expire fs.Duration,
|
||||
Password: f.opt.LinkPassword,
|
||||
}
|
||||
|
||||
if expire < fs.DurationOff {
|
||||
if expire < fs.Duration(time.Hour*24*365*100) {
|
||||
expiry := time.Now().Add(time.Duration(expire))
|
||||
share.Expiry = &expiry
|
||||
}
|
||||
@@ -1860,7 +1854,7 @@ func (o *Object) uploadMultipart(ctx context.Context, in io.Reader, size int64,
|
||||
fs.Debugf(o, "Cancelling multipart upload: %v", err)
|
||||
cancelErr := o.cancelUploadSession(ctx, uploadURL)
|
||||
if cancelErr != nil {
|
||||
fs.Logf(o, "Failed to cancel multipart upload: %v (upload failed due to: %v)", cancelErr, err)
|
||||
fs.Logf(o, "Failed to cancel multipart upload: %v", cancelErr)
|
||||
}
|
||||
})()
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
@@ -1510,6 +1511,11 @@ func s3Connection(ctx context.Context, opt *Options, client *http.Client) (*s3.S
|
||||
}),
|
||||
ExpiryWindow: 3 * time.Minute,
|
||||
},
|
||||
|
||||
// Pick up IAM role if we are in EKS
|
||||
&stscreds.WebIdentityRoleProvider{
|
||||
ExpiryWindow: 3 * time.Minute,
|
||||
},
|
||||
}
|
||||
cred := credentials.NewChainCredentials(providers)
|
||||
|
||||
|
||||
@@ -224,17 +224,6 @@ have a server which returns
|
||||
Then you may need to enable this flag.
|
||||
|
||||
If concurrent reads are disabled, the use_fstat option is ignored.
|
||||
`,
|
||||
Advanced: true,
|
||||
}, {
|
||||
Name: "disable_concurrent_writes",
|
||||
Default: false,
|
||||
Help: `If set don't use concurrent writes
|
||||
|
||||
Normally rclone uses concurrent writes to upload files. This improves
|
||||
the performance greatly, especially for distant servers.
|
||||
|
||||
This option disables concurrent writes should that be necessary.
|
||||
`,
|
||||
Advanced: true,
|
||||
}, {
|
||||
@@ -255,30 +244,29 @@ Set to 0 to keep connections indefinitely.
|
||||
|
||||
// Options defines the configuration for this backend
|
||||
type Options struct {
|
||||
Host string `config:"host"`
|
||||
User string `config:"user"`
|
||||
Port string `config:"port"`
|
||||
Pass string `config:"pass"`
|
||||
KeyPem string `config:"key_pem"`
|
||||
KeyFile string `config:"key_file"`
|
||||
KeyFilePass string `config:"key_file_pass"`
|
||||
PubKeyFile string `config:"pubkey_file"`
|
||||
KnownHostsFile string `config:"known_hosts_file"`
|
||||
KeyUseAgent bool `config:"key_use_agent"`
|
||||
UseInsecureCipher bool `config:"use_insecure_cipher"`
|
||||
DisableHashCheck bool `config:"disable_hashcheck"`
|
||||
AskPassword bool `config:"ask_password"`
|
||||
PathOverride string `config:"path_override"`
|
||||
SetModTime bool `config:"set_modtime"`
|
||||
Md5sumCommand string `config:"md5sum_command"`
|
||||
Sha1sumCommand string `config:"sha1sum_command"`
|
||||
SkipLinks bool `config:"skip_links"`
|
||||
Subsystem string `config:"subsystem"`
|
||||
ServerCommand string `config:"server_command"`
|
||||
UseFstat bool `config:"use_fstat"`
|
||||
DisableConcurrentReads bool `config:"disable_concurrent_reads"`
|
||||
DisableConcurrentWrites bool `config:"disable_concurrent_writes"`
|
||||
IdleTimeout fs.Duration `config:"idle_timeout"`
|
||||
Host string `config:"host"`
|
||||
User string `config:"user"`
|
||||
Port string `config:"port"`
|
||||
Pass string `config:"pass"`
|
||||
KeyPem string `config:"key_pem"`
|
||||
KeyFile string `config:"key_file"`
|
||||
KeyFilePass string `config:"key_file_pass"`
|
||||
PubKeyFile string `config:"pubkey_file"`
|
||||
KnownHostsFile string `config:"known_hosts_file"`
|
||||
KeyUseAgent bool `config:"key_use_agent"`
|
||||
UseInsecureCipher bool `config:"use_insecure_cipher"`
|
||||
DisableHashCheck bool `config:"disable_hashcheck"`
|
||||
AskPassword bool `config:"ask_password"`
|
||||
PathOverride string `config:"path_override"`
|
||||
SetModTime bool `config:"set_modtime"`
|
||||
Md5sumCommand string `config:"md5sum_command"`
|
||||
Sha1sumCommand string `config:"sha1sum_command"`
|
||||
SkipLinks bool `config:"skip_links"`
|
||||
Subsystem string `config:"subsystem"`
|
||||
ServerCommand string `config:"server_command"`
|
||||
UseFstat bool `config:"use_fstat"`
|
||||
DisableConcurrentReads bool `config:"disable_concurrent_reads"`
|
||||
IdleTimeout fs.Duration `config:"idle_timeout"`
|
||||
}
|
||||
|
||||
// Fs stores the interface to the remote SFTP files
|
||||
@@ -426,8 +414,8 @@ func (f *Fs) newSftpClient(conn *ssh.Client, opts ...sftp.ClientOption) (*sftp.C
|
||||
opts = opts[:len(opts):len(opts)] // make sure we don't overwrite the callers opts
|
||||
opts = append(opts,
|
||||
sftp.UseFstat(f.opt.UseFstat),
|
||||
sftp.UseConcurrentReads(!f.opt.DisableConcurrentReads),
|
||||
sftp.UseConcurrentWrites(!f.opt.DisableConcurrentWrites),
|
||||
// FIXME disabled after library reversion
|
||||
// sftp.UseConcurrentReads(!f.opt.DisableConcurrentReads),
|
||||
)
|
||||
if f.opt.DisableConcurrentReads { // FIXME
|
||||
fs.Errorf(f, "Ignoring disable_concurrent_reads after library reversion - see #5197")
|
||||
@@ -1506,19 +1494,6 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.Read
|
||||
return in, nil
|
||||
}
|
||||
|
||||
type sizeReader struct {
|
||||
io.Reader
|
||||
size int64
|
||||
}
|
||||
|
||||
// Size returns the expected size of the stream
|
||||
//
|
||||
// It is used in sftpFile.ReadFrom as a hint to work out the
|
||||
// concurrency needed
|
||||
func (sr *sizeReader) Size() int64 {
|
||||
return sr.size
|
||||
}
|
||||
|
||||
// Update a remote sftp file using the data <in> and ModTime from <src>
|
||||
func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
|
||||
o.fs.addTransfer() // Show transfer in progress
|
||||
@@ -1550,7 +1525,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
||||
fs.Debugf(src, "Removed after failed upload: %v", err)
|
||||
}
|
||||
}
|
||||
_, err = file.ReadFrom(&sizeReader{Reader: in, size: src.Size()})
|
||||
_, err = file.ReadFrom(in)
|
||||
if err != nil {
|
||||
remove()
|
||||
return errors.Wrap(err, "Update ReadFrom failed")
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
package api
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Error contains the error code and message returned by the API
|
||||
type Error struct {
|
||||
Success bool `json:"success,omitempty"`
|
||||
StatusCode int `json:"statusCode,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// Error returns a string for the error and satisfies the error interface
|
||||
func (e Error) Error() string {
|
||||
out := fmt.Sprintf("api error %d", e.StatusCode)
|
||||
if e.Message != "" {
|
||||
out += ": " + e.Message
|
||||
}
|
||||
if e.Data != "" {
|
||||
out += ": " + e.Data
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// FolderEntry represents a Uptobox subfolder when listing folder contents
|
||||
type FolderEntry struct {
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
Description string `json:"fld_descr"`
|
||||
Password string `json:"fld_password"`
|
||||
FullPath string `json:"fullPath"`
|
||||
Path string `json:"fld_name"`
|
||||
Name string `json:"name"`
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
|
||||
// FolderInfo represents the current folder when listing folder contents
|
||||
type FolderInfo struct {
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
Hash string `json:"hash"`
|
||||
FileCount uint64 `json:"fileCount"`
|
||||
TotalFileSize int64 `json:"totalFileSize"`
|
||||
}
|
||||
|
||||
// FileInfo represents a file when listing folder contents
|
||||
type FileInfo struct {
|
||||
Name string `json:"file_name"`
|
||||
Description string `json:"file_descr"`
|
||||
Created string `json:"file_created"`
|
||||
Size int64 `json:"file_size"`
|
||||
Downloads uint64 `json:"file_downloads"`
|
||||
Code string `json:"file_code"`
|
||||
Password string `json:"file_password"`
|
||||
Public int `json:"file_public"`
|
||||
LastDownload string `json:"file_last_download"`
|
||||
ID uint64 `json:"id"`
|
||||
}
|
||||
|
||||
// ReadMetadataResponse is the response when listing folder contents
|
||||
type ReadMetadataResponse struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
CurrentFolder FolderInfo `json:"currentFolder"`
|
||||
Folders []FolderEntry `json:"folders"`
|
||||
Files []FileInfo `json:"files"`
|
||||
PageCount int `json:"pageCount"`
|
||||
TotalFileCount int `json:"totalFileCount"`
|
||||
TotalFileSize int64 `json:"totalFileSize"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// UploadInfo is the response when initiating an upload
|
||||
type UploadInfo struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
UploadLink string `json:"uploadLink"`
|
||||
MaxUpload string `json:"maxUpload"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// UploadResponse is the respnse to a successful upload
|
||||
type UploadResponse struct {
|
||||
Files []struct {
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
URL string `json:"url"`
|
||||
DeleteURL string `json:"deleteUrl"`
|
||||
} `json:"files"`
|
||||
}
|
||||
|
||||
// UpdateResponse is a generic response to various action on files (rename/copy/move)
|
||||
type UpdateResponse struct {
|
||||
Message string `json:"message"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
}
|
||||
|
||||
// Download is the response when requesting a download link
|
||||
type Download struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
DownloadLink string `json:"dlLink"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// MetadataRequestOptions represents all the options when listing folder contents
|
||||
type MetadataRequestOptions struct {
|
||||
Limit uint64
|
||||
Offset uint64
|
||||
SearchField string
|
||||
Search string
|
||||
}
|
||||
|
||||
// CreateFolderRequest is used for creating a folder
|
||||
type CreateFolderRequest struct {
|
||||
Token string `json:"token"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// DeleteFolderRequest is used for deleting a folder
|
||||
type DeleteFolderRequest struct {
|
||||
Token string `json:"token"`
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
}
|
||||
|
||||
// CopyMoveFileRequest is used for moving/copying a file
|
||||
type CopyMoveFileRequest struct {
|
||||
Token string `json:"token"`
|
||||
FileCodes string `json:"file_codes"`
|
||||
DestinationFolderID uint64 `json:"destination_fld_id"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// MoveFolderRequest is used for moving a folder
|
||||
type MoveFolderRequest struct {
|
||||
Token string `json:"token"`
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
DestinationFolderID uint64 `json:"destination_fld_id"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// RenameFolderRequest is used for renaming a folder
|
||||
type RenameFolderRequest struct {
|
||||
Token string `json:"token"`
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
NewName string `json:"new_name"`
|
||||
}
|
||||
|
||||
// UpdateFileInformation is used for renaming a file
|
||||
type UpdateFileInformation struct {
|
||||
Token string `json:"token"`
|
||||
FileCode string `json:"file_code"`
|
||||
NewName string `json:"new_name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Public string `json:"public,omitempty"`
|
||||
}
|
||||
|
||||
// RemoveFileRequest is used for deleting a file
|
||||
type RemoveFileRequest struct {
|
||||
Token string `json:"token"`
|
||||
FileCodes string `json:"file_codes"`
|
||||
}
|
||||
|
||||
// Token represents the authentication token
|
||||
type Token struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
||||
// Test Uptobox filesystem interface
|
||||
package uptobox_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/backend/uptobox"
|
||||
"github.com/rclone/rclone/fstest"
|
||||
"github.com/rclone/rclone/fstest/fstests"
|
||||
)
|
||||
|
||||
// TestIntegration runs integration tests against the remote
|
||||
func TestIntegration(t *testing.T) {
|
||||
if *fstest.RemoteName == "" {
|
||||
*fstest.RemoteName = "TestUptobox:"
|
||||
}
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: *fstest.RemoteName,
|
||||
NilObject: (*uptobox.Object)(nil),
|
||||
})
|
||||
}
|
||||
@@ -125,7 +125,7 @@ func (ca *CookieAuth) getSPCookie(conf *SharepointSuccessResponse) (*CookieRespo
|
||||
return nil, errors.Wrap(err, "Error while constructing endpoint URL")
|
||||
}
|
||||
|
||||
u, err := url.Parse(spRoot.Scheme + "://" + spRoot.Host + "/_forms/default.aspx?wa=wsignin1.0")
|
||||
u, err := url.Parse("https://" + spRoot.Host + "/_forms/default.aspx?wa=wsignin1.0")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error while constructing login URL")
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ package webdav
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -20,7 +18,6 @@ import (
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -37,7 +34,6 @@ import (
|
||||
"github.com/rclone/rclone/fs/fserrors"
|
||||
"github.com/rclone/rclone/fs/fshttp"
|
||||
"github.com/rclone/rclone/fs/hash"
|
||||
"github.com/rclone/rclone/lib/atexit"
|
||||
"github.com/rclone/rclone/lib/encoder"
|
||||
"github.com/rclone/rclone/lib/pacer"
|
||||
"github.com/rclone/rclone/lib/rest"
|
||||
@@ -117,14 +113,6 @@ func init() {
|
||||
Name: config.ConfigEncoding,
|
||||
Help: configEncodingHelp,
|
||||
Advanced: true,
|
||||
}, {
|
||||
Name: "chunk_size",
|
||||
Help: `Chunk size to use for uploading (Nextcloud only)
|
||||
|
||||
Set to 0 to disable chunked uploading.
|
||||
`,
|
||||
Advanced: true,
|
||||
Default: fs.SizeSuffix(0), // off by default
|
||||
}},
|
||||
})
|
||||
}
|
||||
@@ -138,7 +126,6 @@ type Options struct {
|
||||
BearerToken string `config:"bearer_token"`
|
||||
BearerTokenCommand string `config:"bearer_token_command"`
|
||||
Enc encoder.MultiEncoder `config:"encoding"`
|
||||
ChunkSize fs.SizeSuffix `config:"chunk_size"`
|
||||
}
|
||||
|
||||
// Fs represents a remote webdav
|
||||
@@ -149,7 +136,6 @@ type Fs struct {
|
||||
features *fs.Features // optional features
|
||||
endpoint *url.URL // URL of the host
|
||||
endpointURL string // endpoint as a string
|
||||
uploadURL string // upload URL for nextcloud chunked
|
||||
srv *rest.Client // the connection to the one drive server
|
||||
pacer *fs.Pacer // pacer for API calls
|
||||
precision time.Duration // mod time precision
|
||||
@@ -160,7 +146,6 @@ type Fs struct {
|
||||
hasMD5 bool // set if can use owncloud style checksums for MD5
|
||||
hasSHA1 bool // set if can use owncloud style checksums for SHA1
|
||||
ntlmAuthMu sync.Mutex // mutex to serialize NTLM auth roundtrips
|
||||
canChunk bool // set if nextcloud and chunk_size is set
|
||||
}
|
||||
|
||||
// Object describes a webdav object
|
||||
@@ -472,12 +457,6 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// set the chunk size for testing
|
||||
func (f *Fs) setUploadChunkSize(cs fs.SizeSuffix) (old fs.SizeSuffix, err error) {
|
||||
old, f.opt.ChunkSize = f.opt.ChunkSize, cs
|
||||
return
|
||||
}
|
||||
|
||||
// sets the BearerToken up
|
||||
func (f *Fs) setBearerToken(token string) {
|
||||
f.opt.BearerToken = token
|
||||
@@ -521,8 +500,6 @@ func (f *Fs) fetchAndSetBearerToken() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var matchNextcloudURL = regexp.MustCompile(`^.*/dav/files/[^/]+/?$`)
|
||||
|
||||
// setQuirks adjusts the Fs for the vendor passed in
|
||||
func (f *Fs) setQuirks(ctx context.Context, vendor string) error {
|
||||
switch vendor {
|
||||
@@ -536,12 +513,6 @@ func (f *Fs) setQuirks(ctx context.Context, vendor string) error {
|
||||
f.precision = time.Second
|
||||
f.useOCMtime = true
|
||||
f.hasSHA1 = true
|
||||
f.canChunk = true
|
||||
if f.opt.ChunkSize != 0 && !matchNextcloudURL.MatchString(f.endpointURL) {
|
||||
return errors.New("chunked upload with nextcloud must use /dav/files/USER endpoint not /webdav")
|
||||
}
|
||||
f.uploadURL = strings.Replace(f.endpointURL, "/dav/files/", "/dav/uploads/", 1)
|
||||
fs.Logf(nil, f.uploadURL)
|
||||
case "sharepoint":
|
||||
// To mount sharepoint, two Cookies are required
|
||||
// They have to be set instead of BasicAuth
|
||||
@@ -985,7 +956,7 @@ func (f *Fs) copyOrMove(ctx context.Context, src fs.Object, remote string, metho
|
||||
dstPath := f.filePath(remote)
|
||||
err := f.mkParentDir(ctx, dstPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "copy mkParentDir failed")
|
||||
return nil, errors.Wrap(err, "Copy mkParentDir failed")
|
||||
}
|
||||
destinationURL, err := rest.URLJoin(f.endpoint, dstPath)
|
||||
if err != nil {
|
||||
@@ -1009,11 +980,11 @@ func (f *Fs) copyOrMove(ctx context.Context, src fs.Object, remote string, metho
|
||||
return f.shouldRetry(ctx, resp, err)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "copy call failed")
|
||||
return nil, errors.Wrap(err, "Copy call failed")
|
||||
}
|
||||
dstObj, err := f.NewObject(ctx, remote)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "copy NewObject failed")
|
||||
return nil, errors.Wrap(err, "Copy NewObject failed")
|
||||
}
|
||||
return dstObj, nil
|
||||
}
|
||||
@@ -1076,18 +1047,18 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string
|
||||
return fs.ErrorDirExists
|
||||
}
|
||||
if err != fs.ErrorDirNotFound {
|
||||
return errors.Wrap(err, "dirMove dirExists dst failed")
|
||||
return errors.Wrap(err, "DirMove dirExists dst failed")
|
||||
}
|
||||
|
||||
// Make sure the parent directory exists
|
||||
err = f.mkParentDir(ctx, dstPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dirMove mkParentDir dst failed")
|
||||
return errors.Wrap(err, "DirMove mkParentDir dst failed")
|
||||
}
|
||||
|
||||
destinationURL, err := rest.URLJoin(f.endpoint, dstPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dirMove couldn't join URL")
|
||||
return errors.Wrap(err, "DirMove couldn't join URL")
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
@@ -1105,7 +1076,7 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string
|
||||
return f.shouldRetry(ctx, resp, err)
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dirMove MOVE call failed")
|
||||
return errors.Wrap(err, "DirMove MOVE call failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1288,67 +1259,39 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.Read
|
||||
func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (err error) {
|
||||
err = o.fs.mkParentDir(ctx, o.filePath())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "update mkParentDir failed")
|
||||
return errors.Wrap(err, "Update mkParentDir failed")
|
||||
}
|
||||
|
||||
size := src.Size()
|
||||
if o.fs.canChunk && o.fs.opt.ChunkSize > 0 && size > int64(o.fs.opt.ChunkSize) {
|
||||
err = o.updateChunked(ctx, in, src, options...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
contentType := fs.MimeType(ctx, src)
|
||||
filePath := o.filePath()
|
||||
extraHeaders := o.extraHeaders(ctx, src)
|
||||
err = o.updateSimple(ctx, in, filePath, size, contentType, extraHeaders, o.fs.endpointURL, options...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var resp *http.Response
|
||||
opts := rest.Opts{
|
||||
Method: "PUT",
|
||||
Path: o.filePath(),
|
||||
Body: in,
|
||||
NoResponse: true,
|
||||
ContentLength: &size, // FIXME this isn't necessary with owncloud - See https://github.com/nextcloud/nextcloud-snap/issues/365
|
||||
ContentType: fs.MimeType(ctx, src),
|
||||
Options: options,
|
||||
}
|
||||
|
||||
// read metadata from remote
|
||||
o.hasMetaData = false
|
||||
return o.readMetaData(ctx)
|
||||
}
|
||||
|
||||
func (o *Object) extraHeaders(ctx context.Context, src fs.ObjectInfo) map[string]string {
|
||||
extraHeaders := map[string]string{}
|
||||
if o.fs.useOCMtime || o.fs.hasMD5 || o.fs.hasSHA1 {
|
||||
opts.ExtraHeaders = map[string]string{}
|
||||
if o.fs.useOCMtime {
|
||||
extraHeaders["X-OC-Mtime"] = fmt.Sprintf("%d", src.ModTime(ctx).Unix())
|
||||
opts.ExtraHeaders["X-OC-Mtime"] = fmt.Sprintf("%d", src.ModTime(ctx).Unix())
|
||||
}
|
||||
// Set one upload checksum
|
||||
// Owncloud uses one checksum only to check the upload and stores its own SHA1 and MD5
|
||||
// Nextcloud stores the checksum you supply (SHA1 or MD5) but only stores one
|
||||
if o.fs.hasSHA1 {
|
||||
if sha1, _ := src.Hash(ctx, hash.SHA1); sha1 != "" {
|
||||
extraHeaders["OC-Checksum"] = "SHA1:" + sha1
|
||||
opts.ExtraHeaders["OC-Checksum"] = "SHA1:" + sha1
|
||||
}
|
||||
}
|
||||
if o.fs.hasMD5 && extraHeaders["OC-Checksum"] == "" {
|
||||
if o.fs.hasMD5 && opts.ExtraHeaders["OC-Checksum"] == "" {
|
||||
if md5, _ := src.Hash(ctx, hash.MD5); md5 != "" {
|
||||
extraHeaders["OC-Checksum"] = "MD5:" + md5
|
||||
opts.ExtraHeaders["OC-Checksum"] = "MD5:" + md5
|
||||
}
|
||||
}
|
||||
}
|
||||
return extraHeaders
|
||||
}
|
||||
|
||||
// Standard update
|
||||
func (o *Object) updateSimple(ctx context.Context, in io.Reader, filePath string, size int64, contentType string, extraHeaders map[string]string, rootURL string, options ...fs.OpenOption) (err error) {
|
||||
var resp *http.Response
|
||||
opts := rest.Opts{
|
||||
Method: "PUT",
|
||||
Path: filePath,
|
||||
Body: in,
|
||||
NoResponse: true,
|
||||
ContentLength: &size, // FIXME this isn't necessary with owncloud - See https://github.com/nextcloud/nextcloud-snap/issues/365
|
||||
ContentType: contentType,
|
||||
Options: options,
|
||||
ExtraHeaders: extraHeaders,
|
||||
RootURL: rootURL,
|
||||
}
|
||||
err = o.fs.pacer.CallNoRetry(func() (bool, error) {
|
||||
resp, err = o.fs.srv.Call(ctx, &opts)
|
||||
return o.fs.shouldRetry(ctx, resp, err)
|
||||
@@ -1364,85 +1307,9 @@ func (o *Object) updateSimple(ctx context.Context, in io.Reader, filePath string
|
||||
_ = o.Remove(ctx)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Chunked update for Nextcloud (see
|
||||
// https://docs.nextcloud.com/server/20/developer_manual/client_apis/WebDAV/chunking.html)
|
||||
func (o *Object) updateChunked(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (err error) {
|
||||
hasher := md5.New()
|
||||
_, err = hasher.Write([]byte(o.filePath()))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "chunked upload couldn't hash URL")
|
||||
}
|
||||
uploadDir := "rclone-chunked-upload-" + hex.EncodeToString(hasher.Sum(nil))
|
||||
fs.Debugf(src, "Starting multipart upload to temp dir %q", uploadDir)
|
||||
|
||||
opts := rest.Opts{
|
||||
Method: "MKCOL",
|
||||
Path: uploadDir + "/",
|
||||
NoResponse: true,
|
||||
RootURL: o.fs.uploadURL,
|
||||
}
|
||||
err = o.fs.pacer.Call(func() (bool, error) {
|
||||
resp, err := o.fs.srv.Call(ctx, &opts)
|
||||
return o.fs.shouldRetry(ctx, resp, err)
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "making upload directory failed")
|
||||
}
|
||||
defer atexit.OnError(&err, func() {
|
||||
// Try to abort the upload, but ignore the error.
|
||||
fs.Debugf(src, "Cancelling chunked upload")
|
||||
_ = o.fs.Purge(ctx, uploadDir)
|
||||
})()
|
||||
|
||||
var (
|
||||
size = src.Size()
|
||||
uploadedSize = int64(0)
|
||||
partObj = &Object{
|
||||
fs: o.fs,
|
||||
}
|
||||
)
|
||||
for uploadedSize < size {
|
||||
// Upload chunk
|
||||
contentLength := int64(partObj.fs.opt.ChunkSize)
|
||||
if size-uploadedSize < contentLength {
|
||||
contentLength = size - uploadedSize
|
||||
}
|
||||
partObj.remote = fmt.Sprintf("%s/%015d-%015d", uploadDir, uploadedSize, uploadedSize+contentLength)
|
||||
extraHeaders := map[string]string{}
|
||||
err = partObj.updateSimple(ctx, io.LimitReader(in, int64(partObj.fs.opt.ChunkSize)), partObj.remote, contentLength, "", extraHeaders, o.fs.uploadURL, options...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "uploading chunk failed")
|
||||
}
|
||||
uploadedSize += contentLength
|
||||
}
|
||||
|
||||
// Finish
|
||||
var resp *http.Response
|
||||
opts = rest.Opts{
|
||||
Method: "MOVE",
|
||||
Path: o.fs.filePath(path.Join(uploadDir, ".file")),
|
||||
NoResponse: true,
|
||||
Options: options,
|
||||
RootURL: o.fs.uploadURL,
|
||||
}
|
||||
destinationURL, err := rest.URLJoin(o.fs.endpoint, o.filePath())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "finalize chunked upload couldn't join URL")
|
||||
}
|
||||
opts.ExtraHeaders = o.extraHeaders(ctx, src)
|
||||
opts.ExtraHeaders["Destination"] = destinationURL.String()
|
||||
err = o.fs.pacer.CallNoRetry(func() (bool, error) {
|
||||
resp, err = o.fs.srv.Call(ctx, &opts)
|
||||
return o.fs.shouldRetry(ctx, resp, err)
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "finalize chunked upload failed")
|
||||
}
|
||||
return nil
|
||||
// read metadata from remote
|
||||
o.hasMetaData = false
|
||||
return o.readMetaData(ctx)
|
||||
}
|
||||
|
||||
// Remove an object
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Test Webdav filesystem interface
|
||||
package webdav
|
||||
package webdav_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/backend/webdav"
|
||||
"github.com/rclone/rclone/fstest"
|
||||
"github.com/rclone/rclone/fstest/fstests"
|
||||
)
|
||||
@@ -13,10 +13,7 @@ import (
|
||||
func TestIntegration(t *testing.T) {
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: "TestWebdavNextcloud:",
|
||||
NilObject: (*Object)(nil),
|
||||
ChunkedUpload: fstests.ChunkedUploadConfig{
|
||||
MinChunkSize: 1 * fs.MebiByte,
|
||||
},
|
||||
NilObject: (*webdav.Object)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -27,10 +24,7 @@ func TestIntegration2(t *testing.T) {
|
||||
}
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: "TestWebdavOwncloud:",
|
||||
NilObject: (*Object)(nil),
|
||||
ChunkedUpload: fstests.ChunkedUploadConfig{
|
||||
Skip: true,
|
||||
},
|
||||
NilObject: (*webdav.Object)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -41,10 +35,7 @@ func TestIntegration3(t *testing.T) {
|
||||
}
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: "TestWebdavRclone:",
|
||||
NilObject: (*Object)(nil),
|
||||
ChunkedUpload: fstests.ChunkedUploadConfig{
|
||||
Skip: true,
|
||||
},
|
||||
NilObject: (*webdav.Object)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -55,10 +46,6 @@ func TestIntegration4(t *testing.T) {
|
||||
}
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: "TestWebdavNTLM:",
|
||||
NilObject: (*Object)(nil),
|
||||
NilObject: (*webdav.Object)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
func (f *Fs) SetUploadChunkSize(cs fs.SizeSuffix) (fs.SizeSuffix, error) {
|
||||
return f.setUploadChunkSize(cs)
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ docs = [
|
||||
"sftp.md",
|
||||
"sugarsync.md",
|
||||
"tardigrade.md",
|
||||
"uptobox.md",
|
||||
"union.md",
|
||||
"webdav.md",
|
||||
"yandex.md",
|
||||
|
||||
@@ -54,7 +54,6 @@ import (
|
||||
_ "github.com/rclone/rclone/cmd/size"
|
||||
_ "github.com/rclone/rclone/cmd/sync"
|
||||
_ "github.com/rclone/rclone/cmd/test"
|
||||
_ "github.com/rclone/rclone/cmd/test/changenotify"
|
||||
_ "github.com/rclone/rclone/cmd/test/histogram"
|
||||
_ "github.com/rclone/rclone/cmd/test/info"
|
||||
_ "github.com/rclone/rclone/cmd/test/makefiles"
|
||||
|
||||
11
cmd/cmd.go
11
cmd/cmd.go
@@ -75,19 +75,8 @@ const (
|
||||
|
||||
// ShowVersion prints the version to stdout
|
||||
func ShowVersion() {
|
||||
osVersion, osKernel := buildinfo.GetOSVersion()
|
||||
if osVersion == "" {
|
||||
osVersion = "unknown"
|
||||
}
|
||||
if osKernel == "" {
|
||||
osKernel = "unknown"
|
||||
}
|
||||
|
||||
linking, tagString := buildinfo.GetLinkingAndTags()
|
||||
|
||||
fmt.Printf("rclone %s\n", fs.Version)
|
||||
fmt.Printf("- os/version: %s\n", osVersion)
|
||||
fmt.Printf("- os/kernel: %s\n", osKernel)
|
||||
fmt.Printf("- os/type: %s\n", runtime.GOOS)
|
||||
fmt.Printf("- os/arch: %s\n", runtime.GOARCH)
|
||||
fmt.Printf("- go/version: %s\n", runtime.Version())
|
||||
|
||||
@@ -22,7 +22,6 @@ func init() {
|
||||
cmd.Root.AddCommand(configCommand)
|
||||
configCommand.AddCommand(configEditCommand)
|
||||
configCommand.AddCommand(configFileCommand)
|
||||
configCommand.AddCommand(configTouchCommand)
|
||||
configCommand.AddCommand(configShowCommand)
|
||||
configCommand.AddCommand(configDumpCommand)
|
||||
configCommand.AddCommand(configProvidersCommand)
|
||||
@@ -64,15 +63,6 @@ var configFileCommand = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var configTouchCommand = &cobra.Command{
|
||||
Use: "touch",
|
||||
Short: `Ensure configuration file exists.`,
|
||||
Run: func(command *cobra.Command, args []string) {
|
||||
cmd.CheckArgs(0, 0, command, args)
|
||||
config.SaveConfig()
|
||||
},
|
||||
}
|
||||
|
||||
var configShowCommand = &cobra.Command{
|
||||
Use: "show [<remote>]",
|
||||
Short: `Print (decrypted) config file, or the config for a single remote.`,
|
||||
|
||||
@@ -3,6 +3,7 @@ package link
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/cmd"
|
||||
"github.com/rclone/rclone/fs"
|
||||
@@ -12,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
expire = fs.DurationOff
|
||||
expire = fs.Duration(time.Hour * 24 * 365 * 100)
|
||||
unlink = false
|
||||
)
|
||||
|
||||
|
||||
@@ -342,38 +342,19 @@ by specifying |-o FileSecurity="D:P(A;;FA;;;OW)"|, for file all access (FA) to t
|
||||
|
||||
#### Windows caveats
|
||||
|
||||
Drives created as Administrator are not visible to other accounts,
|
||||
not even an account that was elevated to Administrator with the
|
||||
User Account Control (UAC) feature. A result of this is that if you mount
|
||||
to a drive letter from a Command Prompt run as Administrator, and then try
|
||||
to access the same drive from Windows Explorer (which does not run as
|
||||
Administrator), you will not be able to see the mounted drive.
|
||||
Note that drives created as Administrator are not visible by other
|
||||
accounts (including the account that was elevated as
|
||||
Administrator). So if you start a Windows drive from an Administrative
|
||||
Command Prompt and then try to access the same drive from Explorer
|
||||
(which does not run as Administrator), you will not be able to see the
|
||||
new drive.
|
||||
|
||||
If you don't need to access the drive from applications running with
|
||||
administrative privileges, the easiest way around this is to always
|
||||
create the mount from a non-elevated command prompt.
|
||||
|
||||
To make mapped drives available to the user account that created them
|
||||
regardless if elevated or not, there is a special Windows setting called
|
||||
[linked connections](https://docs.microsoft.com/en-us/troubleshoot/windows-client/networking/mapped-drives-not-available-from-elevated-command#detail-to-configure-the-enablelinkedconnections-registry-entry)
|
||||
that can be enabled.
|
||||
|
||||
It is also possible to make a drive mount available to everyone on the system,
|
||||
by running the process creating it as the built-in SYSTEM account.
|
||||
There are several ways to do this: One is to use the command-line
|
||||
utility [PsExec](https://docs.microsoft.com/en-us/sysinternals/downloads/psexec),
|
||||
from Microsoft's Sysinternals suite, which has option |-s| to start
|
||||
processes as the SYSTEM account. Another alternative is to run the mount
|
||||
command from a Windows Scheduled Task, or a Windows Service, configured
|
||||
to run as the SYSTEM account. A third alternative is to use the
|
||||
[WinFsp.Launcher infrastructure](https://github.com/billziss-gh/winfsp/wiki/WinFsp-Service-Architecture)).
|
||||
Note that when running rclone as another user, it will not use
|
||||
the configuration file from your profile unless you tell it to
|
||||
with the [|--config|](https://rclone.org/docs/#config-config-file) option.
|
||||
Read more in the [install documentation](https://rclone.org/install/).
|
||||
|
||||
Note that mapping to a directory path, instead of a drive letter,
|
||||
does not suffer from the same limitations.
|
||||
The easiest way around this is to start the drive from a normal
|
||||
command prompt. It is also possible to start a drive from the SYSTEM
|
||||
account (using [the WinFsp.Launcher
|
||||
infrastructure](https://github.com/billziss-gh/winfsp/wiki/WinFsp-Service-Architecture))
|
||||
which creates drives accessible for everyone on the system or
|
||||
alternatively using [the nssm service manager](https://nssm.cc/usage).
|
||||
|
||||
### Limitations
|
||||
|
||||
|
||||
@@ -485,15 +485,11 @@ func (u *UI) removeEntry(pos int) {
|
||||
|
||||
// delete the entry at the current position
|
||||
func (u *UI) delete() {
|
||||
if u.d == nil || len(u.entries) == 0 {
|
||||
return
|
||||
}
|
||||
ctx := context.Background()
|
||||
cursorPos := u.dirPosMap[u.path]
|
||||
dirPos := u.sortPerm[cursorPos.entry]
|
||||
dirEntry := u.entries[dirPos]
|
||||
dirPos := u.sortPerm[u.dirPosMap[u.path].entry]
|
||||
entry := u.entries[dirPos]
|
||||
u.boxMenu = []string{"cancel", "confirm"}
|
||||
if obj, isFile := dirEntry.(fs.Object); isFile {
|
||||
if obj, isFile := entry.(fs.Object); isFile {
|
||||
u.boxMenuHandler = func(f fs.Fs, p string, o int) (string, error) {
|
||||
if o != 1 {
|
||||
return "Aborted!", nil
|
||||
@@ -503,33 +499,27 @@ func (u *UI) delete() {
|
||||
return "", err
|
||||
}
|
||||
u.removeEntry(dirPos)
|
||||
if cursorPos.entry >= len(u.entries) {
|
||||
u.move(-1) // move back onto a valid entry
|
||||
}
|
||||
return "Successfully deleted file!", nil
|
||||
}
|
||||
u.popupBox([]string{
|
||||
"Delete this file?",
|
||||
u.fsName + dirEntry.String()})
|
||||
u.fsName + entry.String()})
|
||||
} else {
|
||||
u.boxMenuHandler = func(f fs.Fs, p string, o int) (string, error) {
|
||||
if o != 1 {
|
||||
return "Aborted!", nil
|
||||
}
|
||||
err := operations.Purge(ctx, f, dirEntry.String())
|
||||
err := operations.Purge(ctx, f, entry.String())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u.removeEntry(dirPos)
|
||||
if cursorPos.entry >= len(u.entries) {
|
||||
u.move(-1) // move back onto a valid entry
|
||||
}
|
||||
return "Successfully purged folder!", nil
|
||||
}
|
||||
u.popupBox([]string{
|
||||
"Purge this directory?",
|
||||
"ALL files in it will be deleted",
|
||||
u.fsName + dirEntry.String()})
|
||||
u.fsName + entry.String()})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,19 +7,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/cmd"
|
||||
"github.com/rclone/rclone/fs/config/flags"
|
||||
"github.com/rclone/rclone/fs/operations"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
size = int64(-1)
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.Root.AddCommand(commandDefinition)
|
||||
cmdFlags := commandDefinition.Flags()
|
||||
flags.Int64VarP(cmdFlags, &size, "size", "", size, "File size hint to preallocate")
|
||||
}
|
||||
|
||||
var commandDefinition = &cobra.Command{
|
||||
@@ -44,13 +37,6 @@ must fit into RAM. The cutoff needs to be small enough to adhere
|
||||
the limits of your remote, please see there. Generally speaking,
|
||||
setting this cutoff too high will decrease your performance.
|
||||
|
||||
Use the |--size| flag to preallocate the file in advance at the remote end
|
||||
and actually stream it, even if remote backend doesn't support streaming.
|
||||
|
||||
|--size| should be the exact size of the input stream in bytes. If the
|
||||
size of the stream is different in length to the |--size| passed in
|
||||
then the transfer will likely fail.
|
||||
|
||||
Note that the upload can also not be retried because the data is
|
||||
not kept around until the upload succeeds. If you need to transfer
|
||||
a lot of data, you're better off caching locally and then
|
||||
@@ -65,7 +51,7 @@ a lot of data, you're better off caching locally and then
|
||||
|
||||
fdst, dstFileName := cmd.NewFsDstFile(args)
|
||||
cmd.Run(false, false, command, func() error {
|
||||
_, err := operations.RcatSize(context.Background(), fdst, dstFileName, os.Stdin, size, time.Now())
|
||||
_, err := operations.Rcat(context.Background(), fdst, dstFileName, os.Stdin, time.Now())
|
||||
return err
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// Package changenotify tests rclone's changenotify support
|
||||
package changenotify
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/cmd"
|
||||
"github.com/rclone/rclone/cmd/test"
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/config/flags"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
pollInterval = 10 * time.Second
|
||||
)
|
||||
|
||||
func init() {
|
||||
test.Command.AddCommand(commandDefinition)
|
||||
cmdFlags := commandDefinition.Flags()
|
||||
flags.DurationVarP(cmdFlags, &pollInterval, "poll-interval", "", pollInterval, "Time to wait between polling for changes.")
|
||||
}
|
||||
|
||||
var commandDefinition = &cobra.Command{
|
||||
Use: "changenotify remote:",
|
||||
Short: `Log any change notify requests for the remote passed in.`,
|
||||
RunE: func(command *cobra.Command, args []string) error {
|
||||
cmd.CheckArgs(1, 1, command, args)
|
||||
f := cmd.NewFsSrc(args)
|
||||
ctx := context.Background()
|
||||
|
||||
// Start polling function
|
||||
features := f.Features()
|
||||
if do := features.ChangeNotify; do != nil {
|
||||
pollChan := make(chan time.Duration)
|
||||
do(ctx, changeNotify, pollChan)
|
||||
pollChan <- pollInterval
|
||||
fs.Logf(nil, "Waiting for changes, polling every %v", pollInterval)
|
||||
} else {
|
||||
return errors.New("poll-interval is not supported by this remote")
|
||||
}
|
||||
select {}
|
||||
},
|
||||
}
|
||||
|
||||
// changeNotify invalidates the directory cache for the relativePath
|
||||
// passed in.
|
||||
//
|
||||
// if entryType is a directory it invalidates the parent of the directory too.
|
||||
func changeNotify(relativePath string, entryType fs.EntryType) {
|
||||
fs.Logf(nil, "%q: %v", relativePath, entryType)
|
||||
}
|
||||
@@ -3,12 +3,12 @@
|
||||
package makefiles
|
||||
|
||||
import (
|
||||
cryptrand "crypto/rand"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/cmd"
|
||||
"github.com/rclone/rclone/cmd/test"
|
||||
@@ -27,10 +27,8 @@ var (
|
||||
maxFileSize = fs.SizeSuffix(100)
|
||||
minFileNameLength = 4
|
||||
maxFileNameLength = 12
|
||||
seed = int64(1)
|
||||
|
||||
// Globals
|
||||
randSource *rand.Rand
|
||||
directoriesToCreate int
|
||||
totalDirectories int
|
||||
fileNames = map[string]struct{}{} // keep a note of which file name we've used already
|
||||
@@ -46,7 +44,6 @@ func init() {
|
||||
flags.FVarP(cmdFlags, &maxFileSize, "max-file-size", "", "Maximum size of files to create")
|
||||
flags.IntVarP(cmdFlags, &minFileNameLength, "min-name-length", "", minFileNameLength, "Minimum size of file names")
|
||||
flags.IntVarP(cmdFlags, &maxFileNameLength, "max-name-length", "", maxFileNameLength, "Maximum size of file names")
|
||||
flags.Int64VarP(cmdFlags, &seed, "seed", "", seed, "Seed for the random number generator (0 for random)")
|
||||
}
|
||||
|
||||
var commandDefinition = &cobra.Command{
|
||||
@@ -54,36 +51,28 @@ var commandDefinition = &cobra.Command{
|
||||
Short: `Make a random file hierarchy in <dir>`,
|
||||
Run: func(command *cobra.Command, args []string) {
|
||||
cmd.CheckArgs(1, 1, command, args)
|
||||
if seed == 0 {
|
||||
seed = time.Now().UnixNano()
|
||||
fs.Logf(nil, "Using random seed = %d", seed)
|
||||
}
|
||||
randSource = rand.New(rand.NewSource(seed))
|
||||
outputDirectory := args[0]
|
||||
directoriesToCreate = numberOfFiles / averageFilesPerDirectory
|
||||
averageSize := (minFileSize + maxFileSize) / 2
|
||||
start := time.Now()
|
||||
fs.Logf(nil, "Creating %d files of average size %v in %d directories in %q.", numberOfFiles, averageSize, directoriesToCreate, outputDirectory)
|
||||
log.Printf("Creating %d files of average size %v in %d directories in %q.", numberOfFiles, averageSize, directoriesToCreate, outputDirectory)
|
||||
root := &dir{name: outputDirectory, depth: 1}
|
||||
for totalDirectories < directoriesToCreate {
|
||||
root.createDirectories()
|
||||
}
|
||||
dirs := root.list("", []string{})
|
||||
totalBytes := int64(0)
|
||||
for i := 0; i < numberOfFiles; i++ {
|
||||
dir := dirs[randSource.Intn(len(dirs))]
|
||||
totalBytes += writeFile(dir, fileName())
|
||||
dir := dirs[rand.Intn(len(dirs))]
|
||||
writeFile(dir, fileName())
|
||||
}
|
||||
dt := time.Since(start)
|
||||
fs.Logf(nil, "Written %viB in %v at %viB/s.", fs.SizeSuffix(totalBytes), dt.Round(time.Millisecond), fs.SizeSuffix((totalBytes*int64(time.Second))/int64(dt)))
|
||||
log.Printf("Done.")
|
||||
},
|
||||
}
|
||||
|
||||
// fileName creates a unique random file or directory name
|
||||
func fileName() (name string) {
|
||||
for {
|
||||
length := randSource.Intn(maxFileNameLength-minFileNameLength) + minFileNameLength
|
||||
name = random.StringFn(length, randSource.Intn)
|
||||
length := rand.Intn(maxFileNameLength-minFileNameLength) + minFileNameLength
|
||||
name = random.String(length)
|
||||
if _, found := fileNames[name]; !found {
|
||||
break
|
||||
}
|
||||
@@ -110,7 +99,7 @@ func (d *dir) createDirectories() {
|
||||
}
|
||||
d.children = append(d.children, newDir)
|
||||
totalDirectories++
|
||||
switch randSource.Intn(4) {
|
||||
switch rand.Intn(4) {
|
||||
case 0:
|
||||
if d.depth < maxDepth {
|
||||
newDir.createDirectories()
|
||||
@@ -133,7 +122,7 @@ func (d *dir) list(path string, output []string) []string {
|
||||
}
|
||||
|
||||
// writeFile writes a random file at dir/name
|
||||
func writeFile(dir, name string) int64 {
|
||||
func writeFile(dir, name string) {
|
||||
err := os.MkdirAll(dir, 0777)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to make directory %q: %v", dir, err)
|
||||
@@ -143,8 +132,8 @@ func writeFile(dir, name string) int64 {
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open file %q: %v", path, err)
|
||||
}
|
||||
size := randSource.Int63n(int64(maxFileSize-minFileSize)) + int64(minFileSize)
|
||||
_, err = io.CopyN(fd, randSource, size)
|
||||
size := rand.Int63n(int64(maxFileSize-minFileSize)) + int64(minFileSize)
|
||||
_, err = io.CopyN(fd, cryptrand.Reader, size)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write %v bytes to file %q: %v", size, path, err)
|
||||
}
|
||||
@@ -152,6 +141,4 @@ func writeFile(dir, name string) int64 {
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to close file %q: %v", path, err)
|
||||
}
|
||||
fs.Infof(path, "Written file size %v", fs.SizeSuffix(size))
|
||||
return size
|
||||
}
|
||||
|
||||
@@ -29,16 +29,13 @@ var commandDefinition = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: `Show the version number.`,
|
||||
Long: `
|
||||
Show the rclone version number, the go version, the build target
|
||||
OS and architecture, the runtime OS and kernel version and bitness,
|
||||
build tags and the type of executable (static or dynamic).
|
||||
Show the rclone version number, the go version, the build target OS and
|
||||
architecture, build tags and the type of executable (static or dynamic).
|
||||
|
||||
For example:
|
||||
|
||||
$ rclone version
|
||||
rclone v1.55.0
|
||||
- os/version: ubuntu 18.04 (64 bit)
|
||||
- os/kernel: 4.15.0-136-generic (x86_64)
|
||||
rclone v1.54
|
||||
- os/type: linux
|
||||
- os/arch: amd64
|
||||
- go/version: go1.16
|
||||
|
||||
@@ -26,12 +26,12 @@ func TestVersionWorksWithoutAccessibleConfigFile(t *testing.T) {
|
||||
}
|
||||
// re-wire
|
||||
oldOsStdout := os.Stdout
|
||||
oldConfigPath := config.GetConfigPath()
|
||||
assert.NoError(t, config.SetConfigPath(path))
|
||||
oldConfigPath := config.ConfigPath
|
||||
config.ConfigPath = path
|
||||
os.Stdout = nil
|
||||
defer func() {
|
||||
os.Stdout = oldOsStdout
|
||||
assert.NoError(t, config.SetConfigPath(oldConfigPath))
|
||||
config.ConfigPath = oldConfigPath
|
||||
}()
|
||||
|
||||
cmd.Root.SetArgs([]string{"version"})
|
||||
|
||||
@@ -152,7 +152,6 @@ WebDAV or S3, that work out of the box.)
|
||||
{{< provider name="SugarSync" home="https://sugarsync.com/" config="/sugarsync/" >}}
|
||||
{{< provider name="Tardigrade" home="https://tardigrade.io/" config="/tardigrade/" >}}
|
||||
{{< provider name="Tencent Cloud Object Storage (COS)" home="https://intl.cloud.tencent.com/product/cos" config="/s3/#tencent-cos" >}}
|
||||
{{< provider name="Uptobox" home="https://uptobox.com" config="/uptobox/" >}}
|
||||
{{< provider name="Wasabi" home="https://wasabi.com/" config="/s3/#wasabi" >}}
|
||||
{{< provider name="WebDAV" home="https://en.wikipedia.org/wiki/WebDAV" config="/webdav/" >}}
|
||||
{{< provider name="Yandex Disk" home="https://disk.yandex.com/" config="/yandex/" >}}
|
||||
|
||||
@@ -372,7 +372,7 @@ put them back in again.` >}}
|
||||
* Fred <fred@creativeprojects.tech>
|
||||
* Sébastien Gross <renard@users.noreply.github.com>
|
||||
* Maxime Suret <11944422+msuret@users.noreply.github.com>
|
||||
* Caleb Case <caleb@storj.io> <calebcase@gmail.com>
|
||||
* Caleb Case <caleb@storj.io>
|
||||
* Ben Zenker <imbenzenker@gmail.com>
|
||||
* Martin Michlmayr <tbm@cyrius.com>
|
||||
* Brandon McNama <bmcnama@pagerduty.com>
|
||||
@@ -478,12 +478,3 @@ put them back in again.` >}}
|
||||
* Manish Kumar <krmanish260@gmail.com>
|
||||
* x0b <x0bdev@gmail.com>
|
||||
* CERN through the CS3MESH4EOSC Project
|
||||
* Nick Gaya <nicholasgaya+github@gmail.com>
|
||||
* Ashok Gelal <401055+ashokgelal@users.noreply.github.com>
|
||||
* Dominik Mydlil <dominik.mydlil@outlook.com>
|
||||
* Nazar Mishturak <nazarmx@gmail.com>
|
||||
* Ansh Mittal <iamAnshMittal@gmail.com>
|
||||
* noabody <noabody@yahoo.com>
|
||||
* OleFrost <82263101+olefrost@users.noreply.github.com>
|
||||
* Kenny Parsons <kennyparsons93@gmail.com>
|
||||
* Jeffrey Tolar <tolar.jeffrey@gmail.com>
|
||||
|
||||
@@ -172,6 +172,11 @@ the file instead of hiding it.
|
||||
Old versions of files, where available, are visible using the
|
||||
`--b2-versions` flag.
|
||||
|
||||
**NB** Note that `--b2-versions` does not work with crypt at the
|
||||
moment [#1627](https://github.com/rclone/rclone/issues/1627). Using
|
||||
[--backup-dir](/docs/#backup-dir-dir) with rclone is the recommended
|
||||
way of working around this.
|
||||
|
||||
If you wish to remove all the old versions then you can use the
|
||||
`rclone cleanup remote:bucket` command which will delete all the old
|
||||
versions of files, leaving the current ones intact. You can also
|
||||
|
||||
@@ -12,10 +12,10 @@ Get quota information from the remote.
|
||||
## Synopsis
|
||||
|
||||
|
||||
`rclone about`prints quota information about a remote to standard
|
||||
`rclone about` prints quota information about a remote to standard
|
||||
output. The output is typically used, free, quota and trash contents.
|
||||
|
||||
E.g. Typical output from`rclone about remote:`is:
|
||||
E.g. Typical output from `rclone about remote:` is:
|
||||
|
||||
Total: 17G
|
||||
Used: 7.444G
|
||||
@@ -43,7 +43,7 @@ Applying a `--full` flag to the command prints the bytes in full, e.g.
|
||||
Trashed: 104857602
|
||||
Other: 8849156022
|
||||
|
||||
A `--json`flag generates conveniently computer readable output, e.g.
|
||||
A `--json` flag generates conveniently computer readable output, e.g.
|
||||
|
||||
{
|
||||
"total": 18253611008,
|
||||
|
||||
@@ -15,7 +15,7 @@ Copy url content to dest.
|
||||
Download a URL's content and copy it to the destination without saving
|
||||
it in temporary storage.
|
||||
|
||||
Setting `--auto-filename`will cause the file name to be retrieved from
|
||||
Setting `--auto-filename` will cause the file name to be retrieved from
|
||||
the from URL (after any redirections) and used in the destination
|
||||
path. With `--print-filename` in addition, the resuling file name will
|
||||
be printed.
|
||||
|
||||
@@ -184,7 +184,7 @@ metadata about files like in UNIX. One case that may arise is that other program
|
||||
(incorrectly) interprets this as the file being accessible by everyone. For example
|
||||
an SSH client may warn about "unprotected private key file".
|
||||
|
||||
WinFsp 2021 (version 1.9, still in beta) introduces a new FUSE option "FileSecurity",
|
||||
WinFsp 2021 (version 1.9) introduces a new FUSE option "FileSecurity",
|
||||
that allows the complete specification of file security descriptors using
|
||||
[SDDL](https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format).
|
||||
With this you can work around issues such as the mentioned "unprotected private key file"
|
||||
|
||||
@@ -37,7 +37,7 @@ If the old version contains only dots and digits (for example `v1.54.0`)
|
||||
then it's a stable release so you won't need the `--beta` flag. Beta releases
|
||||
have an additional information similar to `v1.54.0-beta.5111.06f1c0c61`.
|
||||
(if you are a developer and use a locally built rclone, the version number
|
||||
will end with `-DEV`, you will have to rebuild it as it obvisously can't
|
||||
will end with `-DEV`, you will have to rebuild it as it obviously can't
|
||||
be distributed).
|
||||
|
||||
If you previously installed rclone via a package manager, the package may
|
||||
|
||||
@@ -57,7 +57,6 @@ See the following for detailed instructions for
|
||||
* [SugarSync](/sugarsync/)
|
||||
* [Tardigrade](/tardigrade/)
|
||||
* [Union](/union/)
|
||||
* [Uptobox](/uptobox/)
|
||||
* [WebDAV](/webdav/)
|
||||
* [Yandex Disk](/yandex/)
|
||||
* [Zoho WorkDrive](/zoho/)
|
||||
@@ -640,54 +639,25 @@ See `--copy-dest` and `--backup-dir`.
|
||||
|
||||
### --config=CONFIG_FILE ###
|
||||
|
||||
Specify the location of the rclone configuration file, to override
|
||||
the default. E.g. `rclone config --config="rclone.conf"`.
|
||||
Specify the location of the rclone configuration file.
|
||||
|
||||
The exact default is a bit complex to describe, due to changes
|
||||
introduced through different versions of rclone while preserving
|
||||
backwards compatibility, but in most cases it is as simple as:
|
||||
Normally the config file is in your home directory as a file called
|
||||
`.config/rclone/rclone.conf` (or `.rclone.conf` if created with an
|
||||
older version). If `$XDG_CONFIG_HOME` is set it will be at
|
||||
`$XDG_CONFIG_HOME/rclone/rclone.conf`.
|
||||
|
||||
- `%APPDATA%/rclone/rclone.conf` on Windows
|
||||
- `~/.config/rclone/rclone.conf` on other
|
||||
|
||||
The complete logic is as follows: Rclone will look for an existing
|
||||
configuration file in any of the following locations, in priority order:
|
||||
|
||||
1. `rclone.conf` (in program directory, where rclone executable is)
|
||||
2. `%APPDATA%/rclone/rclone.conf` (only on Windows)
|
||||
3. `$XDG_CONFIG_HOME/rclone/rclone.conf` (on all systems, including Windows)
|
||||
4. `~/.config/rclone/rclone.conf` (see below for explanation of ~ symbol)
|
||||
5. `~/.rclone.conf`
|
||||
|
||||
If no existing configuration file is found, then a new one will be created
|
||||
in the following location:
|
||||
|
||||
- On Windows: Location 2 listed above, except in the unlikely event
|
||||
that `APPDATA` is not defined, then location 4 is used instead.
|
||||
- On Unix: Location 3 if `XDG_CONFIG_HOME` is defined, else location 4.
|
||||
- Fallback to location 5 (on all OS), when the rclone directory cannot be
|
||||
created, but if also a home directory was not found then path
|
||||
`.rclone.conf` relative to current working directory will be used as
|
||||
a final resort.
|
||||
|
||||
The `~` symbol in paths above represent the home directory of the current user
|
||||
on any OS, and the value is defined as following:
|
||||
|
||||
- On Windows: `%HOME%` if defined, else `%USERPROFILE%`, or else `%HOMEDRIVE%\%HOMEPATH%`.
|
||||
- On Unix: `$HOME` if defined, else by looking up current user in OS-specific user database
|
||||
(e.g. passwd file), or else use the result from shell command `cd && pwd`.
|
||||
If there is a file `rclone.conf` in the same directory as the rclone
|
||||
executable it will be preferred. This file must be created manually
|
||||
for Rclone to use it, it will never be created automatically.
|
||||
|
||||
If you run `rclone config file` you will see where the default
|
||||
location is for you.
|
||||
|
||||
The fact that an existing file `rclone.conf` in the same directory
|
||||
as the rclone executable is always preferred, means that it is easy
|
||||
to run in "portable" mode by downloading rclone executable to a
|
||||
writable directory and then create an empty file `rclone.conf` in the
|
||||
same directory.
|
||||
Use this flag to override the config location, e.g. `rclone
|
||||
--config=".myconfig" config`.
|
||||
|
||||
If the location is set to empty string `""` or path to a file
|
||||
with name `notfound`, or the os null device represented by value `NUL` on
|
||||
If the location is set to empty string `""` or the special value
|
||||
`/notfound`, or the os null device represented by value `NUL` on
|
||||
Windows and `/dev/null` on Unix systems, then rclone will keep the
|
||||
config file in memory only.
|
||||
|
||||
@@ -1920,12 +1890,11 @@ Nevertheless, rclone will read any configuration file found
|
||||
according to the rules described [above](https://rclone.org/docs/#config-config-file).
|
||||
If an encrypted configuration file is found, this means you will be prompted for
|
||||
password (unless using `--password-command`). To avoid this, you can bypass
|
||||
the loading of the default configuration file by overriding the location,
|
||||
e.g. with one of the documented special values for memory-only configuration:
|
||||
|
||||
```
|
||||
rclone genautocomplete bash --config=""
|
||||
```
|
||||
the loading of the configuration file by overriding the location with an empty
|
||||
string `""` or the special value `/notfound`, or the os null device represented
|
||||
by value `NUL` on Windows and `/dev/null` on Unix systems (before rclone
|
||||
version 1.55 only this null device alternative was supported).
|
||||
E.g. `rclone --config="" genautocomplete bash`.
|
||||
|
||||
Developer options
|
||||
-----------------
|
||||
|
||||
@@ -285,12 +285,6 @@ dropbox:dir` will return the error `Failed to purge: There are too
|
||||
many files involved in this operation`. As a work-around do an
|
||||
`rclone delete dropbox:dir` followed by an `rclone rmdir dropbox:dir`.
|
||||
|
||||
When using `rclone link` you'll need to set `--expire` if using a
|
||||
non-personal account otherwise the visibility may not be correct.
|
||||
(Note that `--expire` isn't supported on personal accounts). See the
|
||||
[forum discussion](https://forum.rclone.org/t/rclone-link-dropbox-permissions/23211) and the
|
||||
[dropbox SDK issue](https://github.com/dropbox/dropbox-sdk-go-unofficial/issues/75).
|
||||
|
||||
### Get your own Dropbox App ID ###
|
||||
|
||||
When you use rclone with Dropbox in its default configuration you are using rclone's App ID. This is shared between all the rclone users.
|
||||
|
||||
@@ -153,7 +153,7 @@ These flags are available for every command.
|
||||
--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. The default is rclone/ version (default "rclone/v1.55.0")
|
||||
--user-agent string Set the user-agent to a specified string. The default is rclone/ version (default "rclone/v1.55.1")
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
```
|
||||
|
||||
@@ -415,7 +415,6 @@ and may be set in the config file.
|
||||
--onedrive-link-password string Set the password for links created by the link command.
|
||||
--onedrive-link-scope string Set the scope of the links created by the link command. (default "anonymous")
|
||||
--onedrive-link-type string Set the type of the links created by the link command. (default "view")
|
||||
--onedrive-list-chunk int Size of listing chunk. (default 1000)
|
||||
--onedrive-no-versions Remove all versions on modifying operations
|
||||
--onedrive-region string Choose national cloud region for OneDrive. (default "global")
|
||||
--onedrive-server-side-across-configs Allow server-side operations (e.g. copy) to work across different onedrive configs.
|
||||
|
||||
@@ -12,7 +12,6 @@ Rclone is a Go program and comes as a single binary file.
|
||||
* [Download](/downloads/) the relevant binary.
|
||||
* Extract the `rclone` or `rclone.exe` binary from the archive
|
||||
* Run `rclone config` to setup. See [rclone config docs](/docs/) for more details.
|
||||
* Optionally configure [automatic execution](#autostart).
|
||||
|
||||
See below for some expanded Linux / macOS instructions.
|
||||
|
||||
@@ -227,147 +226,3 @@ Instructions
|
||||
roles:
|
||||
- rclone
|
||||
```
|
||||
|
||||
# Autostart #
|
||||
|
||||
After installing and configuring rclone, as described above, you are ready to use rclone
|
||||
as an interactive command line utility. If your goal is to perform *periodic* operations,
|
||||
such as a regular [sync](https://rclone.org/commands/rclone_sync/), you will probably want
|
||||
to configure your rclone command in your operating system's scheduler. If you need to
|
||||
expose *service*-like features, such as [remote control](https://rclone.org/rc/),
|
||||
[GUI](https://rclone.org/gui/), [serve](https://rclone.org/commands/rclone_serve/)
|
||||
or [mount](https://rclone.org/commands/rclone_move/), you will often want an rclone
|
||||
command always running in the background, and configuring it to run in a service infrastructure
|
||||
may be a better option. Below are some alternatives on how to achieve this on
|
||||
different operating systems.
|
||||
|
||||
NOTE: Before setting up autorun it is highly recommended that you have tested your command
|
||||
manually from a Command Prompt first.
|
||||
|
||||
## Autostart on Windows ##
|
||||
|
||||
The most relevant alternatives for autostart on Windows are:
|
||||
- Run at user log on using the Startup folder
|
||||
- Run at user log on, at system startup or at schedule using Task Scheduler
|
||||
- Run at system startup using Windows service
|
||||
|
||||
### Running in background
|
||||
|
||||
Rclone is a console application, so if not starting from an existing Command Prompt,
|
||||
e.g. when starting rclone.exe from a shortcut, it will open a Command Prompt window.
|
||||
When configuring rclone to run from task scheduler and windows service you are able
|
||||
to set it to run hidden in background. From rclone version 1.54 you can also make it
|
||||
run hidden from anywhere by adding option `--no-console` (it may still flash briefly
|
||||
when the program starts). Since rclone normally writes information and any error
|
||||
messages to the console, you must redirect this to a file to be able to see it.
|
||||
Rclone has a built-in option `--log-file` for that.
|
||||
|
||||
Example command to run a sync in background:
|
||||
```
|
||||
c:\rclone\rclone.exe sync c:\files remote:/files --no-console --log-file c:\rclone\logs\sync_files.txt
|
||||
```
|
||||
|
||||
### User account
|
||||
|
||||
As mentioned in the [mount](https://rclone.org/commands/rclone_move/) documentation,
|
||||
mounted drives created as Administrator are not visible to other accounts, not even the
|
||||
account that was elevated as Administrator. By running the mount command as the
|
||||
built-in `SYSTEM` user account, it will create drives accessible for everyone on
|
||||
the system. Both scheduled task and Windows service can be used to achieve this.
|
||||
|
||||
NOTE: Remember that when rclone runs as the `SYSTEM` user, the user profile
|
||||
that it sees will not be yours. This means that if you normally run rclone with
|
||||
configuration file in the default location, to be able to use the same configuration
|
||||
when running as the system user you must explicitely tell rclone where to find
|
||||
it with the [`--config`](https://rclone.org/docs/#config-config-file) option,
|
||||
or else it will look in the system users profile path (`C:\Windows\System32\config\systemprofile`).
|
||||
To test your command manually from a Command Prompt, you can run it with
|
||||
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 ###
|
||||
|
||||
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
|
||||
store this shortcut in the special "Startup" start-menu folder, Windows will
|
||||
automatically run it at login. To open this folder in Windows Explorer,
|
||||
enter path `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup`,
|
||||
or `C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp` if you want
|
||||
the command to start for *every* user that logs in.
|
||||
|
||||
This is the easiest approach to autostarting of rclone, but it offers no
|
||||
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 ###
|
||||
|
||||
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.
|
||||
periodically on a schedule, on user log on, or at system startup. It can run
|
||||
be configured to run as the current user, or for a mount command that needs to
|
||||
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 ###
|
||||
|
||||
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 ####
|
||||
|
||||
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).
|
||||
|
||||
Example of a PowerShell command that creates a Windows service for mounting
|
||||
some `remote:/files` as drive letter `X:`, for *all* users (service will be running as the
|
||||
local system account):
|
||||
|
||||
```
|
||||
New-Service -Name Rclone -BinaryPathName 'c:\rclone\rclone.exe mount remote:/files X: --config c:\rclone\config\rclone.conf --log-file c:\rclone\logs\mount.txt'
|
||||
```
|
||||
|
||||
The [WinFsp service infrastructure](https://github.com/billziss-gh/winfsp/wiki/WinFsp-Service-Architecture)
|
||||
supports incorporating services for file system implementations, such as rclone,
|
||||
into its own launcher service, as kind of "child services". This has the additional
|
||||
advantage that it also implements a network provider that integrates into
|
||||
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 ####
|
||||
|
||||
To Windows service running any rclone command, the excellent third party utility
|
||||
[NSSM](http://nssm.cc), the "Non-Sucking Service Manager", can be used.
|
||||
It includes some advanced features such as adjusting process periority, defining
|
||||
process environment variables, redirect to file anything written to stdout, and
|
||||
customized response to different exit codes, with a GUI to configure everything from
|
||||
(although it can also be used from command line ).
|
||||
|
||||
There are also several other alternatives. To mention one more,
|
||||
[WinSW](https://github.com/winsw/winsw), "Windows Service Wrapper", is worth checking out.
|
||||
It requires .NET Framework, but it is preinstalled on newer versions of Windows, and it
|
||||
also provides alternative standalone distributions which includes necessary runtime (.NET 5).
|
||||
WinSW is a command-line only utility, where you have to manually create an XML file with
|
||||
service configuration. This may be a drawback for some, but it can also be an advantage
|
||||
as it is easy to back up and re-use the configuration
|
||||
settings, without having go through manual steps in a GUI. One thing to note is that
|
||||
by default it does not restart the service on error, one have to explicit enable this
|
||||
in the configuration file (via the "onfailure" parameter).
|
||||
|
||||
## Autostart on Linux
|
||||
|
||||
### Start as a service
|
||||
|
||||
To always run rclone in background, relevant for mount commands etc,
|
||||
you can use systemd to set up rclone as a system or user service. Running as a
|
||||
system service ensures that it is run at startup even if the user it is running as
|
||||
has no active session. Running rclone as a user service ensures that it only
|
||||
starts after the configured user has logged into the system.
|
||||
|
||||
### Run periodically from cron
|
||||
|
||||
To run a periodic command, such as a copy/sync, you can set up a cron job.
|
||||
|
||||
@@ -53,9 +53,9 @@ export XDG_CONFIG_HOME=config
|
||||
#check installed version of rclone to determine if update is necessary
|
||||
version=$(rclone --version 2>>errors | head -n 1)
|
||||
if [ -z "$install_beta" ]; then
|
||||
current_version=$(curl -fsS https://downloads.rclone.org/version.txt)
|
||||
current_version=$(curl -f https://downloads.rclone.org/version.txt)
|
||||
else
|
||||
current_version=$(curl -fsS https://beta.rclone.org/version.txt)
|
||||
current_version=$(curl -f https://beta.rclone.org/version.txt)
|
||||
fi
|
||||
|
||||
if [ "$version" = "$current_version" ]; then
|
||||
@@ -123,7 +123,7 @@ else
|
||||
rclone_zip="rclone-beta-latest-${OS}-${OS_type}.zip"
|
||||
fi
|
||||
|
||||
curl -OfsS "$download_link"
|
||||
curl -Of "$download_link"
|
||||
unzip_dir="tmp_unzip_dir_for_rclone"
|
||||
# there should be an entry in this switch for each element of unzip_tools_list
|
||||
case "$unzip_tool" in
|
||||
|
||||
@@ -172,7 +172,7 @@ like symlinks under Windows).
|
||||
|
||||
If you supply `--copy-links` or `-L` then rclone will follow the
|
||||
symlink and copy the pointed to file or directory. Note that this
|
||||
flag is incompatible with `--links` / `-l`.
|
||||
flag is incompatible with `-links` / `-l`.
|
||||
|
||||
This flag applies to all commands.
|
||||
|
||||
|
||||
@@ -325,15 +325,6 @@ fall back to normal copy (which will be slightly slower).
|
||||
- Type: bool
|
||||
- Default: false
|
||||
|
||||
#### --onedrive-list-chunk
|
||||
|
||||
Size of listing chunk.
|
||||
|
||||
- Config: list_chunk
|
||||
- Env Var: RCLONE_ONEDRIVE_LIST_CHUNK
|
||||
- Type: int
|
||||
- Default: 1000
|
||||
|
||||
#### --onedrive-no-versions
|
||||
|
||||
Remove all versions on modifying operations
|
||||
|
||||
@@ -48,7 +48,6 @@ Here is an overview of the major features of each cloud storage system.
|
||||
| SFTP | MD5, SHA1 ² | Yes | Depends | No | - |
|
||||
| SugarSync | - | No | No | No | - |
|
||||
| Tardigrade | - | Yes | No | No | - |
|
||||
| Uptobox | - | No | No | Yes | - |
|
||||
| WebDAV | MD5, SHA1 ³ | Yes ⁴ | Depends | No | - |
|
||||
| Yandex Disk | MD5 | Yes | No | No | R |
|
||||
| Zoho WorkDrive | - | No | No | No | - |
|
||||
@@ -362,7 +361,6 @@ upon backend specific capabilities.
|
||||
| SFTP | No | No | Yes | Yes | No | No | Yes | No | Yes | Yes |
|
||||
| SugarSync | Yes | Yes | Yes | Yes | No | No | Yes | Yes | No | Yes |
|
||||
| Tardigrade | Yes † | No | No | No | No | Yes | Yes | No | No | No |
|
||||
| Uptobox | No | Yes | Yes | Yes | No | No | No | No | No | No |
|
||||
| WebDAV | Yes | Yes | Yes | Yes | No | No | Yes ‡ | No | Yes | Yes |
|
||||
| Yandex Disk | Yes | Yes | Yes | Yes | Yes | No | Yes | Yes | Yes | Yes |
|
||||
| Zoho WorkDrive | Yes | Yes | Yes | Yes | No | No | No | No | Yes | Yes |
|
||||
|
||||
@@ -21,10 +21,7 @@ SSH installations.
|
||||
|
||||
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. For example, `rclone lsd remote:`
|
||||
would list the home directory of the user cofigured in the rclone remote config
|
||||
(`i.e /home/sftpuser`). However, `rclone lsd remote:/` would list the root
|
||||
directory for remote machine (i.e. `/`)
|
||||
`remote:` refers to the user's home directory.
|
||||
|
||||
"Note that some SFTP servers will need the leading / - Synology is a
|
||||
good example of this. rsync.net, on the other hand, requires users to
|
||||
@@ -87,10 +84,6 @@ See all directories in the home directory
|
||||
|
||||
rclone lsd remote:
|
||||
|
||||
See all directories in the root directory
|
||||
|
||||
rclone lsd remote:/
|
||||
|
||||
Make a new directory
|
||||
|
||||
rclone mkdir remote:path/to/directory
|
||||
@@ -104,11 +97,6 @@ excess files in the directory.
|
||||
|
||||
rclone sync -i /home/local/directory remote:directory
|
||||
|
||||
Mount the remote path `/srv/www-data/` to the local path
|
||||
`/mnt/www-data`
|
||||
|
||||
rclone mount remote:/srv/www-data/ /mnt/www-data
|
||||
|
||||
### SSH Authentication ###
|
||||
|
||||
The SFTP remote supports three authentication methods:
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
---
|
||||
title: "Uptobox"
|
||||
description: "Rclone docs for Uptobox"
|
||||
---
|
||||
|
||||
{{< icon "fa fa-archive" >}} Uptobox
|
||||
-----------------------------------------
|
||||
|
||||
This is a Backend for Uptobox file storage service. Uptobox is closer to a one-click hoster than a traditional
|
||||
cloud storage provider and therefore not suitable for long term storage.
|
||||
|
||||
Paths are specified as `remote:path`
|
||||
|
||||
Paths may be as deep as required, e.g. `remote:directory/subdirectory`.
|
||||
|
||||
## Setup
|
||||
|
||||
To configure an Uptobox backend you'll need your personal api token. You'll find it in you
|
||||
[account settings](https://uptobox.com/my_account)
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
Here is an example of how to make a remote called `remote` with the default setup. First run:
|
||||
|
||||
rclone config
|
||||
|
||||
This will guide you through an interactive setup process:
|
||||
|
||||
```
|
||||
Current remotes:
|
||||
|
||||
Name Type
|
||||
==== ====
|
||||
TestUptobox uptobox
|
||||
|
||||
e) Edit existing remote
|
||||
n) New remote
|
||||
d) Delete remote
|
||||
r) Rename remote
|
||||
c) Copy remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
e/n/d/r/c/s/q> n
|
||||
name> uptobox
|
||||
Type of storage to configure.
|
||||
Enter a string value. Press Enter for the default ("").
|
||||
Choose a number from below, or type in your own value
|
||||
[...]
|
||||
37 / Uptobox
|
||||
\ "uptobox"
|
||||
[...]
|
||||
Storage> uptobox
|
||||
** See help for uptobox backend at: https://rclone.org/uptobox/ **
|
||||
|
||||
Your API Key, get it from https://uptobox.com/my_account
|
||||
Enter a string value. Press Enter for the default ("").
|
||||
api_key> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Edit advanced config? (y/n)
|
||||
y) Yes
|
||||
n) No (default)
|
||||
y/n> n
|
||||
Remote config
|
||||
--------------------
|
||||
[uptobox]
|
||||
type = uptobox
|
||||
api_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
--------------------
|
||||
y) Yes this is OK (default)
|
||||
e) Edit this remote
|
||||
d) Delete this remote
|
||||
y/e/d>
|
||||
```
|
||||
Once configured you can then use `rclone` like this,
|
||||
|
||||
List directories in top level of your Uptobox
|
||||
|
||||
rclone lsd remote:
|
||||
|
||||
List all the files in your Uptobox
|
||||
|
||||
rclone ls remote:
|
||||
|
||||
To copy a local directory to an Uptobox directory called backup
|
||||
|
||||
rclone copy /home/source remote:backup
|
||||
|
||||
### Modified time and hashes
|
||||
|
||||
Uptobox supports neither modified times nor checksums.
|
||||
|
||||
#### Restricted filename characters
|
||||
|
||||
In addition to the [default restricted characters set](/overview/#restricted-characters)
|
||||
the following characters are also replaced:
|
||||
|
||||
| Character | Value | Replacement |
|
||||
| --------- |:-----:|:-----------:|
|
||||
| " | 0x22 | " |
|
||||
| ` | 0x41 | ` |
|
||||
|
||||
Invalid UTF-8 bytes will also be [replaced](/overview/#invalid-utf8),
|
||||
as they can't be used in XML strings.
|
||||
|
||||
{{< rem autogenerated options start" - DO NOT EDIT - instead edit fs.RegInfo in backend/uptobox/uptobox.go then run make backenddocs" >}}
|
||||
### Standard Options
|
||||
|
||||
Here are the standard options specific to uptobox (Uptobox).
|
||||
|
||||
#### --uptobox-api-key
|
||||
|
||||
Your API Key, get it from https://uptobox.com/my_account
|
||||
|
||||
- Config: api_key
|
||||
- Env Var: RCLONE_UPTOBOX_API_KEY
|
||||
- Type: string
|
||||
- Default: ""
|
||||
|
||||
### Advanced Options
|
||||
|
||||
Here are the advanced options specific to uptobox (Uptobox).
|
||||
|
||||
#### --uptobox-encoding
|
||||
|
||||
This sets the encoding for the backend.
|
||||
|
||||
See: the [encoding section in the overview](/overview/#encoding) for more info.
|
||||
|
||||
- Config: encoding
|
||||
- Env Var: RCLONE_UPTOBOX_ENCODING
|
||||
- Type: MultiEncoder
|
||||
- Default: Slash,LtGt,DoubleQuote,SingleQuote,BackQuote,Dollar,BackSlash,Del,Ctl,LeftSpace,RightSpace,InvalidUtf8,Dot
|
||||
|
||||
{{< rem autogenerated options stop >}}
|
||||
|
||||
### Limitations
|
||||
|
||||
Uptobox will delete inactive files that have not been accessed in 60 days.
|
||||
|
||||
`rclone about` is not supported by this backend an overview of used space can however
|
||||
been seen in the uptobox web interface.
|
||||
@@ -98,7 +98,6 @@
|
||||
<a class="dropdown-item" href="/sftp/"><i class="fa fa-server"></i> SFTP</a>
|
||||
<a class="dropdown-item" href="/sugarsync/"><i class="fas fa-dove"></i> SugarSync</a>
|
||||
<a class="dropdown-item" href="/tardigrade/"><i class="fas fa-dove"></i> Tardigrade</a>
|
||||
<a class="dropdown-item" href="/uptobox/"><i class="fa fa-archive"></i> Uptobox</a>
|
||||
<a class="dropdown-item" href="/union/"><i class="fa fa-link"></i> Union (merge backends)</a>
|
||||
<a class="dropdown-item" href="/webdav/"><i class="fa fa-server"></i> WebDAV</a>
|
||||
<a class="dropdown-item" href="/yandex/"><i class="fa fa-space-shuttle"></i> Yandex Disk</a>
|
||||
|
||||
@@ -1 +1 @@
|
||||
v1.56.0
|
||||
v1.55.1
|
||||
@@ -2,11 +2,9 @@ package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/config/configmap"
|
||||
)
|
||||
|
||||
// Authorize is for remote authorization of headless machines.
|
||||
@@ -18,61 +16,33 @@ import (
|
||||
func Authorize(ctx context.Context, args []string, noAutoBrowser bool) error {
|
||||
ctx = suppressConfirm(ctx)
|
||||
switch len(args) {
|
||||
case 1, 2, 3:
|
||||
case 1, 3:
|
||||
default:
|
||||
return errors.Errorf("invalid number of arguments: %d", len(args))
|
||||
}
|
||||
Type := args[0] // FIXME could read this from input
|
||||
ri, err := fs.Find(Type)
|
||||
if err != nil {
|
||||
return err
|
||||
newType := args[0]
|
||||
f := fs.MustFind(newType)
|
||||
if f.Config == nil {
|
||||
return errors.Errorf("can't authorize fs %q", newType)
|
||||
}
|
||||
if ri.Config == nil {
|
||||
return errors.Errorf("can't authorize fs %q", Type)
|
||||
}
|
||||
|
||||
// Config map for remote
|
||||
inM := configmap.Simple{}
|
||||
|
||||
// Indicate that we are running rclone authorize
|
||||
inM[ConfigAuthorize] = "true"
|
||||
if noAutoBrowser {
|
||||
inM[ConfigAuthNoBrowser] = "true"
|
||||
}
|
||||
|
||||
// Add extra parameters if supplied
|
||||
if len(args) == 2 {
|
||||
err := inM.Decode(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(args) == 3 {
|
||||
inM[ConfigClientID] = args[1]
|
||||
inM[ConfigClientSecret] = args[2]
|
||||
}
|
||||
|
||||
// Name used for temporary remote
|
||||
// Name used for temporary fs
|
||||
name := "**temp-fs**"
|
||||
|
||||
m := fs.ConfigMap(ri, name, inM)
|
||||
outM := configmap.Simple{}
|
||||
m.ClearSetters()
|
||||
m.AddSetter(outM)
|
||||
m.AddGetter(outM, configmap.PriorityNormal)
|
||||
// Make sure we delete it
|
||||
defer DeleteRemote(name)
|
||||
|
||||
ri.Config(ctx, name, m)
|
||||
|
||||
// Print the code for the user to paste
|
||||
out := outM["token"]
|
||||
|
||||
// If received a config blob, then return one
|
||||
if len(args) == 2 {
|
||||
out, err = outM.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Indicate that we are running rclone authorize
|
||||
Data.SetValue(name, ConfigAuthorize, "true")
|
||||
if noAutoBrowser {
|
||||
Data.SetValue(name, ConfigAuthNoBrowser, "true")
|
||||
}
|
||||
fmt.Printf("Paste the following into your remote machine --->\n%s\n<---End paste\n", out)
|
||||
|
||||
if len(args) == 3 {
|
||||
Data.SetValue(name, ConfigClientID, args[1])
|
||||
Data.SetValue(name, ConfigClientSecret, args[2])
|
||||
}
|
||||
|
||||
m := fs.ConfigMap(f, name, nil)
|
||||
f.Config(ctx, name, m)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -22,14 +22,12 @@ import (
|
||||
"github.com/rclone/rclone/fs/config/obscure"
|
||||
"github.com/rclone/rclone/fs/fspath"
|
||||
"github.com/rclone/rclone/fs/rc"
|
||||
"github.com/rclone/rclone/lib/file"
|
||||
"github.com/rclone/rclone/lib/random"
|
||||
)
|
||||
|
||||
const (
|
||||
configFileName = "rclone.conf"
|
||||
hiddenConfigFileName = "." + configFileName
|
||||
noConfigFile = "notfound"
|
||||
|
||||
// ConfigToken is the key used to store the token under
|
||||
ConfigToken = "token"
|
||||
@@ -109,140 +107,72 @@ var (
|
||||
// and any parents.
|
||||
CacheDir = makeCacheDir()
|
||||
|
||||
// ConfigPath points to the config file
|
||||
ConfigPath = makeConfigPath()
|
||||
|
||||
// Password can be used to configure the random password generator
|
||||
Password = random.Password
|
||||
)
|
||||
|
||||
var configPath string
|
||||
|
||||
func init() {
|
||||
// Set the function pointers up in fs
|
||||
fs.ConfigFileGet = FileGetFlag
|
||||
fs.ConfigFileSet = SetValueAndSave
|
||||
configPath = makeConfigPath()
|
||||
}
|
||||
|
||||
// Join directory with filename, and check if exists
|
||||
func findFile(dir string, name string) string {
|
||||
path := filepath.Join(dir, name)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return ""
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// Find current user's home directory
|
||||
func findHomeDir() (string, error) {
|
||||
path, err := homedir.Dir()
|
||||
if err != nil {
|
||||
fs.Debugf(nil, "Home directory lookup failed and cannot be used as configuration location: %v", err)
|
||||
} else if path == "" {
|
||||
// On Unix homedir return success but empty string for user with empty home configured in passwd file
|
||||
fs.Debugf(nil, "Home directory not defined and cannot be used as configuration location")
|
||||
}
|
||||
return path, err
|
||||
}
|
||||
|
||||
// Find rclone executable directory and look for existing rclone.conf there
|
||||
// (<rclone_exe_dir>/rclone.conf)
|
||||
func findLocalConfig() (configDir string, configFile string) {
|
||||
if exePath, err := os.Executable(); err == nil {
|
||||
configDir = filepath.Dir(exePath)
|
||||
configFile = findFile(configDir, configFileName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Get path to Windows AppData config subdirectory for rclone and look for existing rclone.conf there
|
||||
// ($AppData/rclone/rclone.conf)
|
||||
func findAppDataConfig() (configDir string, configFile string) {
|
||||
if appDataDir := os.Getenv("APPDATA"); appDataDir != "" {
|
||||
configDir = filepath.Join(appDataDir, "rclone")
|
||||
configFile = findFile(configDir, configFileName)
|
||||
} else {
|
||||
fs.Debugf(nil, "Environment variable APPDATA is not defined and cannot be used as configuration location")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Get path to XDG config subdirectory for rclone and look for existing rclone.conf there
|
||||
// (see XDG Base Directory specification: https://specifications.freedesktop.org/basedir-spec/latest/).
|
||||
// ($XDG_CONFIG_HOME\rclone\rclone.conf)
|
||||
func findXDGConfig() (configDir string, configFile string) {
|
||||
if xdgConfigDir := os.Getenv("XDG_CONFIG_HOME"); xdgConfigDir != "" {
|
||||
configDir = filepath.Join(xdgConfigDir, "rclone")
|
||||
configFile = findFile(configDir, configFileName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Get path to .config subdirectory for rclone and look for existing rclone.conf there
|
||||
// (~/.config/rclone/rclone.conf)
|
||||
func findDotConfigConfig(home string) (configDir string, configFile string) {
|
||||
if home != "" {
|
||||
configDir = filepath.Join(home, ".config", "rclone")
|
||||
configFile = findFile(configDir, configFileName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Look for existing .rclone.conf (legacy hidden filename) in root of user's home directory
|
||||
// (~/.rclone.conf)
|
||||
func findOldHomeConfig(home string) (configDir string, configFile string) {
|
||||
if home != "" {
|
||||
configDir = home
|
||||
configFile = findFile(home, hiddenConfigFileName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Return the path to the configuration file
|
||||
func makeConfigPath() string {
|
||||
// Look for existing rclone.conf in prioritized list of known locations
|
||||
// Also get configuration directory to use for new config file when no existing is found.
|
||||
var (
|
||||
configFile string
|
||||
configDir string
|
||||
primaryConfigDir string
|
||||
fallbackConfigDir string
|
||||
)
|
||||
// <rclone_exe_dir>/rclone.conf
|
||||
if _, configFile = findLocalConfig(); configFile != "" {
|
||||
return configFile
|
||||
}
|
||||
// Windows: $AppData/rclone/rclone.conf
|
||||
// This is also the default location for new config when no existing is found
|
||||
if runtime.GOOS == "windows" {
|
||||
if primaryConfigDir, configFile = findAppDataConfig(); configFile != "" {
|
||||
return configFile
|
||||
// Use rclone.conf from rclone executable directory if already existing
|
||||
exe, err := os.Executable()
|
||||
if err == nil {
|
||||
exedir := filepath.Dir(exe)
|
||||
cfgpath := filepath.Join(exedir, configFileName)
|
||||
_, err := os.Stat(cfgpath)
|
||||
if err == nil {
|
||||
return cfgpath
|
||||
}
|
||||
}
|
||||
// $XDG_CONFIG_HOME/rclone/rclone.conf
|
||||
// Also looking for this on Windows, for backwards compatibility reasons.
|
||||
if configDir, configFile = findXDGConfig(); configFile != "" {
|
||||
return configFile
|
||||
}
|
||||
if runtime.GOOS != "windows" {
|
||||
// On Unix this is also the default location for new config when no existing is found
|
||||
primaryConfigDir = configDir
|
||||
}
|
||||
// ~/.config/rclone/rclone.conf
|
||||
// This is also the fallback location for new config
|
||||
// (when $AppData on Windows and $XDG_CONFIG_HOME on Unix is not defined)
|
||||
homeDir, homeDirErr := findHomeDir()
|
||||
if fallbackConfigDir, configFile = findDotConfigConfig(homeDir); configFile != "" {
|
||||
return configFile
|
||||
}
|
||||
// ~/.rclone.conf
|
||||
if _, configFile = findOldHomeConfig(homeDir); configFile != "" {
|
||||
return configFile
|
||||
|
||||
// Find user's home directory
|
||||
homeDir, err := homedir.Dir()
|
||||
|
||||
// Find user's configuration directory.
|
||||
// Prefer XDG config path, with fallback to $HOME/.config.
|
||||
// See XDG Base Directory specification
|
||||
// https://specifications.freedesktop.org/basedir-spec/latest/),
|
||||
xdgdir := os.Getenv("XDG_CONFIG_HOME")
|
||||
var cfgdir string
|
||||
if xdgdir != "" {
|
||||
// User's configuration directory for rclone is $XDG_CONFIG_HOME/rclone
|
||||
cfgdir = filepath.Join(xdgdir, "rclone")
|
||||
} else if homeDir != "" {
|
||||
// User's configuration directory for rclone is $HOME/.config/rclone
|
||||
cfgdir = filepath.Join(homeDir, ".config", "rclone")
|
||||
}
|
||||
|
||||
// No existing config file found, prepare proper default for a new one.
|
||||
// But first check if if user supplied a --config variable or environment
|
||||
// variable, since then we skip actually trying to create the default
|
||||
// and report any errors related to it (we can't use pflag for this because
|
||||
// it isn't initialised yet so we search the command line manually).
|
||||
// Use rclone.conf from user's configuration directory if already existing
|
||||
var cfgpath string
|
||||
if cfgdir != "" {
|
||||
cfgpath = filepath.Join(cfgdir, configFileName)
|
||||
_, err := os.Stat(cfgpath)
|
||||
if err == nil {
|
||||
return cfgpath
|
||||
}
|
||||
}
|
||||
|
||||
// Use .rclone.conf from user's home directory if already existing
|
||||
var homeconf string
|
||||
if homeDir != "" {
|
||||
homeconf = filepath.Join(homeDir, hiddenConfigFileName)
|
||||
_, err := os.Stat(homeconf)
|
||||
if err == nil {
|
||||
return homeconf
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if user supplied a --config variable or environment
|
||||
// variable. We can't use pflag for this because it isn't initialised
|
||||
// yet so we search the command line manually.
|
||||
_, configSupplied := os.LookupEnv("RCLONE_CONFIG")
|
||||
if !configSupplied {
|
||||
for _, item := range os.Args {
|
||||
@@ -252,97 +182,48 @@ func makeConfigPath() string {
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we found a configuration directory to be used for new config during search
|
||||
// above, then create it to be ready for rclone.conf file to be written into it
|
||||
// later, and also as a test of permissions to use fallback if not even able to
|
||||
// create the directory.
|
||||
if primaryConfigDir != "" {
|
||||
configDir = primaryConfigDir
|
||||
} else if fallbackConfigDir != "" {
|
||||
configDir = fallbackConfigDir
|
||||
} else {
|
||||
configDir = ""
|
||||
}
|
||||
if configDir != "" {
|
||||
configFile = filepath.Join(configDir, configFileName)
|
||||
|
||||
// If user's configuration directory was found, then try to create it
|
||||
// and assume rclone.conf can be written there. If user supplied config
|
||||
// then skip creating the directory since it will not be used.
|
||||
if cfgpath != "" {
|
||||
// cfgpath != "" implies cfgdir != ""
|
||||
if configSupplied {
|
||||
// User supplied custom config option, just return the default path
|
||||
// as is without creating any directories, since it will not be used
|
||||
// anyway and we don't want to unnecessarily create empty directory.
|
||||
return configFile
|
||||
return cfgpath
|
||||
}
|
||||
var mkdirErr error
|
||||
if mkdirErr = os.MkdirAll(configDir, os.ModePerm); mkdirErr == nil {
|
||||
return configFile
|
||||
}
|
||||
// Problem: Try a fallback location. If we did find a home directory then
|
||||
// just assume file .rclone.conf (legacy hidden filename) can be written in
|
||||
// its root (~/.rclone.conf).
|
||||
if homeDir != "" {
|
||||
fs.Debugf(nil, "Configuration directory could not be created and will not be used: %v", mkdirErr)
|
||||
return filepath.Join(homeDir, hiddenConfigFileName)
|
||||
}
|
||||
if !configSupplied {
|
||||
fs.Errorf(nil, "Couldn't find home directory nor create configuration directory: %v", mkdirErr)
|
||||
}
|
||||
} else if !configSupplied {
|
||||
if homeDirErr != nil {
|
||||
fs.Errorf(nil, "Couldn't find configuration directory nor home directory: %v", homeDirErr)
|
||||
} else {
|
||||
fs.Errorf(nil, "Couldn't find configuration directory nor home directory")
|
||||
err := os.MkdirAll(cfgdir, os.ModePerm)
|
||||
if err == nil {
|
||||
return cfgpath
|
||||
}
|
||||
}
|
||||
// No known location that can be used: Did possibly find a configDir
|
||||
// (XDG_CONFIG_HOME or APPDATA) which couldn't be created, but in any case
|
||||
// did not find a home directory!
|
||||
// Report it as an error, and return as last resort the path relative to current
|
||||
// working directory, of .rclone.conf (legacy hidden filename).
|
||||
|
||||
// Assume .rclone.conf can be written to user's home directory.
|
||||
if homeconf != "" {
|
||||
return homeconf
|
||||
}
|
||||
|
||||
// Default to ./.rclone.conf (current working directory) if everything else fails.
|
||||
if !configSupplied {
|
||||
fs.Errorf(nil, "Couldn't find home directory or read HOME or XDG_CONFIG_HOME environment variables.")
|
||||
fs.Errorf(nil, "Defaulting to storing config in current directory.")
|
||||
fs.Errorf(nil, "Use --config flag to workaround.")
|
||||
fs.Errorf(nil, "Error was: %v", err)
|
||||
}
|
||||
return hiddenConfigFileName
|
||||
}
|
||||
|
||||
// GetConfigPath returns the current config file path
|
||||
func GetConfigPath() string {
|
||||
return configPath
|
||||
}
|
||||
|
||||
// SetConfigPath sets new config file path
|
||||
//
|
||||
// Checks for empty string, os null device, or special path, all of which indicates in-memory config.
|
||||
func SetConfigPath(path string) (err error) {
|
||||
var cfgPath string
|
||||
if path == "" || path == os.DevNull {
|
||||
cfgPath = ""
|
||||
} else if filepath.Base(path) == noConfigFile {
|
||||
cfgPath = ""
|
||||
} else if err = file.IsReserved(path); err != nil {
|
||||
return err
|
||||
} else if cfgPath, err = filepath.Abs(path); err != nil {
|
||||
return err
|
||||
}
|
||||
configPath = cfgPath
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadConfig loads the config file
|
||||
func LoadConfig(ctx context.Context) {
|
||||
// Set RCLONE_CONFIG_DIR for backend config and subprocesses
|
||||
// If empty configPath (in-memory only) the value will be "."
|
||||
_ = os.Setenv("RCLONE_CONFIG_DIR", filepath.Dir(configPath))
|
||||
// Load configuration from file (or initialize sensible default if no file or error)
|
||||
_ = os.Setenv("RCLONE_CONFIG_DIR", filepath.Dir(ConfigPath))
|
||||
|
||||
// Load configuration file.
|
||||
if err := Data.Load(); err == ErrorConfigFileNotFound {
|
||||
if configPath == "" {
|
||||
fs.Debugf(nil, "Config is memory-only - using defaults")
|
||||
} else {
|
||||
fs.Logf(nil, "Config file %q not found - using defaults", configPath)
|
||||
}
|
||||
fs.Logf(nil, "Config file %q not found - using defaults", ConfigPath)
|
||||
} else if err != nil {
|
||||
log.Fatalf("Failed to load config file %q: %v", configPath, err)
|
||||
log.Fatalf("Failed to load config file %q: %v", ConfigPath, err)
|
||||
} else {
|
||||
fs.Debugf(nil, "Using config file from %q", configPath)
|
||||
fs.Debugf(nil, "Using config file from %q", ConfigPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,10 +233,6 @@ var ErrorConfigFileNotFound = errors.New("config file not found")
|
||||
// SaveConfig calling function which saves configuration file.
|
||||
// if SaveConfig returns error trying again after sleep.
|
||||
func SaveConfig() {
|
||||
if configPath == "" {
|
||||
fs.Debugf(nil, "Skipping save for memory-only config")
|
||||
return
|
||||
}
|
||||
ctx := context.Background()
|
||||
ci := fs.GetConfig(ctx)
|
||||
var err error
|
||||
@@ -367,6 +244,7 @@ func SaveConfig() {
|
||||
time.Sleep(time.Duration(waitingTimeMs) * time.Millisecond)
|
||||
}
|
||||
fs.Errorf(nil, "Failed to save config after %d tries: %v", ci.LowLevelRetries, err)
|
||||
return
|
||||
}
|
||||
|
||||
// SetValueAndSave sets the key to the value and saves just that
|
||||
|
||||
@@ -12,10 +12,10 @@ import (
|
||||
)
|
||||
|
||||
func TestConfigLoad(t *testing.T) {
|
||||
oldConfigPath := config.GetConfigPath()
|
||||
assert.NoError(t, config.SetConfigPath("./testdata/plain.conf"))
|
||||
oldConfigPath := config.ConfigPath
|
||||
config.ConfigPath = "./testdata/plain.conf"
|
||||
defer func() {
|
||||
assert.NoError(t, config.SetConfigPath(oldConfigPath))
|
||||
config.ConfigPath = oldConfigPath
|
||||
}()
|
||||
config.ClearConfigPassword()
|
||||
configfile.LoadConfig(context.Background())
|
||||
|
||||
@@ -15,6 +15,9 @@ import (
|
||||
"github.com/rclone/rclone/fs/config"
|
||||
)
|
||||
|
||||
// Special value indicating in memory config file. Empty string works also.
|
||||
const noConfigFile = "/notfound"
|
||||
|
||||
// LoadConfig installs the config file handler and calls config.LoadConfig
|
||||
func LoadConfig(ctx context.Context) {
|
||||
config.Data = &Storage{}
|
||||
@@ -29,22 +32,29 @@ type Storage struct {
|
||||
fi os.FileInfo // stat of the file when last loaded
|
||||
}
|
||||
|
||||
// Return whether we have a real config file or not
|
||||
func (s *Storage) noConfig() bool {
|
||||
return config.ConfigPath == "" || config.ConfigPath == noConfigFile
|
||||
}
|
||||
|
||||
// Check to see if we need to reload the config
|
||||
func (s *Storage) check() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if configPath := config.GetConfigPath(); configPath != "" {
|
||||
// Check to see if config file has changed since it was last loaded
|
||||
fi, err := os.Stat(configPath)
|
||||
if err == nil {
|
||||
// check to see if config file has changed and if it has, reload it
|
||||
if s.fi == nil || !fi.ModTime().Equal(s.fi.ModTime()) || fi.Size() != s.fi.Size() {
|
||||
fs.Debugf(nil, "Config file has changed externaly - reloading")
|
||||
err := s._load()
|
||||
if err != nil {
|
||||
fs.Errorf(nil, "Failed to read config file - using previous config: %v", err)
|
||||
}
|
||||
if s.noConfig() {
|
||||
return
|
||||
}
|
||||
|
||||
// Check to see if config file has changed since it was last loaded
|
||||
fi, err := os.Stat(config.ConfigPath)
|
||||
if err == nil {
|
||||
// check to see if config file has changed and if it has, reload it
|
||||
if s.fi == nil || !fi.ModTime().Equal(s.fi.ModTime()) || fi.Size() != s.fi.Size() {
|
||||
fs.Debugf(nil, "Config file has changed externaly - reloading")
|
||||
err := s._load()
|
||||
if err != nil {
|
||||
fs.Errorf(nil, "Failed to read config file - using previous config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,12 +71,11 @@ func (s *Storage) _load() (err error) {
|
||||
}
|
||||
}()
|
||||
|
||||
configPath := config.GetConfigPath()
|
||||
if configPath == "" {
|
||||
if s.noConfig() {
|
||||
return config.ErrorConfigFileNotFound
|
||||
}
|
||||
|
||||
fd, err := os.Open(configPath)
|
||||
fd, err := os.Open(config.ConfigPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return config.ErrorConfigFileNotFound
|
||||
@@ -76,7 +85,7 @@ func (s *Storage) _load() (err error) {
|
||||
defer fs.CheckClose(fd, &err)
|
||||
|
||||
// Update s.fi with the current file info
|
||||
s.fi, _ = os.Stat(configPath)
|
||||
s.fi, _ = os.Stat(config.ConfigPath)
|
||||
|
||||
cryptReader, err := config.Decrypt(fd)
|
||||
if err != nil {
|
||||
@@ -104,12 +113,11 @@ func (s *Storage) Save() error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
configPath := config.GetConfigPath()
|
||||
if configPath == "" {
|
||||
return errors.Errorf("Failed to save config file: Path is empty")
|
||||
if s.noConfig() {
|
||||
return nil
|
||||
}
|
||||
|
||||
dir, name := filepath.Split(configPath)
|
||||
dir, name := filepath.Split(config.ConfigPath)
|
||||
err := os.MkdirAll(dir, os.ModePerm)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create config directory")
|
||||
@@ -141,7 +149,7 @@ func (s *Storage) Save() error {
|
||||
}
|
||||
|
||||
var fileMode os.FileMode = 0600
|
||||
info, err := os.Stat(configPath)
|
||||
info, err := os.Stat(config.ConfigPath)
|
||||
if err != nil {
|
||||
fs.Debugf(nil, "Using default permissions for config file: %v", fileMode)
|
||||
} else if info.Mode() != fileMode {
|
||||
@@ -149,25 +157,25 @@ func (s *Storage) Save() error {
|
||||
fileMode = info.Mode()
|
||||
}
|
||||
|
||||
attemptCopyGroup(configPath, f.Name())
|
||||
attemptCopyGroup(config.ConfigPath, f.Name())
|
||||
|
||||
err = os.Chmod(f.Name(), fileMode)
|
||||
if err != nil {
|
||||
fs.Errorf(nil, "Failed to set permissions on config file: %v", err)
|
||||
}
|
||||
|
||||
if err = os.Rename(configPath, configPath+".old"); err != nil && !os.IsNotExist(err) {
|
||||
if err = os.Rename(config.ConfigPath, config.ConfigPath+".old"); err != nil && !os.IsNotExist(err) {
|
||||
return errors.Errorf("Failed to move previous config to backup location: %v", err)
|
||||
}
|
||||
if err = os.Rename(f.Name(), configPath); err != nil {
|
||||
if err = os.Rename(f.Name(), config.ConfigPath); err != nil {
|
||||
return errors.Errorf("Failed to move newly written config from %s to final location: %v", f.Name(), err)
|
||||
}
|
||||
if err := os.Remove(configPath + ".old"); err != nil && !os.IsNotExist(err) {
|
||||
if err := os.Remove(config.ConfigPath + ".old"); err != nil && !os.IsNotExist(err) {
|
||||
fs.Errorf(nil, "Failed to remove backup config file: %v", err)
|
||||
}
|
||||
|
||||
// Update s.fi with the newly written file
|
||||
s.fi, _ = os.Stat(configPath)
|
||||
s.fi, _ = os.Stat(config.ConfigPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -39,10 +39,10 @@ func setConfigFile(t *testing.T, data string) func() {
|
||||
|
||||
require.NoError(t, out.Close())
|
||||
|
||||
old := config.GetConfigPath()
|
||||
assert.NoError(t, config.SetConfigPath(filePath))
|
||||
old := config.ConfigPath
|
||||
config.ConfigPath = filePath
|
||||
return func() {
|
||||
assert.NoError(t, config.SetConfigPath(old))
|
||||
config.ConfigPath = old
|
||||
_ = os.Remove(filePath)
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ type = number3
|
||||
`, toUnix(buf))
|
||||
t.Run("Save", func(t *testing.T) {
|
||||
require.NoError(t, data.Save())
|
||||
buf, err := ioutil.ReadFile(config.GetConfigPath())
|
||||
buf, err := ioutil.ReadFile(config.ConfigPath)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, `[one]
|
||||
fruit = potato
|
||||
@@ -188,7 +188,7 @@ func TestConfigFileReload(t *testing.T) {
|
||||
assert.Equal(t, "", value)
|
||||
|
||||
// Now write a new value on the end
|
||||
out, err := os.OpenFile(config.GetConfigPath(), os.O_APPEND|os.O_WRONLY, 0777)
|
||||
out, err := os.OpenFile(config.ConfigPath, os.O_APPEND|os.O_WRONLY, 0777)
|
||||
require.NoError(t, err)
|
||||
fmt.Fprintln(out, "appended = what magic")
|
||||
require.NoError(t, out.Close())
|
||||
@@ -203,7 +203,7 @@ func TestConfigFileDoesNotExist(t *testing.T) {
|
||||
defer setConfigFile(t, configData)()
|
||||
data := &Storage{}
|
||||
|
||||
require.NoError(t, os.Remove(config.GetConfigPath()))
|
||||
require.NoError(t, os.Remove(config.ConfigPath))
|
||||
|
||||
err := data.Load()
|
||||
require.Equal(t, config.ErrorConfigFileNotFound, err)
|
||||
@@ -215,7 +215,7 @@ func TestConfigFileDoesNotExist(t *testing.T) {
|
||||
}
|
||||
|
||||
func testConfigFileNoConfig(t *testing.T, configPath string) {
|
||||
assert.NoError(t, config.SetConfigPath(configPath))
|
||||
config.ConfigPath = configPath
|
||||
data := &Storage{}
|
||||
|
||||
err := data.Load()
|
||||
@@ -227,13 +227,13 @@ func testConfigFileNoConfig(t *testing.T, configPath string) {
|
||||
assert.Equal(t, "42", value)
|
||||
|
||||
err = data.Save()
|
||||
require.Error(t, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestConfigFileNoConfig(t *testing.T) {
|
||||
old := config.GetConfigPath()
|
||||
old := config.ConfigPath
|
||||
defer func() {
|
||||
assert.NoError(t, config.SetConfigPath(old))
|
||||
config.ConfigPath = old
|
||||
}()
|
||||
|
||||
t.Run("Empty", func(t *testing.T) {
|
||||
|
||||
@@ -6,6 +6,7 @@ package configflags
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -22,7 +23,6 @@ var (
|
||||
// these will get interpreted into fs.Config via SetFlags() below
|
||||
verbose int
|
||||
quiet bool
|
||||
configPath string
|
||||
dumpHeaders bool
|
||||
dumpBodies bool
|
||||
deleteBefore bool
|
||||
@@ -45,7 +45,7 @@ func AddFlags(ci *fs.ConfigInfo, flagSet *pflag.FlagSet) {
|
||||
flags.DurationVarP(flagSet, &ci.ModifyWindow, "modify-window", "", ci.ModifyWindow, "Max time diff to be considered the same")
|
||||
flags.IntVarP(flagSet, &ci.Checkers, "checkers", "", ci.Checkers, "Number of checkers to run in parallel.")
|
||||
flags.IntVarP(flagSet, &ci.Transfers, "transfers", "", ci.Transfers, "Number of file transfers to run in parallel.")
|
||||
flags.StringVarP(flagSet, &configPath, "config", "", config.GetConfigPath(), "Config file.")
|
||||
flags.StringVarP(flagSet, &config.ConfigPath, "config", "", config.ConfigPath, "Config file.")
|
||||
flags.StringVarP(flagSet, &config.CacheDir, "cache-dir", "", config.CacheDir, "Directory rclone will use for caching.")
|
||||
flags.BoolVarP(flagSet, &ci.CheckSum, "checksum", "c", ci.CheckSum, "Skip based on checksum (if available) & size, not mod-time & size")
|
||||
flags.BoolVarP(flagSet, &ci.SizeOnly, "size-only", "", ci.SizeOnly, "Skip based on size only, not mod-time or checksum")
|
||||
@@ -267,9 +267,10 @@ func SetFlags(ci *fs.ConfigInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
// Set path to configuration file
|
||||
if err := config.SetConfigPath(configPath); err != nil {
|
||||
log.Fatalf("--config: Failed to set %q as config path: %v", configPath, err)
|
||||
// Make the config file absolute
|
||||
configPath, err := filepath.Abs(config.ConfigPath)
|
||||
if err == nil {
|
||||
config.ConfigPath = configPath
|
||||
}
|
||||
|
||||
// Set whether multi-thread-streams was set
|
||||
|
||||
@@ -2,24 +2,8 @@
|
||||
package configmap
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Priority of getters
|
||||
type Priority int8
|
||||
|
||||
// Priority levels for AddGetter
|
||||
const (
|
||||
PriorityNormal Priority = iota
|
||||
PriorityConfig // use for reading from the config
|
||||
PriorityDefault // use for default values
|
||||
PriorityMax
|
||||
)
|
||||
|
||||
// Getter provides an interface to get config items
|
||||
@@ -45,13 +29,9 @@ type Mapper interface {
|
||||
// Map provides a wrapper around multiple Setter and
|
||||
// Getter interfaces.
|
||||
type Map struct {
|
||||
setters []Setter
|
||||
getters []getprio
|
||||
}
|
||||
|
||||
type getprio struct {
|
||||
getter Getter
|
||||
priority Priority
|
||||
setters []Setter
|
||||
getters []Getter
|
||||
override []Getter
|
||||
}
|
||||
|
||||
// New returns an empty Map
|
||||
@@ -59,12 +39,18 @@ func New() *Map {
|
||||
return &Map{}
|
||||
}
|
||||
|
||||
// AddGetter appends a getter onto the end of the getters in priority order
|
||||
func (c *Map) AddGetter(getter Getter, priority Priority) *Map {
|
||||
c.getters = append(c.getters, getprio{getter, priority})
|
||||
sort.SliceStable(c.getters, func(i, j int) bool {
|
||||
return c.getters[i].priority < c.getters[j].priority
|
||||
})
|
||||
// AddGetter appends a getter onto the end of the getters
|
||||
func (c *Map) AddGetter(getter Getter) *Map {
|
||||
c.getters = append(c.getters, getter)
|
||||
return c
|
||||
}
|
||||
|
||||
// AddOverrideGetter appends a getter onto the end of the getters
|
||||
//
|
||||
// It also appends it onto the override getters for GetOverride
|
||||
func (c *Map) AddOverrideGetter(getter Getter) *Map {
|
||||
c.getters = append(c.getters, getter)
|
||||
c.override = append(c.override, getter)
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -74,34 +60,12 @@ func (c *Map) AddSetter(setter Setter) *Map {
|
||||
return c
|
||||
}
|
||||
|
||||
// ClearSetters removes all the setters set so far
|
||||
func (c *Map) ClearSetters() *Map {
|
||||
c.setters = nil
|
||||
return c
|
||||
}
|
||||
|
||||
// ClearGetters removes all the getters with the priority given
|
||||
func (c *Map) ClearGetters(priority Priority) *Map {
|
||||
getters := c.getters[:0]
|
||||
for _, item := range c.getters {
|
||||
if item.priority != priority {
|
||||
getters = append(getters, item)
|
||||
}
|
||||
}
|
||||
c.getters = getters
|
||||
return c
|
||||
}
|
||||
|
||||
// GetPriority gets an item with the key passed in and return the
|
||||
// value from the first getter to return a result with priority <=
|
||||
// maxPriority. If the item is found then it returns true, otherwise
|
||||
// false.
|
||||
func (c *Map) GetPriority(key string, maxPriority Priority) (value string, ok bool) {
|
||||
for _, item := range c.getters {
|
||||
if item.priority > maxPriority {
|
||||
break
|
||||
}
|
||||
value, ok = item.getter.Get(key)
|
||||
// get gets an item with the key passed in and return the value from
|
||||
// the first getter. If the item is found then it returns true,
|
||||
// otherwise false.
|
||||
func (c *Map) get(key string, getters []Getter) (value string, ok bool) {
|
||||
for _, do := range getters {
|
||||
value, ok = do.Get(key)
|
||||
if ok {
|
||||
return value, ok
|
||||
}
|
||||
@@ -113,7 +77,14 @@ func (c *Map) GetPriority(key string, maxPriority Priority) (value string, ok bo
|
||||
// the first getter. If the item is found then it returns true,
|
||||
// otherwise false.
|
||||
func (c *Map) Get(key string) (value string, ok bool) {
|
||||
return c.GetPriority(key, PriorityMax)
|
||||
return c.get(key, c.getters)
|
||||
}
|
||||
|
||||
// GetOverride gets an item with the key passed in and return the
|
||||
// value from the first override getter. If the item is found then it
|
||||
// returns true, otherwise false.
|
||||
func (c *Map) GetOverride(key string) (value string, ok bool) {
|
||||
return c.get(key, c.override)
|
||||
}
|
||||
|
||||
// Set sets an item into all the stored setters.
|
||||
@@ -164,38 +135,3 @@ func (c Simple) String() string {
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// Encode from c into a string suitable for putting on the command line
|
||||
func (c Simple) Encode() (string, error) {
|
||||
if len(c) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
buf, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "encode simple map")
|
||||
}
|
||||
return base64.RawStdEncoding.EncodeToString(buf), nil
|
||||
}
|
||||
|
||||
// Decode an Encode~d string in into c
|
||||
func (c Simple) Decode(in string) error {
|
||||
// Remove all whitespace from the input string
|
||||
in = strings.Map(func(r rune) rune {
|
||||
if unicode.IsSpace(r) {
|
||||
return -1
|
||||
}
|
||||
return r
|
||||
}, in)
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
decodedM, err := base64.RawStdEncoding.DecodeString(in)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode simple map")
|
||||
}
|
||||
err = json.Unmarshal(decodedM, &c)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parse simple map")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package configmap
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -29,7 +27,7 @@ func TestConfigMapGet(t *testing.T) {
|
||||
"config1": "one",
|
||||
}
|
||||
|
||||
m.AddGetter(m1, PriorityNormal)
|
||||
m.AddGetter(m1)
|
||||
|
||||
value, found = m.Get("config1")
|
||||
assert.Equal(t, "one", value)
|
||||
@@ -44,7 +42,7 @@ func TestConfigMapGet(t *testing.T) {
|
||||
"config2": "two2",
|
||||
}
|
||||
|
||||
m.AddGetter(m2, PriorityNormal)
|
||||
m.AddGetter(m2)
|
||||
|
||||
value, found = m.Get("config1")
|
||||
assert.Equal(t, "one", value)
|
||||
@@ -90,160 +88,56 @@ func TestConfigMapSet(t *testing.T) {
|
||||
"config1": "beetroot",
|
||||
"config2": "potato",
|
||||
}, m2)
|
||||
|
||||
m.ClearSetters()
|
||||
|
||||
// Check that nothing gets set
|
||||
m.Set("config1", "BEETROOT")
|
||||
|
||||
assert.Equal(t, Simple{
|
||||
"config1": "beetroot",
|
||||
"config2": "potato",
|
||||
}, m1)
|
||||
assert.Equal(t, Simple{
|
||||
"config1": "beetroot",
|
||||
"config2": "potato",
|
||||
}, m2)
|
||||
|
||||
}
|
||||
|
||||
func TestConfigMapGetPriority(t *testing.T) {
|
||||
func TestConfigMapGetOverride(t *testing.T) {
|
||||
m := New()
|
||||
|
||||
value, found := m.GetPriority("config1", PriorityMax)
|
||||
value, found := m.GetOverride("config1")
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, false, found)
|
||||
|
||||
value, found = m.GetPriority("config2", PriorityMax)
|
||||
value, found = m.GetOverride("config2")
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, false, found)
|
||||
|
||||
m1 := Simple{
|
||||
"config1": "one",
|
||||
"config3": "three",
|
||||
}
|
||||
|
||||
m.AddGetter(m1, PriorityConfig)
|
||||
m.AddOverrideGetter(m1)
|
||||
|
||||
value, found = m.GetPriority("config1", PriorityNormal)
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, false, found)
|
||||
|
||||
value, found = m.GetPriority("config2", PriorityNormal)
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, false, found)
|
||||
|
||||
value, found = m.GetPriority("config3", PriorityNormal)
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, false, found)
|
||||
|
||||
value, found = m.GetPriority("config1", PriorityConfig)
|
||||
value, found = m.GetOverride("config1")
|
||||
assert.Equal(t, "one", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config2", PriorityConfig)
|
||||
value, found = m.GetOverride("config2")
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, false, found)
|
||||
|
||||
value, found = m.GetPriority("config3", PriorityConfig)
|
||||
assert.Equal(t, "three", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config1", PriorityMax)
|
||||
assert.Equal(t, "one", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config2", PriorityMax)
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, false, found)
|
||||
|
||||
value, found = m.GetPriority("config3", PriorityMax)
|
||||
assert.Equal(t, "three", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
m2 := Simple{
|
||||
"config1": "one2",
|
||||
"config2": "two2",
|
||||
}
|
||||
|
||||
m.AddGetter(m2, PriorityNormal)
|
||||
m.AddGetter(m2)
|
||||
|
||||
value, found = m.GetPriority("config1", PriorityNormal)
|
||||
assert.Equal(t, "one2", value)
|
||||
value, found = m.GetOverride("config1")
|
||||
assert.Equal(t, "one", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config2", PriorityNormal)
|
||||
assert.Equal(t, "two2", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config3", PriorityNormal)
|
||||
value, found = m.GetOverride("config2")
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, false, found)
|
||||
|
||||
value, found = m.GetPriority("config1", PriorityConfig)
|
||||
assert.Equal(t, "one2", value)
|
||||
value, found = m.Get("config1")
|
||||
assert.Equal(t, "one", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config2", PriorityConfig)
|
||||
value, found = m.Get("config2")
|
||||
assert.Equal(t, "two2", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config3", PriorityConfig)
|
||||
assert.Equal(t, "three", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config1", PriorityMax)
|
||||
assert.Equal(t, "one2", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config2", PriorityMax)
|
||||
assert.Equal(t, "two2", value)
|
||||
assert.Equal(t, true, found)
|
||||
|
||||
value, found = m.GetPriority("config3", PriorityMax)
|
||||
assert.Equal(t, "three", value)
|
||||
assert.Equal(t, true, found)
|
||||
}
|
||||
|
||||
func TestConfigMapClearGetters(t *testing.T) {
|
||||
m := New()
|
||||
m1 := Simple{}
|
||||
m2 := Simple{}
|
||||
m3 := Simple{}
|
||||
m.AddGetter(m1, PriorityNormal)
|
||||
m.AddGetter(m2, PriorityDefault)
|
||||
m.AddGetter(m3, PriorityConfig)
|
||||
assert.Equal(t, []getprio{
|
||||
{m1, PriorityNormal},
|
||||
{m3, PriorityConfig},
|
||||
{m2, PriorityDefault},
|
||||
}, m.getters)
|
||||
m.ClearGetters(PriorityConfig)
|
||||
assert.Equal(t, []getprio{
|
||||
{m1, PriorityNormal},
|
||||
{m2, PriorityDefault},
|
||||
}, m.getters)
|
||||
m.ClearGetters(PriorityNormal)
|
||||
assert.Equal(t, []getprio{
|
||||
{m2, PriorityDefault},
|
||||
}, m.getters)
|
||||
m.ClearGetters(PriorityDefault)
|
||||
assert.Equal(t, []getprio{}, m.getters)
|
||||
m.ClearGetters(PriorityDefault)
|
||||
assert.Equal(t, []getprio{}, m.getters)
|
||||
}
|
||||
|
||||
func TestConfigMapClearSetters(t *testing.T) {
|
||||
m := New()
|
||||
m1 := Simple{}
|
||||
m2 := Simple{}
|
||||
m3 := Simple{}
|
||||
m.AddSetter(m1)
|
||||
m.AddSetter(m2)
|
||||
m.AddSetter(m3)
|
||||
assert.Equal(t, []Setter{m1, m2, m3}, m.setters)
|
||||
m.ClearSetters()
|
||||
assert.Equal(t, []Setter(nil), m.setters)
|
||||
}
|
||||
|
||||
func TestSimpleString(t *testing.T) {
|
||||
@@ -269,91 +163,3 @@ func TestSimpleString(t *testing.T) {
|
||||
"apple": "",
|
||||
}.String())
|
||||
}
|
||||
|
||||
func TestSimpleEncode(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in Simple
|
||||
want string
|
||||
}{
|
||||
{
|
||||
in: Simple{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
in: Simple{
|
||||
"one": "potato",
|
||||
},
|
||||
want: "eyJvbmUiOiJwb3RhdG8ifQ",
|
||||
},
|
||||
{
|
||||
in: Simple{
|
||||
"one": "potato",
|
||||
"two": "",
|
||||
},
|
||||
want: "eyJvbmUiOiJwb3RhdG8iLCJ0d28iOiIifQ",
|
||||
},
|
||||
} {
|
||||
got, err := test.in.Encode()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.want, got)
|
||||
gotM := Simple{}
|
||||
err = gotM.Decode(got)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.in, gotM)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleDecode(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
want Simple
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
in: "",
|
||||
want: Simple{},
|
||||
},
|
||||
{
|
||||
in: "eyJvbmUiOiJwb3RhdG8ifQ",
|
||||
want: Simple{
|
||||
"one": "potato",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: " e yJvbm UiOiJwb\r\n 3Rhd\tG8ifQ\n\n ",
|
||||
want: Simple{
|
||||
"one": "potato",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "eyJvbmUiOiJwb3RhdG8iLCJ0d28iOiIifQ",
|
||||
want: Simple{
|
||||
"one": "potato",
|
||||
"two": "",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "!!!!!",
|
||||
want: Simple{},
|
||||
wantErr: "decode simple map",
|
||||
},
|
||||
{
|
||||
in: base64.RawStdEncoding.EncodeToString([]byte(`null`)),
|
||||
want: Simple{},
|
||||
},
|
||||
{
|
||||
in: base64.RawStdEncoding.EncodeToString([]byte(`rubbish`)),
|
||||
want: Simple{},
|
||||
wantErr: "parse simple map",
|
||||
},
|
||||
} {
|
||||
got := Simple{}
|
||||
err := got.Decode(test.in)
|
||||
assert.Equal(t, test.want, got, test.in)
|
||||
if test.wantErr == "" {
|
||||
require.NoError(t, err, test.in)
|
||||
} else {
|
||||
assert.Contains(t, err.Error(), test.wantErr, test.in)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ import (
|
||||
|
||||
func TestConfigLoadEncrypted(t *testing.T) {
|
||||
var err error
|
||||
oldConfigPath := config.GetConfigPath()
|
||||
assert.NoError(t, config.SetConfigPath("./testdata/encrypted.conf"))
|
||||
oldConfigPath := config.ConfigPath
|
||||
config.ConfigPath = "./testdata/encrypted.conf"
|
||||
defer func() {
|
||||
assert.NoError(t, config.SetConfigPath(oldConfigPath))
|
||||
config.ConfigPath = oldConfigPath
|
||||
config.ClearConfigPassword()
|
||||
}()
|
||||
|
||||
@@ -40,13 +40,13 @@ func TestConfigLoadEncrypted(t *testing.T) {
|
||||
func TestConfigLoadEncryptedWithValidPassCommand(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ci := fs.GetConfig(ctx)
|
||||
oldConfigPath := config.GetConfigPath()
|
||||
oldConfigPath := config.ConfigPath
|
||||
oldConfig := *ci
|
||||
assert.NoError(t, config.SetConfigPath("./testdata/encrypted.conf"))
|
||||
config.ConfigPath = "./testdata/encrypted.conf"
|
||||
// using ci.PasswordCommand, correct password
|
||||
ci.PasswordCommand = fs.SpaceSepList{"echo", "asdf"}
|
||||
defer func() {
|
||||
assert.NoError(t, config.SetConfigPath(oldConfigPath))
|
||||
config.ConfigPath = oldConfigPath
|
||||
config.ClearConfigPassword()
|
||||
*ci = oldConfig
|
||||
ci.PasswordCommand = nil
|
||||
@@ -69,13 +69,13 @@ func TestConfigLoadEncryptedWithValidPassCommand(t *testing.T) {
|
||||
func TestConfigLoadEncryptedWithInvalidPassCommand(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ci := fs.GetConfig(ctx)
|
||||
oldConfigPath := config.GetConfigPath()
|
||||
oldConfigPath := config.ConfigPath
|
||||
oldConfig := *ci
|
||||
assert.NoError(t, config.SetConfigPath("./testdata/encrypted.conf"))
|
||||
config.ConfigPath = "./testdata/encrypted.conf"
|
||||
// using ci.PasswordCommand, incorrect password
|
||||
ci.PasswordCommand = fs.SpaceSepList{"echo", "asdf-blurfl"}
|
||||
defer func() {
|
||||
assert.NoError(t, config.SetConfigPath(oldConfigPath))
|
||||
config.ConfigPath = oldConfigPath
|
||||
config.ClearConfigPassword()
|
||||
*ci = oldConfig
|
||||
ci.PasswordCommand = nil
|
||||
@@ -92,24 +92,24 @@ func TestConfigLoadEncryptedFailures(t *testing.T) {
|
||||
var err error
|
||||
|
||||
// This file should be too short to be decoded.
|
||||
oldConfigPath := config.GetConfigPath()
|
||||
assert.NoError(t, config.SetConfigPath("./testdata/enc-short.conf"))
|
||||
defer func() { assert.NoError(t, config.SetConfigPath(oldConfigPath)) }()
|
||||
oldConfigPath := config.ConfigPath
|
||||
config.ConfigPath = "./testdata/enc-short.conf"
|
||||
defer func() { config.ConfigPath = oldConfigPath }()
|
||||
err = config.Data.Load()
|
||||
require.Error(t, err)
|
||||
|
||||
// This file contains invalid base64 characters.
|
||||
assert.NoError(t, config.SetConfigPath("./testdata/enc-invalid.conf"))
|
||||
config.ConfigPath = "./testdata/enc-invalid.conf"
|
||||
err = config.Data.Load()
|
||||
require.Error(t, err)
|
||||
|
||||
// This file contains invalid base64 characters.
|
||||
assert.NoError(t, config.SetConfigPath("./testdata/enc-too-new.conf"))
|
||||
config.ConfigPath = "./testdata/enc-too-new.conf"
|
||||
err = config.Data.Load()
|
||||
require.Error(t, err)
|
||||
|
||||
// This file does not exist.
|
||||
assert.NoError(t, config.SetConfigPath("./testdata/filenotfound.conf"))
|
||||
config.ConfigPath = "./testdata/filenotfound.conf"
|
||||
err = config.Data.Load()
|
||||
assert.Equal(t, config.ErrorConfigFileNotFound, err)
|
||||
}
|
||||
|
||||
@@ -535,16 +535,12 @@ func CopyRemote(name string) {
|
||||
|
||||
// ShowConfigLocation prints the location of the config file in use
|
||||
func ShowConfigLocation() {
|
||||
if configPath := GetConfigPath(); configPath == "" {
|
||||
fmt.Println("Configuration is in memory only")
|
||||
if _, err := os.Stat(ConfigPath); os.IsNotExist(err) {
|
||||
fmt.Println("Configuration file doesn't exist, but rclone will use this path:")
|
||||
} else {
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
fmt.Println("Configuration file doesn't exist, but rclone will use this path:")
|
||||
} else {
|
||||
fmt.Println("Configuration file is stored at:")
|
||||
}
|
||||
fmt.Printf("%s\n", configPath)
|
||||
fmt.Println("Configuration file is stored at:")
|
||||
}
|
||||
fmt.Printf("%s\n", ConfigPath)
|
||||
}
|
||||
|
||||
// ShowConfig prints the (unencrypted) config options
|
||||
|
||||
@@ -34,13 +34,13 @@ func testConfigFile(t *testing.T, configFileName string) func() {
|
||||
|
||||
// temporarily adapt configuration
|
||||
oldOsStdout := os.Stdout
|
||||
oldConfigPath := config.GetConfigPath()
|
||||
oldConfigPath := config.ConfigPath
|
||||
oldConfig := *ci
|
||||
oldConfigFile := config.Data
|
||||
oldReadLine := config.ReadLine
|
||||
oldPassword := config.Password
|
||||
os.Stdout = nil
|
||||
assert.NoError(t, config.SetConfigPath(path))
|
||||
config.ConfigPath = path
|
||||
ci = &fs.ConfigInfo{}
|
||||
|
||||
configfile.LoadConfig(ctx)
|
||||
@@ -69,7 +69,7 @@ func testConfigFile(t *testing.T, configFileName string) func() {
|
||||
assert.NoError(t, err)
|
||||
|
||||
os.Stdout = oldOsStdout
|
||||
assert.NoError(t, config.SetConfigPath(oldConfigPath))
|
||||
config.ConfigPath = oldConfigPath
|
||||
config.ReadLine = oldReadLine
|
||||
config.Password = oldPassword
|
||||
*ci = oldConfig
|
||||
|
||||
59
fs/fs.go
59
fs/fs.go
@@ -125,38 +125,6 @@ func (os Options) Get(name string) *Option {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Overridden discovers which config items have been overridden in the
|
||||
// configmap passed in, either by the config string, command line
|
||||
// flags or environment variables
|
||||
func (os Options) Overridden(m *configmap.Map) configmap.Simple {
|
||||
var overridden = configmap.Simple{}
|
||||
for i := range os {
|
||||
opt := &os[i]
|
||||
value, isSet := m.GetPriority(opt.Name, configmap.PriorityNormal)
|
||||
if isSet {
|
||||
overridden.Set(opt.Name, value)
|
||||
}
|
||||
}
|
||||
return overridden
|
||||
}
|
||||
|
||||
// NonDefault discovers which config values aren't at their default
|
||||
func (os Options) NonDefault(m configmap.Getter) configmap.Simple {
|
||||
var nonDefault = configmap.Simple{}
|
||||
for i := range os {
|
||||
opt := &os[i]
|
||||
value, isSet := m.Get(opt.Name)
|
||||
if !isSet {
|
||||
continue
|
||||
}
|
||||
defaultValue := fmt.Sprint(opt.Default)
|
||||
if value != defaultValue {
|
||||
nonDefault.Set(opt.Name, value)
|
||||
}
|
||||
}
|
||||
return nonDefault
|
||||
}
|
||||
|
||||
// OptionVisibility controls whether the options are visible in the
|
||||
// configurator or the command line.
|
||||
type OptionVisibility byte
|
||||
@@ -1317,8 +1285,7 @@ type setConfigFile string
|
||||
// Set a config item into the config file
|
||||
func (section setConfigFile) Set(key, value string) {
|
||||
if strings.HasPrefix(string(section), ":") {
|
||||
Logf(nil, "Can't save config %q = %q for on the fly backend %q", key, value, section)
|
||||
return
|
||||
Errorf(nil, "Can't save config %q = %q for on the fly backend %q", key, value, section)
|
||||
}
|
||||
Debugf(nil, "Saving config %q = %q in section %q of the config file", key, value, section)
|
||||
err := ConfigFileSet(string(section), key, value)
|
||||
@@ -1354,28 +1321,28 @@ func ConfigMap(fsInfo *RegInfo, configName string, connectionStringConfig config
|
||||
|
||||
// Config from connection string
|
||||
if len(connectionStringConfig) > 0 {
|
||||
config.AddGetter(connectionStringConfig, configmap.PriorityNormal)
|
||||
config.AddOverrideGetter(connectionStringConfig)
|
||||
}
|
||||
|
||||
// flag values
|
||||
if fsInfo != nil {
|
||||
config.AddGetter(®InfoValues{fsInfo, false}, configmap.PriorityNormal)
|
||||
config.AddOverrideGetter(®InfoValues{fsInfo, false})
|
||||
}
|
||||
|
||||
// remote specific environment vars
|
||||
config.AddGetter(configEnvVars(configName), configmap.PriorityNormal)
|
||||
config.AddOverrideGetter(configEnvVars(configName))
|
||||
|
||||
// backend specific environment vars
|
||||
if fsInfo != nil {
|
||||
config.AddGetter(optionEnvVars{fsInfo: fsInfo}, configmap.PriorityNormal)
|
||||
config.AddOverrideGetter(optionEnvVars{fsInfo: fsInfo})
|
||||
}
|
||||
|
||||
// config file
|
||||
config.AddGetter(getConfigFile(configName), configmap.PriorityConfig)
|
||||
config.AddGetter(getConfigFile(configName))
|
||||
|
||||
// default values
|
||||
if fsInfo != nil {
|
||||
config.AddGetter(®InfoValues{fsInfo, true}, configmap.PriorityDefault)
|
||||
config.AddGetter(®InfoValues{fsInfo, true})
|
||||
}
|
||||
|
||||
// Set Config
|
||||
@@ -1414,7 +1381,17 @@ func NewFs(ctx context.Context, path string) (Fs, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
overridden := fsInfo.Options.Overridden(config)
|
||||
// Now discover which config items have been overridden,
|
||||
// either by the config string, command line flags or
|
||||
// environment variables
|
||||
var overridden = configmap.Simple{}
|
||||
for i := range fsInfo.Options {
|
||||
opt := &fsInfo.Options[i]
|
||||
value, isSet := config.GetOverride(opt.Name)
|
||||
if isSet {
|
||||
overridden.Set(opt.Name, value)
|
||||
}
|
||||
}
|
||||
if len(overridden) > 0 {
|
||||
extraConfig := overridden.String()
|
||||
//Debugf(nil, "detected overriden config %q", extraConfig)
|
||||
|
||||
@@ -190,43 +190,6 @@ func TestOptionsGet(t *testing.T) {
|
||||
assert.Nil(t, opt)
|
||||
}
|
||||
|
||||
func TestOptionsOveridden(t *testing.T) {
|
||||
m := configmap.New()
|
||||
m1 := configmap.Simple{
|
||||
"nounc": "m1",
|
||||
"copy_links": "m1",
|
||||
}
|
||||
m.AddGetter(m1, configmap.PriorityNormal)
|
||||
m2 := configmap.Simple{
|
||||
"nounc": "m2",
|
||||
"case_insensitive": "m2",
|
||||
}
|
||||
m.AddGetter(m2, configmap.PriorityConfig)
|
||||
m3 := configmap.Simple{
|
||||
"nounc": "m3",
|
||||
}
|
||||
m.AddGetter(m3, configmap.PriorityDefault)
|
||||
got := testOptions.Overridden(m)
|
||||
assert.Equal(t, configmap.Simple{
|
||||
"copy_links": "m1",
|
||||
"nounc": "m1",
|
||||
}, got)
|
||||
}
|
||||
|
||||
func TestOptionsNonDefault(t *testing.T) {
|
||||
m := configmap.Simple{}
|
||||
got := testOptions.NonDefault(m)
|
||||
assert.Equal(t, configmap.Simple{}, got)
|
||||
|
||||
m["case_insensitive"] = "false"
|
||||
got = testOptions.NonDefault(m)
|
||||
assert.Equal(t, configmap.Simple{}, got)
|
||||
|
||||
m["case_insensitive"] = "true"
|
||||
got = testOptions.NonDefault(m)
|
||||
assert.Equal(t, configmap.Simple{"case_insensitive": "true"}, got)
|
||||
}
|
||||
|
||||
func TestOptionMarshalJSON(t *testing.T) {
|
||||
out, err := json.MarshalIndent(&caseInsensitiveOption, "", "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -155,9 +155,7 @@ func newSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
|
||||
// Input context - cancel this for graceful stop
|
||||
s.inCtx, s.inCancel = context.WithCancel(s.ctx)
|
||||
if s.noTraverse && s.deleteMode != fs.DeleteModeOff {
|
||||
if !fi.HaveFilesFrom() {
|
||||
fs.Errorf(nil, "Ignoring --no-traverse with sync")
|
||||
}
|
||||
fs.Errorf(nil, "Ignoring --no-traverse with sync")
|
||||
s.noTraverse = false
|
||||
}
|
||||
s.trackRenamesStrategy, err = parseTrackRenamesStrategy(ci.TrackRenamesStrategy)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package fs
|
||||
|
||||
// Version of rclone
|
||||
var Version = "v1.56.0-DEV"
|
||||
var Version = "v1.55.1-DEV"
|
||||
|
||||
@@ -69,7 +69,7 @@ func Initialise() {
|
||||
// parse the flags any more so this doesn't happen
|
||||
// automatically
|
||||
if envConfig := os.Getenv("RCLONE_CONFIG"); envConfig != "" {
|
||||
_ = config.SetConfigPath(envConfig)
|
||||
config.ConfigPath = envConfig
|
||||
}
|
||||
configfile.LoadConfig(ctx)
|
||||
accounting.Start(ctx)
|
||||
|
||||
@@ -61,8 +61,6 @@ type ChunkedUploadConfig struct {
|
||||
CeilChunkSize func(fs.SizeSuffix) fs.SizeSuffix
|
||||
// More than one chunk is required on upload
|
||||
NeedMultipleChunks bool
|
||||
// Skip this particular remote
|
||||
Skip bool
|
||||
}
|
||||
|
||||
// SetUploadChunkSizer is a test only interface to change the upload chunk size at runtime
|
||||
@@ -1779,10 +1777,6 @@ func Run(t *testing.T, opt *Opt) {
|
||||
t.Skip("not running with -short")
|
||||
}
|
||||
|
||||
if opt.ChunkedUpload.Skip {
|
||||
t.Skip("skipping as ChunkedUpload.Skip is set")
|
||||
}
|
||||
|
||||
setUploadChunkSizer, _ := f.(SetUploadChunkSizer)
|
||||
if setUploadChunkSizer == nil {
|
||||
t.Skipf("%T does not implement SetUploadChunkSizer", f)
|
||||
|
||||
@@ -189,9 +189,6 @@ backends:
|
||||
- backend: "sftp"
|
||||
remote: "TestSFTPRclone:"
|
||||
fastlist: false
|
||||
- backend: "sftp"
|
||||
remote: "TestSFTPRsyncNet:"
|
||||
fastlist: false
|
||||
- backend: "sugarsync"
|
||||
remote: "TestSugarSync:Test"
|
||||
fastlist: false
|
||||
@@ -326,8 +323,3 @@ backends:
|
||||
fastlist: false
|
||||
ignore:
|
||||
- TestSyncUTFNorm
|
||||
- backend: "uptobox"
|
||||
remote: "TestUptobox:"
|
||||
fastlist: false
|
||||
ignore:
|
||||
- TestRWFileHandleWriteNoWrite
|
||||
|
||||
@@ -17,10 +17,11 @@ start() {
|
||||
nextcloud:latest
|
||||
|
||||
echo type=webdav
|
||||
echo url=http://$(docker_ip)/remote.php/dav/files/$USER/
|
||||
echo url=http://$(docker_ip)/remote.php/webdav/
|
||||
echo user=$USER
|
||||
echo pass=$(rclone obscure $PASS)
|
||||
echo vendor=nextcloud
|
||||
# the tests don't pass if we use the nextcloud features
|
||||
# echo vendor=nextcloud
|
||||
echo _connect=$(docker_ip):80
|
||||
}
|
||||
|
||||
|
||||
70
go.mod
70
go.mod
@@ -4,19 +4,19 @@ go 1.14
|
||||
|
||||
require (
|
||||
bazil.org/fuse v0.0.0-20200524192727-fb710f7dfd05
|
||||
cloud.google.com/go v0.76.0 // indirect
|
||||
github.com/Azure/azure-pipeline-go v0.2.3
|
||||
github.com/Azure/azure-storage-blob-go v0.13.0
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.13
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.10
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c
|
||||
github.com/Microsoft/go-winio v0.4.17 // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.16 // indirect
|
||||
github.com/Unknwon/goconfig v0.0.0-20200908083735-df7de6a44db8
|
||||
github.com/a8m/tree v0.0.0-20210414114729-ce3525c5c2ef
|
||||
github.com/a8m/tree v0.0.0-20210115125333-10a5fd5b637d
|
||||
github.com/aalpar/deheap v0.0.0-20200318053559-9a0c2883bd56
|
||||
github.com/abbot/go-http-auth v0.4.0
|
||||
github.com/anacrolix/dms v1.2.2
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/aws/aws-sdk-go v1.38.22
|
||||
github.com/anacrolix/dms v1.2.0
|
||||
github.com/atotto/clipboard v0.1.2
|
||||
github.com/aws/aws-sdk-go v1.37.3
|
||||
github.com/billziss-gh/cgofuse v1.5.0
|
||||
github.com/buengese/sgzip v0.1.1
|
||||
github.com/calebcase/tmpfile v1.0.2 // indirect
|
||||
@@ -24,64 +24,60 @@ require (
|
||||
github.com/coreos/go-semver v0.3.0
|
||||
github.com/dop251/scsu v0.0.0-20200422003335-8fadfb689669
|
||||
github.com/dropbox/dropbox-sdk-go-unofficial v1.0.1-0.20210114204226-41fdcdae8a53
|
||||
github.com/gabriel-vasile/mimetype v1.2.0
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.1.2
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/hanwen/go-fuse/v2 v2.1.0
|
||||
github.com/hanwen/go-fuse/v2 v2.0.3
|
||||
github.com/iguanesolutions/go-systemd/v5 v5.0.0
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.2
|
||||
github.com/jlaffaye/ftp v0.0.0-20210307004419-5d4190119067
|
||||
github.com/jlaffaye/ftp v0.0.0-20210302195756-c3c8c7ac6590
|
||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||
github.com/klauspost/compress v1.12.1
|
||||
github.com/klauspost/compress v1.11.7
|
||||
github.com/koofr/go-httpclient v0.0.0-20200420163713-93aa7c75b348
|
||||
github.com/koofr/go-koofrclient v0.0.0-20190724113126-8e5366da203a
|
||||
github.com/mattn/go-colorable v0.1.8
|
||||
github.com/mattn/go-runewidth v0.0.12
|
||||
github.com/mattn/go-runewidth v0.0.10
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/ncw/go-acd v0.0.0-20201019170801-fe55f33415b1
|
||||
github.com/ncw/swift/v2 v2.0.0
|
||||
github.com/nsf/termbox-go v1.1.1-0.20210421210813-2ff630277754
|
||||
github.com/nsf/termbox-go v0.0.0-20210114135735-d04385b850e8
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/sftp v1.13.1-0.20210424083437-2b80967078b8
|
||||
github.com/prometheus/client_golang v1.10.0
|
||||
github.com/prometheus/common v0.20.0 // indirect
|
||||
github.com/pkg/sftp v1.12.0
|
||||
github.com/prometheus/client_golang v1.9.0
|
||||
github.com/prometheus/procfs v0.3.0 // indirect
|
||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8
|
||||
github.com/rfjakob/eme v1.1.1
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sevlyar/go-daemon v0.1.5
|
||||
github.com/shirou/gopsutil/v3 v3.21.3
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/sirupsen/logrus v1.7.0
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.11 // indirect
|
||||
github.com/spf13/cobra v1.1.3
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20200416171014-ffad7fcb44b8
|
||||
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
|
||||
github.com/yunify/qingstor-sdk-go/v3 v3.2.0
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
go.opencensus.io v0.22.6 // indirect
|
||||
go.uber.org/zap v1.16.0 // indirect
|
||||
goftp.io/server v0.4.1
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
|
||||
golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d
|
||||
golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7
|
||||
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 // indirect
|
||||
golang.org/x/text v0.3.6
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
google.golang.org/api v0.44.0
|
||||
google.golang.org/genproto v0.0.0-20210416161957-9910b6c460de // indirect
|
||||
google.golang.org/grpc v1.37.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
||||
golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||
golang.org/x/sys v0.0.0-20210313110737-8e9fff1a3a18
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
|
||||
golang.org/x/text v0.3.5
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
|
||||
google.golang.org/api v0.38.0
|
||||
google.golang.org/genproto v0.0.0-20210203152818-3206188e46ba // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
storj.io/common v0.0.0-20210419115916-eabb53ea1332 // indirect
|
||||
storj.io/uplink v1.4.6
|
||||
storj.io/common v0.0.0-20210203145648-3768017a858e // indirect
|
||||
storj.io/uplink v1.4.5
|
||||
)
|
||||
|
||||
218
go.sum
218
go.sum
@@ -17,10 +17,8 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go v0.76.0 h1:Ckw+E/QYZgd/5bpI4wz4h6f+jmpvh9S9uSrKNnbicJI=
|
||||
cloud.google.com/go v0.76.0/go.mod h1:r9EvIAvLrunusnetGdQ50M/gKui1x3zdGW/VELGkdpw=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
@@ -47,14 +45,12 @@ github.com/Azure/azure-storage-blob-go v0.13.0/go.mod h1:pA9kNqtjUeQF2zOSu4s//nU
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.10 h1:r6fZHMaHD8B6LDCn0o5vyBFHIHrM6Ywwx7mb49lPItI=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.10/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
|
||||
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
|
||||
@@ -65,20 +61,17 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
||||
github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w=
|
||||
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjlRbWyNqkPsJ3Fg+tQZCbgeX1VGljbQY=
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/Unknwon/goconfig v0.0.0-20200908083735-df7de6a44db8 h1:1TrMV1HmBApBbM+Hy7RCKZD6UlYWYIPPfoeXomG7+zE=
|
||||
github.com/Unknwon/goconfig v0.0.0-20200908083735-df7de6a44db8/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/a8m/tree v0.0.0-20210414114729-ce3525c5c2ef h1:CEImiMYHUtgFAgG8UMV6Mk4Ld+IgF39eBbhoehcjXEg=
|
||||
github.com/a8m/tree v0.0.0-20210414114729-ce3525c5c2ef/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg=
|
||||
github.com/a8m/tree v0.0.0-20210115125333-10a5fd5b637d h1:4E8RufAN3UQ/weB6AnQ4y5miZCO0Yco8ZdGId41WuQs=
|
||||
github.com/a8m/tree v0.0.0-20210115125333-10a5fd5b637d/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg=
|
||||
github.com/aalpar/deheap v0.0.0-20200318053559-9a0c2883bd56 h1:hJO00l0f92EcQn8Ygc9Y0oP++eESKvcyp+KedtfT5SQ=
|
||||
github.com/aalpar/deheap v0.0.0-20200318053559-9a0c2883bd56/go.mod h1:EJFoWbcEEVK22GYKONJjtMNamGYe6p+3x1Pr6zV5gFs=
|
||||
github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0=
|
||||
@@ -90,8 +83,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/anacrolix/dms v1.2.2 h1:0mk2/DXNqa5KDDbaLgFPf3oMV6VCGdFNh3d/gt4oafM=
|
||||
github.com/anacrolix/dms v1.2.2/go.mod h1:msPKAoppoNRfrYplJqx63FZ+VipDZ4Xsj3KzIQxyU7k=
|
||||
github.com/anacrolix/dms v1.2.0 h1:e5/oAtynS31rCC3yBDoun40SdDPc7uDQryOietVYfck=
|
||||
github.com/anacrolix/dms v1.2.0/go.mod h1:msPKAoppoNRfrYplJqx63FZ+VipDZ4Xsj3KzIQxyU7k=
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||
github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||
github.com/anacrolix/ffprobe v1.0.0/go.mod h1:BIw+Bjol6CWjm/CRWrVLk2Vy+UYlkgmBZ05vpSYqZPw=
|
||||
@@ -103,12 +96,12 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/atotto/clipboard v0.1.2 h1:YZCtFu5Ie8qX2VmVTBnrqLSiU9XOWwqNRmdT3gIQzbY=
|
||||
github.com/atotto/clipboard v0.1.2/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.38.22 h1:hJwaMazDt7EP4Rz/T4RQmdchWWv+YB3+/i6AOUWjVL0=
|
||||
github.com/aws/aws-sdk-go v1.38.22/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.37.3 h1:1f0groABc4AuapskpHf6EBRaG2tqw0Sx3ebCMwfp1Ys=
|
||||
github.com/aws/aws-sdk-go v1.37.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
@@ -123,6 +116,7 @@ github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2w
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.3-0.20201124182144-4031bdc69ded/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
|
||||
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ=
|
||||
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
@@ -193,7 +187,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
||||
@@ -202,8 +195,8 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gabriel-vasile/mimetype v1.2.0 h1:A6z5J8OhjiWFV91sQ3dMI8apYu/tvP9keDaMM3Xu6p4=
|
||||
github.com/gabriel-vasile/mimetype v1.2.0/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
|
||||
github.com/gabriel-vasile/mimetype v1.1.2 h1:gaPnPcNor5aZSVCJVSGipcpbgMWiAAj9z182ocSGbHU=
|
||||
github.com/gabriel-vasile/mimetype v1.1.2/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
@@ -216,9 +209,6 @@ github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgO
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
@@ -232,9 +222,8 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
@@ -242,7 +231,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -257,13 +245,9 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@@ -276,11 +260,10 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -295,7 +278,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -325,8 +307,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hanwen/go-fuse v1.0.0 h1:GxS9Zrn6c35/BnfiVsZVWmsG803xwE7eVRDvcf/BEVc=
|
||||
github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=
|
||||
github.com/hanwen/go-fuse/v2 v2.1.0 h1:+32ffteETaLYClUj0a3aHjZ1hOPxxaNEHiZiujuDaek=
|
||||
github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc=
|
||||
github.com/hanwen/go-fuse/v2 v2.0.3 h1:kpV28BKeSyVgZREItBLnaVBvOEwv2PuhNdKetwnvNHo=
|
||||
github.com/hanwen/go-fuse/v2 v2.0.3/go.mod h1:0EQM6aH2ctVpvZ6a+onrQ/vaykxh2GH7hy3e13vzTUY=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
@@ -379,8 +361,8 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jlaffaye/ftp v0.0.0-20190624084859-c1312a7102bf/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY=
|
||||
github.com/jlaffaye/ftp v0.0.0-20210307004419-5d4190119067 h1:P2S26PMwXl8+ZGuOG3C69LG4be5vHafUayZm9VPw3tU=
|
||||
github.com/jlaffaye/ftp v0.0.0-20210307004419-5d4190119067/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
||||
github.com/jlaffaye/ftp v0.0.0-20210302195756-c3c8c7ac6590 h1:LdzPlwF41dX3RKFAALxs/iHwLHm6T0nScWRdkIVNykM=
|
||||
github.com/jlaffaye/ftp v0.0.0-20210302195756-c3c8c7ac6590/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
@@ -408,8 +390,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.12.1 h1:/+xsCsk06wE38cyiqOR/o7U2fSftcH72xD+BQXmja/g=
|
||||
github.com/klauspost/compress v1.12.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
|
||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/koofr/go-httpclient v0.0.0-20200420163713-93aa7c75b348 h1:Lrn8srO9JDBCf2iPjqy62stl49UDwoOxZ9/NGVi+fnk=
|
||||
@@ -440,8 +422,8 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
@@ -477,10 +459,8 @@ github.com/ncw/swift/v2 v2.0.0/go.mod h1:z0A9RVdYPjNjXVo2pDOPxZ4eu3oarO1P91fTItc
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nsf/termbox-go v1.1.0 h1:R+GIXVMaDxDQ2VHem5vO5h0mI8ZxLECTUNw1ZzXODzI=
|
||||
github.com/nsf/termbox-go v1.1.0/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
|
||||
github.com/nsf/termbox-go v1.1.1-0.20210421210813-2ff630277754 h1:4x51LJd1K+SE/z5cvh711BBMMAS9nHr9V3sXdns3HWQ=
|
||||
github.com/nsf/termbox-go v1.1.1-0.20210421210813-2ff630277754/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
|
||||
github.com/nsf/termbox-go v0.0.0-20210114135735-d04385b850e8 h1:3vzIuru1svOK2sXlg4XcrO3KkGRneIejmfQfR+ptSW8=
|
||||
github.com/nsf/termbox-go v0.0.0-20210114135735-d04385b850e8/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
@@ -522,8 +502,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pkg/sftp v1.12.0 h1:/f3b24xrDhkhddlaobPe2JgBqfdt+gC/NYl0QY9IOuI=
|
||||
github.com/pkg/sftp v1.12.0/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8=
|
||||
github.com/pkg/sftp v1.13.1-0.20210424083437-2b80967078b8 h1:0sHotAvxm+h6PnYq2sz+xbbmPyzCMsubDzTMqT1Gbkw=
|
||||
github.com/pkg/sftp v1.13.1-0.20210424083437-2b80967078b8/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
@@ -533,8 +511,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg=
|
||||
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
|
||||
github.com/prometheus/client_golang v1.9.0 h1:Rrch9mh17XcxvEu9D9DEpb4isxjGBtcevQjKvxPRQIU=
|
||||
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
@@ -548,17 +526,17 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.20.0 h1:pfeDeUdQcIxOMutNjCejsEFp7qeP+/iltHSSmLpE+hU=
|
||||
github.com/prometheus/common v0.20.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
|
||||
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.3.0 h1:Uehi/mxLK0eiUc0H0++5tpMGTexB8wZ598MIgU8VpDM=
|
||||
github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 h1:Y258uzXU/potCYnQd1r6wlAnoMB68BiCkCcCnKx1SH8=
|
||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8/go.mod h1:bSJjRokAHHOhA+XFxplld8w2R/dXLH7Z3BZ532vhFwU=
|
||||
@@ -580,16 +558,13 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sevlyar/go-daemon v0.1.5 h1:Zy/6jLbM8CfqJ4x4RPr7MJlSKt90f00kNM1D401C+Qk=
|
||||
github.com/sevlyar/go-daemon v0.1.5/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
|
||||
github.com/shirou/gopsutil/v3 v3.21.3 h1:wgcdAHZS2H6qy4JFewVTtqfiYxFzCeEJod/mLztdPG8=
|
||||
github.com/shirou/gopsutil/v3 v3.21.3/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
@@ -601,17 +576,15 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.4/go.mod h1:JcK1pCbReQsOsMKF/POFSZCq7drXFybgGmbc27tuwes=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.7 h1:LsGdIXl8mccqJrYEh4Uf4sLVGu/g0tjhNqQzdn9MzVk=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.7/go.mod h1:kj1ViJhlyADa7DiA4xVnTuPA46lFKbM7mxQTrXCuJP4=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.10/go.mod h1:kj1ViJhlyADa7DiA4xVnTuPA46lFKbM7mxQTrXCuJP4=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.11 h1:Jn16HsWhcZuuDYmFcMNdb32mqBN7YLPShCjmX1g6yl8=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.11/go.mod h1:kj1ViJhlyADa7DiA4xVnTuPA46lFKbM7mxQTrXCuJP4=
|
||||
github.com/spacemonkeygo/monotime v0.0.0-20180824235756-e3f48a95f98a/go.mod h1:ul4bvvnCOPZgq8w0nTkSmWVg/hauVpFS97Am1YM1XXo=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
|
||||
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
@@ -637,12 +610,6 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20200416171014-ffad7fcb44b8 h1:IGJQmLBLYBdAknj21W3JsVof0yjEXfy1Q0K3YZebDOg=
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20200416171014-ffad7fcb44b8/go.mod h1:XWL4vDyd3JKmJx+hZWUVgCNmmhZ2dTBcaNDcxH465s0=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
|
||||
github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4=
|
||||
github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
||||
github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8=
|
||||
github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA=
|
||||
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
|
||||
@@ -664,8 +631,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
||||
github.com/yunify/qingstor-sdk-go/v3 v3.2.0 h1:9sB2WZMgjwSUNZhrgvaNGazVltoFUUfuS9f0uCWtTr8=
|
||||
github.com/yunify/qingstor-sdk-go/v3 v3.2.0/go.mod h1:KciFNuMu6F4WLk9nGwwK69sCGKLCdd9f97ac/wfumS4=
|
||||
github.com/zeebo/admission/v3 v3.0.2/go.mod h1:BP3isIv9qa2A7ugEratNq1dnl2oZRXaQUGdU7WXKtbw=
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/errs v1.2.2 h1:5NFypMTuSdoySVTqlNs1dEoU21QVamMQJxW/Fii5O7g=
|
||||
github.com/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
github.com/zeebo/float16 v0.1.0/go.mod h1:fssGvvXu+XS8MH57cKmyrLB/cqioYeYX/2mXCN3a5wo=
|
||||
@@ -683,8 +650,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.22.6 h1:BdkrbWrzDlV9dnbzoP7sfN+dHheJ4J9JOaYxcUDL+ok=
|
||||
go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
@@ -722,10 +689,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA=
|
||||
golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -804,11 +769,8 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d h1:BgJvlyh+UqCUaPlscHJ+PN8GcpfrFdr7NHjd1JL0+Gs=
|
||||
golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -817,12 +779,9 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78 h1:rPRtHfUb0UKZeZ6GH4K4Nt4YRbE9V1u+QZX5upZXqJQ=
|
||||
golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c h1:HiAZXo96zOhVhtFHchj/ojzoxCFiPrp9/j0GtS38V3g=
|
||||
golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -832,9 +791,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -877,6 +835,7 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -885,42 +844,31 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112091331-59c308dcf3cc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210419170143-37df388d1f33 h1:zah5VTTvBlVRELjcDwGLLaWRHZJQsBtplweVYCii0KM=
|
||||
golang.org/x/sys v0.0.0-20210419170143-37df388d1f33/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210313110737-8e9fff1a3a18 h1:jxr7/dEo+rR29uEBoLSWJ1tRHCFAMwFbGUU9nRqzpds=
|
||||
golang.org/x/sys v0.0.0-20210313110737-8e9fff1a3a18/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 h1:VqE9gduFZ4dbR7XoL77lHFp0/DyDUBKSXK7CMFkVcV0=
|
||||
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -1002,11 +950,8 @@ google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSr
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0 h1:URs6qR1lAxDsqWITsQXI4ZkGiYJ5dHtRNiCpfs2OeKA=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/api v0.38.0 h1:vDyWk6eup8eQAidaZ31sNWIn8tZEL8qpbtGkBD4ytQo=
|
||||
google.golang.org/api v0.38.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -1051,13 +996,9 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210416161957-9910b6c460de h1:+nG/xknR+Gc5ByHOtK1dT0Pl3LYo8NLR+Jz3XeBeGEg=
|
||||
google.golang.org/genproto v0.0.0-20210416161957-9910b6c460de/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210202153253-cf70463f6119/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210203152818-3206188e46ba h1:np3A9jnmE/eMtrOwwvUycmQ1XoLyj5nqZ41bAyYLqJ0=
|
||||
google.golang.org/genproto v0.0.0-20210203152818-3206188e46ba/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
@@ -1078,11 +1019,8 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -1092,10 +1030,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -1140,10 +1076,10 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
storj.io/common v0.0.0-20210412024514-5bcb1fff421e/go.mod h1:Udjm4roy/lhL7PHDWlNVhuVxlohcPiyHMeuigw94SDE=
|
||||
storj.io/common v0.0.0-20210419115916-eabb53ea1332 h1:A5AGxOdbi/9JpqWmvaqsnqxxeE5sUCiCn67JBUHPmc4=
|
||||
storj.io/common v0.0.0-20210419115916-eabb53ea1332/go.mod h1:Udjm4roy/lhL7PHDWlNVhuVxlohcPiyHMeuigw94SDE=
|
||||
storj.io/drpc v0.0.20 h1:nzOxsetLi0fJ8xCL92LPlYL0B6iYdDDk1Cpdbn0/r9Y=
|
||||
storj.io/drpc v0.0.20/go.mod h1:eAxUDk8HWvGl9iqznpuphtZ+WIjIGPJFqNXuKHgRiMM=
|
||||
storj.io/uplink v1.4.6 h1:hZf1q5va2yh+mK88t0XSI89/1swffJr1tvA7a+ZvQ30=
|
||||
storj.io/uplink v1.4.6/go.mod h1:CroFLtFtcKj9B0AigacRHuxjNd+jOm9DG45257fTJo0=
|
||||
storj.io/common v0.0.0-20201207172416-78f4e59925c3/go.mod h1:6sepaQTRLuygvA+GNPzdgRPOB1+wFfjde76KBWofbMY=
|
||||
storj.io/common v0.0.0-20210203145648-3768017a858e h1:lMLJoRJ8jmvHd/gtyy73wVry6D5ampTWSX1vh6y4fI4=
|
||||
storj.io/common v0.0.0-20210203145648-3768017a858e/go.mod h1:KhVByBTvjV2rsaUQsft0pKgBRRMvCcY1JsDqt6BWr3I=
|
||||
storj.io/drpc v0.0.16 h1:9sxypc5lKi/0D69cR21BR0S21+IvXfON8L5nXMVNTwQ=
|
||||
storj.io/drpc v0.0.16/go.mod h1:zdmQ93nx4Z35u11pQ+GAnBy4DGOK3HJCSOfeh2RryTo=
|
||||
storj.io/uplink v1.4.5 h1:aeJgbob2YtnVPgzrzw16XwmYr241ibuZBhPqVwvyR3E=
|
||||
storj.io/uplink v1.4.5/go.mod h1:VoxYTP5AzJ+gnzsqptuB5Ra8Old+fVVbwLCmi4jr5y4=
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// +build !openbsd,!windows
|
||||
|
||||
package buildinfo
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
)
|
||||
|
||||
// GetOSVersion returns OS version, kernel and bitness
|
||||
func GetOSVersion() (osVersion, osKernel string) {
|
||||
if platform, _, version, err := host.PlatformInformation(); err == nil && platform != "" {
|
||||
osVersion = platform
|
||||
if version != "" {
|
||||
osVersion += " " + version
|
||||
}
|
||||
}
|
||||
|
||||
if version, err := host.KernelVersion(); err == nil && version != "" {
|
||||
osKernel = version
|
||||
}
|
||||
|
||||
if arch, err := host.KernelArch(); err == nil && arch != "" {
|
||||
if strings.HasSuffix(arch, "64") && osVersion != "" {
|
||||
osVersion += " (64 bit)"
|
||||
}
|
||||
if osKernel != "" {
|
||||
osKernel += " (" + arch + ")"
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// +build openbsd
|
||||
|
||||
package buildinfo
|
||||
|
||||
// gopsutil v3.21.3 fails to build on openbsd:
|
||||
// Error: .../go/pkg/mod/github.com/tklauser/go-sysconf@v0.3.4/sysconf_openbsd.go:22:28: undefined: unix.RLIMIT_NPROC
|
||||
// Error: .../go/pkg/mod/github.com/shirou/gopsutil/v3@v3.21.3/process/process.go:163:15: undefined: pidsWithContext
|
||||
// and so on...
|
||||
|
||||
// GetOSVersion returns OS version, kernel and bitness
|
||||
func GetOSVersion() (osVersion, osKernel string) {
|
||||
return "OpenBSD", ""
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
// +build !openbsd !windows
|
||||
|
||||
package buildinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
// GetOSVersion returns OS version, kernel and bitness
|
||||
// On Windows it performs additional output enhancements.
|
||||
func GetOSVersion() (osVersion, osKernel string) {
|
||||
if platform, _, version, err := host.PlatformInformation(); err == nil && platform != "" {
|
||||
osVersion = platform
|
||||
if version != "" {
|
||||
osVersion += " " + version
|
||||
}
|
||||
}
|
||||
|
||||
if version, err := host.KernelVersion(); err == nil && version != "" {
|
||||
osKernel = version
|
||||
|
||||
// Prevent duplication of output on Windows
|
||||
if strings.Contains(osVersion, osKernel) {
|
||||
deduped := strings.TrimSpace(strings.Replace(osVersion, osKernel, "", 1))
|
||||
if deduped != "" {
|
||||
osVersion = deduped
|
||||
}
|
||||
}
|
||||
|
||||
// Simplify kernel output: `RELEASE.BUILD Build BUILD` -> `RELEASE.BUILD`
|
||||
match := regexp.MustCompile(`^([\d\.]+?\.)(\d+) Build (\d+)$`).FindStringSubmatch(osKernel)
|
||||
if len(match) == 4 && match[2] == match[3] {
|
||||
osKernel = match[1] + match[2]
|
||||
}
|
||||
}
|
||||
|
||||
friendlyName := getRegistryVersionString("ReleaseId")
|
||||
if osVersion != "" && friendlyName != "" {
|
||||
osVersion += " " + friendlyName
|
||||
}
|
||||
|
||||
updateRevision := getRegistryVersionInt("UBR")
|
||||
if osKernel != "" && updateRevision != 0 {
|
||||
osKernel += fmt.Sprintf(".%d", updateRevision)
|
||||
}
|
||||
|
||||
if arch, err := host.KernelArch(); err == nil && arch != "" {
|
||||
if strings.HasSuffix(arch, "64") && osVersion != "" {
|
||||
osVersion += " (64 bit)"
|
||||
}
|
||||
if osKernel != "" {
|
||||
osKernel += " (" + arch + ")"
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var regVersionKeyUTF16 = windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Windows NT\CurrentVersion`)
|
||||
|
||||
func getRegistryVersionString(name string) string {
|
||||
var (
|
||||
err error
|
||||
handle windows.Handle
|
||||
bufLen uint32
|
||||
valType uint32
|
||||
)
|
||||
|
||||
err = windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, regVersionKeyUTF16, 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &handle)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer func() {
|
||||
_ = windows.RegCloseKey(handle)
|
||||
}()
|
||||
|
||||
nameUTF16 := windows.StringToUTF16Ptr(name)
|
||||
err = windows.RegQueryValueEx(handle, nameUTF16, nil, &valType, nil, &bufLen)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
regBuf := make([]uint16, bufLen/2+1)
|
||||
err = windows.RegQueryValueEx(handle, nameUTF16, nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return windows.UTF16ToString(regBuf[:])
|
||||
}
|
||||
|
||||
func getRegistryVersionInt(name string) int {
|
||||
var (
|
||||
err error
|
||||
handle windows.Handle
|
||||
bufLen uint32
|
||||
valType uint32
|
||||
)
|
||||
|
||||
err = windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, regVersionKeyUTF16, 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &handle)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
defer func() {
|
||||
_ = windows.RegCloseKey(handle)
|
||||
}()
|
||||
|
||||
nameUTF16 := windows.StringToUTF16Ptr(name)
|
||||
err = windows.RegQueryValueEx(handle, nameUTF16, nil, &valType, nil, &bufLen)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
if valType != registry.DWORD || bufLen != 4 {
|
||||
return 0
|
||||
}
|
||||
var val32 uint32
|
||||
err = windows.RegQueryValueEx(handle, nameUTF16, nil, &valType, (*byte)(unsafe.Pointer(&val32)), &bufLen)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return int(val32)
|
||||
}
|
||||
@@ -13,8 +13,3 @@ import "os"
|
||||
// Under both Unix and Windows this will allow open files to be
|
||||
// renamed and or deleted.
|
||||
var OpenFile = os.OpenFile
|
||||
|
||||
// IsReserved checks if path contains a reserved name
|
||||
func IsReserved(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -153,29 +152,3 @@ func TestOpenFileOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Smoke test the IsReserved function
|
||||
func TestIsReserved(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("Skipping test on !windows")
|
||||
}
|
||||
// Regular name
|
||||
require.NoError(t, IsReserved("readme.txt"))
|
||||
require.NoError(t, IsReserved("some/path/readme.txt"))
|
||||
// Empty
|
||||
require.Error(t, IsReserved(""))
|
||||
// Separators only
|
||||
require.Error(t, IsReserved("/"))
|
||||
require.Error(t, IsReserved("////"))
|
||||
require.Error(t, IsReserved("./././././"))
|
||||
// Legacy device name
|
||||
require.Error(t, IsReserved("NUL"))
|
||||
require.Error(t, IsReserved("nul"))
|
||||
require.Error(t, IsReserved("Nul"))
|
||||
require.Error(t, IsReserved("NUL.txt"))
|
||||
require.Error(t, IsReserved("some/path/to/nul.txt"))
|
||||
require.NoError(t, IsReserved("NULL"))
|
||||
// Name end with a space or a period
|
||||
require.Error(t, IsReserved("test."))
|
||||
require.Error(t, IsReserved("test "))
|
||||
}
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
@@ -67,36 +64,3 @@ func OpenFile(path string, mode int, perm os.FileMode) (*os.File, error) {
|
||||
}
|
||||
return os.NewFile(uintptr(h), path), nil
|
||||
}
|
||||
|
||||
// IsReserved checks if path contains a reserved name
|
||||
func IsReserved(path string) error {
|
||||
if path == "" {
|
||||
return errors.New("path is empty")
|
||||
}
|
||||
base := filepath.Base(path)
|
||||
// If the path is empty or reduces to ".", Base returns ".".
|
||||
if base == "." {
|
||||
return errors.New("path is '.'")
|
||||
}
|
||||
// If the path consists entirely of separators, Base returns a single separator.
|
||||
if base == string(filepath.Separator) {
|
||||
return errors.New("path consists entirely of separators")
|
||||
}
|
||||
// Do not end a file or directory name with a space or a period. Although the underlying
|
||||
// file system may support such names, the Windows shell and user interface does not.
|
||||
// (https://docs.microsoft.com/en-gb/windows/win32/fileio/naming-a-file)
|
||||
suffix := base[len(base)-1]
|
||||
switch suffix {
|
||||
case ' ':
|
||||
return errors.New("base file name ends with a space")
|
||||
case '.':
|
||||
return errors.New("base file name ends with a period")
|
||||
}
|
||||
// Do not use names of legacy (DOS) devices, not even as basename without extension,
|
||||
// as this will refer to the actual device.
|
||||
// (https://docs.microsoft.com/en-gb/windows/win32/fileio/naming-a-file)
|
||||
if reserved, _ := regexp.MatchString(`^(?i:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)`, base); reserved {
|
||||
return errors.New("base file name is reserved windows device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9])")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/config"
|
||||
"github.com/rclone/rclone/fs/config/configmap"
|
||||
"github.com/rclone/rclone/fs/fserrors"
|
||||
"github.com/rclone/rclone/fs/fshttp"
|
||||
"github.com/rclone/rclone/lib/random"
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
@@ -167,11 +166,9 @@ type TokenSource struct {
|
||||
expiryTimer *time.Timer // signals whenever the token expires
|
||||
}
|
||||
|
||||
// If token has expired then first try re-reading it (and its refresh token)
|
||||
// from the config file in case a concurrently running rclone has updated them
|
||||
// already.
|
||||
// Returns whether either of the two tokens has been reread.
|
||||
func (ts *TokenSource) reReadToken() (changed bool) {
|
||||
// If token has expired then first try re-reading it from the config
|
||||
// file in case a concurrently running rclone has updated it already
|
||||
func (ts *TokenSource) reReadToken() bool {
|
||||
tokenString, found := ts.m.Get(config.ConfigToken)
|
||||
if !found || tokenString == "" {
|
||||
fs.Debugf(ts.name, "Failed to read token out of config file")
|
||||
@@ -183,23 +180,14 @@ func (ts *TokenSource) reReadToken() (changed bool) {
|
||||
fs.Debugf(ts.name, "Failed to parse token out of config file: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if !newToken.Valid() {
|
||||
fs.Debugf(ts.name, "Loaded invalid token from config file - ignoring")
|
||||
} else {
|
||||
fs.Debugf(ts.name, "Loaded fresh token from config file")
|
||||
changed = true
|
||||
return false
|
||||
}
|
||||
if newToken.RefreshToken != "" && newToken.RefreshToken != ts.token.RefreshToken {
|
||||
fs.Debugf(ts.name, "Loaded new refresh token from config file")
|
||||
changed = true
|
||||
}
|
||||
|
||||
if changed {
|
||||
ts.token = newToken
|
||||
ts.tokenSource = nil // invalidate since we changed the token
|
||||
}
|
||||
return changed
|
||||
fs.Debugf(ts.name, "Loaded fresh token from config file")
|
||||
ts.token = newToken
|
||||
ts.tokenSource = nil // invalidate since we changed the token
|
||||
return true
|
||||
}
|
||||
|
||||
// Token returns a token or an error.
|
||||
@@ -224,10 +212,6 @@ func (ts *TokenSource) Token() (*oauth2.Token, error) {
|
||||
if !ts.token.Valid() {
|
||||
if ts.reReadToken() {
|
||||
changed = true
|
||||
} else if ts.token.RefreshToken == "" {
|
||||
return nil, fserrors.FatalError(
|
||||
fmt.Errorf("token expired and there's no refresh token - manually refresh with \"rclone config reconnect %s:\"", ts.name),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,59 +447,19 @@ Execute the following on the machine with the web browser (same rclone
|
||||
version recommended):
|
||||
|
||||
`)
|
||||
// Find the configuration
|
||||
ri, err := fs.Find(id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "oauthutil authorize")
|
||||
}
|
||||
// Find the overridden options
|
||||
inM := ri.Options.NonDefault(m)
|
||||
delete(inM, config.ConfigToken) // delete token as we are refreshing it
|
||||
for k, v := range inM {
|
||||
fs.Debugf(nil, "sending %s = %q", k, v)
|
||||
}
|
||||
// Encode them into a string
|
||||
mCopyString, err := inM.Encode()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "oauthutil authorize encode")
|
||||
}
|
||||
// Write what the user has to do
|
||||
useNewFormat := len(mCopyString) > 0
|
||||
if useNewFormat {
|
||||
fmt.Printf("\trclone authorize %q %q\n", id, mCopyString)
|
||||
if changed {
|
||||
fmt.Printf("\trclone authorize %q -- %q %q\n", id, oauthConfig.ClientID, oauthConfig.ClientSecret)
|
||||
} else {
|
||||
fmt.Printf("\trclone authorize %q\n", id)
|
||||
}
|
||||
fmt.Println("\nThen paste the result below:")
|
||||
// Read the updates to the config
|
||||
var outM configmap.Simple
|
||||
var token oauth2.Token
|
||||
for {
|
||||
outM = configmap.Simple{}
|
||||
token = oauth2.Token{}
|
||||
code := config.ReadNonEmptyLine("result> ")
|
||||
|
||||
if useNewFormat {
|
||||
err = outM.Decode(code)
|
||||
} else {
|
||||
err = json.Unmarshal([]byte(code), &token)
|
||||
}
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Printf("Couldn't decode response - try again (make sure you are using a matching version of rclone on both sides: %v\n", err)
|
||||
code := config.ReadNonEmptyLine("result> ")
|
||||
token := &oauth2.Token{}
|
||||
err := json.Unmarshal([]byte(code), token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the config updates
|
||||
if useNewFormat {
|
||||
for k, v := range outM {
|
||||
m.Set(k, v)
|
||||
fs.Debugf(nil, "received %s = %q", k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return PutToken(name, m, &token, true)
|
||||
return PutToken(name, m, token, true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,6 +526,14 @@ version recommended):
|
||||
return errors.Wrap(err, "failed to get token")
|
||||
}
|
||||
|
||||
// Print code if we are doing a manual auth
|
||||
if authorizeOnly {
|
||||
result, err := json.Marshal(token)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to marshal token")
|
||||
}
|
||||
fmt.Printf("Paste the following into your remote machine --->\n%s\n<---End paste\n", result)
|
||||
}
|
||||
return PutToken(name, m, token, true)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,10 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// StringFn create a random string for test purposes using the random
|
||||
// number generator function passed in.
|
||||
// String create a random string for test purposes.
|
||||
//
|
||||
// Do not use these for passwords.
|
||||
func StringFn(n int, randIntn func(n int) int) string {
|
||||
func String(n int) string {
|
||||
const (
|
||||
vowel = "aeiou"
|
||||
consonant = "bcdfghjklmnpqrstvwxyz"
|
||||
@@ -26,18 +25,11 @@ func StringFn(n int, randIntn func(n int) int) string {
|
||||
for i := range out {
|
||||
source := pattern[p]
|
||||
p = (p + 1) % len(pattern)
|
||||
out[i] = source[randIntn(len(source))]
|
||||
out[i] = source[mathrand.Intn(len(source))]
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// String create a random string for test purposes.
|
||||
//
|
||||
// Do not use these for passwords.
|
||||
func String(n int) string {
|
||||
return StringFn(n, mathrand.Intn)
|
||||
}
|
||||
|
||||
// Password creates a crypto strong password which is just about
|
||||
// memorable. The password is composed of printable ASCII characters
|
||||
// from the base64 alphabet.
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// Package version provides machinery for versioning file names
|
||||
// with a timestamp-based version string
|
||||
package version
|
||||
|
||||
import (
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const versionFormat = "-v2006-01-02-150405.000"
|
||||
|
||||
var versionRegexp = regexp.MustCompile("-v\\d{4}-\\d{2}-\\d{2}-\\d{6}-\\d{3}")
|
||||
|
||||
// Add returns fileName modified to include t as the version
|
||||
func Add(fileName string, t time.Time) string {
|
||||
ext := path.Ext(fileName)
|
||||
base := fileName[:len(fileName)-len(ext)]
|
||||
s := t.Format(versionFormat)
|
||||
// Replace the '.' with a '-'
|
||||
s = strings.Replace(s, ".", "-", -1)
|
||||
return base + s + ext
|
||||
}
|
||||
|
||||
// Remove returns a modified fileName without the version string and the time it represented
|
||||
// If the fileName did not have a version then time.Time{} is returned along with an unmodified fileName
|
||||
func Remove(fileName string) (t time.Time, fileNameWithoutVersion string) {
|
||||
fileNameWithoutVersion = fileName
|
||||
ext := path.Ext(fileName)
|
||||
base := fileName[:len(fileName)-len(ext)]
|
||||
if len(base) < len(versionFormat) {
|
||||
return
|
||||
}
|
||||
versionStart := len(base) - len(versionFormat)
|
||||
// Check it ends in -xxx
|
||||
if base[len(base)-4] != '-' {
|
||||
return
|
||||
}
|
||||
// Replace with .xxx for parsing
|
||||
base = base[:len(base)-4] + "." + base[len(base)-3:]
|
||||
newT, err := time.Parse(versionFormat, base[versionStart:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return newT, base[:versionStart] + ext
|
||||
}
|
||||
|
||||
// Match returns true if the fileName has a version string
|
||||
func Match(fileName string) bool {
|
||||
return versionRegexp.MatchString(fileName)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package version_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fstest"
|
||||
"github.com/rclone/rclone/lib/version"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
emptyT time.Time
|
||||
t0 = fstest.Time("1970-01-01T01:01:01.123456789Z")
|
||||
t0r = fstest.Time("1970-01-01T01:01:01.123000000Z")
|
||||
t1 = fstest.Time("2001-02-03T04:05:06.123000000Z")
|
||||
)
|
||||
|
||||
func TestVersionAdd(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
t time.Time
|
||||
in string
|
||||
expected string
|
||||
}{
|
||||
{t0, "potato.txt", "potato-v1970-01-01-010101-123.txt"},
|
||||
{t0, "potato-v2001-02-03-040506-123.txt", "potato-v2001-02-03-040506-123-v1970-01-01-010101-123.txt"},
|
||||
{t0, "123.!!lipps", "123-v1970-01-01-010101-123.!!lipps"},
|
||||
{t1, "potato", "potato-v2001-02-03-040506-123"},
|
||||
{t1, "", "-v2001-02-03-040506-123"},
|
||||
} {
|
||||
actual := version.Add(test.in, test.t)
|
||||
assert.Equal(t, test.expected, actual, test.in)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionRemove(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
expectedT time.Time
|
||||
expectedRemote string
|
||||
}{
|
||||
{"potato.txt", emptyT, "potato.txt"},
|
||||
{"potato-v1970-01-01-010101-123.txt", t0r, "potato.txt"},
|
||||
{"potato-v2001-02-03-040506-123-v1970-01-01-010101-123.txt", t0r, "potato-v2001-02-03-040506-123.txt"},
|
||||
{"potato-v2001-02-03-040506-123", t1, "potato"},
|
||||
{"-v2001-02-03-040506-123", t1, ""},
|
||||
{"potato-v2A01-02-03-040506-123", emptyT, "potato-v2A01-02-03-040506-123"},
|
||||
{"potato-v2001-02-03-040506=123", emptyT, "potato-v2001-02-03-040506=123"},
|
||||
} {
|
||||
actualT, actualRemote := version.Remove(test.in)
|
||||
assert.Equal(t, test.expectedT, actualT, test.in)
|
||||
assert.Equal(t, test.expectedRemote, actualRemote, test.in)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionMatch(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
expected bool
|
||||
}{
|
||||
{"potato.txt", false},
|
||||
{"potato", false},
|
||||
{"", false},
|
||||
{"potato-v1970-01-01-010101-123.txt", true},
|
||||
{"potato-v2001-02-03-040506-123-v1970-01-01-010101-123.txt", true},
|
||||
{"potato-v2001-02-03-040506-123", true},
|
||||
{"-v2001-02-03-040506-123", true},
|
||||
{"-v9999-99-99-999999-999", true},
|
||||
} {
|
||||
actual := version.Match(test.in)
|
||||
assert.Equal(t, test.expected, actual, test.in)
|
||||
}
|
||||
}
|
||||
119
rclone.1
generated
119
rclone.1
generated
@@ -1,7 +1,7 @@
|
||||
.\"t
|
||||
.\" Automatically generated by Pandoc 2.5
|
||||
.\"
|
||||
.TH "rclone" "1" "Mar 31, 2021" "User Manual" ""
|
||||
.TH "rclone" "1" "Apr 26, 2021" "User Manual" ""
|
||||
.hy
|
||||
.SH Rclone syncs your files to cloud storage
|
||||
.PP
|
||||
@@ -1838,12 +1838,12 @@ commands, flags and backends.
|
||||
Get quota information from the remote.
|
||||
.SS Synopsis
|
||||
.PP
|
||||
\f[C]rclone about\f[R]prints quota information about a remote to
|
||||
\f[C]rclone about\f[R] prints quota information about a remote to
|
||||
standard output.
|
||||
The output is typically used, free, quota and trash contents.
|
||||
.PP
|
||||
E.g.
|
||||
Typical output from\f[C]rclone about remote:\f[R]is:
|
||||
Typical output from \f[C]rclone about remote:\f[R] is:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
@@ -1887,7 +1887,7 @@ Other: 8849156022
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
A \f[C]\-\-json\f[R]flag generates conveniently computer readable
|
||||
A \f[C]\-\-json\f[R] flag generates conveniently computer readable
|
||||
output, e.g.
|
||||
.IP
|
||||
.nf
|
||||
@@ -2558,7 +2558,7 @@ Copy url content to dest.
|
||||
Download a URL\[aq]s content and copy it to the destination without
|
||||
saving it in temporary storage.
|
||||
.PP
|
||||
Setting \f[C]\-\-auto\-filename\f[R]will cause the file name to be
|
||||
Setting \f[C]\-\-auto\-filename\f[R] will cause the file name to be
|
||||
retrieved from the from URL (after any redirections) and used in the
|
||||
destination path.
|
||||
With \f[C]\-\-print\-filename\f[R] in addition, the resuling file name
|
||||
@@ -3677,7 +3677,7 @@ this as the file being accessible by everyone.
|
||||
For example an SSH client may warn about \[dq]unprotected private key
|
||||
file\[dq].
|
||||
.PP
|
||||
WinFsp 2021 (version 1.9, still in beta) introduces a new FUSE option
|
||||
WinFsp 2021 (version 1.9) introduces a new FUSE option
|
||||
\[dq]FileSecurity\[dq], that allows the complete specification of file
|
||||
security descriptors using
|
||||
SDDL (https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format).
|
||||
@@ -4632,7 +4632,7 @@ Beta releases have an additional information similar to
|
||||
\f[C]v1.54.0\-beta.5111.06f1c0c61\f[R].
|
||||
(if you are a developer and use a locally built rclone, the version
|
||||
number will end with \f[C]\-DEV\f[R], you will have to rebuild it as it
|
||||
obvisously can\[aq]t be distributed).
|
||||
obviously can\[aq]t be distributed).
|
||||
.PP
|
||||
If you previously installed rclone via a package manager, the package
|
||||
may include local documentation or configure services.
|
||||
@@ -8720,7 +8720,7 @@ If you run \f[C]rclone config file\f[R] you will see where the default
|
||||
location is for you.
|
||||
.PP
|
||||
Use this flag to override the config location, e.g.
|
||||
\f[C]rclone \-\-config=\[dq].myconfig\[dq] .config\f[R].
|
||||
\f[C]rclone \-\-config=\[dq].myconfig\[dq] config\f[R].
|
||||
.PP
|
||||
If the location is set to empty string \f[C]\[dq]\[dq]\f[R] or the
|
||||
special value \f[C]/notfound\f[R], or the os null device represented by
|
||||
@@ -10363,7 +10363,7 @@ mys3:
|
||||
Note that if you want to create a remote using environment variables you
|
||||
must create the \f[C]..._TYPE\f[R] variable as above.
|
||||
.PP
|
||||
Note also that now rclone has connectionstrings, it is probably easier
|
||||
Note also that now rclone has connection strings, it is probably easier
|
||||
to use those instead which makes the above example
|
||||
.IP
|
||||
.nf
|
||||
@@ -15925,7 +15925,7 @@ These flags are available for every command.
|
||||
\-\-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. The default is rclone/ version (default \[dq]rclone/v1.55.0\[dq])
|
||||
\-\-user\-agent string Set the user\-agent to a specified string. The default is rclone/ version (default \[dq]rclone/v1.55.1\[dq])
|
||||
\-v, \-\-verbose count Print lots more stuff (repeat for more)
|
||||
\f[R]
|
||||
.fi
|
||||
@@ -39340,6 +39340,105 @@ Options:
|
||||
.IP \[bu] 2
|
||||
\[dq]error\[dq]: return an error based on option value
|
||||
.SH Changelog
|
||||
.SS v1.55.1 \- 2021\-04\-26
|
||||
.PP
|
||||
See commits (https://github.com/rclone/rclone/compare/v1.55.0...v1.55.1)
|
||||
.IP \[bu] 2
|
||||
Bug Fixes
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
selfupdate
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Dont detect FUSE if build is static (Ivan Andreev)
|
||||
.IP \[bu] 2
|
||||
Add build tag noselfupdate (Ivan Andreev)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
sync: Fix incorrect error reported by graceful cutoff (Nick Craig\-Wood)
|
||||
.IP \[bu] 2
|
||||
install.sh: fix macOS arm64 download (Nick Craig\-Wood)
|
||||
.IP \[bu] 2
|
||||
build: Fix version numbers in android branch builds (Nick Craig\-Wood)
|
||||
.IP \[bu] 2
|
||||
docs
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Contributing.md: update setup instructions for go1.16 (Nick Gaya)
|
||||
.IP \[bu] 2
|
||||
WinFsp 2021 is out of beta (albertony)
|
||||
.IP \[bu] 2
|
||||
Minor cleanup of space around code section (albertony)
|
||||
.IP \[bu] 2
|
||||
Fixed some typos (albertony)
|
||||
.RE
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
VFS
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix a code path which allows dirty data to be removed causing data loss
|
||||
(Nick Craig\-Wood)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Compress
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix compressed name regexp (buengese)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Drive
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix backend copyid of google doc to directory (Nick Craig\-Wood)
|
||||
.IP \[bu] 2
|
||||
Don\[aq]t open browser when service account...
|
||||
(Ansh Mittal)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Dropbox
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Add missing team_data.member scope for use with \-\-impersonate (Nick
|
||||
Craig\-Wood)
|
||||
.IP \[bu] 2
|
||||
Fix About after scopes changes \- rclone config reconnect needed (Nick
|
||||
Craig\-Wood)
|
||||
.IP \[bu] 2
|
||||
Fix Unable to decrypt returned paths from changeNotify (Nick
|
||||
Craig\-Wood)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
FTP
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix implicit TLS (Ivan Andreev)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Onedrive
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Work around for random \[dq]Unable to initialize RPS\[dq] errors
|
||||
(OleFrost)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
SFTP
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Revert sftp library to v1.12.0 from v1.13.0 to fix performance
|
||||
regression (Nick Craig\-Wood)
|
||||
.IP \[bu] 2
|
||||
Fix Update ReadFrom failed: failed to send packet: EOF errors (Nick
|
||||
Craig\-Wood)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Zoho
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix error when region isn\[aq]t set (buengese)
|
||||
.IP \[bu] 2
|
||||
Do not ask for mountpoint twice when using headless setup (buengese)
|
||||
.RE
|
||||
.SS v1.55.0 \- 2021\-03\-31
|
||||
.PP
|
||||
See commits (https://github.com/rclone/rclone/compare/v1.54.0...v1.55.0)
|
||||
|
||||
Reference in New Issue
Block a user