mirror-url 3.1.14__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.
- mirror_url-3.1.14/LICENSE +21 -0
- mirror_url-3.1.14/PKG-INFO +171 -0
- mirror_url-3.1.14/README.md +98 -0
- mirror_url-3.1.14/pyproject.toml +143 -0
- mirror_url-3.1.14/setup.cfg +4 -0
- mirror_url-3.1.14/src/mirror_url/__init__.py +48 -0
- mirror_url-3.1.14/src/mirror_url/__main__.py +21 -0
- mirror_url-3.1.14/src/mirror_url/_core/__init__.py +9 -0
- mirror_url-3.1.14/src/mirror_url/_core/_base.py +1289 -0
- mirror_url-3.1.14/src/mirror_url/_core/cleanup.py +335 -0
- mirror_url-3.1.14/src/mirror_url/_core/compare.py +705 -0
- mirror_url-3.1.14/src/mirror_url/_core/downloads.py +306 -0
- mirror_url-3.1.14/src/mirror_url/_core/report.py +762 -0
- mirror_url-3.1.14/src/mirror_url/_core/scan.py +340 -0
- mirror_url-3.1.14/src/mirror_url/_core/urls.py +306 -0
- mirror_url-3.1.14/src/mirror_url/_version.py +12 -0
- mirror_url-3.1.14/src/mirror_url/async_connection.py +1331 -0
- mirror_url-3.1.14/src/mirror_url/cache.py +457 -0
- mirror_url-3.1.14/src/mirror_url/circuit_breaker.py +388 -0
- mirror_url-3.1.14/src/mirror_url/cli.py +1665 -0
- mirror_url-3.1.14/src/mirror_url/compat.py +81 -0
- mirror_url-3.1.14/src/mirror_url/concurrency.py +300 -0
- mirror_url-3.1.14/src/mirror_url/config.py +756 -0
- mirror_url-3.1.14/src/mirror_url/connection.py +850 -0
- mirror_url-3.1.14/src/mirror_url/constants.py +212 -0
- mirror_url-3.1.14/src/mirror_url/core.py +39 -0
- mirror_url-3.1.14/src/mirror_url/decorators.py +105 -0
- mirror_url-3.1.14/src/mirror_url/download.py +1709 -0
- mirror_url-3.1.14/src/mirror_url/enums.py +79 -0
- mirror_url-3.1.14/src/mirror_url/exceptions.py +155 -0
- mirror_url-3.1.14/src/mirror_url/health.py +272 -0
- mirror_url-3.1.14/src/mirror_url/metrics.py +433 -0
- mirror_url-3.1.14/src/mirror_url/models.py +195 -0
- mirror_url-3.1.14/src/mirror_url/monitoring.py +294 -0
- mirror_url-3.1.14/src/mirror_url/parsing.py +176 -0
- mirror_url-3.1.14/src/mirror_url/primitives.py +411 -0
- mirror_url-3.1.14/src/mirror_url/progress.py +355 -0
- mirror_url-3.1.14/src/mirror_url/queue.py +137 -0
- mirror_url-3.1.14/src/mirror_url/rate_limiter.py +335 -0
- mirror_url-3.1.14/src/mirror_url/scanner.py +254 -0
- mirror_url-3.1.14/src/mirror_url/security.py +620 -0
- mirror_url-3.1.14/src/mirror_url/storage.py +631 -0
- mirror_url-3.1.14/src/mirror_url/transport.py +312 -0
- mirror_url-3.1.14/src/mirror_url/tuner.py +123 -0
- mirror_url-3.1.14/src/mirror_url/utils.py +410 -0
- mirror_url-3.1.14/src/mirror_url.egg-info/PKG-INFO +171 -0
- mirror_url-3.1.14/src/mirror_url.egg-info/SOURCES.txt +54 -0
- mirror_url-3.1.14/src/mirror_url.egg-info/dependency_links.txt +1 -0
- mirror_url-3.1.14/src/mirror_url.egg-info/entry_points.txt +2 -0
- mirror_url-3.1.14/src/mirror_url.egg-info/requires.txt +29 -0
- mirror_url-3.1.14/src/mirror_url.egg-info/top_level.txt +1 -0
- mirror_url-3.1.14/tests/test_integration.py +53 -0
- mirror_url-3.1.14/tests/test_security.py +119 -0
- mirror_url-3.1.14/tests/test_smoke.py +47 -0
- mirror_url-3.1.14/tests/test_subsystems.py +302 -0
- mirror_url-3.1.14/tests/test_utils.py +33 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BP
|
|
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,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mirror-url
|
|
3
|
+
Version: 3.1.14
|
|
4
|
+
Summary: Enterprise-grade remote directory mirroring tool with adaptive concurrency, integrity checks, and SSRF-hardened transport.
|
|
5
|
+
Author: BP
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 BP
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/bpodlipnik/mirror-url
|
|
29
|
+
Project-URL: Repository, https://github.com/bpodlipnik/mirror-url
|
|
30
|
+
Project-URL: Issues, https://github.com/bpodlipnik/mirror-url/issues
|
|
31
|
+
Keywords: mirror,download,http,scraper,directory,async,httpx
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
|
+
Classifier: Environment :: Console
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: Intended Audience :: System Administrators
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Operating System :: OS Independent
|
|
38
|
+
Classifier: Programming Language :: Python :: 3
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
44
|
+
Classifier: Topic :: System :: Archiving :: Mirroring
|
|
45
|
+
Requires-Python: >=3.9
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
License-File: LICENSE
|
|
48
|
+
Requires-Dist: httpx>=0.24
|
|
49
|
+
Requires-Dist: pydantic>=2.0
|
|
50
|
+
Requires-Dist: PyYAML>=6.0
|
|
51
|
+
Provides-Extra: fast
|
|
52
|
+
Requires-Dist: stringzilla>=3.0; extra == "fast"
|
|
53
|
+
Requires-Dist: lxml>=4.9; extra == "fast"
|
|
54
|
+
Provides-Extra: progress
|
|
55
|
+
Requires-Dist: tqdm>=4.65; extra == "progress"
|
|
56
|
+
Provides-Extra: monitor
|
|
57
|
+
Requires-Dist: psutil>=5.9; extra == "monitor"
|
|
58
|
+
Provides-Extra: all
|
|
59
|
+
Requires-Dist: stringzilla>=3.0; extra == "all"
|
|
60
|
+
Requires-Dist: lxml>=4.9; extra == "all"
|
|
61
|
+
Requires-Dist: tqdm>=4.65; extra == "all"
|
|
62
|
+
Requires-Dist: psutil>=5.9; extra == "all"
|
|
63
|
+
Provides-Extra: dev
|
|
64
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
65
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
66
|
+
Requires-Dist: pytest-cov>=4.1; extra == "dev"
|
|
67
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
68
|
+
Requires-Dist: black>=24.0; extra == "dev"
|
|
69
|
+
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
70
|
+
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
|
|
71
|
+
Requires-Dist: pre-commit>=3.5; extra == "dev"
|
|
72
|
+
Dynamic: license-file
|
|
73
|
+
|
|
74
|
+
# MirrorURL
|
|
75
|
+
|
|
76
|
+
[](https://github.com/bpodlipnik/mirror-url/actions/workflows/ci.yml)
|
|
77
|
+
[](https://www.python.org)
|
|
78
|
+
[](./LICENSE)
|
|
79
|
+
|
|
80
|
+
Enterprise-grade remote directory mirroring tool. MirrorURL recursively
|
|
81
|
+
discovers files behind an HTTP(S) directory listing and mirrors them locally
|
|
82
|
+
with adaptive concurrency, resumable/partial downloads, integrity verification,
|
|
83
|
+
and an SSRF-hardened transport layer.
|
|
84
|
+
|
|
85
|
+
> **Status:** Refactor complete. The full implementation now lives in the
|
|
86
|
+
> [`src/mirror_url/`](./src/mirror_url) package (30 modules), migrated verbatim
|
|
87
|
+
> from the original single-file script per [`REFACTORING_PLAN.md`](./REFACTORING_PLAN.md).
|
|
88
|
+
> The legacy [`mirror_url.py`](./mirror_url.py) is retained only as a frozen
|
|
89
|
+
> reference and can be deleted once you've run the test suite against the package
|
|
90
|
+
> in an environment with the runtime dependencies installed (see Development).
|
|
91
|
+
|
|
92
|
+
## Features
|
|
93
|
+
|
|
94
|
+
- **Recursive discovery** of remote directory trees (BFS, depth/exclude limits, cycle-safe).
|
|
95
|
+
- **True parallel downloads** — multiple files and multiple chunks per file concurrently.
|
|
96
|
+
- **Adaptive async concurrency** that tunes itself to server RTT, throughput, and error rate.
|
|
97
|
+
- **Resumable & partial downloads** with HTTP range requests and chunk assembly.
|
|
98
|
+
- **Integrity checks** — size/timestamp comparison, ETag handling, content hashing.
|
|
99
|
+
- **Resilience** — per-domain circuit breakers, exponential backoff, rate limiting.
|
|
100
|
+
- **Security** — path-traversal and symlink-bomb defenses, private-IP/SSRF guards, URL-scope enforcement.
|
|
101
|
+
- **Operability** — metrics collection, multi-level progress, optional HTTP health-check server.
|
|
102
|
+
- **Caching** — filesystem and disk-backed indexes to skip unchanged content.
|
|
103
|
+
|
|
104
|
+
## Installation
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# From source (editable, recommended during the refactor)
|
|
108
|
+
pip install -e ".[all,dev]"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Python 3.9+ is required. Core dependencies: `httpx`, `pydantic` (v2), `PyYAML`.
|
|
112
|
+
Optional extras: `fast` (stringzilla, lxml), `progress` (tqdm), `monitor` (psutil).
|
|
113
|
+
|
|
114
|
+
## Usage
|
|
115
|
+
|
|
116
|
+
Run via the console entry point or the module:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
mirror-url https://example.com/files/ --output ./mirror
|
|
120
|
+
# or
|
|
121
|
+
python -m mirror_url https://example.com/files/ --output ./mirror
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Run `mirror-url --help` for the full option list.
|
|
125
|
+
|
|
126
|
+
Configuration can also be supplied via a YAML file (see `MirrorConfig` /
|
|
127
|
+
`load_config_from_args`).
|
|
128
|
+
|
|
129
|
+
📖 **Full documentation:** see the [User Guide](./docs/USER_GUIDE.md)
|
|
130
|
+
([HTML version](./docs/USER_GUIDE.html)) for detailed installation, CLI
|
|
131
|
+
reference, config-file format, download modes, security notes, the Python API,
|
|
132
|
+
and troubleshooting.
|
|
133
|
+
|
|
134
|
+
## Development
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pip install -e ".[dev]"
|
|
138
|
+
pre-commit install
|
|
139
|
+
|
|
140
|
+
ruff check . # lint
|
|
141
|
+
black --check . # format check
|
|
142
|
+
mypy # type-check the new package
|
|
143
|
+
pytest -m "not integration" # fast test lane
|
|
144
|
+
pytest # full suite (includes integration)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Continuous integration runs lint + tests across Python 3.9–3.12 (see
|
|
148
|
+
`.github/workflows/ci.yml`).
|
|
149
|
+
|
|
150
|
+
## Project layout
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
src/mirror_url/ # the package (30 modules, dependency-layered)
|
|
154
|
+
tests/ # pytest suite
|
|
155
|
+
mirror_url.py # legacy monolith (frozen reference, pending removal)
|
|
156
|
+
REFACTORING_PLAN.md # module breakdown + migration roadmap
|
|
157
|
+
CHANGELOG.md # notable changes (Keep a Changelog format)
|
|
158
|
+
CONTRIBUTING.md # dev setup, checks, conventions
|
|
159
|
+
pyproject.toml # packaging, deps, tool config
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Contributing
|
|
163
|
+
|
|
164
|
+
Contributions are welcome — see [CONTRIBUTING.md](./CONTRIBUTING.md) for the dev
|
|
165
|
+
setup, the checks CI runs, and the project conventions (dependency layering,
|
|
166
|
+
lint policy, behavior-preserving refactors). Notable changes are tracked in
|
|
167
|
+
[CHANGELOG.md](./CHANGELOG.md).
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
[MIT](./LICENSE) © BP
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# MirrorURL
|
|
2
|
+
|
|
3
|
+
[](https://github.com/bpodlipnik/mirror-url/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.python.org)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
|
|
7
|
+
Enterprise-grade remote directory mirroring tool. MirrorURL recursively
|
|
8
|
+
discovers files behind an HTTP(S) directory listing and mirrors them locally
|
|
9
|
+
with adaptive concurrency, resumable/partial downloads, integrity verification,
|
|
10
|
+
and an SSRF-hardened transport layer.
|
|
11
|
+
|
|
12
|
+
> **Status:** Refactor complete. The full implementation now lives in the
|
|
13
|
+
> [`src/mirror_url/`](./src/mirror_url) package (30 modules), migrated verbatim
|
|
14
|
+
> from the original single-file script per [`REFACTORING_PLAN.md`](./REFACTORING_PLAN.md).
|
|
15
|
+
> The legacy [`mirror_url.py`](./mirror_url.py) is retained only as a frozen
|
|
16
|
+
> reference and can be deleted once you've run the test suite against the package
|
|
17
|
+
> in an environment with the runtime dependencies installed (see Development).
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **Recursive discovery** of remote directory trees (BFS, depth/exclude limits, cycle-safe).
|
|
22
|
+
- **True parallel downloads** — multiple files and multiple chunks per file concurrently.
|
|
23
|
+
- **Adaptive async concurrency** that tunes itself to server RTT, throughput, and error rate.
|
|
24
|
+
- **Resumable & partial downloads** with HTTP range requests and chunk assembly.
|
|
25
|
+
- **Integrity checks** — size/timestamp comparison, ETag handling, content hashing.
|
|
26
|
+
- **Resilience** — per-domain circuit breakers, exponential backoff, rate limiting.
|
|
27
|
+
- **Security** — path-traversal and symlink-bomb defenses, private-IP/SSRF guards, URL-scope enforcement.
|
|
28
|
+
- **Operability** — metrics collection, multi-level progress, optional HTTP health-check server.
|
|
29
|
+
- **Caching** — filesystem and disk-backed indexes to skip unchanged content.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# From source (editable, recommended during the refactor)
|
|
35
|
+
pip install -e ".[all,dev]"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Python 3.9+ is required. Core dependencies: `httpx`, `pydantic` (v2), `PyYAML`.
|
|
39
|
+
Optional extras: `fast` (stringzilla, lxml), `progress` (tqdm), `monitor` (psutil).
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
Run via the console entry point or the module:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
mirror-url https://example.com/files/ --output ./mirror
|
|
47
|
+
# or
|
|
48
|
+
python -m mirror_url https://example.com/files/ --output ./mirror
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Run `mirror-url --help` for the full option list.
|
|
52
|
+
|
|
53
|
+
Configuration can also be supplied via a YAML file (see `MirrorConfig` /
|
|
54
|
+
`load_config_from_args`).
|
|
55
|
+
|
|
56
|
+
📖 **Full documentation:** see the [User Guide](./docs/USER_GUIDE.md)
|
|
57
|
+
([HTML version](./docs/USER_GUIDE.html)) for detailed installation, CLI
|
|
58
|
+
reference, config-file format, download modes, security notes, the Python API,
|
|
59
|
+
and troubleshooting.
|
|
60
|
+
|
|
61
|
+
## Development
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install -e ".[dev]"
|
|
65
|
+
pre-commit install
|
|
66
|
+
|
|
67
|
+
ruff check . # lint
|
|
68
|
+
black --check . # format check
|
|
69
|
+
mypy # type-check the new package
|
|
70
|
+
pytest -m "not integration" # fast test lane
|
|
71
|
+
pytest # full suite (includes integration)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Continuous integration runs lint + tests across Python 3.9–3.12 (see
|
|
75
|
+
`.github/workflows/ci.yml`).
|
|
76
|
+
|
|
77
|
+
## Project layout
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
src/mirror_url/ # the package (30 modules, dependency-layered)
|
|
81
|
+
tests/ # pytest suite
|
|
82
|
+
mirror_url.py # legacy monolith (frozen reference, pending removal)
|
|
83
|
+
REFACTORING_PLAN.md # module breakdown + migration roadmap
|
|
84
|
+
CHANGELOG.md # notable changes (Keep a Changelog format)
|
|
85
|
+
CONTRIBUTING.md # dev setup, checks, conventions
|
|
86
|
+
pyproject.toml # packaging, deps, tool config
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Contributing
|
|
90
|
+
|
|
91
|
+
Contributions are welcome — see [CONTRIBUTING.md](./CONTRIBUTING.md) for the dev
|
|
92
|
+
setup, the checks CI runs, and the project conventions (dependency layering,
|
|
93
|
+
lint policy, behavior-preserving refactors). Notable changes are tracked in
|
|
94
|
+
[CHANGELOG.md](./CHANGELOG.md).
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
[MIT](./LICENSE) © BP
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mirror-url"
|
|
7
|
+
version = "3.1.14"
|
|
8
|
+
description = "Enterprise-grade remote directory mirroring tool with adaptive concurrency, integrity checks, and SSRF-hardened transport."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
authors = [{ name = "BP" }]
|
|
13
|
+
keywords = ["mirror", "download", "http", "scraper", "directory", "async", "httpx"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: System Administrators",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
27
|
+
"Topic :: System :: Archiving :: Mirroring",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# Core runtime dependencies (imported unconditionally by the package).
|
|
31
|
+
dependencies = [
|
|
32
|
+
"httpx>=0.24",
|
|
33
|
+
"pydantic>=2.0",
|
|
34
|
+
"PyYAML>=6.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
# Optional accelerators / niceties — guarded by try/except in the code.
|
|
39
|
+
fast = ["stringzilla>=3.0", "lxml>=4.9"]
|
|
40
|
+
progress = ["tqdm>=4.65"]
|
|
41
|
+
monitor = ["psutil>=5.9"]
|
|
42
|
+
all = ["stringzilla>=3.0", "lxml>=4.9", "tqdm>=4.65", "psutil>=5.9"]
|
|
43
|
+
|
|
44
|
+
# Development / CI toolchain.
|
|
45
|
+
dev = [
|
|
46
|
+
"pytest>=7.4",
|
|
47
|
+
"pytest-asyncio>=0.21",
|
|
48
|
+
"pytest-cov>=4.1",
|
|
49
|
+
"ruff>=0.4",
|
|
50
|
+
"black>=24.0",
|
|
51
|
+
"mypy>=1.8",
|
|
52
|
+
"types-PyYAML>=6.0", # type stubs for the yaml import (silences import-untyped)
|
|
53
|
+
"pre-commit>=3.5",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[project.urls]
|
|
57
|
+
Homepage = "https://github.com/bpodlipnik/mirror-url"
|
|
58
|
+
Repository = "https://github.com/bpodlipnik/mirror-url"
|
|
59
|
+
Issues = "https://github.com/bpodlipnik/mirror-url/issues"
|
|
60
|
+
|
|
61
|
+
# Console entry point: the `mirror-url` command runs mirror_url.cli:main.
|
|
62
|
+
[project.scripts]
|
|
63
|
+
mirror-url = "mirror_url.cli:main"
|
|
64
|
+
|
|
65
|
+
[tool.setuptools]
|
|
66
|
+
package-dir = { "" = "src" }
|
|
67
|
+
|
|
68
|
+
[tool.setuptools.packages.find]
|
|
69
|
+
where = ["src"]
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# Tooling configuration
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
[tool.black]
|
|
75
|
+
line-length = 100
|
|
76
|
+
target-version = ["py39", "py310", "py311", "py312"]
|
|
77
|
+
|
|
78
|
+
[tool.ruff]
|
|
79
|
+
line-length = 100
|
|
80
|
+
target-version = "py39"
|
|
81
|
+
src = ["src", "tests"]
|
|
82
|
+
# The legacy monolith is a frozen reference (and read-only in some checkouts):
|
|
83
|
+
# exclude it from BOTH linting and formatting. `per-file-ignores` below only
|
|
84
|
+
# affects lint, so this top-level exclude is what keeps `ruff format` from
|
|
85
|
+
# trying to rewrite it.
|
|
86
|
+
extend-exclude = ["mirror_url.py"]
|
|
87
|
+
|
|
88
|
+
[tool.ruff.lint]
|
|
89
|
+
# Correctness-focused rule set. UP (pyupgrade) and SIM are intentionally
|
|
90
|
+
# omitted: this package is a verbatim port of working code that supports
|
|
91
|
+
# Python 3.9 with classic typing (Dict/Optional), and we don't want to churn
|
|
92
|
+
# ~350 lines of audited logic to modernize syntax or rewrite control flow.
|
|
93
|
+
# Bump requires-python to >=3.10 and re-enable UP if/when 3.9 is dropped.
|
|
94
|
+
select = ["E", "F", "W", "I", "B", "C4"]
|
|
95
|
+
ignore = [
|
|
96
|
+
"E501", # line length is handled by the formatter
|
|
97
|
+
"B008", # function call in argument defaults (intentional in a few places)
|
|
98
|
+
# The following bugbear rules fire only on code carried over verbatim from
|
|
99
|
+
# the original single-file script; they are deliberately preserved here so
|
|
100
|
+
# the port stays behavior-identical. Revisit during the optional core/
|
|
101
|
+
# mixin refactor (see REFACTORING_PLAN.md §4.1).
|
|
102
|
+
"B904", # raise ... from err — only affects traceback chaining, not control flow
|
|
103
|
+
"B007", # unused loop control variable
|
|
104
|
+
"B019", # lru_cache on a method (MirrorURL._parse_url_cached): a real latent
|
|
105
|
+
# leak inherited from the monolith — preserved, not silently rewritten
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint.per-file-ignores]
|
|
109
|
+
"tests/*" = ["B"]
|
|
110
|
+
# The legacy monolith is excluded from lint (frozen reference, pending deletion).
|
|
111
|
+
"mirror_url.py" = ["ALL"]
|
|
112
|
+
|
|
113
|
+
[tool.mypy]
|
|
114
|
+
# Advisory, lenient type-checking. This package is a verbatim port of working,
|
|
115
|
+
# largely-untyped code, so mypy is run as a signal (CI uses continue-on-error),
|
|
116
|
+
# not a gate. The settings below surface genuine type mismatches without
|
|
117
|
+
# demanding annotations on every function or descending into untyped bodies.
|
|
118
|
+
# Tightening (disallow_untyped_defs, check_untyped_defs, strict) is a good
|
|
119
|
+
# incremental follow-up, ideally alongside the core/ mixin refactor.
|
|
120
|
+
python_version = "3.9"
|
|
121
|
+
files = ["src/mirror_url"]
|
|
122
|
+
ignore_missing_imports = true # optional deps (stringzilla, lxml, tqdm, psutil) have no stubs
|
|
123
|
+
follow_imports = "silent"
|
|
124
|
+
disallow_untyped_defs = false
|
|
125
|
+
check_untyped_defs = false
|
|
126
|
+
# The original code predates strict implicit-Optional enforcement and relies on
|
|
127
|
+
# `param: T = None` in a few signatures. Restore the permissive behavior rather
|
|
128
|
+
# than churn the verbatim port; tighten alongside a dedicated typing pass.
|
|
129
|
+
no_implicit_optional = false
|
|
130
|
+
warn_unused_ignores = false
|
|
131
|
+
warn_redundant_casts = true
|
|
132
|
+
warn_unreachable = false
|
|
133
|
+
# The legacy monolith is not part of the package and is not type-checked.
|
|
134
|
+
exclude = ["mirror_url\\.py$", "tests/"]
|
|
135
|
+
|
|
136
|
+
[tool.pytest.ini_options]
|
|
137
|
+
minversion = "7.0"
|
|
138
|
+
testpaths = ["tests"]
|
|
139
|
+
asyncio_mode = "auto"
|
|
140
|
+
addopts = "-ra --strict-markers"
|
|
141
|
+
markers = [
|
|
142
|
+
"integration: end-to-end tests that exercise real I/O (deselect with -m 'not integration')",
|
|
143
|
+
]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""MirrorURL — enterprise-grade remote directory mirroring tool.
|
|
2
|
+
|
|
3
|
+
This package is the modular successor to the single-file ``mirror_url.py``
|
|
4
|
+
script. During the refactor the monolith remains the runnable source of truth;
|
|
5
|
+
the submodules here are being populated incrementally (see
|
|
6
|
+
``REFACTORING_PLAN.md``).
|
|
7
|
+
|
|
8
|
+
Public API (intended, once migration completes)::
|
|
9
|
+
|
|
10
|
+
from mirror_url import MirrorURL, MirrorConfig, main
|
|
11
|
+
|
|
12
|
+
The re-exports below are commented out until the corresponding modules are
|
|
13
|
+
populated, so that ``import mirror_url`` succeeds at every step of the migration.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from ._version import __author__, __version__
|
|
19
|
+
|
|
20
|
+
# --- Public API --------------------------------------------------------------
|
|
21
|
+
from .cli import main
|
|
22
|
+
from .config import MirrorConfig, load_config_from_args
|
|
23
|
+
from .core import MirrorURL
|
|
24
|
+
from .exceptions import (
|
|
25
|
+
ConfigError,
|
|
26
|
+
DownloadError,
|
|
27
|
+
MirrorConnectionError,
|
|
28
|
+
MirrorError,
|
|
29
|
+
PathTraversalError,
|
|
30
|
+
SecurityError,
|
|
31
|
+
URLScopeError,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"__version__",
|
|
36
|
+
"__author__",
|
|
37
|
+
"MirrorURL",
|
|
38
|
+
"MirrorConfig",
|
|
39
|
+
"load_config_from_args",
|
|
40
|
+
"main",
|
|
41
|
+
"MirrorError",
|
|
42
|
+
"MirrorConnectionError",
|
|
43
|
+
"PathTraversalError",
|
|
44
|
+
"URLScopeError",
|
|
45
|
+
"ConfigError",
|
|
46
|
+
"SecurityError",
|
|
47
|
+
"DownloadError",
|
|
48
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Enable ``python -m mirror_url``.
|
|
2
|
+
|
|
3
|
+
Delegates to the CLI entry point once ``cli`` is populated.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _run() -> None:
|
|
10
|
+
try:
|
|
11
|
+
from .cli import main
|
|
12
|
+
except ImportError as exc: # pragma: no cover - pre-migration guard
|
|
13
|
+
raise SystemExit(
|
|
14
|
+
"mirror_url.cli is not populated yet. During the refactor, run the "
|
|
15
|
+
"original script directly: `python mirror_url.py ...`"
|
|
16
|
+
) from exc
|
|
17
|
+
main()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
if __name__ == "__main__":
|
|
21
|
+
_run()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Private implementation subpackage for the ``MirrorURL`` orchestrator.
|
|
2
|
+
|
|
3
|
+
``MirrorURL`` is composed from the mixins in this package (one responsibility
|
|
4
|
+
per module) by ``mirror_url.core``. Import the public class from there:
|
|
5
|
+
|
|
6
|
+
from mirror_url.core import MirrorURL # or: from mirror_url import MirrorURL
|
|
7
|
+
|
|
8
|
+
See ``REFACTORING_PLAN.md`` §4.1 for the split rationale.
|
|
9
|
+
"""
|