easyclone 0.2.0__tar.gz → 0.3.0__tar.gz
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.
- {easyclone-0.2.0/src/easyclone.egg-info → easyclone-0.3.0}/PKG-INFO +16 -12
- {easyclone-0.2.0 → easyclone-0.3.0}/README.md +15 -11
- {easyclone-0.2.0 → easyclone-0.3.0}/pyproject.toml +1 -1
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/config.py +7 -20
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/utils/path_manipulation.py +3 -2
- easyclone-0.3.0/src/easyclone/utypes/config.py +26 -0
- {easyclone-0.2.0 → easyclone-0.3.0/src/easyclone.egg-info}/PKG-INFO +16 -12
- easyclone-0.2.0/src/easyclone/utypes/config.py +0 -16
- {easyclone-0.2.0 → easyclone-0.3.0}/LICENSE +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/setup.cfg +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/__main__.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/ipc/__init__.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/ipc/client.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/ipc/server.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/main.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/rclone/__init__.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/rclone/backup.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/rclone/create_dirs.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/rclone/operations.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/shared/__init__.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/shared/sync_status.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/utils/__init__.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/utils/essentials.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/utypes/__init__.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/utypes/enums.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone/utypes/models.py +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone.egg-info/SOURCES.txt +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone.egg-info/dependency_links.txt +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone.egg-info/entry_points.txt +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone.egg-info/requires.txt +0 -0
- {easyclone-0.2.0 → easyclone-0.3.0}/src/easyclone.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: easyclone
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Very convenient Rclone bulk backup wrapper
|
|
5
5
|
Project-URL: Repository, https://github.com/dybdeskarphet/easyclone
|
|
6
6
|
Project-URL: Documentation, https://github.com/dybdeskarphet/easyclone
|
|
@@ -19,13 +19,13 @@ Dynamic: license-file
|
|
|
19
19
|
|
|
20
20
|
You define what to back up, where to back it up, and EasyClone handles the syncs and copies — clean, fast, and reliable.
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Features
|
|
23
23
|
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* Sync & Copy support per-path
|
|
25
|
+
* Backup multiple paths at once
|
|
26
|
+
* Human-friendly TOML config
|
|
27
|
+
* IPC-ready architecture for future GUI or monitoring tools
|
|
28
|
+
* Optional verbose logging
|
|
29
29
|
|
|
30
30
|
## Installation
|
|
31
31
|
|
|
@@ -36,7 +36,11 @@ pip install easyclone
|
|
|
36
36
|
pipx install easyclone
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Configuration
|
|
40
|
+
|
|
41
|
+
The config file is at `~/.config/easyclone/config.toml`
|
|
42
|
+
|
|
43
|
+
## Requirements
|
|
40
44
|
|
|
41
45
|
* Python **3.13+**
|
|
42
46
|
* [`rclone`](https://rclone.org/) installed and accessible in your `$PATH`
|
|
@@ -44,7 +48,7 @@ pipx install easyclone
|
|
|
44
48
|
* `toml>=0.10.2`
|
|
45
49
|
* `typer>=0.16.0`
|
|
46
50
|
|
|
47
|
-
##
|
|
51
|
+
## Example Usage
|
|
48
52
|
|
|
49
53
|
```bash
|
|
50
54
|
easyclone start-backup
|
|
@@ -56,16 +60,16 @@ It will:
|
|
|
56
60
|
* Copy the paths in `copy_paths`
|
|
57
61
|
* Use the `remote_name` and `root_dir` to target your cloud storage
|
|
58
62
|
|
|
59
|
-
##
|
|
63
|
+
## Contributing
|
|
60
64
|
|
|
61
65
|
PRs welcome. Bug reports even more welcome.
|
|
62
66
|
|
|
63
|
-
##
|
|
67
|
+
## FAQ
|
|
64
68
|
|
|
65
69
|
Why does it create the folders first?
|
|
66
70
|
> Because services like Google Drive support multiple folders with the same name in the same directory. So when you try to concurrently backup paths from the same directory, it will create the parent directory more than once, and we don't want that.
|
|
67
71
|
|
|
68
|
-
##
|
|
72
|
+
## License
|
|
69
73
|
|
|
70
74
|
GPLv3 — do whatever you want, just don't blame me if you sync your `/` folder to the cloud :)
|
|
71
75
|
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
You define what to back up, where to back it up, and EasyClone handles the syncs and copies — clean, fast, and reliable.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Features
|
|
8
8
|
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* Sync & Copy support per-path
|
|
10
|
+
* Backup multiple paths at once
|
|
11
|
+
* Human-friendly TOML config
|
|
12
|
+
* IPC-ready architecture for future GUI or monitoring tools
|
|
13
|
+
* Optional verbose logging
|
|
14
14
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
@@ -21,7 +21,11 @@ pip install easyclone
|
|
|
21
21
|
pipx install easyclone
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
The config file is at `~/.config/easyclone/config.toml`
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
25
29
|
|
|
26
30
|
* Python **3.13+**
|
|
27
31
|
* [`rclone`](https://rclone.org/) installed and accessible in your `$PATH`
|
|
@@ -29,7 +33,7 @@ pipx install easyclone
|
|
|
29
33
|
* `toml>=0.10.2`
|
|
30
34
|
* `typer>=0.16.0`
|
|
31
35
|
|
|
32
|
-
##
|
|
36
|
+
## Example Usage
|
|
33
37
|
|
|
34
38
|
```bash
|
|
35
39
|
easyclone start-backup
|
|
@@ -41,16 +45,16 @@ It will:
|
|
|
41
45
|
* Copy the paths in `copy_paths`
|
|
42
46
|
* Use the `remote_name` and `root_dir` to target your cloud storage
|
|
43
47
|
|
|
44
|
-
##
|
|
48
|
+
## Contributing
|
|
45
49
|
|
|
46
50
|
PRs welcome. Bug reports even more welcome.
|
|
47
51
|
|
|
48
|
-
##
|
|
52
|
+
## FAQ
|
|
49
53
|
|
|
50
54
|
Why does it create the folders first?
|
|
51
55
|
> Because services like Google Drive support multiple folders with the same name in the same directory. So when you try to concurrently backup paths from the same directory, it will create the parent directory more than once, and we don't want that.
|
|
52
56
|
|
|
53
|
-
##
|
|
57
|
+
## License
|
|
54
58
|
|
|
55
59
|
GPLv3 — do whatever you want, just don't blame me if you sync your `/` folder to the cloud :)
|
|
56
60
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
import json
|
|
2
3
|
from threading import Lock
|
|
3
4
|
from os import getenv
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from easyclone.utypes.enums import LogLevel
|
|
6
|
-
from easyclone.utypes.config import BackupConfigModel, ConfigModel
|
|
7
|
+
from easyclone.utypes.config import BackupConfigModel, ConfigModel
|
|
7
8
|
import toml
|
|
8
9
|
|
|
9
10
|
class Config:
|
|
@@ -31,21 +32,6 @@ class Config:
|
|
|
31
32
|
copy_paths=[],
|
|
32
33
|
remote_name="GoogleDrive",
|
|
33
34
|
root_dir="Backups/PC",
|
|
34
|
-
verbose_log=False
|
|
35
|
-
),
|
|
36
|
-
rclone=RcloneConfigModel(
|
|
37
|
-
args=[
|
|
38
|
-
"--update",
|
|
39
|
-
"--verbose",
|
|
40
|
-
"--transfers 30",
|
|
41
|
-
"--checkers 8",
|
|
42
|
-
"--contimeout 60s",
|
|
43
|
-
"--timeout 300s",
|
|
44
|
-
"--retries 3",
|
|
45
|
-
"--low-level-retries 10",
|
|
46
|
-
"--stats 1s"
|
|
47
|
-
],
|
|
48
|
-
concurrent_limit=50
|
|
49
35
|
)
|
|
50
36
|
)
|
|
51
37
|
|
|
@@ -66,6 +52,10 @@ class Config:
|
|
|
66
52
|
|
|
67
53
|
self._path = config_file
|
|
68
54
|
|
|
55
|
+
def _config_normalize(self, config: ConfigModel):
|
|
56
|
+
config.backup.root_dir = config.backup.root_dir.strip("/")
|
|
57
|
+
return config
|
|
58
|
+
|
|
69
59
|
def _load_config(self):
|
|
70
60
|
from easyclone.utils.essentials import log
|
|
71
61
|
self._get_config_path()
|
|
@@ -83,10 +73,7 @@ class Config:
|
|
|
83
73
|
try:
|
|
84
74
|
parsed_toml = toml.loads(parsed_string)
|
|
85
75
|
validated_config = ConfigModel.model_validate(parsed_toml)
|
|
86
|
-
|
|
87
|
-
# Normalize config
|
|
88
|
-
validated_config.backup.root_dir = validated_config.backup.root_dir.strip("/")
|
|
89
|
-
|
|
76
|
+
validated_config = self._config_normalize(validated_config)
|
|
90
77
|
return validated_config
|
|
91
78
|
except Exception as e:
|
|
92
79
|
log(f"Invalid config: {e}", LogLevel.ERROR)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
import os
|
|
3
4
|
from easyclone.utypes.enums import PathType
|
|
@@ -10,7 +11,7 @@ def organize_paths(paths: list[str], remote_name: str) -> OrganizedPaths:
|
|
|
10
11
|
root_dir = cfg.backup.root_dir
|
|
11
12
|
|
|
12
13
|
for path in paths:
|
|
13
|
-
p = Path(path
|
|
14
|
+
p = Path(os.path.expandvars(os.path.expanduser(path)))
|
|
14
15
|
|
|
15
16
|
if not os.path.exists(p):
|
|
16
17
|
empty_paths.append(path)
|
|
@@ -28,7 +29,7 @@ def organize_paths(paths: list[str], remote_name: str) -> OrganizedPaths:
|
|
|
28
29
|
"dest": f"{remote_name}:{root_dir}{dest_dir}",
|
|
29
30
|
"path_type": PathType.FILE.value
|
|
30
31
|
})
|
|
31
|
-
|
|
32
|
+
|
|
32
33
|
return {
|
|
33
34
|
"valid_paths": source_dest_array,
|
|
34
35
|
"empty_paths": empty_paths
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
|
|
3
|
+
class BackupConfigModel(BaseModel):
|
|
4
|
+
sync_paths: list[str]
|
|
5
|
+
copy_paths: list[str]
|
|
6
|
+
remote_name: str
|
|
7
|
+
root_dir: str
|
|
8
|
+
verbose_log: bool = False
|
|
9
|
+
|
|
10
|
+
class RcloneConfigModel(BaseModel):
|
|
11
|
+
args: list[str] = [
|
|
12
|
+
"--update",
|
|
13
|
+
"--verbose",
|
|
14
|
+
"--transfers 30",
|
|
15
|
+
"--checkers 8",
|
|
16
|
+
"--contimeout 60s",
|
|
17
|
+
"--timeout 300s",
|
|
18
|
+
"--retries 3",
|
|
19
|
+
"--low-level-retries 10",
|
|
20
|
+
"--stats 1s"
|
|
21
|
+
]
|
|
22
|
+
concurrent_limit: int = 50
|
|
23
|
+
|
|
24
|
+
class ConfigModel(BaseModel):
|
|
25
|
+
backup: BackupConfigModel
|
|
26
|
+
rclone: RcloneConfigModel = RcloneConfigModel()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: easyclone
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Very convenient Rclone bulk backup wrapper
|
|
5
5
|
Project-URL: Repository, https://github.com/dybdeskarphet/easyclone
|
|
6
6
|
Project-URL: Documentation, https://github.com/dybdeskarphet/easyclone
|
|
@@ -19,13 +19,13 @@ Dynamic: license-file
|
|
|
19
19
|
|
|
20
20
|
You define what to back up, where to back it up, and EasyClone handles the syncs and copies — clean, fast, and reliable.
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Features
|
|
23
23
|
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* Sync & Copy support per-path
|
|
25
|
+
* Backup multiple paths at once
|
|
26
|
+
* Human-friendly TOML config
|
|
27
|
+
* IPC-ready architecture for future GUI or monitoring tools
|
|
28
|
+
* Optional verbose logging
|
|
29
29
|
|
|
30
30
|
## Installation
|
|
31
31
|
|
|
@@ -36,7 +36,11 @@ pip install easyclone
|
|
|
36
36
|
pipx install easyclone
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Configuration
|
|
40
|
+
|
|
41
|
+
The config file is at `~/.config/easyclone/config.toml`
|
|
42
|
+
|
|
43
|
+
## Requirements
|
|
40
44
|
|
|
41
45
|
* Python **3.13+**
|
|
42
46
|
* [`rclone`](https://rclone.org/) installed and accessible in your `$PATH`
|
|
@@ -44,7 +48,7 @@ pipx install easyclone
|
|
|
44
48
|
* `toml>=0.10.2`
|
|
45
49
|
* `typer>=0.16.0`
|
|
46
50
|
|
|
47
|
-
##
|
|
51
|
+
## Example Usage
|
|
48
52
|
|
|
49
53
|
```bash
|
|
50
54
|
easyclone start-backup
|
|
@@ -56,16 +60,16 @@ It will:
|
|
|
56
60
|
* Copy the paths in `copy_paths`
|
|
57
61
|
* Use the `remote_name` and `root_dir` to target your cloud storage
|
|
58
62
|
|
|
59
|
-
##
|
|
63
|
+
## Contributing
|
|
60
64
|
|
|
61
65
|
PRs welcome. Bug reports even more welcome.
|
|
62
66
|
|
|
63
|
-
##
|
|
67
|
+
## FAQ
|
|
64
68
|
|
|
65
69
|
Why does it create the folders first?
|
|
66
70
|
> Because services like Google Drive support multiple folders with the same name in the same directory. So when you try to concurrently backup paths from the same directory, it will create the parent directory more than once, and we don't want that.
|
|
67
71
|
|
|
68
|
-
##
|
|
72
|
+
## License
|
|
69
73
|
|
|
70
74
|
GPLv3 — do whatever you want, just don't blame me if you sync your `/` folder to the cloud :)
|
|
71
75
|
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from pydantic import BaseModel
|
|
2
|
-
|
|
3
|
-
class BackupConfigModel(BaseModel):
|
|
4
|
-
sync_paths: list[str]
|
|
5
|
-
copy_paths: list[str]
|
|
6
|
-
remote_name: str
|
|
7
|
-
root_dir: str
|
|
8
|
-
verbose_log: bool
|
|
9
|
-
|
|
10
|
-
class RcloneConfigModel(BaseModel):
|
|
11
|
-
args: list[str]
|
|
12
|
-
concurrent_limit: int
|
|
13
|
-
|
|
14
|
-
class ConfigModel(BaseModel):
|
|
15
|
-
backup: BackupConfigModel
|
|
16
|
-
rclone: RcloneConfigModel
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|