downctl 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.
- downctl-0.1.0/.gitignore +44 -0
- downctl-0.1.0/CHANGELOG.md +130 -0
- downctl-0.1.0/LICENSE +21 -0
- downctl-0.1.0/PKG-INFO +702 -0
- downctl-0.1.0/README.en.md +106 -0
- downctl-0.1.0/README.md +635 -0
- downctl-0.1.0/docs/cli.md +154 -0
- downctl-0.1.0/docs/cli.zh.md +112 -0
- downctl-0.1.0/docs/design.md +157 -0
- downctl-0.1.0/docs/design.zh.md +262 -0
- downctl-0.1.0/docs/index.md +136 -0
- downctl-0.1.0/docs/index.zh.md +135 -0
- downctl-0.1.0/docs/plugins.md +133 -0
- downctl-0.1.0/docs/plugins.zh.md +125 -0
- downctl-0.1.0/examples/plugins/README.md +29 -0
- downctl-0.1.0/examples/plugins/example_source.py +35 -0
- downctl-0.1.0/pyproject.toml +163 -0
- downctl-0.1.0/src/downctl/__init__.py +13 -0
- downctl-0.1.0/src/downctl/__main__.py +8 -0
- downctl-0.1.0/src/downctl/app.py +732 -0
- downctl-0.1.0/src/downctl/builtin/__init__.py +48 -0
- downctl-0.1.0/src/downctl/builtin/hooks/__init__.py +10 -0
- downctl-0.1.0/src/downctl/builtin/hooks/archive_hook.py +144 -0
- downctl-0.1.0/src/downctl/builtin/hooks/logfile_hook.py +32 -0
- downctl-0.1.0/src/downctl/builtin/hooks/manifest_hook.py +76 -0
- downctl-0.1.0/src/downctl/builtin/hooks/webhook_hook.py +70 -0
- downctl-0.1.0/src/downctl/builtin/reporters/__init__.py +9 -0
- downctl-0.1.0/src/downctl/builtin/reporters/json_reporter.py +62 -0
- downctl-0.1.0/src/downctl/builtin/reporters/quiet_reporter.py +27 -0
- downctl-0.1.0/src/downctl/builtin/reporters/tqdm_reporter.py +91 -0
- downctl-0.1.0/src/downctl/builtin/routers/__init__.py +7 -0
- downctl-0.1.0/src/downctl/builtin/routers/mirror_router.py +27 -0
- downctl-0.1.0/src/downctl/builtin/sinks/__init__.py +7 -0
- downctl-0.1.0/src/downctl/builtin/sinks/filesystem_sink.py +36 -0
- downctl-0.1.0/src/downctl/builtin/sources/__init__.py +19 -0
- downctl-0.1.0/src/downctl/builtin/sources/_sigv4.py +107 -0
- downctl-0.1.0/src/downctl/builtin/sources/file_source.py +67 -0
- downctl-0.1.0/src/downctl/builtin/sources/github_source.py +120 -0
- downctl-0.1.0/src/downctl/builtin/sources/huggingface_source.py +140 -0
- downctl-0.1.0/src/downctl/builtin/sources/s3_source.py +226 -0
- downctl-0.1.0/src/downctl/builtin/sources/sftp_source.py +135 -0
- downctl-0.1.0/src/downctl/builtin/sources/url_source.py +47 -0
- downctl-0.1.0/src/downctl/builtin/transports/__init__.py +9 -0
- downctl-0.1.0/src/downctl/builtin/transports/_sftp.py +77 -0
- downctl-0.1.0/src/downctl/builtin/transports/file_transport.py +101 -0
- downctl-0.1.0/src/downctl/builtin/transports/http_transport.py +77 -0
- downctl-0.1.0/src/downctl/builtin/transports/sftp_transport.py +139 -0
- downctl-0.1.0/src/downctl/builtin/verifiers/__init__.py +7 -0
- downctl-0.1.0/src/downctl/builtin/verifiers/sha256_verifier.py +31 -0
- downctl-0.1.0/src/downctl/cli.py +213 -0
- downctl-0.1.0/src/downctl/config.py +153 -0
- downctl-0.1.0/src/downctl/console.py +87 -0
- downctl-0.1.0/src/downctl/core/__init__.py +30 -0
- downctl-0.1.0/src/downctl/core/context.py +48 -0
- downctl-0.1.0/src/downctl/core/engine.py +265 -0
- downctl-0.1.0/src/downctl/core/errors.py +56 -0
- downctl-0.1.0/src/downctl/core/locks.py +67 -0
- downctl-0.1.0/src/downctl/core/pieces.py +258 -0
- downctl-0.1.0/src/downctl/core/ratelimit.py +34 -0
- downctl-0.1.0/src/downctl/core/task.py +30 -0
- downctl-0.1.0/src/downctl/core/transfer.py +381 -0
- downctl-0.1.0/src/downctl/core/watchdog.py +53 -0
- downctl-0.1.0/src/downctl/platform_utils.py +166 -0
- downctl-0.1.0/src/downctl/plugin/__init__.py +42 -0
- downctl-0.1.0/src/downctl/plugin/hooks.py +65 -0
- downctl-0.1.0/src/downctl/plugin/loader.py +92 -0
- downctl-0.1.0/src/downctl/plugin/protocols.py +145 -0
- downctl-0.1.0/src/downctl/plugin/registry.py +75 -0
- downctl-0.1.0/src/downctl/probe.py +44 -0
- downctl-0.1.0/src/downctl/py.typed +0 -0
- downctl-0.1.0/src/downctl/session.py +50 -0
- downctl-0.1.0/tests/conftest.py +10 -0
- downctl-0.1.0/tests/integration/conftest.py +118 -0
- downctl-0.1.0/tests/integration/test_cli_get.py +152 -0
- downctl-0.1.0/tests/integration/test_engine.py +91 -0
- downctl-0.1.0/tests/integration/test_file_source.py +81 -0
- downctl-0.1.0/tests/integration/test_github_source.py +148 -0
- downctl-0.1.0/tests/integration/test_huggingface.py +144 -0
- downctl-0.1.0/tests/integration/test_s3_source.py +166 -0
- downctl-0.1.0/tests/integration/test_sftp_source.py +110 -0
- downctl-0.1.0/tests/integration/test_smoke.py +27 -0
- downctl-0.1.0/tests/integration/test_transfer.py +135 -0
- downctl-0.1.0/tests/integration/test_webhook_hook.py +81 -0
- downctl-0.1.0/tests/unit/test_archive_hook.py +80 -0
- downctl-0.1.0/tests/unit/test_builtins.py +47 -0
- downctl-0.1.0/tests/unit/test_clean.py +70 -0
- downctl-0.1.0/tests/unit/test_cli.py +70 -0
- downctl-0.1.0/tests/unit/test_config.py +38 -0
- downctl-0.1.0/tests/unit/test_console.py +69 -0
- downctl-0.1.0/tests/unit/test_failed_log.py +34 -0
- downctl-0.1.0/tests/unit/test_github_source_unit.py +29 -0
- downctl-0.1.0/tests/unit/test_hooks.py +38 -0
- downctl-0.1.0/tests/unit/test_huggingface_source.py +62 -0
- downctl-0.1.0/tests/unit/test_manifest_hook.py +46 -0
- downctl-0.1.0/tests/unit/test_pieces.py +108 -0
- downctl-0.1.0/tests/unit/test_platform_utils.py +64 -0
- downctl-0.1.0/tests/unit/test_plugins.py +60 -0
- downctl-0.1.0/tests/unit/test_review_fixes.py +149 -0
- downctl-0.1.0/tests/unit/test_session.py +22 -0
- downctl-0.1.0/tests/unit/test_sigv4.py +68 -0
- downctl-0.1.0/tests/unit/test_status.py +59 -0
- downctl-0.1.0/tests/unit/test_tqdm_reporter.py +42 -0
- downctl-0.1.0/tests/unit/test_watchdog.py +38 -0
downctl-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
site/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
*.egg
|
|
12
|
+
.eggs/
|
|
13
|
+
wheels/
|
|
14
|
+
|
|
15
|
+
# Virtual environments
|
|
16
|
+
.venv/
|
|
17
|
+
venv/
|
|
18
|
+
env/
|
|
19
|
+
|
|
20
|
+
# Test / coverage
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
.coverage
|
|
25
|
+
.coverage.*
|
|
26
|
+
htmlcov/
|
|
27
|
+
coverage.xml
|
|
28
|
+
.tox/
|
|
29
|
+
.nox/
|
|
30
|
+
|
|
31
|
+
# Editors / OS
|
|
32
|
+
.idea/
|
|
33
|
+
.vscode/
|
|
34
|
+
*.swp
|
|
35
|
+
.DS_Store
|
|
36
|
+
Thumbs.db
|
|
37
|
+
|
|
38
|
+
# downctl runtime artifacts
|
|
39
|
+
*.downctl-pieces
|
|
40
|
+
*.lock/
|
|
41
|
+
downctl.log
|
|
42
|
+
|
|
43
|
+
# Legacy single-file script (not part of this project)
|
|
44
|
+
hf-download.py
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-10-17
|
|
8
|
+
|
|
9
|
+
First release.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- P1 skeleton: package layout, plugin contracts (7 categories), plugin
|
|
14
|
+
registry/loader/event bus, CLI surface, TOML configuration, packaging and
|
|
15
|
+
CI.
|
|
16
|
+
- P2 core engine:
|
|
17
|
+
- resumable piece bitmap (`core.pieces`) with authoritative out-of-order
|
|
18
|
+
resume, `fsync`-backed ledger, atomic save and hole-detection guards
|
|
19
|
+
- multi-connection transfer (`core.transfer`) with stall watchdog, single
|
|
20
|
+
stream fallback for unknown sizes and Range-less servers
|
|
21
|
+
- download orchestration (`core.engine`) with retries, disk pre-flight,
|
|
22
|
+
file locking, checksum verification and a concurrent task runner
|
|
23
|
+
- transport contract now exposes a streaming `Response`; the HTTP transport
|
|
24
|
+
maps aiohttp errors onto the downctl exception hierarchy so the core is
|
|
25
|
+
HTTP-library agnostic
|
|
26
|
+
- integration tests with a controllable local HTTP server (full download,
|
|
27
|
+
out-of-order resume, Range fallback, unknown size, stall-then-resume)
|
|
28
|
+
- P4/P5 usable CLI and built-in plugins:
|
|
29
|
+
- `downctl get` resolves targets through source plugins, probes sizes,
|
|
30
|
+
applies mirror rewrites and runs the engine with a chosen reporter
|
|
31
|
+
- `downctl probe`, `plugin list|info`, `config init|show|path`, `doctor`
|
|
32
|
+
and `wizard` are implemented
|
|
33
|
+
- options: `-d/-o/-j/-t/-r/-p`, `--checksum`, `--mirror`, `--source`,
|
|
34
|
+
`--reporter`, `--include/--exclude`, `--dry-run`, `--retry-failed`,
|
|
35
|
+
`-l/--list`, `--local-plugins`
|
|
36
|
+
- failed-target log (`.downctl.failed`) with `--retry-failed`
|
|
37
|
+
- session factory, TOML config wiring and `DOWNCTL_CONFIG` override
|
|
38
|
+
- integration tests drive the real CLI flow against a local server
|
|
39
|
+
- HuggingFace source plugin:
|
|
40
|
+
- expands `hf://org/name[@revision]` (and bare `org/name`) for models and
|
|
41
|
+
datasets via the Hub API
|
|
42
|
+
- honours `--include`/`--exclude`, `--revision` and the
|
|
43
|
+
`[plugins.huggingface]` mirror/token options; verifies LFS sha256
|
|
44
|
+
- integration tests against a fake Hub plus real-world verification
|
|
45
|
+
- Docs and repository tooling:
|
|
46
|
+
- `py.typed` marker (PEP 561) and inline types
|
|
47
|
+
- docs site config (`mkdocs.yml`) plus CLI and plugin guides
|
|
48
|
+
- issue/PR templates, Dependabot config and `RELEASING.md`
|
|
49
|
+
- GitHub Releases source plugin (`gh://owner/repo[@tag]`):
|
|
50
|
+
- lists release assets via the REST API, honours `--include`/`--exclude`
|
|
51
|
+
- uses asset `sha256` digests for verification; `[plugins.github]` api/token
|
|
52
|
+
- integration tests against a fake API plus end-to-end download
|
|
53
|
+
- configurable `connections` and `stall` (config and `--connections`/
|
|
54
|
+
`--stall`), threaded through the engine
|
|
55
|
+
- S3 source plugin (`s3://bucket/key` and prefixes):
|
|
56
|
+
- SigV4 query-string presigning (no extra dependency), so the HTTP
|
|
57
|
+
transport fetches S3 objects incl. ranged transfers
|
|
58
|
+
- prefix listing via ListObjectsV2 with pagination; `[plugins.s3]`
|
|
59
|
+
endpoint/region/credentials/path_style; object size via presigned HEAD
|
|
60
|
+
- tests against a fake S3 endpoint plus SigV4 unit tests
|
|
61
|
+
- resume and failure handling:
|
|
62
|
+
- failed log v2 stores the resolved URL, target path, checksum and size,
|
|
63
|
+
so `--retry-failed` restores repo subpaths and verification
|
|
64
|
+
- `--continue` skips targets that fail to resolve or probe instead of
|
|
65
|
+
aborting the whole run
|
|
66
|
+
- unified console output with `-q/--quiet` and `-v/--verbose`; quiet mode
|
|
67
|
+
also switches to the `quiet` reporter; tqdm progress bar polished
|
|
68
|
+
- `downctl status` scans a directory for in-progress (piece bitmap) and
|
|
69
|
+
failed downloads
|
|
70
|
+
- hook plugins can be enabled with `--hook NAME` or `[core] hooks = [...]`
|
|
71
|
+
- `--user-agent` for a custom HTTP User-Agent
|
|
72
|
+
- Dockerfile (multi-stage, wheel-based) and `.dockerignore`
|
|
73
|
+
- aggregate progress: the tqdm reporter shows an overall bar across files
|
|
74
|
+
- `archive` hook extracts zip/tar archives on completion (path-traversal and
|
|
75
|
+
link-safe); `keep`/`into` options
|
|
76
|
+
- `--checksums FILE` verifies downloads against a `sha256sum`-style file
|
|
77
|
+
- SFTP source and transport (`sftp://[user@]host[:port]/path`), optional
|
|
78
|
+
`asyncssh` dependency (`downctl[sftp]`); supports directory listing and
|
|
79
|
+
ranged (multi-connection) transfers
|
|
80
|
+
- `webhook` hook POSTs selected lifecycle events as JSON
|
|
81
|
+
- `manifest` hook writes a `sha256sum` manifest of completed downloads
|
|
82
|
+
- coverage gate (75%) in the test configuration and CI
|
|
83
|
+
- documentation: the primary `README.md` is now a detailed Chinese guide
|
|
84
|
+
(install, usage, sources, configuration, plugins, troubleshooting); the
|
|
85
|
+
English version lives at `README.en.md`
|
|
86
|
+
- global rate limiting: the `--limit-rate` budget is now shared across all
|
|
87
|
+
concurrent files (previously each file was limited independently)
|
|
88
|
+
- `-H/--header` (repeatable) and `-u/--user USER:PASS` for custom headers and
|
|
89
|
+
HTTP Basic auth
|
|
90
|
+
- `downctl clean [DIR]` removes leftover bitmaps, the failed log and stale
|
|
91
|
+
lock directories
|
|
92
|
+
- `file://` source and transport for local files/directories (recursive,
|
|
93
|
+
ranged); console warnings/errors are now colored on a TTY
|
|
94
|
+
- concurrent downloads (job > 1) show an overall progress bar with a
|
|
95
|
+
completed-files count; optional shell completion via `argcomplete`
|
|
96
|
+
(`downctl[completion]`)
|
|
97
|
+
- docs site published to GitHub Pages (Actions-based, keeping a single
|
|
98
|
+
master branch) with a generated coverage badge; CI gains a `pip-audit`
|
|
99
|
+
dependency-vulnerability job
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
|
|
103
|
+
- webhook hook now flushes in-flight POSTs at shutdown (via an event-bus
|
|
104
|
+
`aclose`), so late events such as `on_task_finish`/`on_finish` are no
|
|
105
|
+
longer dropped
|
|
106
|
+
- the CLI reports network/library errors as clean messages instead of
|
|
107
|
+
dumping a traceback (use `-v` for the traceback)
|
|
108
|
+
- single-stream downloads no longer cancel the read generator to poll for
|
|
109
|
+
progress (which could look like a clean EOF and truncate the file); a
|
|
110
|
+
watchdog task aborts instead
|
|
111
|
+
- reject piece bitmaps whose length does not match the piece count
|
|
112
|
+
- confine source-provided relative targets to the destination directory
|
|
113
|
+
(mitigates `..`/percent-encoded path traversal from remote metadata)
|
|
114
|
+
- lock acquisition treats a missing pid file as held (avoids a takeover race)
|
|
115
|
+
- a file that cannot be opened for writing fails instead of retrying forever
|
|
116
|
+
- an unknown checksum algorithm now fails the file instead of silently passing
|
|
117
|
+
- checksum give-up discards the bad file so it is not trusted on the next run
|
|
118
|
+
- SFTP: guard connection creation with a lock, key the cache by credentials,
|
|
119
|
+
evict broken connections, and never leak inline credentials across hosts
|
|
120
|
+
- archive hook normalizes backslashes (Windows traversal) and extracts off the
|
|
121
|
+
event loop; `logfile`/SFTP key paths expand `~`; manifest uses POSIX
|
|
122
|
+
separators; GitHub tag is URL-quoted and private assets carry the token;
|
|
123
|
+
JSON reporter throttles progress; HTTP 408/425 are retried
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
|
|
127
|
+
- version is now dynamic, sourced from `src/downctl/__init__.py`
|
|
128
|
+
- the docs site is bilingual (English + 简体中文) via `mkdocs-static-i18n`
|
|
129
|
+
|
|
130
|
+
[0.1.0]: https://github.com/ThzxxArt/downctl/releases/tag/v0.1.0
|
downctl-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ThzxxArt
|
|
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.
|