Files
wehub-resource-sync bcbd1bdb22
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:30:44 +08:00

145 lines
4.5 KiB
Python

import inspect
from collections import deque
from collections.abc import AsyncIterator
from typing import Any, Callable
from mirage.accessor.base import Accessor
from mirage.cache.read_through import cache_aware_read
from mirage.types import PathSpec
from mirage.utils.stream import ensure_stream
async def tail(
src: bytes | AsyncIterator[bytes],
*,
n: int | None = None,
c: int | None = None,
from_line: int | None = None,
) -> AsyncIterator[bytes]:
if from_line is not None:
start = max(1, from_line)
skip = start - 1
if skip == 0:
async for chunk in ensure_stream(src):
yield chunk
return
skipped = 0
emitting = False
async for chunk in ensure_stream(src):
if emitting:
yield chunk
continue
count = chunk.count(b"\n")
if skipped + count < skip:
skipped += count
continue
i = 0
for _ in range(skip - skipped):
j = chunk.find(b"\n", i)
i = j + 1
skipped = skip
emitting = True
if i < len(chunk):
yield chunk[i:]
return
if c is not None:
target_c = abs(c)
if target_c == 0:
return
buf = b""
async for chunk in ensure_stream(src):
buf += chunk
if len(buf) > target_c:
buf = buf[-target_c:]
if buf:
yield buf
return
target = abs(n) if n is not None else 10
if target == 0:
return
recent: deque[bytes] = deque(maxlen=target)
buf = b""
async for chunk in ensure_stream(src):
buf += chunk
while b"\n" in buf:
line, buf = buf.split(b"\n", 1)
recent.append(line + b"\n")
if buf:
recent.append(buf)
for line in recent:
yield line
def tail_multi(
paths: list[PathSpec],
*,
read: Callable[..., Any],
accessor: Accessor | None = None,
index: object = None,
n: int | None = None,
c: int | None = None,
from_line: int | None = None,
show_headers: bool = False,
) -> AsyncIterator[bytes]:
"""Run tail over multiple already-resolved paths.
Globs are expanded by the caller, so ``paths`` is a flat list of concrete
entries. When ``show_headers`` is set a ``==> path <==`` banner is emitted
before each file (POSIX/GNU tail with multiple files), separated by a blank
line between files. The per-file source is produced lazily by ``read``.
This is a plain ``def`` returning the async generator: the cache-aware
wrap captures the active manager now, when the command calls
``tail_multi`` inside the mount's cache-manager scope, not when the
returned stream is drained later (after that scope is gone).
Args:
paths (list[PathSpec]): Resolved paths; only ``.virtual`` is read.
read (Callable[..., Any]): Reader called as ``read(accessor, path,
index)``; returns bytes, an awaitable of bytes, or an async byte
iterator.
accessor (Accessor | None): Backend accessor passed
through to ``read``.
index (object): Index cache store passed through to ``read``.
n (int | None): Line count.
c (int | None): Byte count.
from_line (int | None): 1-based start line for ``tail -n +N``.
show_headers (bool): Emit ``==> path <==`` banners between files.
"""
return _tail_multi(paths,
read=cache_aware_read(read),
accessor=accessor,
index=index,
n=n,
c=c,
from_line=from_line,
show_headers=show_headers)
async def _tail_multi(
paths: list[PathSpec],
*,
read: Callable[..., Any],
accessor: Accessor | None = None,
index: object = None,
n: int | None = None,
c: int | None = None,
from_line: int | None = None,
show_headers: bool = False,
) -> AsyncIterator[bytes]:
for i, p in enumerate(paths):
if show_headers:
header = f"==> {p.raw_path} <==\n"
if i > 0:
header = "\n" + header
yield header.encode()
source = read(accessor, p, index)
if inspect.isawaitable(source):
source = await source
async for chunk in tail(source, n=n, c=c, from_line=from_line):
yield chunk