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
152 lines
7.2 KiB
Python
152 lines
7.2 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 asyncio
|
|
|
|
from mirage import MountMode, RAMResource, Workspace
|
|
|
|
ws = Workspace(
|
|
{"/data/": RAMResource()},
|
|
mode=MountMode.WRITE,
|
|
)
|
|
|
|
ws.dispatch("mkdir", "/data/logs")
|
|
ws.dispatch("mkdir", "/data/src")
|
|
APP_LOG = (b"INFO server started\nERROR disk full\n"
|
|
b"INFO request ok\nERROR timeout\n")
|
|
ws.dispatch("tee", "/data/logs/app.log", data=APP_LOG)
|
|
ws.dispatch("tee",
|
|
"/data/src/main.py",
|
|
data=b'def main():\n print("hello")\n')
|
|
ws.dispatch("tee",
|
|
"/data/src/utils.py",
|
|
data=b"def add(a, b):\n return a + b\n")
|
|
ws.dispatch("tee", "/data/notes.txt", data=b"line one\nline two\nline three\n")
|
|
|
|
|
|
async def log_result(label: str, io) -> None:
|
|
stdout = (await io.stdout_str()).rstrip("\n")
|
|
stderr = (await io.stderr_str()).rstrip("\n")
|
|
code = io.exit_code
|
|
print(f"\n{'─' * 60}")
|
|
print(f" $ {label}")
|
|
print(f" exit_code={code}")
|
|
if stdout:
|
|
for line in stdout.splitlines():
|
|
print(f" stdout │ {line}")
|
|
if stderr:
|
|
for line in stderr.splitlines():
|
|
print(f" stderr │ {line}")
|
|
if not stdout and not stderr:
|
|
print(" (no output)")
|
|
|
|
|
|
async def main():
|
|
print("=" * 60)
|
|
print(" Stderr Warnings & Error Handling Demo")
|
|
print("=" * 60)
|
|
|
|
# ── file not found ───────────────────────────────────────────────────
|
|
io = await ws.execute("cat /data/nonexistent.txt")
|
|
await log_result("cat /data/nonexistent.txt", io)
|
|
|
|
# ── ls on missing directory ──────────────────────────────────────────
|
|
io = await ws.execute("ls /data/missing/")
|
|
await log_result("ls /data/missing/", io)
|
|
|
|
# ── grep on missing file ─────────────────────────────────────────────
|
|
io = await ws.execute("grep hello /data/ghost.txt")
|
|
await log_result("grep hello /data/ghost.txt", io)
|
|
|
|
# ── find on missing path ─────────────────────────────────────────────
|
|
io = await ws.execute("find /data/nowhere")
|
|
await log_result("find /data/nowhere", io)
|
|
|
|
# ── recursive grep with -l (files only) on valid dir ─────────────────
|
|
io = await ws.execute("grep -rl def /data/src")
|
|
await log_result("grep -rl def /data/src", io)
|
|
|
|
# ── pipe: error in first stage ───────────────────────────────────────
|
|
io = await ws.execute("cat /data/nonexistent.txt | head -n 1")
|
|
await log_result("cat /data/nonexistent.txt | head -n 1", io)
|
|
|
|
# ── pipe: valid read, grep finds nothing ─────────────────────────────
|
|
io = await ws.execute("cat /data/notes.txt | grep ZZZZZ")
|
|
await log_result("cat /data/notes.txt | grep ZZZZZ", io)
|
|
|
|
# ── && chain: first fails → second skipped ──────────────────────────
|
|
io = await ws.execute(
|
|
"cat /data/nonexistent.txt && echo 'this should not print'")
|
|
await log_result("cat /data/nonexistent.txt && echo 'should not print'",
|
|
io)
|
|
|
|
# ── || chain: first fails → fallback runs ────────────────────────────
|
|
io = await ws.execute(
|
|
"cat /data/nonexistent.txt || echo 'fallback executed'")
|
|
await log_result("cat /data/nonexistent.txt || echo 'fallback executed'",
|
|
io)
|
|
|
|
# ── complex: (grep | sort) && echo ok || echo fail ───────────────────
|
|
io = await ws.execute(
|
|
"(grep ERROR /data/logs/app.log | sort) && echo ok || echo fail")
|
|
await log_result(
|
|
"(grep ERROR /data/logs/app.log | sort) && echo ok || echo fail", io)
|
|
|
|
# ── complex: same but grep finds nothing → fail path ─────────────────
|
|
io = await ws.execute(
|
|
"(grep ZZZZZ /data/logs/app.log | sort) && echo ok || echo fail")
|
|
await log_result(
|
|
"(grep ZZZZZ /data/logs/app.log | sort) && echo ok || echo fail", io)
|
|
|
|
# ── semicolon: independent commands, first fails ─────────────────────
|
|
io = await ws.execute(
|
|
"cat /data/nonexistent.txt ; cat /data/notes.txt | head -n 1")
|
|
await log_result(
|
|
"cat /data/nonexistent.txt ; cat /data/notes.txt | head -n 1", io)
|
|
|
|
# ── rm missing file (no -f) vs rm -f ────────────────────────────────
|
|
io = await ws.execute("rm /data/nonexistent.txt")
|
|
await log_result("rm /data/nonexistent.txt", io)
|
|
|
|
io = await ws.execute("rm -f /data/nonexistent.txt")
|
|
await log_result("rm -f /data/nonexistent.txt", io)
|
|
|
|
# ── diff with missing file ───────────────────────────────────────────
|
|
io = await ws.execute("diff /data/notes.txt /data/nonexistent.txt")
|
|
await log_result("diff /data/notes.txt /data/nonexistent.txt", io)
|
|
|
|
# ── stat on missing file ─────────────────────────────────────────────
|
|
io = await ws.execute("stat /data/nonexistent.txt")
|
|
await log_result("stat /data/nonexistent.txt", io)
|
|
|
|
# ── tree on missing dir ──────────────────────────────────────────────
|
|
io = await ws.execute("tree /data/nowhere")
|
|
await log_result("tree /data/nowhere", io)
|
|
|
|
# ── multi-pipe success: grep | sort | head ───────────────────────────
|
|
io = await ws.execute("grep ERROR /data/logs/app.log | sort | head -n 1")
|
|
await log_result("grep ERROR /data/logs/app.log | sort | head -n 1", io)
|
|
|
|
# ── execution history: exit codes per command ─────────────────────
|
|
print(f"\n{'═' * 60}")
|
|
print(" Execution History")
|
|
print(f"{'═' * 60}")
|
|
|
|
for entry in (await ws.history())[-6:]:
|
|
print(f"\n $ {entry['command']}")
|
|
print(f" exit={entry['exit_code']}")
|
|
|
|
|
|
asyncio.run(main())
|