Skip to content

Commit 6cc9954

Browse files
lucapinelloclaude
andcommitted
Merge v12 polish: bundle igv.min.js + drop regen entries for deleted files
Eliminates the cold-cache race where regens running in parallel produced HTMLs with CDN <script> tags instead of inlined IGV.js. Bundles igv.min.js as a package resource (chorus/analysis/static/igv.min.js) with resolution order bundled → legacy cache → CDN → HF. Also drops the two ENFORMER_EXAMPLES entries that wrote to files deleted in f15d926. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 parents 7bc67e5 + 13f01ee commit 6cc9954

5 files changed

Lines changed: 165 additions & 49 deletions

File tree

chorus/analysis/_igv_report.py

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,44 +17,55 @@
1717

1818
logger = logging.getLogger(__name__)
1919

20-
# IGV.js: prefer local cached copy (inlined), fall back to CDN.
20+
# IGV.js is bundled as a package resource at
21+
# ``chorus/analysis/static/igv.min.js`` so every install has an offline-
22+
# usable copy without any network round-trip. The legacy CDN + HF
23+
# fallback paths remain as secondary options in case a downstream
24+
# consumer stripped the static file from the wheel.
2125
#
22-
# The committed HTML reports need IGV.js to render the embedded genome
23-
# browser. To stay robust when the viewer is offline / behind a proxy / on
24-
# a network that MITMs TLS (observed during the 2026-04-16 audit:
25-
# `net::ERR_CERT_AUTHORITY_INVALID` on 2/19 reports), we lazy-download
26-
# the bundle once into ``~/.chorus/lib/igv.min.js`` the first time
27-
# ``build_igv_html`` runs on a machine, then inline the JS into every
28-
# subsequent report. If the download fails we silently fall back to the
29-
# CDN <script> tag so report generation still succeeds.
26+
# Inlining the JS into every report makes the committed HTMLs
27+
# self-contained (viewable offline, through SSL-MITM proxies, on air-gapped
28+
# hosts). The CDN <script> fallback is the last resort and only triggers
29+
# when both the bundled copy and both network paths fail.
3030
_IGV_CDN = "https://cdn.jsdelivr.net/npm/igv@3.1.1/dist/igv.min.js"
3131
_IGV_LOCAL = Path.home() / ".chorus" / "lib" / "igv.min.js"
32-
# HuggingFace mirror — secondary fallback for environments where the
33-
# institutional proxy MITMs TLS and breaks stdlib ``urllib`` but leaves
34-
# ``huggingface_hub`` (httpx + certifi) working. Requires the file to
35-
# exist in the dataset; gracefully no-ops if it doesn't.
32+
_IGV_BUNDLED = Path(__file__).parent / "static" / "igv.min.js"
33+
# HuggingFace mirror — tertiary fallback for unusual installs where the
34+
# bundled resource is missing (e.g. stripped by a packer) and stdlib
35+
# urllib is blocked by a MITM proxy.
3636
_IGV_HF_REPO = "lucapinello/chorus-backgrounds"
3737
_IGV_HF_FILENAME = "igv.min.js"
3838

3939

4040
def _ensure_igv_local() -> Path | None:
41-
"""Ensure ``_IGV_LOCAL`` exists; download it on first use.
42-
43-
Tries (1) the CDN via stdlib ``urllib`` (``download_with_resume``),
44-
then (2) the HuggingFace mirror via ``huggingface_hub`` if the CDN
45-
path fails (typical on SSL-MITM institutional networks where
46-
stdlib ``urllib`` rejects the proxy's self-signed cert but
47-
``httpx + certifi`` accepts it).
48-
49-
Returns the local path when the file is available, ``None`` if
50-
both downloads failed (callers then fall back to a CDN <script>
51-
tag in the rendered HTML).
41+
"""Return a path to ``igv.min.js`` that callers can read + inline.
42+
43+
Resolution order:
44+
1. ``chorus/analysis/static/igv.min.js`` — bundled with the
45+
package. Always present in a standard install; no network
46+
touched.
47+
2. ``~/.chorus/lib/igv.min.js`` — legacy cache from earlier chorus
48+
versions. Kept for continuity.
49+
3. CDN via stdlib ``urllib`` (``download_with_resume``).
50+
4. HuggingFace dataset mirror via ``huggingface_hub``.
51+
52+
Returns the local path when the file is available, ``None`` if all
53+
four sources failed (callers then fall back to a CDN ``<script>``
54+
tag in the rendered HTML — reports remain viewable online).
5255
"""
56+
# 1. Bundled package resource (fast path — no I/O beyond the stat).
57+
if _IGV_BUNDLED.exists() and _IGV_BUNDLED.stat().st_size > 0:
58+
return _IGV_BUNDLED
59+
60+
# 2. Legacy user cache from pre-v13 installs.
5361
if _IGV_LOCAL.exists() and _IGV_LOCAL.stat().st_size > 0:
5462
return _IGV_LOCAL
63+
64+
# Bundled file missing (stripped by a packer?) and no legacy cache.
65+
# Fall back to the download paths to stay functional.
5566
_IGV_LOCAL.parent.mkdir(parents=True, exist_ok=True)
5667

57-
# Attempt 1: CDN via stdlib urllib.
68+
# 3. CDN via stdlib urllib.
5869
try:
5970
from chorus.utils.http import download_with_resume
6071
download_with_resume(_IGV_CDN, _IGV_LOCAL, label="igv.min.js")
@@ -64,8 +75,8 @@ def _ensure_igv_local() -> Path | None:
6475
except Exception as exc:
6576
logger.debug("CDN fetch of igv.min.js failed (%s); trying HF mirror.", exc)
6677

67-
# Attempt 2: HuggingFace mirror (works through SSL-MITM proxies
68-
# where stdlib urllib fails — huggingface_hub uses httpx+certifi).
78+
# 4. HuggingFace mirror (works through SSL-MITM proxies where stdlib
79+
# urllib fails — huggingface_hub uses httpx + certifi).
6980
try:
7081
from huggingface_hub import hf_hub_download
7182
downloaded = hf_hub_download(
@@ -74,8 +85,6 @@ def _ensure_igv_local() -> Path | None:
7485
repo_type="dataset",
7586
local_dir=str(_IGV_LOCAL.parent),
7687
)
77-
# hf_hub_download returns the actual local path; move to
78-
# canonical _IGV_LOCAL if different.
7988
dp = Path(downloaded)
8089
if dp != _IGV_LOCAL and dp.exists():
8190
dp.replace(_IGV_LOCAL)
@@ -84,8 +93,8 @@ def _ensure_igv_local() -> Path | None:
8493
return _IGV_LOCAL
8594
except Exception as exc:
8695
logger.warning(
87-
"Could not pre-cache igv.min.js from CDN or HF mirror (%s); "
88-
"reports will reference %s at view time.",
96+
"igv.min.js unavailable: bundled resource missing, CDN and HF "
97+
"mirror both failed (%s); reports will reference %s at view time.",
8998
exc, _IGV_CDN,
9099
)
91100
return None

0 commit comments

Comments
 (0)