withcache 0.12.0__tar.gz → 0.13.1__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.
- {withcache-0.12.0 → withcache-0.13.1}/PKG-INFO +10 -8
- {withcache-0.12.0 → withcache-0.13.1}/README.md +9 -7
- {withcache-0.12.0 → withcache-0.13.1}/shim/build.zig.zon +1 -1
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/__init__.py +1 -1
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_api.py +27 -4
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_app.py +268 -62
- withcache-0.13.1/src/withcache/_events_log.py +277 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_templates/ui/_layout.html +3 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_templates/ui/dashboard.html +35 -17
- withcache-0.13.1/src/withcache/_templates/ui/events.html +125 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/client.py +22 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/server.py +90 -10
- withcache-0.13.1/tests/test_fastapi_events.py +205 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_fastapi_ui_pages.py +4 -3
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_withcache.py +66 -0
- {withcache-0.12.0 → withcache-0.13.1}/.gitignore +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/LICENSE +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/deploy/Containerfile +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/deploy/compose.local-build.yml +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/deploy/compose.yml +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/deploy/envvars.example +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/hatch_build.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/pyproject.toml +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/shim/build.zig +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/shim/shim.zig +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_settings_store.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_shim.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_table_state.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_templates/ui/_table_macros.html +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_templates/ui/catalog.html +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_templates/ui/login.html +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_templates/ui/misses.html +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/_templates/ui/settings.html +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/curlwithcache.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/oras.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/static/bootstrap-icons.min.css +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/static/bootstrap.min.css +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/static/fonts/bootstrap-icons.woff +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/static/fonts/bootstrap-icons.woff2 +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/static/htmx.min.js +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/src/withcache/wgetwithcache.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_differential.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_fastapi_admin_forms.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_fastapi_blob.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_fastapi_catalog_api.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_fastapi_scaffold.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_fastapi_settings_persistence.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_fastapi_uvicorn_smoke.py +0 -0
- {withcache-0.12.0 → withcache-0.13.1}/tests/test_oras.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: withcache
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.1
|
|
4
4
|
Summary: Operator-curated, URL-keyed artifact cache for a small lab (CUDA/ROCm/DOCA/firmware)
|
|
5
5
|
Project-URL: Homepage, https://github.com/safl/withcache
|
|
6
6
|
Author-email: "Simon A. F. Lund" <safl@safl.dk>
|
|
@@ -68,14 +68,16 @@ disk.
|
|
|
68
68
|
|
|
69
69
|
| Path | What it is |
|
|
70
70
|
|-------------------------------|-------------------------------------------------------------|
|
|
71
|
-
| `src/withcache/server.py` | The cache-host: blob store + miss table + **background download manager** +
|
|
71
|
+
| `src/withcache/server.py` | The cache-host: blob store + miss table + **background download manager** + events log |
|
|
72
|
+
| `src/withcache/_app.py` | FastAPI app factory + operator UI wiring (Bootstrap 5 + Bootstrap Icons + HTMX) |
|
|
72
73
|
| `src/withcache/_shim.py` | Shared shim core (find URL → probe → rewrite → exec) |
|
|
73
74
|
| `src/withcache/curlwithcache.py` / `wgetwithcache.py` | The Python `curl` / `wget` shims |
|
|
74
75
|
| `shim/shim.zig` | The native shim: one static binary, both tools via `argv[0]` |
|
|
75
76
|
| `deploy/Containerfile`, `deploy/compose.yml` | Single Podman/Docker host deploy |
|
|
76
77
|
|
|
77
|
-
The cache-host
|
|
78
|
-
|
|
78
|
+
The cache-host runs on FastAPI + Jinja + Bootstrap (matching bty +
|
|
79
|
+
nbdmux for one trio-consistent chrome); the shims (Python and
|
|
80
|
+
native) are dependency-free so they drop into any environment.
|
|
79
81
|
|
|
80
82
|
## Install
|
|
81
83
|
|
|
@@ -245,11 +247,11 @@ Notes & limits (all degrade gracefully; worst case is "no caching, curl still wo
|
|
|
245
247
|
|
|
246
248
|
`http://withcache-server:8081/` (Bootstrap 5 + Bootstrap Icons + HTMX, bundled
|
|
247
249
|
offline; matches bty's chrome for a consistent trio) is a five-page dashboard:
|
|
248
|
-
- **
|
|
249
|
-
- **
|
|
250
|
+
- **Dashboard** (landing): catalog + cache + activity summary, health checklist, and the last N audit events.
|
|
251
|
+
- **Catalog**: image catalog fetched from a nosi-style `catalog.toml` (URL configured on Settings > Catalog source). Add entries via the subnav's inline "Add ORAS" / "Add HTTPS" forms or "Fetch default" button, then **Download** each entry. Rows carry hits, size, download progress (live), and cached/failed pills.
|
|
250
252
|
- **Misses**: URLs clients asked for that aren't downloaded yet. Each with **Fetch** (promotes to a catalog entry AND downloads it) and **Dismiss** (forget it).
|
|
251
|
-
- **
|
|
252
|
-
- **Settings**: identity + storage paths + catalog source + logging (uvicorn level) + auth.
|
|
253
|
+
- **Events**: append-only audit log with a free-text filter and per-page pagination. Failure rows carry an ack button; the dashboard's Health tripwire flags unacknowledged failures.
|
|
254
|
+
- **Settings**: identity + storage paths + catalog source (editable) + logging (uvicorn level) + auth.
|
|
253
255
|
|
|
254
256
|
## Auth
|
|
255
257
|
|
|
@@ -45,14 +45,16 @@ disk.
|
|
|
45
45
|
|
|
46
46
|
| Path | What it is |
|
|
47
47
|
|-------------------------------|-------------------------------------------------------------|
|
|
48
|
-
| `src/withcache/server.py` | The cache-host: blob store + miss table + **background download manager** +
|
|
48
|
+
| `src/withcache/server.py` | The cache-host: blob store + miss table + **background download manager** + events log |
|
|
49
|
+
| `src/withcache/_app.py` | FastAPI app factory + operator UI wiring (Bootstrap 5 + Bootstrap Icons + HTMX) |
|
|
49
50
|
| `src/withcache/_shim.py` | Shared shim core (find URL → probe → rewrite → exec) |
|
|
50
51
|
| `src/withcache/curlwithcache.py` / `wgetwithcache.py` | The Python `curl` / `wget` shims |
|
|
51
52
|
| `shim/shim.zig` | The native shim: one static binary, both tools via `argv[0]` |
|
|
52
53
|
| `deploy/Containerfile`, `deploy/compose.yml` | Single Podman/Docker host deploy |
|
|
53
54
|
|
|
54
|
-
The cache-host
|
|
55
|
-
|
|
55
|
+
The cache-host runs on FastAPI + Jinja + Bootstrap (matching bty +
|
|
56
|
+
nbdmux for one trio-consistent chrome); the shims (Python and
|
|
57
|
+
native) are dependency-free so they drop into any environment.
|
|
56
58
|
|
|
57
59
|
## Install
|
|
58
60
|
|
|
@@ -222,11 +224,11 @@ Notes & limits (all degrade gracefully; worst case is "no caching, curl still wo
|
|
|
222
224
|
|
|
223
225
|
`http://withcache-server:8081/` (Bootstrap 5 + Bootstrap Icons + HTMX, bundled
|
|
224
226
|
offline; matches bty's chrome for a consistent trio) is a five-page dashboard:
|
|
225
|
-
- **
|
|
226
|
-
- **
|
|
227
|
+
- **Dashboard** (landing): catalog + cache + activity summary, health checklist, and the last N audit events.
|
|
228
|
+
- **Catalog**: image catalog fetched from a nosi-style `catalog.toml` (URL configured on Settings > Catalog source). Add entries via the subnav's inline "Add ORAS" / "Add HTTPS" forms or "Fetch default" button, then **Download** each entry. Rows carry hits, size, download progress (live), and cached/failed pills.
|
|
227
229
|
- **Misses**: URLs clients asked for that aren't downloaded yet. Each with **Fetch** (promotes to a catalog entry AND downloads it) and **Dismiss** (forget it).
|
|
228
|
-
- **
|
|
229
|
-
- **Settings**: identity + storage paths + catalog source + logging (uvicorn level) + auth.
|
|
230
|
+
- **Events**: append-only audit log with a free-text filter and per-page pagination. Failure rows carry an ack button; the dashboard's Health tripwire flags unacknowledged failures.
|
|
231
|
+
- **Settings**: identity + storage paths + catalog source (editable) + logging (uvicorn level) + auth.
|
|
230
232
|
|
|
231
233
|
## Auth
|
|
232
234
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
.name = .withcache_shim,
|
|
3
3
|
// Zig requires a literal here; keep it in lockstep with the project's
|
|
4
4
|
// single source (src/withcache/__init__.py) via `make bump` / `make version-check`.
|
|
5
|
-
.version = "0.
|
|
5
|
+
.version = "0.13.1",
|
|
6
6
|
.fingerprint = 0xd7d96c5ed212ccaa,
|
|
7
7
|
.minimum_zig_version = "0.16.0",
|
|
8
8
|
.paths = .{
|
|
@@ -22,6 +22,6 @@ inherit the framework floor.
|
|
|
22
22
|
from . import oras
|
|
23
23
|
from .client import blob_url, cache_base, is_cached, serve_url
|
|
24
24
|
|
|
25
|
-
__version__ = "0.
|
|
25
|
+
__version__ = "0.13.1"
|
|
26
26
|
|
|
27
27
|
__all__ = ["__version__", "blob_url", "cache_base", "is_cached", "oras", "serve_url"]
|
|
@@ -22,14 +22,17 @@ v0.11.0) promotes a missed URL to a catalog entry + enqueues the
|
|
|
22
22
|
Download in one click.
|
|
23
23
|
|
|
24
24
|
Streaming shape: FastAPI ``StreamingResponse`` with a generator
|
|
25
|
-
that reads chunks from the on-disk blob at 64 KiB reads
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
that reads chunks from the on-disk blob at 64 KiB reads. The
|
|
26
|
+
Downloads-page real-time progress tracker was retired in v0.12.0
|
|
27
|
+
along with that page; per-entry download progress now folds into
|
|
28
|
+
the Catalog page's Downloaded column, populated from the
|
|
29
|
+
DownloadManager's job list directly.
|
|
28
30
|
"""
|
|
29
31
|
|
|
30
32
|
from __future__ import annotations
|
|
31
33
|
|
|
32
34
|
import base64
|
|
35
|
+
import contextlib
|
|
33
36
|
import urllib.parse
|
|
34
37
|
from collections.abc import Iterator
|
|
35
38
|
from typing import Any
|
|
@@ -88,7 +91,27 @@ def _serve_blob(
|
|
|
88
91
|
row = None
|
|
89
92
|
|
|
90
93
|
if row is None:
|
|
91
|
-
store.record_miss(url)
|
|
94
|
+
fresh = store.record_miss(url)
|
|
95
|
+
if fresh:
|
|
96
|
+
# First miss for this URL: emit an audit event so the
|
|
97
|
+
# operator sees it on /ui/events. Subsequent misses for
|
|
98
|
+
# the same URL bump the counter without re-emitting.
|
|
99
|
+
from . import _events_log
|
|
100
|
+
|
|
101
|
+
with contextlib.suppress(Exception):
|
|
102
|
+
with store.conn() as ev_conn:
|
|
103
|
+
_events_log.record(
|
|
104
|
+
ev_conn,
|
|
105
|
+
kind="blob.miss.recorded",
|
|
106
|
+
summary=f"First cache miss for {url}",
|
|
107
|
+
subject_kind="blob",
|
|
108
|
+
subject_id=url,
|
|
109
|
+
actor="client",
|
|
110
|
+
source_ip=_events_log.normalize_ip(
|
|
111
|
+
request.client.host if request.client else None
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
ev_conn.commit()
|
|
92
115
|
return PlainTextResponse(
|
|
93
116
|
"cache miss: this URL hasn't been downloaded yet. "
|
|
94
117
|
"Pick the matching catalog entry on /ui/catalog and hit Download.\n",
|