hamidrezam 0.1.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.
- hamidrezam-0.1.0/LICENSE +21 -0
- hamidrezam-0.1.0/PKG-INFO +282 -0
- hamidrezam-0.1.0/README.md +249 -0
- hamidrezam-0.1.0/pyproject.toml +64 -0
- hamidrezam-0.1.0/setup.cfg +4 -0
- hamidrezam-0.1.0/src/hamidrezam/__init__.py +48 -0
- hamidrezam-0.1.0/src/hamidrezam/__main__.py +10 -0
- hamidrezam-0.1.0/src/hamidrezam/cli/__init__.py +13 -0
- hamidrezam-0.1.0/src/hamidrezam/cli/commands.py +247 -0
- hamidrezam-0.1.0/src/hamidrezam/cli/main.py +118 -0
- hamidrezam-0.1.0/src/hamidrezam/config/__init__.py +6 -0
- hamidrezam-0.1.0/src/hamidrezam/config/loader.py +151 -0
- hamidrezam-0.1.0/src/hamidrezam/config/models.py +76 -0
- hamidrezam-0.1.0/src/hamidrezam/core/__init__.py +24 -0
- hamidrezam-0.1.0/src/hamidrezam/core/backup.py +261 -0
- hamidrezam-0.1.0/src/hamidrezam/core/manifest.py +38 -0
- hamidrezam-0.1.0/src/hamidrezam/core/restore.py +139 -0
- hamidrezam-0.1.0/src/hamidrezam/core/scanner.py +352 -0
- hamidrezam-0.1.0/src/hamidrezam/core/statistics.py +42 -0
- hamidrezam-0.1.0/src/hamidrezam/core/verifier.py +87 -0
- hamidrezam-0.1.0/src/hamidrezam/exceptions.py +31 -0
- hamidrezam-0.1.0/src/hamidrezam/filters/__init__.py +7 -0
- hamidrezam-0.1.0/src/hamidrezam/filters/base.py +34 -0
- hamidrezam-0.1.0/src/hamidrezam/filters/engine.py +287 -0
- hamidrezam-0.1.0/src/hamidrezam/filters/rules.py +240 -0
- hamidrezam-0.1.0/src/hamidrezam/formats/__init__.py +13 -0
- hamidrezam-0.1.0/src/hamidrezam/formats/base.py +58 -0
- hamidrezam-0.1.0/src/hamidrezam/formats/zip.py +94 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/__init__.py +21 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/ai.py +47 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/base.py +15 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/detector.py +54 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/frontend.py +60 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/generic.py +15 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/node.py +44 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/php.py +23 -0
- hamidrezam-0.1.0/src/hamidrezam/profiles/python.py +36 -0
- hamidrezam-0.1.0/src/hamidrezam/py.typed +0 -0
- hamidrezam-0.1.0/src/hamidrezam/security/__init__.py +5 -0
- hamidrezam-0.1.0/src/hamidrezam/security/archive.py +45 -0
- hamidrezam-0.1.0/src/hamidrezam/utils/__init__.py +7 -0
- hamidrezam-0.1.0/src/hamidrezam/utils/hashing.py +25 -0
- hamidrezam-0.1.0/src/hamidrezam/utils/paths.py +23 -0
- hamidrezam-0.1.0/src/hamidrezam/utils/sizes.py +45 -0
- hamidrezam-0.1.0/src/hamidrezam/version.py +3 -0
- hamidrezam-0.1.0/src/hamidrezam.egg-info/PKG-INFO +282 -0
- hamidrezam-0.1.0/src/hamidrezam.egg-info/SOURCES.txt +49 -0
- hamidrezam-0.1.0/src/hamidrezam.egg-info/dependency_links.txt +1 -0
- hamidrezam-0.1.0/src/hamidrezam.egg-info/entry_points.txt +2 -0
- hamidrezam-0.1.0/src/hamidrezam.egg-info/requires.txt +10 -0
- hamidrezam-0.1.0/src/hamidrezam.egg-info/top_level.txt +1 -0
hamidrezam-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hamidreza Moghaddam Kohi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hamidrezam
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Hamidrezam — safe, intelligent software-project backup tool (library + CLI)
|
|
5
|
+
Author-email: Hamidreza Moghaddam Kohi <info@hamidrezamoghaddam.ir>
|
|
6
|
+
Maintainer-email: Hamidreza Moghaddam Kohi <info@hamidrezamoghaddam.ir>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://hamidrezamoghaddam.ir/
|
|
9
|
+
Keywords: backup,archive,project,cli,developer-tools,zip
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: System :: Archiving :: Backup
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: tomli>=2; python_version < "3.11"
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
29
|
+
Requires-Dist: build>=1; extra == "dev"
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# Hamidrezam — Safe, Intelligent Software-Project Backups
|
|
35
|
+
|
|
36
|
+
Hamidrezam (`pip install hamidrezam`) is a professional Python library + CLI that creates **clean, optimized project archives** while guaranteeing one non-negotiable invariant:
|
|
37
|
+
|
|
38
|
+
> **Hamidrezam NEVER modifies the source project.**
|
|
39
|
+
|
|
40
|
+
Excluded files (`node_modules`, `.venv`, caches, build artifacts, …) are excluded **only from the archive**. They are never deleted, moved, renamed, or touched on disk. Hamidrezam streams selected files **directly into the ZIP** — no temporary cleaned copies.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install hamidrezam
|
|
44
|
+
hamidrezam backup ./my-project
|
|
45
|
+
# -> ./backups/my-project_2026-09-20_10-50-00.zip
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Expected output:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
✓ Project scanned
|
|
52
|
+
✓ Exclusions applied
|
|
53
|
+
✓ Archive created
|
|
54
|
+
✓ Manifest generated
|
|
55
|
+
✓ Archive verified
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Why Hamidrezam?
|
|
59
|
+
|
|
60
|
+
Developer machines accumulate gigabytes of reproducible data: virtualenvs, `node_modules`, `__pycache__`, `.next/`, `.tox/`, ML runs, logs. Copying all of it for a backup is slow and wasteful — but hand-deleting it is dangerous. Hamidrezam automates the safe middle ground:
|
|
61
|
+
|
|
62
|
+
- **Safe** — read-only scan; source hashes unchanged (covered by a dedicated integrity test).
|
|
63
|
+
- **Predictable** — every decision has a reason (`hamidrezam explain`).
|
|
64
|
+
- **Transparent** — exclusion report + in-archive manifest with SHA-256 per file.
|
|
65
|
+
- **Fast** — single-pass streaming, chunked hashing, no temp copies.
|
|
66
|
+
- **Cross-platform** — `pathlib` throughout; Windows/Linux/macOS.
|
|
67
|
+
- **Configurable** — CLI > `.hamidrezam.toml` > global config > defaults.
|
|
68
|
+
- **Scriptable & extensible** — typed Python API + `BackupWriter` abstraction (ZIP today, `tar.gz` reserved).
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
- Auto-detection of Python, Node.js/npm/pnpm/Yarn, React, Next.js, Vue, Nuxt, PHP, Laravel, Docker, AI/ML, generic/mixed projects.
|
|
73
|
+
- Sensible default exclusions (dependencies, venvs, caches, artifacts, temp, ML outputs) with opt-in knobs for `dist/`/`build/`, IDE dirs, ML outputs.
|
|
74
|
+
- Secrets (`.env*`, `secrets.json`, …) and large-file policies: `include` / `exclude` / `warn` (default `warn` = include + warning).
|
|
75
|
+
- `--dry-run` planning, `explain` auditing, `verify` integrity checks, safe `restore` with traversal protection.
|
|
76
|
+
- Output-inside-source self-inclusion guard; never-silently-overwrite naming.
|
|
77
|
+
- Zero runtime dependencies (stdlib only; `tomli` backport on Python < 3.11).
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install hamidrezam
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Requires Python ≥ 3.9. Verify:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
hamidrezam version
|
|
89
|
+
python -m hamidrezam version
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Quick start
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
hamidrezam backup ./my-project
|
|
96
|
+
hamidrezam backup ./my-project --dry-run
|
|
97
|
+
hamidrezam backup ./my-project --include-git
|
|
98
|
+
hamidrezam backup ./my-project --format zip
|
|
99
|
+
hamidrezam backup . --exclude "*.log" --exclude "data/tmp/"
|
|
100
|
+
hamidrezam verify ./backups/my-project_2026-09-20_10-50-00.zip
|
|
101
|
+
hamidrezam restore ./backups/my-project_2026-09-20_10-50-00.zip ./restored --overwrite
|
|
102
|
+
hamidrezam explain ./my-project
|
|
103
|
+
hamidrezam list ./backups/my-project_2026-09-20_10-50-00.zip
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## CLI usage
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
hamidrezam backup <source> [--output ./backups] [--name NAME] [--format zip]
|
|
110
|
+
[--dry-run] [--include-git]
|
|
111
|
+
[--exclude GLOB]... [--include GLOB]...
|
|
112
|
+
[--secret-mode warn|include|exclude]
|
|
113
|
+
[--large-mode warn|include|exclude] [--max-size 2GB]
|
|
114
|
+
[--symlink-mode preserve|skip|follow] [--no-compression]
|
|
115
|
+
hamidrezam restore <backup.zip> <destination> [--overwrite]
|
|
116
|
+
hamidrezam verify <backup.zip> [--check-hashes]
|
|
117
|
+
hamidrezam explain <source>
|
|
118
|
+
hamidrezam list <backup.zip>
|
|
119
|
+
hamidrezam version
|
|
120
|
+
python -m hamidrezam <same as above>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Include/exclude precedence: **output-safety > `--include` > protected source-of-truth files > `--exclude` > secrets/large policies > default rules > include**. In short: explicit `--include` wins over default excludes; explicit `--exclude` still wins over protected files (your explicit choice); the archive can never include itself.
|
|
124
|
+
|
|
125
|
+
## Python API
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from hamidrezam import BackupManager, BackupConfig
|
|
129
|
+
|
|
130
|
+
manager = BackupManager()
|
|
131
|
+
result = manager.backup(source="./my-project", output="./backups")
|
|
132
|
+
print(result.archive_path, result.verified)
|
|
133
|
+
|
|
134
|
+
config = BackupConfig(include_git=False, secret_mode="warn", max_size="2GB")
|
|
135
|
+
manager = BackupManager(config=config)
|
|
136
|
+
dry = manager.backup("./project", dry_run=True)
|
|
137
|
+
print(dry.files_included, dry.files_excluded)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Typed results: `BackupResult`, `ScanResult`, `VerificationResult`, `RestoreResult`, `BackupStatistics` (with `archive_path`, `files_included/excluded`, `bytes_included/excluded`, `duration`, `sha256`, `warnings`, …).
|
|
141
|
+
|
|
142
|
+
## Supported project types
|
|
143
|
+
|
|
144
|
+
No manual `--type` flag needed. Signals include `pyproject.toml`/`requirements.txt`/`Pipfile` → Python; `package.json` → Node.js (+ `package-lock.json` → npm, `pnpm-lock.yaml` → pnpm, `yarn.lock` → Yarn; `react`/`next`/`vue`/`nuxt` deps → frameworks); `composer.json` → PHP, `artisan` → Laravel; `Dockerfile`/`docker-compose.yml`/`compose.yml` → Docker; notebooks/`wandb`/`.mlflow` → AI/ML. Multiple labels can apply at once.
|
|
145
|
+
|
|
146
|
+
## Default exclusions
|
|
147
|
+
|
|
148
|
+
| Area | Excluded (from archive only) |
|
|
149
|
+
|---|---|
|
|
150
|
+
| Python | `.venv/`, `venv/`, `env/`, `ENV/`, `__pycache__/`, `.pytest_cache/`, `.mypy_cache/`, `.ruff_cache/`, `.tox/`, `.nox/`, `.coverage`, `htmlcov/`, `*.pyc/pyo/pyd`, `*.egg-info/` |
|
|
151
|
+
| Node/frontend | `node_modules/`, `.npm/`, `.yarn/`, `.pnpm-store/`, `.next/`, `.nuxt/`, `.parcel-cache/`, `.turbo/`, `.cache/`, `coverage/` |
|
|
152
|
+
| AI/ML | `.ipynb_checkpoints/`, `.mlflow/`, `wandb/`, `runs/`, `logs/`, `.cache/` (+ `outputs/`, `checkpoints/` unless `include_outputs=true`) |
|
|
153
|
+
| General | `.cache/`, `tmp/`, `temp/`, `*.tmp`, `*.temp`, `.DS_Store`, `Thumbs.db`, `*.swp/swo` |
|
|
154
|
+
| Build | `dist/`, `build/` unless `include_dist_build=true` |
|
|
155
|
+
| IDE | `.idea/`, `.vscode/` only when `include=false` (default `true` = preserved) |
|
|
156
|
+
| Git | `.git/` unless `--include-git` / `[git] include=true` |
|
|
157
|
+
|
|
158
|
+
Never excluded by default: `README.md`, `LICENSE`, `.gitignore`, `.gitattributes`, `Dockerfile`, compose files, `package.json`, lock files (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `poetry.lock`, `uv.lock`, `Pipfile.lock`, `composer.lock`), `requirements.txt`, `pyproject.toml`, `composer.json`. Model weights (`*.pt/.pth/.onnx/.safetensors/.ckpt/.bin`) are never auto-excluded for being large — they trigger `warn`.
|
|
159
|
+
|
|
160
|
+
## Configuration (`.hamidrezam.toml`)
|
|
161
|
+
|
|
162
|
+
Place in the project root; see `examples/.hamidrezam.toml`:
|
|
163
|
+
|
|
164
|
+
```toml
|
|
165
|
+
[backup]
|
|
166
|
+
format = "zip"
|
|
167
|
+
compression = true
|
|
168
|
+
output = "./backups"
|
|
169
|
+
|
|
170
|
+
[git]
|
|
171
|
+
include = false
|
|
172
|
+
|
|
173
|
+
[secrets]
|
|
174
|
+
mode = "warn"
|
|
175
|
+
|
|
176
|
+
[large_files]
|
|
177
|
+
mode = "warn"
|
|
178
|
+
max_size = "2GB"
|
|
179
|
+
|
|
180
|
+
[symlinks]
|
|
181
|
+
mode = "preserve"
|
|
182
|
+
|
|
183
|
+
[ide]
|
|
184
|
+
include = true
|
|
185
|
+
|
|
186
|
+
[build]
|
|
187
|
+
include_dist_build = false
|
|
188
|
+
|
|
189
|
+
[ml]
|
|
190
|
+
include_outputs = false
|
|
191
|
+
|
|
192
|
+
[custom]
|
|
193
|
+
exclude = ["*.log"]
|
|
194
|
+
include = []
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Priority: **CLI args > `.hamidrezam.toml` > global config (`~/.config/hamidrezam/config.toml` or `~/.hamidrezam.toml`) > defaults**.
|
|
198
|
+
|
|
199
|
+
## Secrets policy
|
|
200
|
+
|
|
201
|
+
`.env`, `.env.local/.production/.development/.staging`, `secrets.json`, `credentials.json` (plus generic `.env.*`; `.env.example` is treated as a safe template). Default `warn`: included + listed as a warning. Use `exclude` to drop, `include` to silence the warning.
|
|
202
|
+
|
|
203
|
+
## Large files
|
|
204
|
+
|
|
205
|
+
Any file over `max_size` (default `2GB`; accepts `500MB`, `1024`, …) follows `large_files.mode` (default `warn`). Never silently dropped.
|
|
206
|
+
|
|
207
|
+
## Git handling
|
|
208
|
+
|
|
209
|
+
`.git/` excluded by default (`include_git=false`). Enable per-run (`--include-git`) or per-project (`[git] include=true`). `.gitignore`/`.gitattributes` are always preserved.
|
|
210
|
+
|
|
211
|
+
## Restore
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
hamidrezam restore backup.zip ./restored-project --overwrite
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Validates the archive, rejects `../` and absolute entries, confines writes to the destination, preserves structure, skips existing files unless `--overwrite`, restores symlinks best-effort (falls back to regular files on Windows without privilege).
|
|
218
|
+
|
|
219
|
+
## Verification
|
|
220
|
+
|
|
221
|
+
Every backup auto-verifies (ZIP integrity + manifest schema). Re-check later:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
hamidrezam verify backup.zip
|
|
225
|
+
hamidrezam verify backup.zip --check-hashes # re-hash contents vs manifest
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Each archive embeds `.hamidrezam/manifest.json` with `tool`, `version`, `created_at`, `project_name`, `profiles`, `statistics`, `warnings`, and per-file `path/size/sha256/modified_time` (relative paths only).
|
|
229
|
+
|
|
230
|
+
## Security
|
|
231
|
+
|
|
232
|
+
- No blind extraction; all member names validated.
|
|
233
|
+
- Symlinks never followed outside the project; loops detected via `(st_dev, st_ino)`.
|
|
234
|
+
- Broken links, special files (sockets/FIFOs/devices), permission errors → skipped with warnings, never fatal.
|
|
235
|
+
- Secrets/large files surface as warnings, never silently leaked/dropped.
|
|
236
|
+
|
|
237
|
+
## Examples
|
|
238
|
+
|
|
239
|
+
- `examples/.hamidrezam.toml` — annotated config.
|
|
240
|
+
- `examples/basic_backup.py` — `python examples/basic_backup.py` after install.
|
|
241
|
+
|
|
242
|
+
## Development
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
python -m venv .venv && source .venv/bin/activate
|
|
246
|
+
pip install -e ".[dev]"
|
|
247
|
+
pytest
|
|
248
|
+
python -m build
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Testing
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
pytest # full suite
|
|
255
|
+
pytest tests/unit
|
|
256
|
+
pytest tests/integration
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Covers scanner (nesting/empty/unicode/spaces), exclusions, secrets, large files, ZIP+manifest+hashes, restore/overwrite/traversal, symlinks (broken/outside/skip), CLI exit codes, and the mandatory **source-integrity** test (hashes + paths + mtimes identical before/after backup).
|
|
260
|
+
|
|
261
|
+
## Roadmap
|
|
262
|
+
|
|
263
|
+
- `tar.gz` writer (`TarGzBackupWriter` via the existing `BackupWriter` interface).
|
|
264
|
+
- Opt-in `.gitignore`-aware mode, negation (`!`) support.
|
|
265
|
+
- Progress bars, JSON output (`--json`), exclusion-size report table.
|
|
266
|
+
- `hamidrezam init` config generator.
|
|
267
|
+
|
|
268
|
+
## Known limitations (0.1.0)
|
|
269
|
+
|
|
270
|
+
- Only `zip` format (`--format tar.gz` fails with a clear future-reserved message).
|
|
271
|
+
- `.gitignore` patterns are parsed by `GitIgnoreRule` for API use but not auto-applied to backups (avoids surprising drops of `.env`-style files).
|
|
272
|
+
- `runs/`, `logs/`, `tmp/`, `temp/`, `outputs/`, `checkpoints/` directory names are excluded wherever they appear; rename intentional source dirs or use `--include` to keep them.
|
|
273
|
+
- Symlink restore on Windows may fall back to regular files without Developer Mode/admin.
|
|
274
|
+
|
|
275
|
+
## License
|
|
276
|
+
|
|
277
|
+
MIT — see `LICENSE`.
|
|
278
|
+
|
|
279
|
+
## Author
|
|
280
|
+
|
|
281
|
+
**Hamidreza Moghaddam Kohi** — Full Stack Developer · AI · Automation
|
|
282
|
+
Website: <https://hamidrezamoghaddam.ir/> · Email: <info@hamidrezamoghaddam.ir>
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Hamidrezam — Safe, Intelligent Software-Project Backups
|
|
2
|
+
|
|
3
|
+
Hamidrezam (`pip install hamidrezam`) is a professional Python library + CLI that creates **clean, optimized project archives** while guaranteeing one non-negotiable invariant:
|
|
4
|
+
|
|
5
|
+
> **Hamidrezam NEVER modifies the source project.**
|
|
6
|
+
|
|
7
|
+
Excluded files (`node_modules`, `.venv`, caches, build artifacts, …) are excluded **only from the archive**. They are never deleted, moved, renamed, or touched on disk. Hamidrezam streams selected files **directly into the ZIP** — no temporary cleaned copies.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install hamidrezam
|
|
11
|
+
hamidrezam backup ./my-project
|
|
12
|
+
# -> ./backups/my-project_2026-09-20_10-50-00.zip
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Expected output:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
✓ Project scanned
|
|
19
|
+
✓ Exclusions applied
|
|
20
|
+
✓ Archive created
|
|
21
|
+
✓ Manifest generated
|
|
22
|
+
✓ Archive verified
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Why Hamidrezam?
|
|
26
|
+
|
|
27
|
+
Developer machines accumulate gigabytes of reproducible data: virtualenvs, `node_modules`, `__pycache__`, `.next/`, `.tox/`, ML runs, logs. Copying all of it for a backup is slow and wasteful — but hand-deleting it is dangerous. Hamidrezam automates the safe middle ground:
|
|
28
|
+
|
|
29
|
+
- **Safe** — read-only scan; source hashes unchanged (covered by a dedicated integrity test).
|
|
30
|
+
- **Predictable** — every decision has a reason (`hamidrezam explain`).
|
|
31
|
+
- **Transparent** — exclusion report + in-archive manifest with SHA-256 per file.
|
|
32
|
+
- **Fast** — single-pass streaming, chunked hashing, no temp copies.
|
|
33
|
+
- **Cross-platform** — `pathlib` throughout; Windows/Linux/macOS.
|
|
34
|
+
- **Configurable** — CLI > `.hamidrezam.toml` > global config > defaults.
|
|
35
|
+
- **Scriptable & extensible** — typed Python API + `BackupWriter` abstraction (ZIP today, `tar.gz` reserved).
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- Auto-detection of Python, Node.js/npm/pnpm/Yarn, React, Next.js, Vue, Nuxt, PHP, Laravel, Docker, AI/ML, generic/mixed projects.
|
|
40
|
+
- Sensible default exclusions (dependencies, venvs, caches, artifacts, temp, ML outputs) with opt-in knobs for `dist/`/`build/`, IDE dirs, ML outputs.
|
|
41
|
+
- Secrets (`.env*`, `secrets.json`, …) and large-file policies: `include` / `exclude` / `warn` (default `warn` = include + warning).
|
|
42
|
+
- `--dry-run` planning, `explain` auditing, `verify` integrity checks, safe `restore` with traversal protection.
|
|
43
|
+
- Output-inside-source self-inclusion guard; never-silently-overwrite naming.
|
|
44
|
+
- Zero runtime dependencies (stdlib only; `tomli` backport on Python < 3.11).
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install hamidrezam
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Requires Python ≥ 3.9. Verify:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
hamidrezam version
|
|
56
|
+
python -m hamidrezam version
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
hamidrezam backup ./my-project
|
|
63
|
+
hamidrezam backup ./my-project --dry-run
|
|
64
|
+
hamidrezam backup ./my-project --include-git
|
|
65
|
+
hamidrezam backup ./my-project --format zip
|
|
66
|
+
hamidrezam backup . --exclude "*.log" --exclude "data/tmp/"
|
|
67
|
+
hamidrezam verify ./backups/my-project_2026-09-20_10-50-00.zip
|
|
68
|
+
hamidrezam restore ./backups/my-project_2026-09-20_10-50-00.zip ./restored --overwrite
|
|
69
|
+
hamidrezam explain ./my-project
|
|
70
|
+
hamidrezam list ./backups/my-project_2026-09-20_10-50-00.zip
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## CLI usage
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
hamidrezam backup <source> [--output ./backups] [--name NAME] [--format zip]
|
|
77
|
+
[--dry-run] [--include-git]
|
|
78
|
+
[--exclude GLOB]... [--include GLOB]...
|
|
79
|
+
[--secret-mode warn|include|exclude]
|
|
80
|
+
[--large-mode warn|include|exclude] [--max-size 2GB]
|
|
81
|
+
[--symlink-mode preserve|skip|follow] [--no-compression]
|
|
82
|
+
hamidrezam restore <backup.zip> <destination> [--overwrite]
|
|
83
|
+
hamidrezam verify <backup.zip> [--check-hashes]
|
|
84
|
+
hamidrezam explain <source>
|
|
85
|
+
hamidrezam list <backup.zip>
|
|
86
|
+
hamidrezam version
|
|
87
|
+
python -m hamidrezam <same as above>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Include/exclude precedence: **output-safety > `--include` > protected source-of-truth files > `--exclude` > secrets/large policies > default rules > include**. In short: explicit `--include` wins over default excludes; explicit `--exclude` still wins over protected files (your explicit choice); the archive can never include itself.
|
|
91
|
+
|
|
92
|
+
## Python API
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from hamidrezam import BackupManager, BackupConfig
|
|
96
|
+
|
|
97
|
+
manager = BackupManager()
|
|
98
|
+
result = manager.backup(source="./my-project", output="./backups")
|
|
99
|
+
print(result.archive_path, result.verified)
|
|
100
|
+
|
|
101
|
+
config = BackupConfig(include_git=False, secret_mode="warn", max_size="2GB")
|
|
102
|
+
manager = BackupManager(config=config)
|
|
103
|
+
dry = manager.backup("./project", dry_run=True)
|
|
104
|
+
print(dry.files_included, dry.files_excluded)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Typed results: `BackupResult`, `ScanResult`, `VerificationResult`, `RestoreResult`, `BackupStatistics` (with `archive_path`, `files_included/excluded`, `bytes_included/excluded`, `duration`, `sha256`, `warnings`, …).
|
|
108
|
+
|
|
109
|
+
## Supported project types
|
|
110
|
+
|
|
111
|
+
No manual `--type` flag needed. Signals include `pyproject.toml`/`requirements.txt`/`Pipfile` → Python; `package.json` → Node.js (+ `package-lock.json` → npm, `pnpm-lock.yaml` → pnpm, `yarn.lock` → Yarn; `react`/`next`/`vue`/`nuxt` deps → frameworks); `composer.json` → PHP, `artisan` → Laravel; `Dockerfile`/`docker-compose.yml`/`compose.yml` → Docker; notebooks/`wandb`/`.mlflow` → AI/ML. Multiple labels can apply at once.
|
|
112
|
+
|
|
113
|
+
## Default exclusions
|
|
114
|
+
|
|
115
|
+
| Area | Excluded (from archive only) |
|
|
116
|
+
|---|---|
|
|
117
|
+
| Python | `.venv/`, `venv/`, `env/`, `ENV/`, `__pycache__/`, `.pytest_cache/`, `.mypy_cache/`, `.ruff_cache/`, `.tox/`, `.nox/`, `.coverage`, `htmlcov/`, `*.pyc/pyo/pyd`, `*.egg-info/` |
|
|
118
|
+
| Node/frontend | `node_modules/`, `.npm/`, `.yarn/`, `.pnpm-store/`, `.next/`, `.nuxt/`, `.parcel-cache/`, `.turbo/`, `.cache/`, `coverage/` |
|
|
119
|
+
| AI/ML | `.ipynb_checkpoints/`, `.mlflow/`, `wandb/`, `runs/`, `logs/`, `.cache/` (+ `outputs/`, `checkpoints/` unless `include_outputs=true`) |
|
|
120
|
+
| General | `.cache/`, `tmp/`, `temp/`, `*.tmp`, `*.temp`, `.DS_Store`, `Thumbs.db`, `*.swp/swo` |
|
|
121
|
+
| Build | `dist/`, `build/` unless `include_dist_build=true` |
|
|
122
|
+
| IDE | `.idea/`, `.vscode/` only when `include=false` (default `true` = preserved) |
|
|
123
|
+
| Git | `.git/` unless `--include-git` / `[git] include=true` |
|
|
124
|
+
|
|
125
|
+
Never excluded by default: `README.md`, `LICENSE`, `.gitignore`, `.gitattributes`, `Dockerfile`, compose files, `package.json`, lock files (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `poetry.lock`, `uv.lock`, `Pipfile.lock`, `composer.lock`), `requirements.txt`, `pyproject.toml`, `composer.json`. Model weights (`*.pt/.pth/.onnx/.safetensors/.ckpt/.bin`) are never auto-excluded for being large — they trigger `warn`.
|
|
126
|
+
|
|
127
|
+
## Configuration (`.hamidrezam.toml`)
|
|
128
|
+
|
|
129
|
+
Place in the project root; see `examples/.hamidrezam.toml`:
|
|
130
|
+
|
|
131
|
+
```toml
|
|
132
|
+
[backup]
|
|
133
|
+
format = "zip"
|
|
134
|
+
compression = true
|
|
135
|
+
output = "./backups"
|
|
136
|
+
|
|
137
|
+
[git]
|
|
138
|
+
include = false
|
|
139
|
+
|
|
140
|
+
[secrets]
|
|
141
|
+
mode = "warn"
|
|
142
|
+
|
|
143
|
+
[large_files]
|
|
144
|
+
mode = "warn"
|
|
145
|
+
max_size = "2GB"
|
|
146
|
+
|
|
147
|
+
[symlinks]
|
|
148
|
+
mode = "preserve"
|
|
149
|
+
|
|
150
|
+
[ide]
|
|
151
|
+
include = true
|
|
152
|
+
|
|
153
|
+
[build]
|
|
154
|
+
include_dist_build = false
|
|
155
|
+
|
|
156
|
+
[ml]
|
|
157
|
+
include_outputs = false
|
|
158
|
+
|
|
159
|
+
[custom]
|
|
160
|
+
exclude = ["*.log"]
|
|
161
|
+
include = []
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Priority: **CLI args > `.hamidrezam.toml` > global config (`~/.config/hamidrezam/config.toml` or `~/.hamidrezam.toml`) > defaults**.
|
|
165
|
+
|
|
166
|
+
## Secrets policy
|
|
167
|
+
|
|
168
|
+
`.env`, `.env.local/.production/.development/.staging`, `secrets.json`, `credentials.json` (plus generic `.env.*`; `.env.example` is treated as a safe template). Default `warn`: included + listed as a warning. Use `exclude` to drop, `include` to silence the warning.
|
|
169
|
+
|
|
170
|
+
## Large files
|
|
171
|
+
|
|
172
|
+
Any file over `max_size` (default `2GB`; accepts `500MB`, `1024`, …) follows `large_files.mode` (default `warn`). Never silently dropped.
|
|
173
|
+
|
|
174
|
+
## Git handling
|
|
175
|
+
|
|
176
|
+
`.git/` excluded by default (`include_git=false`). Enable per-run (`--include-git`) or per-project (`[git] include=true`). `.gitignore`/`.gitattributes` are always preserved.
|
|
177
|
+
|
|
178
|
+
## Restore
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
hamidrezam restore backup.zip ./restored-project --overwrite
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Validates the archive, rejects `../` and absolute entries, confines writes to the destination, preserves structure, skips existing files unless `--overwrite`, restores symlinks best-effort (falls back to regular files on Windows without privilege).
|
|
185
|
+
|
|
186
|
+
## Verification
|
|
187
|
+
|
|
188
|
+
Every backup auto-verifies (ZIP integrity + manifest schema). Re-check later:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
hamidrezam verify backup.zip
|
|
192
|
+
hamidrezam verify backup.zip --check-hashes # re-hash contents vs manifest
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Each archive embeds `.hamidrezam/manifest.json` with `tool`, `version`, `created_at`, `project_name`, `profiles`, `statistics`, `warnings`, and per-file `path/size/sha256/modified_time` (relative paths only).
|
|
196
|
+
|
|
197
|
+
## Security
|
|
198
|
+
|
|
199
|
+
- No blind extraction; all member names validated.
|
|
200
|
+
- Symlinks never followed outside the project; loops detected via `(st_dev, st_ino)`.
|
|
201
|
+
- Broken links, special files (sockets/FIFOs/devices), permission errors → skipped with warnings, never fatal.
|
|
202
|
+
- Secrets/large files surface as warnings, never silently leaked/dropped.
|
|
203
|
+
|
|
204
|
+
## Examples
|
|
205
|
+
|
|
206
|
+
- `examples/.hamidrezam.toml` — annotated config.
|
|
207
|
+
- `examples/basic_backup.py` — `python examples/basic_backup.py` after install.
|
|
208
|
+
|
|
209
|
+
## Development
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
python -m venv .venv && source .venv/bin/activate
|
|
213
|
+
pip install -e ".[dev]"
|
|
214
|
+
pytest
|
|
215
|
+
python -m build
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Testing
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
pytest # full suite
|
|
222
|
+
pytest tests/unit
|
|
223
|
+
pytest tests/integration
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Covers scanner (nesting/empty/unicode/spaces), exclusions, secrets, large files, ZIP+manifest+hashes, restore/overwrite/traversal, symlinks (broken/outside/skip), CLI exit codes, and the mandatory **source-integrity** test (hashes + paths + mtimes identical before/after backup).
|
|
227
|
+
|
|
228
|
+
## Roadmap
|
|
229
|
+
|
|
230
|
+
- `tar.gz` writer (`TarGzBackupWriter` via the existing `BackupWriter` interface).
|
|
231
|
+
- Opt-in `.gitignore`-aware mode, negation (`!`) support.
|
|
232
|
+
- Progress bars, JSON output (`--json`), exclusion-size report table.
|
|
233
|
+
- `hamidrezam init` config generator.
|
|
234
|
+
|
|
235
|
+
## Known limitations (0.1.0)
|
|
236
|
+
|
|
237
|
+
- Only `zip` format (`--format tar.gz` fails with a clear future-reserved message).
|
|
238
|
+
- `.gitignore` patterns are parsed by `GitIgnoreRule` for API use but not auto-applied to backups (avoids surprising drops of `.env`-style files).
|
|
239
|
+
- `runs/`, `logs/`, `tmp/`, `temp/`, `outputs/`, `checkpoints/` directory names are excluded wherever they appear; rename intentional source dirs or use `--include` to keep them.
|
|
240
|
+
- Symlink restore on Windows may fall back to regular files without Developer Mode/admin.
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
MIT — see `LICENSE`.
|
|
245
|
+
|
|
246
|
+
## Author
|
|
247
|
+
|
|
248
|
+
**Hamidreza Moghaddam Kohi** — Full Stack Developer · AI · Automation
|
|
249
|
+
Website: <https://hamidrezamoghaddam.ir/> · Email: <info@hamidrezamoghaddam.ir>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel", "build"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hamidrezam"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Hamidrezam — safe, intelligent software-project backup tool (library + CLI)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Hamidreza Moghaddam Kohi", email = "info@hamidrezamoghaddam.ir" }
|
|
14
|
+
]
|
|
15
|
+
maintainers = [
|
|
16
|
+
{ name = "Hamidreza Moghaddam Kohi", email = "info@hamidrezamoghaddam.ir" }
|
|
17
|
+
]
|
|
18
|
+
keywords = ["backup", "archive", "project", "cli", "developer-tools", "zip"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Topic :: System :: Archiving :: Backup",
|
|
30
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
31
|
+
"Topic :: Utilities",
|
|
32
|
+
"Typing :: Typed",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"tomli>=2; python_version < '3.11'",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest>=7",
|
|
41
|
+
"build>=1",
|
|
42
|
+
]
|
|
43
|
+
test = [
|
|
44
|
+
"pytest>=7",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Homepage = "https://hamidrezamoghaddam.ir/"
|
|
49
|
+
|
|
50
|
+
[project.scripts]
|
|
51
|
+
hamidrezam = "hamidrezam.cli.main:main"
|
|
52
|
+
|
|
53
|
+
[tool.setuptools.packages.find]
|
|
54
|
+
where = ["src"]
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.package-data]
|
|
57
|
+
hamidrezam = ["py.typed"]
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
addopts = "-q"
|
|
62
|
+
|
|
63
|
+
[tool.ruff]
|
|
64
|
+
target-version = "py39"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Public Python API for hamidrezam.
|
|
2
|
+
|
|
3
|
+
Example:
|
|
4
|
+
from hamidrezam import BackupManager, BackupConfig
|
|
5
|
+
|
|
6
|
+
manager = BackupManager()
|
|
7
|
+
result = manager.backup(source="./my-project", output="./backups")
|
|
8
|
+
print(result.archive_path)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from hamidrezam.version import __version__
|
|
14
|
+
from hamidrezam.exceptions import (
|
|
15
|
+
HamidrezamError,
|
|
16
|
+
ConfigurationError,
|
|
17
|
+
SourceNotFoundError,
|
|
18
|
+
BackupError,
|
|
19
|
+
RestoreError,
|
|
20
|
+
VerificationError,
|
|
21
|
+
UnsafeArchiveError,
|
|
22
|
+
)
|
|
23
|
+
from hamidrezam.config.models import BackupConfig
|
|
24
|
+
from hamidrezam.core.backup import BackupManager, BackupResult
|
|
25
|
+
from hamidrezam.core.scanner import ScanResult, FileEntry, ExcludedEntry
|
|
26
|
+
from hamidrezam.core.restore import RestoreResult
|
|
27
|
+
from hamidrezam.core.verifier import VerificationResult
|
|
28
|
+
from hamidrezam.core.statistics import BackupStatistics
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"__version__",
|
|
32
|
+
"HamidrezamError",
|
|
33
|
+
"ConfigurationError",
|
|
34
|
+
"SourceNotFoundError",
|
|
35
|
+
"BackupError",
|
|
36
|
+
"RestoreError",
|
|
37
|
+
"VerificationError",
|
|
38
|
+
"UnsafeArchiveError",
|
|
39
|
+
"BackupConfig",
|
|
40
|
+
"BackupManager",
|
|
41
|
+
"BackupResult",
|
|
42
|
+
"ScanResult",
|
|
43
|
+
"FileEntry",
|
|
44
|
+
"ExcludedEntry",
|
|
45
|
+
"RestoreResult",
|
|
46
|
+
"VerificationResult",
|
|
47
|
+
"BackupStatistics",
|
|
48
|
+
]
|