withcache 0.8.0__tar.gz → 0.8.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.8.0 → withcache-0.8.1}/PKG-INFO +8 -6
- {withcache-0.8.0 → withcache-0.8.1}/README.md +7 -5
- {withcache-0.8.0 → withcache-0.8.1}/shim/build.zig.zon +1 -1
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/__init__.py +1 -1
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/server.py +12 -9
- {withcache-0.8.0 → withcache-0.8.1}/tests/test_withcache.py +2 -2
- {withcache-0.8.0 → withcache-0.8.1}/.gitignore +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/LICENSE +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/deploy/Containerfile +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/deploy/compose.yml +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/hatch_build.py +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/pyproject.toml +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/shim/build.zig +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/shim/shim.zig +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/_shim.py +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/client.py +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/curlwithcache.py +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/oras.py +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/static/bootstrap-icons.min.css +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/static/bootstrap.min.css +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/static/fonts/bootstrap-icons.woff +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/static/fonts/bootstrap-icons.woff2 +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/static/htmx.min.js +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/src/withcache/wgetwithcache.py +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/tests/test_differential.py +0 -0
- {withcache-0.8.0 → withcache-0.8.1}/tests/test_oras.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: withcache
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.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>
|
|
@@ -61,7 +61,7 @@ optional **operator-curated** model (`--curate`: a miss queue a human approves).
|
|
|
61
61
|
|
|
62
62
|
| Path | What it is |
|
|
63
63
|
|-------------------------------|-------------------------------------------------------------|
|
|
64
|
-
| `src/withcache/server.py` | The cache-host: blob store + miss table + **background download manager** + operator UI (
|
|
64
|
+
| `src/withcache/server.py` | The cache-host: blob store + miss table + **background download manager** + operator UI (Bootstrap 5 + Bootstrap Icons + HTMX) |
|
|
65
65
|
| `src/withcache/_shim.py` | Shared shim core (find URL → probe → rewrite → exec) |
|
|
66
66
|
| `src/withcache/curlwithcache.py` / `wgetwithcache.py` | The Python `curl` / `wget` shims |
|
|
67
67
|
| `shim/shim.zig` | The native shim: one static binary, both tools via `argv[0]` |
|
|
@@ -237,11 +237,13 @@ Notes & limits (all degrade gracefully; worst case is "no caching, curl still wo
|
|
|
237
237
|
|
|
238
238
|
## Operator UI
|
|
239
239
|
|
|
240
|
-
`http://withcache-server:8081/` (
|
|
240
|
+
`http://withcache-server:8081/` (Bootstrap 5 + Bootstrap Icons + HTMX, bundled
|
|
241
|
+
offline; matches bty's chrome for a consistent trio) is a five-page dashboard:
|
|
242
|
+
- **Cached** (landing): URL, size, **hits** (times served) and **misses** (times requested before it was cached), SHA-256, fetched-at, each with **Delete** to free space.
|
|
243
|
+
- **Streams**: in-flight stream-through-and-store fetches serving bytes to a client while writing to disk.
|
|
244
|
+
- **Downloads**: live progress bars, `queued/running/completed/cancelled/failed`, **Cancel**, and **Clear finished**. Downloads run in a background worker pool, not in the request, so large pulls never block, modelled on [bty]'s job managers. The subnav Fetch form pre-seeds an artifact before anyone misses it.
|
|
241
245
|
- **Misses**: auto-fetched by default, or (under `--curate`) each with **Download** (queues a background pull) and **Dismiss**.
|
|
242
|
-
- **
|
|
243
|
-
- **Cached artifacts**: URL, size, **hits** (times served) and **misses** (times requested before it was cached), SHA-256, fetched-at, each with **Delete** to free space.
|
|
244
|
-
- **Add from URI**: pre-seed an artifact before anyone misses it.
|
|
246
|
+
- **Catalog**: image catalog fetched from a nosi-style `catalog.toml` (URL configurable via `$WITHCACHE_CATALOG_URL` or the subnav Set&fetch input); pre-seed by URL via the "Add image from oras" input.
|
|
245
247
|
|
|
246
248
|
## Auth
|
|
247
249
|
|
|
@@ -43,7 +43,7 @@ optional **operator-curated** model (`--curate`: a miss queue a human approves).
|
|
|
43
43
|
|
|
44
44
|
| Path | What it is |
|
|
45
45
|
|-------------------------------|-------------------------------------------------------------|
|
|
46
|
-
| `src/withcache/server.py` | The cache-host: blob store + miss table + **background download manager** + operator UI (
|
|
46
|
+
| `src/withcache/server.py` | The cache-host: blob store + miss table + **background download manager** + operator UI (Bootstrap 5 + Bootstrap Icons + HTMX) |
|
|
47
47
|
| `src/withcache/_shim.py` | Shared shim core (find URL → probe → rewrite → exec) |
|
|
48
48
|
| `src/withcache/curlwithcache.py` / `wgetwithcache.py` | The Python `curl` / `wget` shims |
|
|
49
49
|
| `shim/shim.zig` | The native shim: one static binary, both tools via `argv[0]` |
|
|
@@ -219,11 +219,13 @@ Notes & limits (all degrade gracefully; worst case is "no caching, curl still wo
|
|
|
219
219
|
|
|
220
220
|
## Operator UI
|
|
221
221
|
|
|
222
|
-
`http://withcache-server:8081/` (
|
|
222
|
+
`http://withcache-server:8081/` (Bootstrap 5 + Bootstrap Icons + HTMX, bundled
|
|
223
|
+
offline; matches bty's chrome for a consistent trio) is a five-page dashboard:
|
|
224
|
+
- **Cached** (landing): URL, size, **hits** (times served) and **misses** (times requested before it was cached), SHA-256, fetched-at, each with **Delete** to free space.
|
|
225
|
+
- **Streams**: in-flight stream-through-and-store fetches serving bytes to a client while writing to disk.
|
|
226
|
+
- **Downloads**: live progress bars, `queued/running/completed/cancelled/failed`, **Cancel**, and **Clear finished**. Downloads run in a background worker pool, not in the request, so large pulls never block, modelled on [bty]'s job managers. The subnav Fetch form pre-seeds an artifact before anyone misses it.
|
|
223
227
|
- **Misses**: auto-fetched by default, or (under `--curate`) each with **Download** (queues a background pull) and **Dismiss**.
|
|
224
|
-
- **
|
|
225
|
-
- **Cached artifacts**: URL, size, **hits** (times served) and **misses** (times requested before it was cached), SHA-256, fetched-at, each with **Delete** to free space.
|
|
226
|
-
- **Add from URI**: pre-seed an artifact before anyone misses it.
|
|
228
|
+
- **Catalog**: image catalog fetched from a nosi-style `catalog.toml` (URL configurable via `$WITHCACHE_CATALOG_URL` or the subnav Set&fetch input); pre-seed by URL via the "Add image from oras" input.
|
|
227
229
|
|
|
228
230
|
## Auth
|
|
229
231
|
|
|
@@ -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.8.
|
|
5
|
+
.version = "0.8.1",
|
|
6
6
|
.fingerprint = 0xd7d96c5ed212ccaa,
|
|
7
7
|
.minimum_zig_version = "0.16.0",
|
|
8
8
|
.paths = .{
|
|
@@ -17,6 +17,6 @@ All modules are stdlib-only and self-contained.
|
|
|
17
17
|
from . import oras
|
|
18
18
|
from .client import blob_url, cache_base, is_cached, serve_url
|
|
19
19
|
|
|
20
|
-
__version__ = "0.8.
|
|
20
|
+
__version__ = "0.8.1"
|
|
21
21
|
|
|
22
22
|
__all__ = ["__version__", "blob_url", "cache_base", "is_cached", "oras", "serve_url"]
|
|
@@ -6,7 +6,7 @@ their origin URL. By default a cache miss is auto-fetched: it is recorded in the
|
|
|
6
6
|
miss table and pulled from origin in the background, so the next request hits
|
|
7
7
|
(the client falls through to origin on the first miss). Run with `--curate` to
|
|
8
8
|
require an operator to approve each pull via a small web UI instead; either way
|
|
9
|
-
you can pre-seed an artifact with the
|
|
9
|
+
you can pre-seed an artifact with the Downloads-page Fetch form.
|
|
10
10
|
|
|
11
11
|
This is the only component that needs internet egress (and any vendor creds).
|
|
12
12
|
Clients never write to it.
|
|
@@ -180,12 +180,12 @@ def _serialise_catalog(entries: list[dict[str, Any]]) -> bytes:
|
|
|
180
180
|
class CatalogState:
|
|
181
181
|
"""Live state of the fetched image catalog.
|
|
182
182
|
|
|
183
|
-
withcache does not run a background poller
|
|
184
|
-
fetched at process start (best-effort
|
|
185
|
-
the last successful fetch survives a
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
183
|
+
withcache does not run a background poller and does not refetch
|
|
184
|
+
on a TTL. The catalog is fetched at process start (best-effort;
|
|
185
|
+
a persisted result from the last successful fetch survives a
|
|
186
|
+
restart) and force-refetched by the operator via the Refresh
|
|
187
|
+
button on the Catalog page (POST /admin/catalog_refresh); every
|
|
188
|
+
other render reads whatever is currently in memory.
|
|
189
189
|
|
|
190
190
|
The raw TOML bytes are persisted to ``<data_dir>/catalog.toml``
|
|
191
191
|
so a restart doesn't wipe the last known good catalog and the
|
|
@@ -1690,13 +1690,16 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|
|
1690
1690
|
subnav_html: str,
|
|
1691
1691
|
body_html: str,
|
|
1692
1692
|
) -> str:
|
|
1693
|
+
brand_cls = "navbar-brand fw-semibold"
|
|
1694
|
+
if nav_active == "cached":
|
|
1695
|
+
brand_cls += " brand-active"
|
|
1693
1696
|
return f"""{self._head(title)}
|
|
1694
1697
|
<body class="bg-light">
|
|
1695
1698
|
<div class="sticky-header">
|
|
1696
1699
|
<div class="brand-accent"></div>
|
|
1697
1700
|
<nav class="navbar navbar-expand-md bg-dark navbar-dark py-2">
|
|
1698
1701
|
<div class="container">
|
|
1699
|
-
<a class="
|
|
1702
|
+
<a class="{brand_cls}" href="/ui/cached">
|
|
1700
1703
|
<i class="bi bi-database brand-icon me-1"></i>WITHCACHE
|
|
1701
1704
|
</a>
|
|
1702
1705
|
<div class="d-flex flex-grow-1 align-items-center flex-wrap">
|
|
@@ -1884,7 +1887,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|
|
1884
1887
|
'<input class="form-control form-control-sm" type="url" name="url" '
|
|
1885
1888
|
'style="width: 22rem;" '
|
|
1886
1889
|
'placeholder="https://origin/path/artifact.tar.gz" required>'
|
|
1887
|
-
'<button class="btn btn-sm btn-primary" type="submit" title="
|
|
1890
|
+
'<button class="btn btn-sm btn-primary" type="submit" title="Fetch URI"'
|
|
1888
1891
|
">Fetch</button>"
|
|
1889
1892
|
"</form>"
|
|
1890
1893
|
)
|
|
@@ -1062,10 +1062,10 @@ class TestMultiPageNavigation(unittest.TestCase):
|
|
|
1062
1062
|
self.assertIn(f'id="{key}-fragment"', body)
|
|
1063
1063
|
self.assertIn('class="nav-btn active"', body)
|
|
1064
1064
|
|
|
1065
|
-
def
|
|
1065
|
+
def test_downloads_subnav_has_fetch_form(self):
|
|
1066
1066
|
body = self._get("/ui/downloads")
|
|
1067
1067
|
self.assertIn('hx-post="/admin/fetch"', body)
|
|
1068
|
-
self.assertIn("
|
|
1068
|
+
self.assertIn(">Fetch</button>", body)
|
|
1069
1069
|
|
|
1070
1070
|
def test_catalog_subnav_has_url_and_oras_forms(self):
|
|
1071
1071
|
body = self._get("/ui/catalog")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|