Files
Zecheng Zhang 5639b62790 fix(os): route every path-taking os verb through the workspace
make_os_module patched 10 os names, so every other os call inside a
Workspace block reached the host filesystem with a virtual path in hand.
runtime/verbs.py and verbs.ts now classify every guest filesystem verb
once: 23 route through an op door, 14 refuse with a condition, 30 pass
through to the host, and an unclassified name defaults to ENOTSUP.

patch_process installs the routing as attributes on the real os module
instead of swapping sys.modules["os"], so a plain module-level import os
routes and pathlib, shutil and glob follow. os.stat answers a real
os.stat_result, which is what shutil.copystat and os.path.samefile need.
2026-08-20 20:13:46 -07:00

83 lines
2.9 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
import json
import os
from dotenv import load_dotenv
from mirage import MountMode, Workspace
from mirage.resource.gmail import GmailConfig, GmailResource
load_dotenv(".env.development")
config = GmailConfig(
client_id=os.environ["GOOGLE_CLIENT_ID"],
client_secret=os.environ["GOOGLE_CLIENT_SECRET"],
refresh_token=os.environ["GOOGLE_REFRESH_TOKEN"],
)
resource = GmailResource(config=config)
async def main():
with Workspace({"/gmail/": resource}, mode=MountMode.READ) as ws:
print("=== VFS MODE: open() reads from Gmail transparently ===\n")
print("--- os.listdir() labels ---")
labels = os.listdir("/gmail")
for label in labels:
print(f" {label}")
print("\n--- os.listdir() INBOX (date folders) ---")
dates = os.listdir("/gmail/INBOX")
for date in dates[:5]:
print(f" {date}")
first_date = dates[0] if dates else None
entries = os.listdir(
f"/gmail/INBOX/{first_date}") if first_date else []
messages = [e for e in entries if e.endswith(".gmail.json")]
for msg in messages[:5]:
print(f" {first_date}/{msg}")
if messages:
first = messages[0]
path = f"/gmail/INBOX/{first_date}/{first}"
print("\n--- open() + read first message ---")
with open(path) as f:
content = f.read()
parsed = json.loads(content)
print(f" subject: {parsed.get('subject', 'N/A')}")
print(f" from: {parsed.get('from', 'N/A')}")
print(f" snippet: {parsed.get('snippet', '')[:120]}...")
print("\n--- os.path.exists() ---")
print(f" {first}: {os.path.exists(path)}")
print(f" nonexistent: {os.path.exists('/gmail/INBOX/nope.json')}")
print("\n--- bash history ---")
with open("/.bash_history") as f:
for i, line in enumerate(f):
if i >= 6:
break
print(f" {line.rstrip()[:120]}")
records = ws.ops.records
total = sum(r.bytes for r in records)
print(f"\nStats: {len(records)} ops, {total} bytes transferred")
asyncio.run(main())