fix(engines): a source tarball with a link in it still extracts
The stdlib data filter raises on a link to an absolute path, and the pinned Matcha-TTS tarball ships one (data -> its author's training folder), which aborted the fetch and with it the CosyVoice install. Found by building the real environment. Links are now skipped on every interpreter, as the pre-3.11.4 path already did.
This commit is contained in:
@@ -1273,8 +1273,8 @@ def _download_and_extract(job: dict, url: str, dest: Path, work_root: Path, env_
|
||||
with tempfile.TemporaryDirectory(dir=str(root)) as tmp_dir:
|
||||
with tarfile.open(tmp_tar, "r:gz") as tf:
|
||||
try:
|
||||
tf.extractall(tmp_dir, filter="data") # stdlib safe-extract (3.11.4+)
|
||||
except TypeError: # pragma: no cover — pre-filter= interpreters
|
||||
tf.extractall(tmp_dir, filter=_no_links_data_filter) # 3.11.4+
|
||||
except (TypeError, AttributeError): # pragma: no cover — no filter= / data_filter
|
||||
_safe_extract_members(tf, tmp_dir)
|
||||
entries = [p for p in Path(tmp_dir).iterdir() if p.is_dir()]
|
||||
if len(entries) != 1:
|
||||
@@ -1345,6 +1345,21 @@ def _run_post_install(spec: SidecarSpec, job: dict, py: Path, checkout: Path) ->
|
||||
)
|
||||
|
||||
|
||||
def _no_links_data_filter(member: "tarfile.TarInfo", path: str):
|
||||
"""The stdlib "data" filter, except that links are skipped, not fatal.
|
||||
|
||||
The "data" filter raises on a link to an absolute path, and the pinned
|
||||
Matcha-TTS tarball (a CosyVoice submodule) ships one: ``data`` points at
|
||||
its author's own training-data folder. That aborted the whole fetch. No
|
||||
installer here uses a link from a source tree, symlinks need privileges
|
||||
on Windows, and the pre-3.11.4 path below already drops them, so both
|
||||
paths now behave the same.
|
||||
"""
|
||||
if member.issym() or member.islnk():
|
||||
return None
|
||||
return tarfile.data_filter(member, path)
|
||||
|
||||
|
||||
def _safe_extract_members(tf: "tarfile.TarFile", dest: str) -> None:
|
||||
"""Tar-slip-guarded extraction for interpreters without
|
||||
``extractall(filter="data")`` (Python < 3.11.4).
|
||||
|
||||
@@ -1455,3 +1455,36 @@ def test_cosyvoice_post_install_code_compiles_for_any_checkout_path():
|
||||
spec = si.get_spec("cosyvoice")
|
||||
compile(si._expand(spec.post_install_code, Path("C:/Program Files/x y/CosyVoice")),
|
||||
"<post-install>", "exec")
|
||||
|
||||
|
||||
|
||||
def _tarball_with_absolute_symlink() -> bytes:
|
||||
"""Shaped like the pinned Matcha-TTS tarball: a package plus a `data` link
|
||||
to a folder on its author's machine."""
|
||||
buf = io.BytesIO()
|
||||
with tarfile.open(fileobj=buf, mode="w:gz") as tf:
|
||||
data = b"x = 1\n"
|
||||
info = tarfile.TarInfo("Matcha-abc/matcha/__init__.py")
|
||||
info.size = len(data)
|
||||
tf.addfile(info, io.BytesIO(data))
|
||||
link = tarfile.TarInfo("Matcha-abc/data")
|
||||
link.type = tarfile.SYMTYPE
|
||||
link.linkname = "/home/someone/Projects/Grad-TTS/data"
|
||||
tf.addfile(link)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def test_a_tarball_with_an_absolute_link_still_extracts(monkeypatch, tmp_path):
|
||||
"""The stdlib "data" filter raises AbsoluteLinkError on such a link, which
|
||||
aborted the Matcha-TTS fetch and with it the CosyVoice install."""
|
||||
import httpx
|
||||
|
||||
monkeypatch.setattr(httpx, "stream", lambda method, url, **kw: _FakeStream(_tarball_with_absolute_symlink()))
|
||||
dest = tmp_path / "third_party" / "Matcha-TTS"
|
||||
dest.parent.mkdir(parents=True)
|
||||
job = si._new_job("fake-side")
|
||||
|
||||
si._download_and_extract(job, "https://example.test/m.tar.gz", dest, tmp_path, "OMNIVOICE_FAKE_SIDE_DIR")
|
||||
|
||||
assert (dest / "matcha" / "__init__.py").is_file()
|
||||
assert not (dest / "data").exists() and not (dest / "data").is_symlink()
|
||||
|
||||
Reference in New Issue
Block a user