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

216 lines
8.8 KiB
Python

# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import tree_sitter
from mirage.commands.builtin.utils.safeguard import run_with_timeout
from mirage.io import IOResult
from mirage.io.stream import async_chain, close_quietly, merge_stdout_stderr
from mirage.io.types import ByteSource, materialize
from mirage.shell.barrier import BarrierPolicy, apply_barrier
from mirage.shell.call_stack import CallStack
from mirage.shell.types import ERREXIT_EXEMPT_TYPES
from mirage.shell.types import NodeType as NT
from mirage.workspace.session import Session
from mirage.workspace.types import ExecutionNode
async def handle_pipe(
execute_node,
commands: list[tree_sitter.Node],
stderr_flags: list[bool],
session: Session,
stdin: ByteSource | None = None,
call_stack: CallStack | None = None,
) -> tuple[ByteSource | None, IOResult, ExecutionNode]:
"""Connect commands via pipes: stdout -> stdin."""
current_stdin = stdin
last_stdout: ByteSource | None = None
child_nodes: list[ExecutionNode] = []
ios: list[IOResult] = []
intermediate_streams: list[ByteSource] = []
try:
for i, cmd in enumerate(commands):
stdout, io, child_exec = await execute_node(
cmd, session, current_stdin, call_stack)
ios.append(io)
child_nodes.append(child_exec)
if i < len(commands) - 1:
pipe_stderr = (i < len(stderr_flags) and stderr_flags[i])
if pipe_stderr:
current_stdin = merge_stdout_stderr(stdout, io)
else:
current_stdin = stdout
if current_stdin is None:
current_stdin = b""
if not isinstance(current_stdin, bytes):
intermediate_streams.append(current_stdin)
last_stdout = stdout
if last_stdout is not None and not isinstance(last_stdout, bytes):
materialized = await run_with_timeout(
materialize(last_stdout), session.pipeline_timeout_seconds,
"pipeline")
last_stdout = materialized
finally:
# Explicitly close any intermediate generators that may still
# be holding resource resources (HTTP connections, file
# handles). Harmless on exhausted streams.
for s in intermediate_streams:
await close_quietly(s)
last_io = ios[-1]
last_io.sync_exit_code()
if session.shell_options.get("pipefail"):
for io in ios:
io.sync_exit_code()
rightmost_failure = next(
(io.exit_code for io in reversed(ios) if io.exit_code != 0), 0)
if rightmost_failure != 0:
last_io.exit_code = rightmost_failure
merged_stderr_parts: list[bytes] = []
merged_reads: dict[str, ByteSource] = {}
merged_writes: dict[str, ByteSource] = {}
merged_cache: list[str] = []
for io, child in zip(ios, child_nodes):
io.sync_exit_code()
child.exit_code = io.exit_code
stderr_bytes = await materialize(io.stderr)
if stderr_bytes:
merged_stderr_parts.append(stderr_bytes)
merged_reads.update(io.reads)
merged_writes.update(io.writes)
merged_cache.extend(io.cache)
if merged_stderr_parts:
last_io.stderr = b"".join(merged_stderr_parts)
last_io.reads = merged_reads
last_io.writes = merged_writes
last_io.cache = merged_cache
exec_node = ExecutionNode(op="|",
exit_code=last_io.exit_code,
children=child_nodes)
return last_stdout, last_io, exec_node
async def handle_connection(
execute_node,
left: tree_sitter.Node,
op: str,
right: tree_sitter.Node,
session: Session,
stdin: ByteSource | None = None,
call_stack: CallStack | None = None,
) -> tuple[ByteSource | None, IOResult, ExecutionNode]:
"""Handle &&, ||"""
left_stdout, left_io, left_exec = await execute_node(
left, session, stdin, call_stack)
children = [left_exec]
if op == NT.AND:
left_bytes = await apply_barrier(left_stdout, left_io,
BarrierPolicy.VALUE)
session.last_exit_code = left_io.exit_code
if left_io.exit_code != 0:
return left_bytes, left_io, ExecutionNode(
op="&&", exit_code=left_io.exit_code, children=children)
right_stdout, right_io, right_exec = (await execute_node(
right, session, stdin, call_stack))
children.append(right_exec)
right_bytes = await materialize(right_stdout)
merged = await left_io.merge(right_io)
combined = async_chain(left_bytes, right_bytes)
return combined, merged, ExecutionNode(op="&&",
exit_code=merged.exit_code,
children=children)
if op == NT.OR:
left_bytes = await apply_barrier(left_stdout, left_io,
BarrierPolicy.VALUE)
session.last_exit_code = left_io.exit_code
if left_io.exit_code == 0:
return left_bytes, left_io, ExecutionNode(
op="||", exit_code=left_io.exit_code, children=children)
right_stdout, right_io, right_exec = (await execute_node(
right, session, stdin, call_stack))
children.append(right_exec)
right_bytes = await materialize(right_stdout)
merged = await left_io.merge(right_io)
combined = async_chain(left_bytes, right_bytes)
return combined, merged, ExecutionNode(op="||",
exit_code=merged.exit_code,
children=children)
# semicolon or other
left_bytes = await apply_barrier(left_stdout, left_io, BarrierPolicy.VALUE)
session.last_exit_code = left_io.exit_code
right_stdout, right_io, right_exec = await execute_node(
right, session, stdin, call_stack)
children.append(right_exec)
# Materialize right side to match && and || behavior, ensuring
# lazy exit codes (e.g. from exit_on_empty) are finalized before
# the combined stream is returned to the caller.
right_bytes = await materialize(right_stdout)
merged = await left_io.merge(right_io)
combined = async_chain(left_bytes, right_bytes)
return combined, merged, ExecutionNode(op=str(op),
exit_code=merged.exit_code,
children=children)
async def handle_subshell(
execute_node,
body: list[tree_sitter.Node],
session: Session,
stdin: ByteSource | None = None,
call_stack: CallStack | None = None,
) -> tuple[ByteSource | None, IOResult, ExecutionNode]:
"""Execute body in isolated env."""
saved_cwd = session.cwd
saved_env = dict(session.env)
saved_options = dict(session.shell_options)
saved_readonly = set(session.readonly_vars)
saved_arrays = {k: list(v) for k, v in session.arrays.items()}
saved_functions = dict(session.functions)
saved_positional = list(getattr(session, "positional_args", None) or [])
try:
all_stdout: list = []
merged_io = IOResult()
last_exec = ExecutionNode(command="()", exit_code=0)
for child in body:
stdout, io, last_exec = await execute_node(child, session, stdin,
call_stack)
if stdout is not None:
all_stdout.append(stdout)
merged_io = await merged_io.merge(io)
if (io.exit_code != 0 and session.shell_options.get("errexit")
and child.type not in ERREXIT_EXEMPT_TYPES):
merged_io.exit_code = io.exit_code
break
if len(all_stdout) == 1:
return all_stdout[0], merged_io, last_exec
combined = async_chain(*all_stdout) if all_stdout else None
return combined, merged_io, last_exec
finally:
session.cwd = saved_cwd
session.env = saved_env
session.shell_options = saved_options
session.readonly_vars = saved_readonly
session.arrays = saved_arrays
session.functions = saved_functions
session.positional_args = saved_positional