rclone-api 1.0.15__py2.py3-none-any.whl → 1.0.17__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rclone_api/__init__.py +2 -0
- rclone_api/exec.py +13 -0
- rclone_api/process.py +124 -0
- rclone_api/rclone.py +39 -0
- rclone_api/util.py +2 -2
- rclone_api-1.0.17.dist-info/METADATA +149 -0
- {rclone_api-1.0.15.dist-info → rclone_api-1.0.17.dist-info}/RECORD +10 -9
- rclone_api-1.0.15.dist-info/METADATA +0 -34
- {rclone_api-1.0.15.dist-info → rclone_api-1.0.17.dist-info}/LICENSE +0 -0
- {rclone_api-1.0.15.dist-info → rclone_api-1.0.17.dist-info}/WHEEL +0 -0
- {rclone_api-1.0.15.dist-info → rclone_api-1.0.17.dist-info}/top_level.txt +0 -0
rclone_api/__init__.py
CHANGED
@@ -3,6 +3,7 @@ from .dir import Dir
|
|
3
3
|
from .dir_listing import DirListing
|
4
4
|
from .file import File
|
5
5
|
from .filelist import FileList
|
6
|
+
from .process import Process
|
6
7
|
from .rclone import Rclone
|
7
8
|
from .remote import Remote
|
8
9
|
from .rpath import RPath
|
@@ -16,4 +17,5 @@ __all__ = [
|
|
16
17
|
"RPath",
|
17
18
|
"DirListing",
|
18
19
|
"FileList",
|
20
|
+
"Process",
|
19
21
|
]
|
rclone_api/exec.py
CHANGED
@@ -3,6 +3,7 @@ from dataclasses import dataclass
|
|
3
3
|
from pathlib import Path
|
4
4
|
|
5
5
|
from rclone_api.config import Config
|
6
|
+
from rclone_api.process import Process, ProcessArgs
|
6
7
|
|
7
8
|
|
8
9
|
@dataclass
|
@@ -17,3 +18,15 @@ class RcloneExec:
|
|
17
18
|
from rclone_api.util import rclone_execute
|
18
19
|
|
19
20
|
return rclone_execute(cmd, self.rclone_config, self.rclone_exe, check=check)
|
21
|
+
|
22
|
+
def launch_process(self, cmd: list[str]) -> Process:
|
23
|
+
"""Launch rclone process."""
|
24
|
+
|
25
|
+
args: ProcessArgs = ProcessArgs(
|
26
|
+
cmd=cmd,
|
27
|
+
rclone_conf=self.rclone_config,
|
28
|
+
rclone_exe=self.rclone_exe,
|
29
|
+
cmd_list=cmd,
|
30
|
+
)
|
31
|
+
process = Process(args)
|
32
|
+
return process
|
rclone_api/process.py
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
import os
|
2
|
+
import subprocess
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from pathlib import Path
|
5
|
+
from tempfile import TemporaryDirectory
|
6
|
+
from typing import Any
|
7
|
+
|
8
|
+
from rclone_api.config import Config
|
9
|
+
from rclone_api.util import get_verbose
|
10
|
+
|
11
|
+
# def rclone_launch_process(
|
12
|
+
# cmd: list[str],
|
13
|
+
# rclone_conf: Path | Config,
|
14
|
+
# rclone_exe: Path,
|
15
|
+
# verbose: bool | None = None,
|
16
|
+
# ) -> subprocess.Popen:
|
17
|
+
# tempdir: TemporaryDirectory | None = None
|
18
|
+
# verbose = _get_verbose(verbose)
|
19
|
+
# assert verbose is not None
|
20
|
+
|
21
|
+
# try:
|
22
|
+
# if isinstance(rclone_conf, Config):
|
23
|
+
# tempdir = TemporaryDirectory()
|
24
|
+
# tmpfile = Path(tempdir.name) / "rclone.conf"
|
25
|
+
# tmpfile.write_text(rclone_conf.text, encoding="utf-8")
|
26
|
+
# rclone_conf = tmpfile
|
27
|
+
# cmd = (
|
28
|
+
# [str(rclone_exe.resolve())] + ["--config", str(rclone_conf.resolve())] + cmd
|
29
|
+
# )
|
30
|
+
# if verbose:
|
31
|
+
# cmd_str = subprocess.list2cmdline(cmd)
|
32
|
+
# print(f"Running: {cmd_str}")
|
33
|
+
# cp = subprocess.Popen(
|
34
|
+
# cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False
|
35
|
+
# )
|
36
|
+
# return cp
|
37
|
+
# finally:
|
38
|
+
# if tempdir:
|
39
|
+
# try:
|
40
|
+
# tempdir.cleanup()
|
41
|
+
# except Exception as e:
|
42
|
+
# print(f"Error cleaning up tempdir: {e}")
|
43
|
+
|
44
|
+
|
45
|
+
def _get_verbose(verbose: bool | None) -> bool:
|
46
|
+
if verbose is not None:
|
47
|
+
return verbose
|
48
|
+
# get it from the environment
|
49
|
+
return bool(int(os.getenv("RCLONE_API_VERBOSE", "0")))
|
50
|
+
|
51
|
+
|
52
|
+
@dataclass
|
53
|
+
class ProcessArgs:
|
54
|
+
cmd: list[str]
|
55
|
+
rclone_conf: Path | Config
|
56
|
+
rclone_exe: Path
|
57
|
+
cmd_list: list[str]
|
58
|
+
verbose: bool | None = None
|
59
|
+
|
60
|
+
|
61
|
+
class Process:
|
62
|
+
def __init__(self, args: ProcessArgs) -> None:
|
63
|
+
assert args.rclone_exe.exists()
|
64
|
+
self.args = args
|
65
|
+
self.tempdir: TemporaryDirectory | None = None
|
66
|
+
verbose = get_verbose(args.verbose)
|
67
|
+
if isinstance(args.rclone_conf, Config):
|
68
|
+
self.tempdir = TemporaryDirectory()
|
69
|
+
tmpfile = Path(self.tempdir.name) / "rclone.conf"
|
70
|
+
tmpfile.write_text(args.rclone_conf.text, encoding="utf-8")
|
71
|
+
rclone_conf = tmpfile
|
72
|
+
else:
|
73
|
+
rclone_conf = args.rclone_conf
|
74
|
+
|
75
|
+
assert rclone_conf.exists()
|
76
|
+
|
77
|
+
self.cmd = (
|
78
|
+
[str(args.rclone_exe.resolve())]
|
79
|
+
+ ["--config", str(rclone_conf.resolve())]
|
80
|
+
+ args.cmd
|
81
|
+
)
|
82
|
+
if verbose:
|
83
|
+
cmd_str = subprocess.list2cmdline(self.cmd)
|
84
|
+
print(f"Running: {cmd_str}")
|
85
|
+
self.process = subprocess.Popen(self.cmd, shell=False)
|
86
|
+
|
87
|
+
def cleanup(self) -> None:
|
88
|
+
if self.tempdir:
|
89
|
+
try:
|
90
|
+
self.tempdir.cleanup()
|
91
|
+
except Exception as e:
|
92
|
+
print(f"Error cleaning up tempdir: {e}")
|
93
|
+
|
94
|
+
def __del__(self) -> None:
|
95
|
+
self.cleanup()
|
96
|
+
|
97
|
+
def kill(self) -> None:
|
98
|
+
self.cleanup()
|
99
|
+
return self.process.kill()
|
100
|
+
|
101
|
+
def terminate(self) -> None:
|
102
|
+
self.cleanup()
|
103
|
+
return self.process.terminate()
|
104
|
+
|
105
|
+
@property
|
106
|
+
def returncode(self) -> int | None:
|
107
|
+
return self.process.returncode
|
108
|
+
|
109
|
+
@property
|
110
|
+
def stdout(self) -> Any:
|
111
|
+
return self.process.stdout
|
112
|
+
|
113
|
+
@property
|
114
|
+
def stderr(self) -> Any:
|
115
|
+
return self.process.stderr
|
116
|
+
|
117
|
+
def poll(self) -> int | None:
|
118
|
+
return self.process.poll()
|
119
|
+
|
120
|
+
def wait(self) -> int:
|
121
|
+
return self.process.wait()
|
122
|
+
|
123
|
+
def send_signal(self, signal: int) -> None:
|
124
|
+
return self.process.send_signal(signal)
|
rclone_api/rclone.py
CHANGED
@@ -3,6 +3,7 @@ Unit test file.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import subprocess
|
6
|
+
import time
|
6
7
|
from concurrent.futures import ThreadPoolExecutor
|
7
8
|
from fnmatch import fnmatch
|
8
9
|
from pathlib import Path
|
@@ -15,6 +16,7 @@ from rclone_api.dir_listing import DirListing
|
|
15
16
|
from rclone_api.exec import RcloneExec
|
16
17
|
from rclone_api.file import File
|
17
18
|
from rclone_api.filelist import FileList
|
19
|
+
from rclone_api.process import Process
|
18
20
|
from rclone_api.remote import Remote
|
19
21
|
from rclone_api.rpath import RPath
|
20
22
|
from rclone_api.util import get_rclone_exe, to_path
|
@@ -33,6 +35,9 @@ class Rclone:
|
|
33
35
|
def _run(self, cmd: list[str], check: bool = True) -> subprocess.CompletedProcess:
|
34
36
|
return self._exec.execute(cmd, check=check)
|
35
37
|
|
38
|
+
def _launch_process(self, cmd: list[str]) -> Process:
|
39
|
+
return self._exec.launch_process(cmd)
|
40
|
+
|
36
41
|
def ls(
|
37
42
|
self,
|
38
43
|
path: Dir | Remote | str,
|
@@ -232,3 +237,37 @@ class Rclone:
|
|
232
237
|
if args is not None:
|
233
238
|
cmd_list += args
|
234
239
|
return self._run(cmd_list)
|
240
|
+
|
241
|
+
def mount(
|
242
|
+
self, src: Remote | Dir | str, outdir: Path, allow_writes=False, use_links=True
|
243
|
+
) -> Process:
|
244
|
+
"""Mount a remote or directory to a local path.
|
245
|
+
|
246
|
+
Args:
|
247
|
+
src: Remote or directory to mount
|
248
|
+
outdir: Local path to mount to
|
249
|
+
|
250
|
+
Returns:
|
251
|
+
CompletedProcess from the mount command execution
|
252
|
+
|
253
|
+
Raises:
|
254
|
+
subprocess.CalledProcessError: If the mount operation fails
|
255
|
+
"""
|
256
|
+
if outdir.exists():
|
257
|
+
is_empty = not list(outdir.iterdir())
|
258
|
+
if not is_empty:
|
259
|
+
raise ValueError(
|
260
|
+
f"Mount directory already exists and is not empty: {outdir}"
|
261
|
+
)
|
262
|
+
outdir.rmdir()
|
263
|
+
src_str = convert_to_str(src)
|
264
|
+
cmd_list: list[str] = ["mount", src_str, str(outdir)]
|
265
|
+
if not allow_writes:
|
266
|
+
cmd_list.append("--read-only")
|
267
|
+
if use_links:
|
268
|
+
cmd_list.append("--links")
|
269
|
+
proc = self._launch_process(cmd_list)
|
270
|
+
time.sleep(2) # give it a moment to mount
|
271
|
+
if proc.poll() is not None:
|
272
|
+
raise ValueError("Mount process failed to start")
|
273
|
+
return proc
|
rclone_api/util.py
CHANGED
@@ -54,7 +54,7 @@ def to_path(item: Dir | Remote | str, rclone: Any) -> RPath:
|
|
54
54
|
raise ValueError(f"Invalid type for item: {type(item)}")
|
55
55
|
|
56
56
|
|
57
|
-
def
|
57
|
+
def get_verbose(verbose: bool | None) -> bool:
|
58
58
|
if verbose is not None:
|
59
59
|
return verbose
|
60
60
|
# get it from the environment
|
@@ -79,7 +79,7 @@ def rclone_execute(
|
|
79
79
|
verbose: bool | None = None,
|
80
80
|
) -> subprocess.CompletedProcess:
|
81
81
|
tempdir: TemporaryDirectory | None = None
|
82
|
-
verbose =
|
82
|
+
verbose = get_verbose(verbose)
|
83
83
|
assert verbose is not None
|
84
84
|
|
85
85
|
try:
|
@@ -0,0 +1,149 @@
|
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: rclone_api
|
3
|
+
Version: 1.0.17
|
4
|
+
Summary: rclone api in python
|
5
|
+
Home-page: https://github.com/zackees/rclone-api
|
6
|
+
Maintainer: Zachary Vorhies
|
7
|
+
License: BSD 3-Clause License
|
8
|
+
Keywords: template-python-cmd
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Requires-Python: >=3.10
|
11
|
+
Description-Content-Type: text/markdown
|
12
|
+
License-File: LICENSE
|
13
|
+
Requires-Dist: python-dotenv>=1.0.0
|
14
|
+
Dynamic: home-page
|
15
|
+
Dynamic: maintainer
|
16
|
+
|
17
|
+
# rclone-api
|
18
|
+
|
19
|
+
[](https://github.com/zackees/rclone-api/actions/workflows/lint.yml)
|
20
|
+
[](https://github.com/zackees/rclone-api/actions/workflows/push_macos.yml)
|
21
|
+
[](https://github.com/zackees/rclone-api/actions/workflows/push_ubuntu.yml)
|
22
|
+
[](https://github.com/zackees/rclone-api/actions/workflows/push_win.yml)
|
23
|
+
|
24
|
+
Api version of rclone. It's well tested. It's a pretty low level api without the bells and whistles of other apis, but it will get the job done.
|
25
|
+
|
26
|
+
You will need to have rclone installed and on your path.
|
27
|
+
|
28
|
+
One of the benefits of this api is that it does not use `shell=True`, which can keep `rclone` running in some instances even when try to kill the process.
|
29
|
+
|
30
|
+
# Install
|
31
|
+
|
32
|
+
`pip install rclone-api`
|
33
|
+
|
34
|
+
|
35
|
+
# Examples
|
36
|
+
|
37
|
+
You can use env variables or use a `.env` file to store your secrets.
|
38
|
+
|
39
|
+
|
40
|
+
# Rclone API Usage Examples
|
41
|
+
|
42
|
+
This script demonstrates how to interact with DigitalOcean Spaces using `rclone_api`.
|
43
|
+
|
44
|
+
## Setup & Usage
|
45
|
+
|
46
|
+
Ensure you have set the required environment variables:
|
47
|
+
|
48
|
+
- `BUCKET_NAME`
|
49
|
+
- `BUCKET_KEY_PUBLIC`
|
50
|
+
- `BUCKET_KEY_SECRET`
|
51
|
+
- `BUCKET_URL`
|
52
|
+
|
53
|
+
Then, run the following Python script:
|
54
|
+
|
55
|
+
```python
|
56
|
+
import os
|
57
|
+
from rclone_api import Config, DirListing, File, Rclone, Remote
|
58
|
+
|
59
|
+
# Load environment variables
|
60
|
+
BUCKET_NAME = os.getenv("BUCKET_NAME")
|
61
|
+
BUCKET_KEY_PUBLIC = os.getenv("BUCKET_KEY_PUBLIC")
|
62
|
+
BUCKET_KEY_SECRET = os.getenv("BUCKET_KEY_SECRET")
|
63
|
+
BUCKET_URL = "sfo3.digitaloceanspaces.com"
|
64
|
+
|
65
|
+
# Generate Rclone Configuration
|
66
|
+
def generate_rclone_config() -> Config:
|
67
|
+
config_text = f"""
|
68
|
+
[dst]
|
69
|
+
type = s3
|
70
|
+
provider = DigitalOcean
|
71
|
+
access_key_id = {BUCKET_KEY_PUBLIC}
|
72
|
+
secret_access_key = {BUCKET_KEY_SECRET}
|
73
|
+
endpoint = {BUCKET_URL}
|
74
|
+
"""
|
75
|
+
return Config(config_text)
|
76
|
+
|
77
|
+
rclone = Rclone(generate_rclone_config())
|
78
|
+
|
79
|
+
# List Available Remotes
|
80
|
+
print("\n=== Available Remotes ===")
|
81
|
+
remotes = rclone.listremotes()
|
82
|
+
for remote in remotes:
|
83
|
+
print(remote)
|
84
|
+
|
85
|
+
# List Contents of the Root Bucket
|
86
|
+
print("\n=== Listing Root Bucket ===")
|
87
|
+
listing = rclone.ls(f"dst:{BUCKET_NAME}", max_depth=-1)
|
88
|
+
|
89
|
+
print("\nDirectories:")
|
90
|
+
for dir in listing.dirs:
|
91
|
+
print(dir)
|
92
|
+
|
93
|
+
print("\nFiles:")
|
94
|
+
for file in listing.files:
|
95
|
+
print(file)
|
96
|
+
|
97
|
+
# List a Specific Subdirectory
|
98
|
+
print("\n=== Listing 'zachs_video' Subdirectory ===")
|
99
|
+
path = f"dst:{BUCKET_NAME}/zachs_video"
|
100
|
+
listing = rclone.ls(path)
|
101
|
+
print(listing)
|
102
|
+
|
103
|
+
# List PNG Files in a Subdirectory
|
104
|
+
print("\n=== Listing PNG Files ===")
|
105
|
+
listing = rclone.ls(path, glob="*.png")
|
106
|
+
|
107
|
+
if listing.files:
|
108
|
+
for file in listing.files:
|
109
|
+
print(file)
|
110
|
+
|
111
|
+
# Copy a File
|
112
|
+
print("\n=== Copying a File ===")
|
113
|
+
if listing.files:
|
114
|
+
file = listing.files[0]
|
115
|
+
new_path = f"dst:{BUCKET_NAME}/zachs_video/{file.name}_copy"
|
116
|
+
rclone.copyfile(file, new_path)
|
117
|
+
print(f"Copied {file.name} to {new_path}")
|
118
|
+
|
119
|
+
# Copy Multiple Files
|
120
|
+
print("\n=== Copying Multiple Files ===")
|
121
|
+
if listing.files:
|
122
|
+
file_mapping = {file.name: file.name + "_copy" for file in listing.files[:2]}
|
123
|
+
rclone.copyfiles(file_mapping)
|
124
|
+
print(f"Copied files: {file_mapping}")
|
125
|
+
|
126
|
+
# Delete a File
|
127
|
+
print("\n=== Deleting a File ===")
|
128
|
+
file_to_delete = f"dst:{BUCKET_NAME}/zachs_video/sample.png_copy"
|
129
|
+
rclone.deletefiles([file_to_delete])
|
130
|
+
print(f"Deleted {file_to_delete}")
|
131
|
+
|
132
|
+
# Walk Through a Directory
|
133
|
+
print("\n=== Walking Through a Directory ===")
|
134
|
+
for dirlisting in rclone.walk(f"dst:{BUCKET_NAME}", max_depth=1):
|
135
|
+
print(dirlisting)
|
136
|
+
|
137
|
+
print("Done.")
|
138
|
+
```
|
139
|
+
|
140
|
+
|
141
|
+
To develop software, run `. ./activate`
|
142
|
+
|
143
|
+
# Windows
|
144
|
+
|
145
|
+
This environment requires you to use `git-bash`.
|
146
|
+
|
147
|
+
# Linting
|
148
|
+
|
149
|
+
Run `./lint`
|
@@ -1,20 +1,21 @@
|
|
1
|
-
rclone_api/__init__.py,sha256=
|
1
|
+
rclone_api/__init__.py,sha256=UWQMbhE4WOQ3Skfb0LagFKW8PUKUGOm9_T3z--5FHiY,388
|
2
2
|
rclone_api/cli.py,sha256=dibfAZIh0kXWsBbfp3onKLjyZXo54mTzDjUdzJlDlWo,231
|
3
3
|
rclone_api/config.py,sha256=tP6cU9DnCCEIRc_KP9HPur1jFLLg2QGFSxNwFm6_MVw,118
|
4
4
|
rclone_api/convert.py,sha256=Mx9Qo7zhkOedJd8LdhPvNGHp8znJzOk4f_2KWnoGc78,1012
|
5
5
|
rclone_api/dir.py,sha256=xUV4i9_E7QHrqHld2IPBlon1CGaAp8qQYMKfJTyVvoQ,2088
|
6
6
|
rclone_api/dir_listing.py,sha256=8t5Jx9ZVOJPqGKTJbWaES6bjgogUT2bnpbPVWwK1Fcs,1124
|
7
|
-
rclone_api/exec.py,sha256=
|
7
|
+
rclone_api/exec.py,sha256=9qSOpZo8YRYxv3hOvNr57ApnY2KbjxwT1QNr8OgcLM4,883
|
8
8
|
rclone_api/file.py,sha256=D02iHJW1LhfOiM_R_yPHP8_ApnDiYrkuraVcrV8-qkw,1246
|
9
9
|
rclone_api/filelist.py,sha256=xbiusvNgaB_b_kQOZoHMJJxn6TWGtPrWd2J042BI28o,767
|
10
|
-
rclone_api/
|
10
|
+
rclone_api/process.py,sha256=QLI-65R4Jvov9oOJSVY5UpDOS2xj6m-9YCg8upR4-0M,3560
|
11
|
+
rclone_api/rclone.py,sha256=hvzo5zZmP5IQAtuwLcsTeeazDY0slqz76DdulV2mn3s,9640
|
11
12
|
rclone_api/remote.py,sha256=c9hlRKBCg1BFB9MCINaQIoCg10qyAkeqiS4brl8ce-8,343
|
12
13
|
rclone_api/rpath.py,sha256=8ZA_1wxWtskwcy0I8V2VbjKDmzPkiWd8Q2JQSvh-sYE,2586
|
13
|
-
rclone_api/util.py,sha256=
|
14
|
+
rclone_api/util.py,sha256=BDRJ2MIceDoKVTjUQBwyhjbA8UwPrZ-0ZSa9xyMJd0E,3343
|
14
15
|
rclone_api/walk.py,sha256=J78-bY2AhNpt2ICsI5LqmXRE7oC6wVDoKoicIoU6XMg,1953
|
15
16
|
rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
|
16
|
-
rclone_api-1.0.
|
17
|
-
rclone_api-1.0.
|
18
|
-
rclone_api-1.0.
|
19
|
-
rclone_api-1.0.
|
20
|
-
rclone_api-1.0.
|
17
|
+
rclone_api-1.0.17.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
18
|
+
rclone_api-1.0.17.dist-info/METADATA,sha256=9_ahew4G4YXDjXQljGkoA8s1KZa76mPrv3TZ99c2Xo4,4421
|
19
|
+
rclone_api-1.0.17.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
|
20
|
+
rclone_api-1.0.17.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
21
|
+
rclone_api-1.0.17.dist-info/RECORD,,
|
@@ -1,34 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.2
|
2
|
-
Name: rclone_api
|
3
|
-
Version: 1.0.15
|
4
|
-
Summary: rclone api in python
|
5
|
-
Home-page: https://github.com/zackees/rclone-api
|
6
|
-
Maintainer: Zachary Vorhies
|
7
|
-
License: BSD 3-Clause License
|
8
|
-
Keywords: template-python-cmd
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
10
|
-
Requires-Python: >=3.10
|
11
|
-
Description-Content-Type: text/markdown
|
12
|
-
License-File: LICENSE
|
13
|
-
Requires-Dist: python-dotenv>=1.0.0
|
14
|
-
Dynamic: home-page
|
15
|
-
Dynamic: maintainer
|
16
|
-
|
17
|
-
# rclone-api
|
18
|
-
|
19
|
-
[](https://github.com/zackees/rclone-api/actions/workflows/lint.yml)
|
20
|
-
[](https://github.com/zackees/rclone-api/actions/workflows/push_macos.yml)
|
21
|
-
[](https://github.com/zackees/rclone-api/actions/workflows/push_ubuntu.yml)
|
22
|
-
[](https://github.com/zackees/rclone-api/actions/workflows/push_win.yml)
|
23
|
-
|
24
|
-
Api version of rclone. It's well tested. It's just released so this readme is a little to be desired.
|
25
|
-
|
26
|
-
To develop software, run `. ./activate`
|
27
|
-
|
28
|
-
# Windows
|
29
|
-
|
30
|
-
This environment requires you to use `git-bash`.
|
31
|
-
|
32
|
-
# Linting
|
33
|
-
|
34
|
-
Run `./lint`
|
File without changes
|
File without changes
|
File without changes
|