file-backuper 1.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.
- file_backuper-1.3.0/.github/workflows/publish.yml +50 -0
- file_backuper-1.3.0/.gitignore +57 -0
- file_backuper-1.3.0/PKG-INFO +4 -0
- file_backuper-1.3.0/PLAN.md +35 -0
- file_backuper-1.3.0/README.md +397 -0
- file_backuper-1.3.0/backuper_app/__init__.py +0 -0
- file_backuper-1.3.0/backuper_app/backup/__init__.py +6 -0
- file_backuper-1.3.0/backuper_app/backup/analyzer.py +99 -0
- file_backuper-1.3.0/backuper_app/backup/archive.py +63 -0
- file_backuper-1.3.0/backuper_app/backup/backuper.py +181 -0
- file_backuper-1.3.0/backuper_app/backup/compression.py +38 -0
- file_backuper-1.3.0/backuper_app/backup/filter_engine.py +59 -0
- file_backuper-1.3.0/backuper_app/backup/initializer.py +95 -0
- file_backuper-1.3.0/backuper_app/backup/manifest.py +44 -0
- file_backuper-1.3.0/backuper_app/backup/restore.py +57 -0
- file_backuper-1.3.0/backuper_app/backup/retention.py +37 -0
- file_backuper-1.3.0/backuper_app/backup/verify.py +29 -0
- file_backuper-1.3.0/backuper_app/cli.py +270 -0
- file_backuper-1.3.0/backuper_app/config/__init__.py +1 -0
- file_backuper-1.3.0/backuper_app/config/config.py +80 -0
- file_backuper-1.3.0/backuper_app/dto.py +28 -0
- file_backuper-1.3.0/backuper_app/exception.py +14 -0
- file_backuper-1.3.0/backuper_app/main.py +62 -0
- file_backuper-1.3.0/backuper_app/utils/__init__.py +4 -0
- file_backuper-1.3.0/backuper_app/utils/archive_resolver.py +39 -0
- file_backuper-1.3.0/backuper_app/utils/capacity.py +41 -0
- file_backuper-1.3.0/backuper_app/utils/checksum.py +58 -0
- file_backuper-1.3.0/backuper_app/utils/logger.py +11 -0
- file_backuper-1.3.0/config.toml +25 -0
- file_backuper-1.3.0/pyproject.toml +15 -0
- file_backuper-1.3.0/uv.lock +8 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-python@v6
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.x"
|
|
18
|
+
|
|
19
|
+
- name: Install build
|
|
20
|
+
run: python -m pip install build
|
|
21
|
+
|
|
22
|
+
- name: Build package
|
|
23
|
+
run: python -m build
|
|
24
|
+
|
|
25
|
+
- name: Upload artifacts
|
|
26
|
+
uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: python-package
|
|
29
|
+
path: dist/
|
|
30
|
+
|
|
31
|
+
publish:
|
|
32
|
+
needs: build
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
|
|
35
|
+
environment:
|
|
36
|
+
name: pypi
|
|
37
|
+
url: https://pypi.org/p/file-backuper
|
|
38
|
+
|
|
39
|
+
permissions:
|
|
40
|
+
id-token: write
|
|
41
|
+
|
|
42
|
+
steps:
|
|
43
|
+
- name: Download artifacts
|
|
44
|
+
uses: actions/download-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: python-package
|
|
47
|
+
path: dist/
|
|
48
|
+
|
|
49
|
+
- name: Publish to PyPI
|
|
50
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# --- Python ---
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
env/
|
|
8
|
+
venv/
|
|
9
|
+
.venv/
|
|
10
|
+
pip-log.txt
|
|
11
|
+
pip-delete-this-directory.txt
|
|
12
|
+
.tox/
|
|
13
|
+
.coverage
|
|
14
|
+
.coverage.*
|
|
15
|
+
.cache
|
|
16
|
+
nosetests.xml
|
|
17
|
+
coverage.xml
|
|
18
|
+
*.cover
|
|
19
|
+
*.log
|
|
20
|
+
.hypothesis/
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
|
|
24
|
+
# --- Editor / IDE ---
|
|
25
|
+
.vscode/
|
|
26
|
+
.idea/
|
|
27
|
+
*.swp
|
|
28
|
+
*.swo
|
|
29
|
+
*.swn
|
|
30
|
+
.DS_Store
|
|
31
|
+
|
|
32
|
+
# --- OS / Arch Linux / Environment ---
|
|
33
|
+
# File sistem atau file konfigurasi lokal
|
|
34
|
+
.directory
|
|
35
|
+
Desktop.ini
|
|
36
|
+
Thumbs.db
|
|
37
|
+
*.sublime-*
|
|
38
|
+
.env
|
|
39
|
+
.env.*
|
|
40
|
+
|
|
41
|
+
# --- Security & Recon Files (Opsional) ---
|
|
42
|
+
# Kalau kamu simpan hasil scan/recon, jangan sampai ikut ke-push!
|
|
43
|
+
*.dumpcap
|
|
44
|
+
*.pcap
|
|
45
|
+
*.txt
|
|
46
|
+
results/
|
|
47
|
+
scans/
|
|
48
|
+
wordlists/
|
|
49
|
+
|
|
50
|
+
# --- Project ---
|
|
51
|
+
# Tambahkan folder hasil build atau output spesifikmu di sini
|
|
52
|
+
dist/
|
|
53
|
+
build/
|
|
54
|
+
*.egg-info/
|
|
55
|
+
systemd/
|
|
56
|
+
test/
|
|
57
|
+
test_config.toml
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Nama Project
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
Program backup yang otomatis ignore unnecessary file,
|
|
5
|
+
membutuhkan path target dan peth destination untuk menjalankan program,
|
|
6
|
+
otomatis men copy file kecuali ignore ke folder destination
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
- 🔴 Input path target and dst
|
|
10
|
+
- 🔴 Copy file 1 per satu dan buat directory nya
|
|
11
|
+
- 🔴 Check eksistensi directory dan cek jika bukan file
|
|
12
|
+
- 🟡 copy file menggunakan loop dan melakukan filtering untuk ignore list
|
|
13
|
+
- 🟢 default nama backup = _backup
|
|
14
|
+
- 🟢
|
|
15
|
+
|
|
16
|
+
## Struktur
|
|
17
|
+
- File_Backuper
|
|
18
|
+
- .venv
|
|
19
|
+
- app
|
|
20
|
+
- main.py
|
|
21
|
+
- ignore
|
|
22
|
+
- PLAN.md
|
|
23
|
+
- .gitignore
|
|
24
|
+
|
|
25
|
+
## Alur
|
|
26
|
+
- User memasukan input manual untuk target dan destination path
|
|
27
|
+
- Program mengecek eksistensi target
|
|
28
|
+
- Program mengecek eksistensi destination, jika dst ada tapi file akan error, jika tidak ada maka akan dibuat otomatis
|
|
29
|
+
- memetakan isi di dalam target
|
|
30
|
+
- melakukan looping untuk setiap item, jika ignore maka skip, jika directory, masuk ke dalamnya
|
|
31
|
+
|
|
32
|
+
## Pseudocode
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## Catatan / Ideas
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# File Backuper
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Finsa-SC/backup-service/releases/tag/v1.2.0)
|
|
4
|
+
[](https://www.python.org/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
A powerful, modular CLI backup utility for creating, restoring, and verifying file backups with advanced features like compression, retention policies, and data integrity verification.
|
|
8
|
+
|
|
9
|
+
> **Latest Release:** v1.2.0 — Now supports setting default file config during initialization!
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Flexible Backup Creation** - Backup files and directories with include/exclude filtering
|
|
14
|
+
- **Multiple Compression Methods** - Support for gzip and zstd compression algorithms
|
|
15
|
+
- **Retention Policies** - Automatically manage backup rotation and keep only the last N backups
|
|
16
|
+
- **Data Integrity** - Built-in checksum verification for backup validation
|
|
17
|
+
- **Restore Capabilities** - Extract backups by file path or date with integrity checking
|
|
18
|
+
- **Symbolic Link Handling** - Choose how to handle symlinks (ignore, follow, or preserve)
|
|
19
|
+
- **Archive Support** - Automatically archive expired backups to a separate location
|
|
20
|
+
- **Dry-Run Mode** - Preview backup operations before execution
|
|
21
|
+
- **Configuration-Based** - TOML-based configuration for easy management
|
|
22
|
+
- **Detailed Logging** - Comprehensive logging for monitoring and troubleshooting
|
|
23
|
+
|
|
24
|
+
## What's New in v1.2.0
|
|
25
|
+
|
|
26
|
+
- ✨ **Default File Config in Init** - Set default configuration file during initialization
|
|
27
|
+
- 🔧 Improved configuration workflow
|
|
28
|
+
- 📋 [Full Changelog](https://github.com/Finsa-SC/backup-service/releases/tag/v1.2.0)
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
### Requirements
|
|
33
|
+
- Python >= 3.14
|
|
34
|
+
- pip or uv
|
|
35
|
+
|
|
36
|
+
### From GitHub Releases
|
|
37
|
+
|
|
38
|
+
Download and install the latest release:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Extract the release
|
|
42
|
+
unzip file-backuper-1.2.0.tar.gz
|
|
43
|
+
cd backup-service
|
|
44
|
+
|
|
45
|
+
# Install
|
|
46
|
+
pip install .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### From Source
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/Finsa-SC/backup-service.git
|
|
53
|
+
cd backup-service
|
|
54
|
+
pip install -e .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Using uv (recommended)
|
|
58
|
+
```bash
|
|
59
|
+
uv pip install -e .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This creates the `backuper` command available in your PATH.
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
### 1. Initialize Configuration
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
backuper init --target /path/to/backup --destination /path/to/backups
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or with all options:
|
|
73
|
+
```bash
|
|
74
|
+
backuper init /etc/backuper/config.toml \
|
|
75
|
+
--target /home/user/documents \
|
|
76
|
+
--destination /mnt/backups \
|
|
77
|
+
--retention 5 \
|
|
78
|
+
--compression zstd \
|
|
79
|
+
--link-mode preserve
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Create a Backup
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
backuper backup --config /etc/backuper/config.toml
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Preview before executing:
|
|
89
|
+
```bash
|
|
90
|
+
backuper backup --config /etc/backuper/config.toml --dry-run
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Restore from Backup
|
|
94
|
+
|
|
95
|
+
Restore a specific file:
|
|
96
|
+
```bash
|
|
97
|
+
backuper restore --file /path/to/backup/file.tar.gz --destination /tmp/restore
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Restore a backup by date:
|
|
101
|
+
```bash
|
|
102
|
+
backuper restore --date "2024-01-15" --archive-path /mnt/backups --destination /tmp/restore
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 4. Verify Backup Integrity
|
|
106
|
+
|
|
107
|
+
Verify a specific backup file:
|
|
108
|
+
```bash
|
|
109
|
+
backuper verify --file /path/to/backup/file.tar.gz
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Verify a backup by date:
|
|
113
|
+
```bash
|
|
114
|
+
backuper verify --date "2024-01-15" --archive-path /mnt/backups
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
Configuration is managed through a TOML file (default: `config.toml`).
|
|
120
|
+
|
|
121
|
+
### Example Configuration
|
|
122
|
+
|
|
123
|
+
```toml
|
|
124
|
+
[backup]
|
|
125
|
+
backup_name = "my_backup"
|
|
126
|
+
target = "/home/user/documents"
|
|
127
|
+
destination = "/mnt/backups"
|
|
128
|
+
compression = "zstd" # or "gzip"
|
|
129
|
+
keep_last = 5
|
|
130
|
+
link_mode = "preserve" # options: ignore, follow, preserve
|
|
131
|
+
archive_enable = true
|
|
132
|
+
archive_path = "/mnt/backups/archive"
|
|
133
|
+
|
|
134
|
+
[filter]
|
|
135
|
+
include = ["*.txt", "*.pdf"]
|
|
136
|
+
exclude = ["*.tmp", "*.cache"]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Configuration Options
|
|
140
|
+
|
|
141
|
+
| Option | Type | Description |
|
|
142
|
+
|--------|------|-------------|
|
|
143
|
+
| `backup_name` | string | Name identifier for this backup job |
|
|
144
|
+
| `target` | path | Source directory/file to backup |
|
|
145
|
+
| `destination` | path | Directory where backups are stored |
|
|
146
|
+
| `compression` | string | Compression method: `gzip` or `zstd` |
|
|
147
|
+
| `keep_last` | integer | Number of backups to retain (0 = keep all) |
|
|
148
|
+
| `link_mode` | string | Symlink handling: `ignore`, `follow`, or `preserve` |
|
|
149
|
+
| `archive_enable` | boolean | Archive expired backups instead of deleting |
|
|
150
|
+
| `archive_path` | path | Directory for archived backups (if enabled) |
|
|
151
|
+
| `include` | array | File patterns to include (optional) |
|
|
152
|
+
| `exclude` | array | File patterns to exclude (optional) |
|
|
153
|
+
|
|
154
|
+
## Command Reference
|
|
155
|
+
|
|
156
|
+
### backup
|
|
157
|
+
Create a new backup with retention and archival support.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
backuper backup --config CONFIG_PATH [--dry-run]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Options:**
|
|
164
|
+
- `--config CONFIG_PATH` (required): Path to configuration file
|
|
165
|
+
- `--dry-run`: Preview without actually creating backup
|
|
166
|
+
|
|
167
|
+
### restore
|
|
168
|
+
Extract backup data by file path or date with integrity verification.
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
backuper restore [--file FILE_PATH | --date DATE] --destination DEST_PATH [--archive-path ARCHIVE_PATH]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Options:**
|
|
175
|
+
- `--file FILE_PATH`: Path to specific backup file to restore
|
|
176
|
+
- `--date DATE`: Date of backup to restore (requires `--archive-path`)
|
|
177
|
+
- `--destination DEST_PATH`: Where to extract files (default: `/tmp/backup_restore`)
|
|
178
|
+
- `--archive-path ARCHIVE_PATH`: Path to archive directory (required when using `--date`)
|
|
179
|
+
|
|
180
|
+
### verify
|
|
181
|
+
Verify backup integrity using stored checksums.
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
backuper verify [--file FILE_PATH | --date DATE] [--archive-path ARCHIVE_PATH]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Options:**
|
|
188
|
+
- `--file FILE_PATH`: Path to backup file to verify
|
|
189
|
+
- `--date DATE`: Date of backup to verify (requires `--archive-path`)
|
|
190
|
+
- `--archive-path ARCHIVE_PATH`: Path to archive directory
|
|
191
|
+
|
|
192
|
+
### init
|
|
193
|
+
Create an initial configuration file from template.
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
backuper init [CONFIG_PATH] [--target TARGET] [--destination DEST] [--retention N] [--compression METHOD] [--link-mode MODE]
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Options:**
|
|
200
|
+
- `CONFIG_PATH`: Configuration file path (default: `/etc/backuper/config.toml`)
|
|
201
|
+
- `--target`: Source directory to backup
|
|
202
|
+
- `--destination`: Backup destination directory
|
|
203
|
+
- `--retention`: Number of backups to keep
|
|
204
|
+
- `--compression`: Compression method (`gzip` or `zstd`)
|
|
205
|
+
- `--link-mode`: Symlink handling mode
|
|
206
|
+
|
|
207
|
+
## Architecture
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
backuper_app/
|
|
211
|
+
├── backup/ # Core backup functionality
|
|
212
|
+
│ ├── backuper.py # Main backup engine
|
|
213
|
+
│ ├── compression.py # Compression handling
|
|
214
|
+
│ ├── retention.py # Backup rotation & cleanup
|
|
215
|
+
│ ├── archive.py # Archive management
|
|
216
|
+
│ ├── restore.py # Restore operations
|
|
217
|
+
│ ├── verify.py # Integrity verification
|
|
218
|
+
│ ├── analyzer.py # File analysis & filtering
|
|
219
|
+
│ ├── filter_engine.py # Include/exclude filtering
|
|
220
|
+
│ ├── manifest.py # Backup metadata
|
|
221
|
+
│ └── initializer.py # Config initialization
|
|
222
|
+
├── config/ # Configuration handling
|
|
223
|
+
│ └── config.py # Config parsing & validation
|
|
224
|
+
├── utils/ # Utility functions
|
|
225
|
+
│ ├── checksum.py # Hash & verification
|
|
226
|
+
│ ├── logger.py # Logging setup
|
|
227
|
+
│ ├── capacity.py # Size calculations
|
|
228
|
+
│ └── archive_resolver.py # Archive path resolution
|
|
229
|
+
└── main.py # CLI entry point
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Workflow
|
|
233
|
+
|
|
234
|
+
### Backup Workflow
|
|
235
|
+
1. Load configuration from TOML file
|
|
236
|
+
2. Analyze source directory with filtering
|
|
237
|
+
3. Create compressed archive (gzip or zstd)
|
|
238
|
+
4. Generate checksum for integrity verification
|
|
239
|
+
5. Check retention policy
|
|
240
|
+
6. Archive or delete old backups based on retention settings
|
|
241
|
+
|
|
242
|
+
### Restore Workflow
|
|
243
|
+
1. Validate backup file checksum
|
|
244
|
+
2. Extract archive to destination
|
|
245
|
+
3. Restore file permissions and metadata
|
|
246
|
+
|
|
247
|
+
### Verification Workflow
|
|
248
|
+
1. Calculate checksum of backup file
|
|
249
|
+
2. Compare with stored checksum
|
|
250
|
+
3. Report integrity status
|
|
251
|
+
|
|
252
|
+
## Examples
|
|
253
|
+
|
|
254
|
+
### Backup with retention
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Create initial config
|
|
258
|
+
backuper init my_backup.toml \
|
|
259
|
+
--target /home/user/documents \
|
|
260
|
+
--destination /mnt/backups \
|
|
261
|
+
--retention 7 \
|
|
262
|
+
--compression zstd
|
|
263
|
+
|
|
264
|
+
# Create backup (keeps last 7 backups)
|
|
265
|
+
backuper backup --config my_backup.toml
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Backup with filtering
|
|
269
|
+
|
|
270
|
+
```toml
|
|
271
|
+
[backup]
|
|
272
|
+
backup_name = "selective_backup"
|
|
273
|
+
target = "/home/user"
|
|
274
|
+
destination = "/mnt/backups"
|
|
275
|
+
compression = "zstd"
|
|
276
|
+
|
|
277
|
+
[filter]
|
|
278
|
+
include = ["*.txt", "*.pdf", "Documents/**"]
|
|
279
|
+
exclude = ["*.tmp", ".git/**", "node_modules/**"]
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Scheduled backups with systemd
|
|
283
|
+
|
|
284
|
+
```ini
|
|
285
|
+
# /etc/systemd/system/backuper.service
|
|
286
|
+
[Unit]
|
|
287
|
+
Description=File Backuper Service
|
|
288
|
+
After=network.target
|
|
289
|
+
|
|
290
|
+
[Service]
|
|
291
|
+
Type=oneshot
|
|
292
|
+
ExecStart=/usr/local/bin/backuper backup --config /etc/backuper/config.toml
|
|
293
|
+
User=backup
|
|
294
|
+
StandardOutput=journal
|
|
295
|
+
|
|
296
|
+
# /etc/systemd/system/backuper.timer
|
|
297
|
+
[Unit]
|
|
298
|
+
Description=Daily Backup Timer
|
|
299
|
+
Requires=backuper.service
|
|
300
|
+
|
|
301
|
+
[Timer]
|
|
302
|
+
OnCalendar=daily
|
|
303
|
+
OnCalendar=00:02
|
|
304
|
+
Persistent=true
|
|
305
|
+
|
|
306
|
+
[Install]
|
|
307
|
+
WantedBy=timers.target
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Error Handling
|
|
311
|
+
|
|
312
|
+
The tool provides clear error messages for common issues:
|
|
313
|
+
|
|
314
|
+
- **Invalid config**: Check TOML syntax and required fields
|
|
315
|
+
- **Permission denied**: Verify read/write permissions on source and destination
|
|
316
|
+
- **Checksum mismatch**: Backup may be corrupted, re-create backup
|
|
317
|
+
- **Insufficient space**: Ensure destination has enough free space
|
|
318
|
+
|
|
319
|
+
## Performance Notes
|
|
320
|
+
|
|
321
|
+
- **Compression**: zstd typically offers better compression ratios than gzip
|
|
322
|
+
- **Retention**: Archiving is preferred over deletion for safety
|
|
323
|
+
- **Symbolic links**: Use `preserve` mode to maintain symlink structure
|
|
324
|
+
- **Large files**: Dry-run mode helps preview operations before execution
|
|
325
|
+
|
|
326
|
+
## Development
|
|
327
|
+
|
|
328
|
+
### Project Structure
|
|
329
|
+
- Modular design with clear separation of concerns
|
|
330
|
+
- Type hints for better IDE support
|
|
331
|
+
- Comprehensive logging throughout
|
|
332
|
+
- Exception handling with custom `BackuperError`
|
|
333
|
+
|
|
334
|
+
### Running Tests
|
|
335
|
+
```bash
|
|
336
|
+
python -m pytest test/
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## License
|
|
340
|
+
|
|
341
|
+
[Add your license here]
|
|
342
|
+
|
|
343
|
+
## Contributing
|
|
344
|
+
|
|
345
|
+
Contributions are welcome! Please ensure:
|
|
346
|
+
- Code follows the existing style
|
|
347
|
+
- New features include tests
|
|
348
|
+
- Documentation is updated
|
|
349
|
+
- Commit messages are descriptive
|
|
350
|
+
|
|
351
|
+
## Support & Resources
|
|
352
|
+
|
|
353
|
+
- 📖 [Documentation](https://github.com/Finsa-SC/backup-service)
|
|
354
|
+
- 🐛 [Issue Tracker](https://github.com/Finsa-SC/backup-service/issues)
|
|
355
|
+
- 📝 [Releases](https://github.com/Finsa-SC/backup-service/releases)
|
|
356
|
+
- 💬 For questions, open an issue on GitHub
|
|
357
|
+
|
|
358
|
+
## Troubleshooting
|
|
359
|
+
|
|
360
|
+
**Backup stuck or slow?**
|
|
361
|
+
- Use `--dry-run` to check what's being processed
|
|
362
|
+
- Check exclude patterns if too many files
|
|
363
|
+
- Monitor disk I/O with `iostat`
|
|
364
|
+
|
|
365
|
+
**Restore fails?**
|
|
366
|
+
- Verify backup file exists and is accessible
|
|
367
|
+
- Check checksum: `backuper verify --file <backup>`
|
|
368
|
+
- Ensure destination has write permissions
|
|
369
|
+
|
|
370
|
+
**Config errors?**
|
|
371
|
+
- Validate TOML syntax at https://www.toml-lint.com/
|
|
372
|
+
- Ensure all paths are absolute and exist
|
|
373
|
+
- Check file permissions for config file
|
|
374
|
+
|
|
375
|
+
## Release History
|
|
376
|
+
|
|
377
|
+
### v1.2.0 (Current)
|
|
378
|
+
**Released:** Recently
|
|
379
|
+
- ✨ Feature to set default file config in init
|
|
380
|
+
- 🔧 Enhanced configuration initialization workflow
|
|
381
|
+
- 📚 Improved documentation
|
|
382
|
+
|
|
383
|
+
[View Release](https://github.com/Finsa-SC/backup-service/releases/tag/v1.2.0)
|
|
384
|
+
|
|
385
|
+
### v1.0.1
|
|
386
|
+
- Previous stable release
|
|
387
|
+
|
|
388
|
+
### v1.0.0
|
|
389
|
+
- Initial release
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Version Info
|
|
394
|
+
|
|
395
|
+
**Current version:** 1.2.0
|
|
396
|
+
**Python requirement:** >= 3.14
|
|
397
|
+
**Latest release:** [v1.2.0](https://github.com/Finsa-SC/backup-service/releases/tag/v1.2.0)
|
|
File without changes
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from backuper_app.utils import get_logger, format_size
|
|
3
|
+
|
|
4
|
+
logger = get_logger(__name__)
|
|
5
|
+
|
|
6
|
+
class Analyzer:
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
target_path: Path,
|
|
10
|
+
destination: Path,
|
|
11
|
+
files: list[Path],
|
|
12
|
+
backup_total: int,
|
|
13
|
+
compression_type: str,
|
|
14
|
+
link_mode: str,
|
|
15
|
+
archive_enabled: bool,
|
|
16
|
+
archive_path: Path|None,
|
|
17
|
+
include: list[str],
|
|
18
|
+
exclude: list[str],
|
|
19
|
+
retention: int | None,
|
|
20
|
+
):
|
|
21
|
+
self.target = target_path
|
|
22
|
+
self.destination = destination
|
|
23
|
+
self.files = files
|
|
24
|
+
self.backup_total = backup_total
|
|
25
|
+
self.compression = compression_type
|
|
26
|
+
self.link_mode = link_mode
|
|
27
|
+
self.archive_enabled = archive_enabled
|
|
28
|
+
self.archive_path = archive_path
|
|
29
|
+
self.include = include
|
|
30
|
+
self.exclude = exclude
|
|
31
|
+
self.retention = retention
|
|
32
|
+
|
|
33
|
+
def get_file_statistic(self) -> dict[str, int]:
|
|
34
|
+
mapping = dict(file=0, directory=0, symlink=0, socket=0, unknown=0)
|
|
35
|
+
for file in self.files:
|
|
36
|
+
if file.is_file():
|
|
37
|
+
mapping['file'] += 1
|
|
38
|
+
elif file.is_dir():
|
|
39
|
+
mapping['directory'] += 1
|
|
40
|
+
elif file.is_symlink():
|
|
41
|
+
mapping['symlink'] += 1
|
|
42
|
+
elif file.is_socket():
|
|
43
|
+
mapping['socket'] += 1
|
|
44
|
+
else:
|
|
45
|
+
mapping['unknown'] += 1
|
|
46
|
+
|
|
47
|
+
return mapping
|
|
48
|
+
|
|
49
|
+
def show_statistic(self, file_statistic: dict[str, int]) -> None:
|
|
50
|
+
from backuper_app.utils import analyze_estimate_size, format_size
|
|
51
|
+
|
|
52
|
+
logger.info("Starting dry run...")
|
|
53
|
+
|
|
54
|
+
#Backup info
|
|
55
|
+
logger.info(f"""
|
|
56
|
+
Backup
|
|
57
|
+
Target : {self.target if self.target.exists() else '-'}
|
|
58
|
+
Destination : {self.destination if self.destination.exists() else '-'}
|
|
59
|
+
Compression : {self.compression}
|
|
60
|
+
Link mode : {self.link_mode}
|
|
61
|
+
""")
|
|
62
|
+
|
|
63
|
+
#Filter
|
|
64
|
+
logger.info(f"""
|
|
65
|
+
Filter
|
|
66
|
+
Include : {self.include}
|
|
67
|
+
exclude : {self.exclude}
|
|
68
|
+
""")
|
|
69
|
+
|
|
70
|
+
#File statistic
|
|
71
|
+
matched_file = ["\n\tStatistics"]
|
|
72
|
+
for type_file, value in file_statistic.items():
|
|
73
|
+
matched_file.append(f"\t{type_file:<12}: {value}")
|
|
74
|
+
matched_file.append(f"\t{'Filtered':<12}: {self.backup_total}")
|
|
75
|
+
|
|
76
|
+
estimated_size = analyze_estimate_size(self.files)
|
|
77
|
+
matched_file.append(f"\tEstimate size: {format_size(estimated_size)}")
|
|
78
|
+
|
|
79
|
+
logger.info("\n".join(matched_file))
|
|
80
|
+
|
|
81
|
+
#Action
|
|
82
|
+
logger.info(f"""
|
|
83
|
+
Action
|
|
84
|
+
Manifest : Yes
|
|
85
|
+
Checksum : Yes
|
|
86
|
+
Archive : {self.archive_enabled}
|
|
87
|
+
Archive Path: {self.archive_path if self.archive_enabled and self.archive_path.is_dir() else "-"}
|
|
88
|
+
Keep last : {self.retention if self.retention else '-'}
|
|
89
|
+
""")
|
|
90
|
+
|
|
91
|
+
logger.info("""
|
|
92
|
+
Result
|
|
93
|
+
Dry run completed successfully
|
|
94
|
+
No filesystem changes were made
|
|
95
|
+
""")
|
|
96
|
+
|
|
97
|
+
def analyze_statistic(self):
|
|
98
|
+
mapping = self.get_file_statistic()
|
|
99
|
+
self.show_statistic(mapping)
|