refactor(seam): dispatcher-built CommandOpts, typed adapter ops, named ParsedCommand, one DispatchFn home (#609 items 26+23) (#772)
* wip(seam): py dispatcher builds CommandOpts; handlers take (accessor, paths, texts, opts); adapter op protocols; DispatchFn typing Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(seam): dispatcher-built CommandOpts, typed adapter ops, named ParsedCommand, one DispatchFn home (#609 items 26+23) Item 26 (T2-8 seam typing), all four pieces, plus task 23's static FlagView query-name gate: - The python dispatcher (Mount.execute_cmd) now constructs one CommandOpts per invocation and calls every handler as fn(accessor, paths, texts, opts) — the TS convention. Flags stop sharing a bag with injected context, accepts_kwarg opt-in dies, and all 72 builders, 75 bespoke wrappers and ~30 provision functions become pure wiring; the provision path builds the same bag with command/spec set. Generics that took trailing fact params (ls, find, tree, zip, tar, du, file, stat) now read opts.links/opts.mounts/... like their TS twins. - adapter.py gains per-slot op protocols (ReaddirOp/StatOp/WriteOp/...) mirroring adapter.ts, so wiring readdir where stat belongs no longer type-checks; Builder.fn/provision and CommandIO fields are typed. Surfaced and fixed real drift: hf/databricks mkdir had index before parents (a positional parents call would land in index), wget -O dropped its PathSpec value under as_str. - TS parseFlags returns a named ParsedCommand (twin of the py NamedTuple) instead of a 15-slot positional tuple; optionError takes (cmdName, parsed) like python's option_error. - DispatchFn moves to runtime/types.ts (python's home for the same protocol); the crossmount re-export inversion and the CommandDispatch duplicate are gone; 38 python files stop spelling it Callable[..., Any]. The dead CommandOpts.resource field (zero readers) is deleted along with the CrossResourceStub that existed to fill it. - Task 23: tests/commands/test_flag_query_names.py and commands/flag_query_names.test.ts fail on a FlagView query naming a dest no spec bound in the module declares, without needing the code path to run (both verified to fire on a planted typo). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(examples): redis example calls provisions with the 4-positional shape file_read_provision/head_tail_provision/metadata_provision are (accessor, paths, texts, opts) now; the direct demo calls still passed the old command= kwarg, crashing the example before the persistence section (CI examples gate). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(integ): pin the #772 fixes where the harness can reach them - find -empty on chroma + github (the wrappers used to drop the flag, which would flood every path; -empty now rides find_generic), plus a -not -empty composition case on each so the pin has positive output - mkdir -p gains databricks/databricks-prefix (zero prior mkdir coverage on that backend; the param-order bug itself is only reachable positionally, so MkdirOp+mypy is its real gate) - wget -O / curl -o were already pinned by integ/resources/http Both hosts green: py chroma+github 83 ok, ts all five targets 4070 ok. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: bytecii <bytecii@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -323,35 +323,19 @@ they bite:
|
||||
backend, so a backend author never implements, stores, or forwards one. This
|
||||
is the whole point of keeping them in the namespace; do not push link
|
||||
awareness down into a resource or an accessor.
|
||||
- **A command opts in by naming the parameter, nothing else.** Declare
|
||||
`links: LinkView | None = None` on the wrapper and the generic and the
|
||||
dispatcher starts passing it; delete the parameter and it stops. `execute_cmd`
|
||||
offers the fact to every handler and `accepts_kwarg` (`utils/params.py`)
|
||||
decides delivery from the signature, so there is no allowlist, spec field, or
|
||||
registry that can fall out of step. A bare `**kwargs` deliberately does not
|
||||
count as consent: every wrapper has one, and it is the opaque bag of the
|
||||
user's typed command-line flags, forwarded wholesale to the generic. Counting
|
||||
it would file a live namespace object among the parsed flags of every command
|
||||
in the repo. This is the same rule already stated for `stdin`/`index`/`prefix`
|
||||
under "Command wrappers and flags", and `stat_overlay` is delivered the same
|
||||
way.
|
||||
`LinkView` bundles every link fact (`stat_at`, `children`, `subtree`,
|
||||
`resolve`, `exists`, `target_stat`) so a command that grows a new need adds a
|
||||
field read, not a new keyword threaded through `execute_cmd`, the builder and
|
||||
the generic. Families wired today: `ls`, `stat`, `find`, `du`, `file`.
|
||||
`exists` and `target_stat` answer through the op dispatcher, not one
|
||||
- **A command consumes a fact by reading the `opts` field, nothing else.**
|
||||
Every namespace fact (`links`, `stat_overlay`, `stat_path`, `readdir_path`,
|
||||
`child_mounts`, `mounts`) rides `CommandOpts` into every handler, identically
|
||||
in both languages; the generic that wants one reads `opts.links` and the rest
|
||||
ignore it, so there is no opt-in registry, spec field, or signature
|
||||
convention that can fall out of step. `LinkView` bundles every link fact
|
||||
(`stat_at`, `children`, `subtree`, `resolve`, `exists`, `target_stat`) so a
|
||||
command that grows a new need adds a field read, not a new keyword threaded
|
||||
through `execute_cmd`, the builder and the generic. Families reading links
|
||||
today: `ls`, `stat`, `find`, `du`, `file` — in the generics, so a bespoke
|
||||
wrapper that delegates (as all of them now do) inherits link awareness for
|
||||
free. `exists` and `target_stat` answer through the op dispatcher, not one
|
||||
backend's stat, so a link that points into another mount resolves correctly.
|
||||
- **A bespoke command in one of those families must declare it too.** The
|
||||
opt-in is the whole mechanism, so a backend that ships its own `find`/`ls`/
|
||||
`du`/`stat`/`file` and omits the parameter still runs, still exits 0, and
|
||||
simply cannot see a link, which nothing notices until someone makes one on
|
||||
that backend. `tests/commands/test_links_optin.py` asserts it instead: it
|
||||
derives the link-aware names from the generic builders and fails naming any
|
||||
registered command that shadows one without accepting `links`. TypeScript
|
||||
needs no equivalent because wrappers forward the whole `opts` object, so a
|
||||
generic reads `opts.links` whatever the wrapper declares; the bespoke email
|
||||
find routes through `findGeneric`/`walkFind` like the factory, so no TS
|
||||
command walks its own tree any more.
|
||||
- **Merge links in the generic, above the native-op/walk fork.** `find` and `du`
|
||||
each have two paths: a backend with a native op (`find_core`, `du_size`/
|
||||
`du_entries`) and a backend walked by `readdir`. Link merging lives in one
|
||||
@@ -632,8 +616,8 @@ Invoke the venv's `pre-commit` binary directly (not via `uv --directory python r
|
||||
- Don't add too many printings or comments in the code.
|
||||
- Don't add README.md unless I ask you to do so.
|
||||
- Use uv add to install new dependencies.
|
||||
- **Command wrappers and flags.** The dispatcher passes parsed command-line flags as keyword arguments. Wrappers must declare dispatcher-injected parameters (`stdin`, `index`, `prefix`) explicitly in their signature — never fish them out of `**flags` with `.get()`. Treat `**flags: FlagValue` as an opaque bag of true command-line flags and forward it wholesale to the generic command. A wrapper must not name a flag it cannot receive: the parser maps every spelling onto one canonical dest (the long form whenever an option declares one), so a parameter named after a short spelling with a long twin is permanently unfilled — `tests/commands/test_no_dead_flag_params.py` fails on one. When a wrapper genuinely needs a flag value itself (e.g. a search push-down), read it through `FlagView` (`fl = FlagView(flags)` then `fl.as_bool("F")`, `fl.as_int("m")`, `fl.as_str("type")`, `fl.as_list("e")`) or a shared domain accessor like `pattern_arg` — never raw `flags.get(...)` / isinstance chains, and never a raw `kwargs`/`_extra` read either (`tests/commands/test_no_raw_flag_reads.py` matches all three bag names). **A PATH-typed flag reaches a python command as a `PathSpec`, not a string** — the executor promotes it (`workspace/executor/command/flags.py`), so read it with `fl.as_paths(name)`; `as_str` reads it as absent and the operand is silently never used. TypeScript's bag carries the resolved virtual-path string instead, so its twin is `fl.asStr(name)`.
|
||||
- **Generic commands own flag interpretation.** Backend wrappers are wiring only (glob resolution, backend I/O injection, pass-through of `texts` and `flags`); all flag semantics live in the generic command for that family, mirroring the TS generics. Adding or changing a flag should touch the spec and the generic, not N wrappers.
|
||||
- **Command handlers take `(accessor, paths, texts, opts)` — the same four positionals in both languages.** The dispatcher (`Mount.execute_cmd` / `Mount.executeCmd`) constructs one `CommandOpts` per invocation carrying stdin, the flag bag, cwd, the mount prefix, the index, and every namespace fact; the provision path builds the same bag with `command`/`spec` set (`ProvisionFn` has the same four-positional shape). Handlers never declare a flag or an injected fact as a parameter — `tests/commands/test_no_dead_flag_params.py` pins the exact signature. When a wrapper genuinely needs a flag value itself (e.g. a search push-down), read it through a spec-bound `FlagView` (`fl = FlagView(opts.flags, spec=SPECS["grep"])` then `fl.as_bool("F")`, `fl.as_int("m")`, `fl.as_str("type")`, `fl.as_list("e")`) or a shared domain accessor like `pattern_arg` — never raw `flags.get(...)` / isinstance chains, and never a raw `kwargs`/`_extra` read either (`tests/commands/test_no_raw_flag_reads.py`). To override a flag before delegating, pass `dataclasses.replace(opts, flags=bag)` down, never a hand-built `CommandOpts`. **A PATH-typed flag reaches a python command as a `PathSpec`, not a string** — the executor promotes it (`workspace/executor/command/flags.py`), so read it with `fl.as_paths(name)`; `as_str` reads it as absent and the operand is silently never used. TypeScript's bag carries the resolved virtual-path string instead, so its twin is `fl.asStr(name)`.
|
||||
- **Generic commands own flag interpretation.** Backend wrappers are wiring only (glob resolution, backend I/O injection, pass-through of `texts` and `opts`); all flag semantics live in the generic command for that family, mirroring the TS generics. Adding or changing a flag should touch the spec and the generic, not N wrappers. Every literal `FlagView` query name must be a dest of a spec bound in the same module — `tests/commands/test_flag_query_names.py` and `commands/flag_query_names.test.ts` fail on a typo'd spelling without needing the code path to run.
|
||||
- **Generics parse flags once into a frozen struct.** Each generic defines a `@dataclass(frozen=True, slots=True)` flag struct plus a module-level `parse_flags(fl, ...)` (mirroring the TS `parseFlags` struct); the function body reads only struct attributes, never string keys. Construct the FlagView with the command's spec (`FlagView(flags, spec=SPECS["grep"])`) so a typo in a flag name raises KeyError instead of silently reading as False/None.
|
||||
- **Never annotate anything as `object`** — not a parameter, not a return, not a type argument (`dict[str, object]`, `Callable[..., object]`). `object` reads as "we did not decide": it accepts bytes where JSON was meant and a PathSpec where a flag value was meant, so every use site pays for it with an isinstance chain back to the set the author had in mind. Name the real type instead:
|
||||
- a parsed command-line flag is `FlagValue` (`mirage.commands.spec.types`) — `**flags: FlagValue`, `Mapping[str, FlagValue]`, `FlagValue | None` for a single raw read. The TypeScript side has always called it `FlagValue` too (`commands/spec/types.ts`); keep the two spellings identical.
|
||||
|
||||
@@ -22,6 +22,7 @@ from mirage import MountMode, Workspace
|
||||
from mirage.commands.builtin.redis._provision import (file_read_provision,
|
||||
head_tail_provision,
|
||||
metadata_provision)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.resource.redis import RedisResource
|
||||
from mirage.types import PathSpec
|
||||
|
||||
@@ -196,17 +197,20 @@ async def main() -> None:
|
||||
]
|
||||
accessor = resource.accessor
|
||||
|
||||
read_cost = await file_read_provision(accessor, paths, command="cat")
|
||||
read_cost = await file_read_provision(accessor, paths, [],
|
||||
CommandOpts(command="cat"))
|
||||
print(" file_read_provision(accessor, [hello.txt, user.json]):")
|
||||
print(f" network_read = {read_cost.network_read} bytes "
|
||||
f"({read_cost.read_ops} reads)")
|
||||
print(f" precision = {read_cost.precision}")
|
||||
|
||||
head_cost = await head_tail_provision(accessor, paths, command="head -n 1")
|
||||
head_cost = await head_tail_provision(accessor, paths, [],
|
||||
CommandOpts(command="head -n 1"))
|
||||
print(" head_tail_provision(...) — Redis fetches full value regardless:")
|
||||
print(f" network_read = {head_cost.network_read} bytes")
|
||||
|
||||
meta_cost = await metadata_provision(accessor, paths, command="stat")
|
||||
meta_cost = await metadata_provision(accessor, paths, [],
|
||||
CommandOpts(command="stat"))
|
||||
print(" metadata_provision(...) — stat/ls/find cost zero network bytes:")
|
||||
print(f" network_read = {meta_cost.network_read} bytes")
|
||||
print(f" read_ops = {meta_cost.read_ops}")
|
||||
|
||||
@@ -610,6 +610,32 @@
|
||||
"stdout": "CHANGELOG.md\nguides\npolicies\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "chroma_find_empty",
|
||||
"seq": 630054,
|
||||
"targets": [
|
||||
"chroma"
|
||||
],
|
||||
"command": "find /knowledge/ -empty",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "chroma_find_empty_composes_with_name",
|
||||
"seq": 630055,
|
||||
"targets": [
|
||||
"chroma"
|
||||
],
|
||||
"command": "find /knowledge/ -name '*.md' -not -empty",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "/knowledge/CHANGELOG.md\n/knowledge/guides/auth.md\n/knowledge/guides/quickstart.md\n/knowledge/policies/archived.md\n/knowledge/policies/privacy.md\n/knowledge/policies/refunds.md\n",
|
||||
"stderr": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -142,6 +142,32 @@
|
||||
"stdout": "/repo/docs/architecture.md\n/repo/src/auth/step_1.py\n/repo/src/route/step_3.py\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "github_find_empty",
|
||||
"seq": 530012,
|
||||
"targets": [
|
||||
"github"
|
||||
],
|
||||
"command": "find /repo -empty",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "github_find_empty_composes_with_name",
|
||||
"seq": 530013,
|
||||
"targets": [
|
||||
"github"
|
||||
],
|
||||
"command": "find /repo/docs -name '*.md' -not -empty",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "/repo/docs/architecture.md\n/repo/docs/contributing.md\n/repo/docs/release.md\n",
|
||||
"stderr": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
@@ -41,8 +43,10 @@
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
@@ -73,8 +77,10 @@
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.box import BoxAccessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.box.narrow import narrow_scope
|
||||
from mirage.commands.builtin.generic.grep import grep as generic_grep
|
||||
from mirage.commands.builtin.generic_bind.adapter import bound_op
|
||||
from mirage.commands.builtin.grep_helper import pattern_arg
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.box.read import read as _read
|
||||
from mirage.core.box.read import stream as _stream
|
||||
from mirage.core.box.readdir import readdir as _readdir
|
||||
@@ -30,16 +30,9 @@ from mirage.types import PathSpec
|
||||
|
||||
|
||||
@command("grep", resource="box", spec=SPECS["grep"])
|
||||
async def grep(
|
||||
accessor: BoxAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["grep"])
|
||||
async def grep(accessor: BoxAccessor, paths: list[PathSpec], texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["grep"])
|
||||
pattern = pattern_arg(texts, fl)
|
||||
|
||||
resolved: list[PathSpec] = []
|
||||
@@ -49,7 +42,7 @@ async def grep(
|
||||
# zero counts (-c) from files a narrowed superset would never visit.
|
||||
resolved, used_search = await narrow_scope(
|
||||
accessor,
|
||||
index,
|
||||
opts.index,
|
||||
paths,
|
||||
pattern,
|
||||
fixed_string=fl.as_bool("F"),
|
||||
@@ -63,10 +56,10 @@ async def grep(
|
||||
return await generic_grep(
|
||||
resolved,
|
||||
texts,
|
||||
flags,
|
||||
readdir=bound_op(_readdir, accessor, index),
|
||||
stat=bound_op(_stat, accessor, index),
|
||||
read_bytes=bound_op(_read, accessor, index),
|
||||
read_stream=bound_op(_stream, accessor, index),
|
||||
stdin=stdin,
|
||||
opts.flags,
|
||||
readdir=bound_op(_readdir, accessor, opts.index),
|
||||
stat=bound_op(_stat, accessor, opts.index),
|
||||
read_bytes=bound_op(_read, accessor, opts.index),
|
||||
read_stream=bound_op(_stream, accessor, opts.index),
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
from collections.abc import Mapping
|
||||
|
||||
from mirage.accessor.box import BoxAccessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.box.narrow import narrow_scope
|
||||
from mirage.commands.builtin.generic.rg import rg as generic_rg
|
||||
from mirage.commands.builtin.generic_bind.adapter import bound_op
|
||||
from mirage.commands.builtin.grep_helper import pattern_arg
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
@@ -67,26 +67,19 @@ def _keep_visible(
|
||||
|
||||
|
||||
@command("rg", resource="box", spec=SPECS["rg"])
|
||||
async def rg(
|
||||
accessor: BoxAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["rg"])
|
||||
async def rg(accessor: BoxAccessor, paths: list[PathSpec], texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["rg"])
|
||||
pattern_str = pattern_arg(texts, fl)
|
||||
|
||||
run_flags: Mapping[str, FlagValue] = flags
|
||||
run_flags: Mapping[str, FlagValue] = opts.flags
|
||||
if paths:
|
||||
# -v needs the walk (a narrowed superset hides fully non-matching
|
||||
# files whose every line matches inverted); --type/--glob keep the
|
||||
# walk so their file filtering stays in one place.
|
||||
narrowed, used_search = await narrow_scope(
|
||||
accessor,
|
||||
index,
|
||||
opts.index,
|
||||
paths,
|
||||
pattern_str,
|
||||
fixed_string=fl.as_bool("F"),
|
||||
@@ -103,16 +96,16 @@ async def rg(
|
||||
# arrive as explicit operands, so force the label flag -- unless
|
||||
# -I suppresses labels.
|
||||
if not fl.as_bool("args_I"):
|
||||
run_flags = {**flags, "H": True}
|
||||
run_flags = {**opts.flags, "H": True}
|
||||
paths = narrowed
|
||||
|
||||
return await generic_rg(
|
||||
paths,
|
||||
texts,
|
||||
run_flags,
|
||||
readdir=bound_op(_readdir, accessor, index),
|
||||
stat=bound_op(_stat, accessor, index),
|
||||
read_bytes=bound_op(_read, accessor, index),
|
||||
read_stream=bound_op(_stream, accessor, index),
|
||||
stdin=stdin,
|
||||
readdir=bound_op(_readdir, accessor, opts.index),
|
||||
stat=bound_op(_stat, accessor, opts.index),
|
||||
read_bytes=bound_op(_read, accessor, opts.index),
|
||||
read_stream=bound_op(_stream, accessor, opts.index),
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
from dataclasses import replace
|
||||
from functools import partial
|
||||
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.chroma.io import resolve_glob
|
||||
from mirage.commands.builtin.generic.find import find as generic_find
|
||||
from mirage.commands.builtin.generic.find import find_generic
|
||||
from mirage.commands.builtin.utils.output import format_records
|
||||
from mirage.commands.builtin.utils.paths import default_paths
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.chroma.find import find as find_core
|
||||
from mirage.core.chroma.stat import stat as stat_core
|
||||
from mirage.core.chroma.stat import stat_light
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import LinkView, StatPath
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.key_prefix import mount_prefix_of
|
||||
|
||||
|
||||
def _is_bare_name(texts: tuple[str, ...]) -> bool:
|
||||
def _is_bare_name(texts: list[str]) -> bool:
|
||||
return bool(texts) and not texts[0].startswith("-") and texts[0] not in (
|
||||
"(", ")", "!")
|
||||
|
||||
|
||||
def _default_name(name: str | None, texts: tuple[str, ...]) -> str | None:
|
||||
def _default_name(name: str | None, texts: list[str]) -> str | None:
|
||||
if name is not None:
|
||||
return name
|
||||
if _is_bare_name(texts):
|
||||
@@ -30,9 +30,9 @@ def _default_name(name: str | None, texts: tuple[str, ...]) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
def _expr_texts(texts: tuple[str, ...]) -> tuple[str, ...]:
|
||||
def _expr_texts(texts: list[str]) -> list[str]:
|
||||
if _is_bare_name(texts):
|
||||
return ()
|
||||
return []
|
||||
return texts
|
||||
|
||||
|
||||
@@ -54,42 +54,28 @@ async def _normalize_find_output(
|
||||
async def find(
|
||||
accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
name: str | None = None,
|
||||
type: str | None = None,
|
||||
maxdepth: str | None = None,
|
||||
size: str | None = None,
|
||||
mtime: str | None = None,
|
||||
iname: str | None = None,
|
||||
path: str | None = None,
|
||||
mindepth: str | None = None,
|
||||
index: IndexCacheStore,
|
||||
cwd: PathSpec | None = None,
|
||||
L: bool = False,
|
||||
links: LinkView | None = None,
|
||||
stat_path: StatPath | None = None,
|
||||
**_extra: FlagValue,
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
paths = default_paths(paths, cwd)
|
||||
paths = await resolve_glob(accessor, paths, index)
|
||||
paths = default_paths(paths, opts.cwd)
|
||||
paths = await resolve_glob(accessor, paths, opts.index)
|
||||
search_path = paths[0]
|
||||
stat_fn = (partial(stat_core, accessor, index=index) if mtime is not None
|
||||
else partial(stat_light, accessor, index=index))
|
||||
stdout, io = await generic_find(paths,
|
||||
|
||||
fl = FlagView(opts.flags, spec=SPECS["find"])
|
||||
# Push-down choices: a bare word acts as the -name filter, and the
|
||||
# heavier per-document stat is only paid when -mtime needs times.
|
||||
bag = dict(opts.flags)
|
||||
default_name = _default_name(fl.as_str("name"), texts)
|
||||
if default_name is not None:
|
||||
bag["name"] = default_name
|
||||
stat_fn = (partial(stat_core, accessor, index=opts.index)
|
||||
if fl.as_str("mtime") is not None else partial(
|
||||
stat_light, accessor, index=opts.index))
|
||||
stdout, io = await find_generic(paths,
|
||||
_expr_texts(texts),
|
||||
replace(opts, flags=bag),
|
||||
find_core=partial(find_core,
|
||||
accessor,
|
||||
index=index),
|
||||
stat=stat_fn,
|
||||
name=_default_name(name, texts),
|
||||
type=type,
|
||||
size=size,
|
||||
mtime=mtime,
|
||||
maxdepth=maxdepth,
|
||||
iname=iname,
|
||||
path=path,
|
||||
mindepth=mindepth,
|
||||
links=links,
|
||||
stat_path=stat_path,
|
||||
follow=L)
|
||||
index=opts.index),
|
||||
stat=stat_fn)
|
||||
return await _normalize_find_output(stdout, search_path), io
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.chroma.io import resolve_glob
|
||||
from mirage.commands.builtin.utils.paths import default_paths
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.chroma import search as search_core
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
@@ -20,27 +20,27 @@ def is_mount_root(path: PathSpec) -> bool:
|
||||
async def search(
|
||||
accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
top_k: str | int = 10,
|
||||
index: IndexCacheStore,
|
||||
cwd: PathSpec | None = None,
|
||||
**_extra: FlagValue,
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["search"])
|
||||
if not texts:
|
||||
raise ValueError("search: query is required")
|
||||
query = texts[0]
|
||||
target_paths = default_paths(paths, cwd)
|
||||
target_paths = default_paths(paths, opts.cwd)
|
||||
mount_prefix = mount_prefix_of(
|
||||
target_paths[0].virtual,
|
||||
target_paths[0].resource_path) if target_paths else ""
|
||||
if any(is_mount_root(path) for path in target_paths):
|
||||
resolved_paths: list[PathSpec] = []
|
||||
else:
|
||||
resolved_paths = await resolve_glob(accessor, target_paths, index)
|
||||
output = await search_core.search_segments(accessor,
|
||||
query,
|
||||
resolved_paths,
|
||||
index,
|
||||
top_k=int(top_k),
|
||||
mount_prefix=mount_prefix)
|
||||
resolved_paths = await resolve_glob(accessor, target_paths, opts.index)
|
||||
top_k = fl.as_int("top_k")
|
||||
output = await search_core.search_segments(
|
||||
accessor,
|
||||
query,
|
||||
resolved_paths,
|
||||
opts.index,
|
||||
top_k=top_k if top_k is not None else 10,
|
||||
mount_prefix=mount_prefix)
|
||||
return output, IOResult()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.generic.cat import cat_generic
|
||||
from mirage.commands.builtin.generic_bind import CommandIO
|
||||
from mirage.commands.builtin.generic_bind.adapter import (bound_op,
|
||||
@@ -8,7 +7,6 @@ from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
@@ -22,20 +20,15 @@ def make_cat(ops: CommandIO):
|
||||
"""
|
||||
|
||||
@command("cat", resource="dify", spec=SPECS["cat"])
|
||||
async def cat(
|
||||
accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
async def cat(accessor, paths: list[PathSpec], texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await cat_generic(resolved,
|
||||
list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_stream, accessor, index),
|
||||
opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_stream, accessor,
|
||||
opts.index),
|
||||
local=ops.local)
|
||||
|
||||
return cat
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from dataclasses import replace
|
||||
from functools import partial
|
||||
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.dify.io import resolve_glob
|
||||
from mirage.commands.builtin.generic.find import find_generic
|
||||
from mirage.commands.builtin.utils.output import format_records
|
||||
@@ -8,22 +8,21 @@ from mirage.commands.builtin.utils.paths import default_paths
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.dify.find import find as find_core
|
||||
from mirage.core.dify.stat import stat as stat_core
|
||||
from mirage.core.dify.stat import stat_light
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import LinkView, StatPath
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.key_prefix import mount_prefix_of
|
||||
|
||||
|
||||
def _is_bare_name(texts: tuple[str, ...]) -> bool:
|
||||
def _is_bare_name(texts: list[str]) -> bool:
|
||||
return bool(texts) and not texts[0].startswith("-") and texts[0] not in (
|
||||
"(", ")", "!")
|
||||
|
||||
|
||||
def _default_name(name: str | None, texts: tuple[str, ...]) -> str | None:
|
||||
def _default_name(name: str | None, texts: list[str]) -> str | None:
|
||||
if name is not None:
|
||||
return name
|
||||
if _is_bare_name(texts):
|
||||
@@ -31,9 +30,9 @@ def _default_name(name: str | None, texts: tuple[str, ...]) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
def _expr_texts(texts: tuple[str, ...]) -> tuple[str, ...]:
|
||||
def _expr_texts(texts: list[str]) -> list[str]:
|
||||
if _is_bare_name(texts):
|
||||
return ()
|
||||
return []
|
||||
return texts
|
||||
|
||||
|
||||
@@ -52,36 +51,27 @@ async def _normalize_find_output(
|
||||
|
||||
|
||||
@command("find", resource="dify", spec=SPECS["find"])
|
||||
async def find(
|
||||
accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
index: IndexCacheStore,
|
||||
cwd: PathSpec | None = None,
|
||||
links: LinkView | None = None,
|
||||
stat_path: StatPath | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
paths = default_paths(paths, cwd)
|
||||
paths = await resolve_glob(accessor, paths, index)
|
||||
async def find(accessor, paths: list[PathSpec], texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
paths = default_paths(paths, opts.cwd)
|
||||
paths = await resolve_glob(accessor, paths, opts.index)
|
||||
search_path = paths[0]
|
||||
|
||||
fl = FlagView(flags, spec=SPECS["find"])
|
||||
fl = FlagView(opts.flags, spec=SPECS["find"])
|
||||
# Push-down choices: a bare word acts as the -name filter, and the
|
||||
# heavier per-document stat is only paid when -mtime needs times.
|
||||
bag = dict(flags)
|
||||
bag = dict(opts.flags)
|
||||
default_name = _default_name(fl.as_str("name"), texts)
|
||||
if default_name is not None:
|
||||
bag["name"] = default_name
|
||||
stat_fn = (partial(stat_core, accessor, index=index) if fl.as_str("mtime")
|
||||
is not None else partial(stat_light, accessor, index=index))
|
||||
stat_fn = (partial(stat_core, accessor, index=opts.index)
|
||||
if fl.as_str("mtime") is not None else partial(
|
||||
stat_light, accessor, index=opts.index))
|
||||
stdout, io = await find_generic(paths,
|
||||
list(_expr_texts(texts)),
|
||||
CommandOpts(flags=bag),
|
||||
_expr_texts(texts),
|
||||
replace(opts, flags=bag),
|
||||
find_core=partial(find_core,
|
||||
accessor,
|
||||
index=index),
|
||||
stat=stat_fn,
|
||||
stat_path=stat_path,
|
||||
links=links)
|
||||
index=opts.index),
|
||||
stat=stat_fn)
|
||||
return await _normalize_find_output(stdout, search_path), io
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.dify.io import resolve_glob
|
||||
from mirage.commands.builtin.utils.paths import default_paths
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.dify import search as search_core
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
@@ -20,31 +20,29 @@ def is_mount_root(path: PathSpec) -> bool:
|
||||
async def search(
|
||||
accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
method: str = "semantic",
|
||||
top_k: str | int = 10,
|
||||
threshold: str | float = 0.0,
|
||||
index: IndexCacheStore,
|
||||
cwd: PathSpec | None = None,
|
||||
**_extra: FlagValue,
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["search"])
|
||||
if not texts:
|
||||
raise ValueError("search: query is required")
|
||||
query = texts[0]
|
||||
target_paths = default_paths(paths, cwd)
|
||||
target_paths = default_paths(paths, opts.cwd)
|
||||
mount_prefix = mount_prefix_of(
|
||||
target_paths[0].virtual,
|
||||
target_paths[0].resource_path) if target_paths else ""
|
||||
if any(is_mount_root(path) for path in target_paths):
|
||||
resolved_paths: list[PathSpec] = []
|
||||
else:
|
||||
resolved_paths = await resolve_glob(accessor, target_paths, index)
|
||||
output = await search_core.search_segments(accessor,
|
||||
query,
|
||||
resolved_paths,
|
||||
index,
|
||||
method=method,
|
||||
top_k=int(top_k),
|
||||
threshold=float(threshold),
|
||||
mount_prefix=mount_prefix)
|
||||
resolved_paths = await resolve_glob(accessor, target_paths, opts.index)
|
||||
top_k = fl.as_int("top_k")
|
||||
output = await search_core.search_segments(
|
||||
accessor,
|
||||
query,
|
||||
resolved_paths,
|
||||
opts.index,
|
||||
method=fl.as_str("method") or "semantic",
|
||||
top_k=top_k if top_k is not None else 10,
|
||||
threshold=fl.as_float("threshold") or 0.0,
|
||||
mount_prefix=mount_prefix)
|
||||
return output, IOResult()
|
||||
|
||||
@@ -13,18 +13,19 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import logging
|
||||
from dataclasses import replace
|
||||
|
||||
from mirage.accessor.discord import DiscordAccessor
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.discord._provision import file_read_provision
|
||||
from mirage.commands.builtin.discord.io import resolve_glob
|
||||
from mirage.commands.builtin.generic.grep import grep as generic_grep
|
||||
from mirage.commands.builtin.generic_bind.adapter import bound_op
|
||||
from mirage.commands.builtin.grep_helper import pattern_arg
|
||||
from mirage.commands.builtin.utils.output import format_records
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.discord.channels import list_channels
|
||||
from mirage.core.discord.entry import channel_dirname
|
||||
from mirage.core.discord.formatters import format_grep_results
|
||||
@@ -41,39 +42,30 @@ from mirage.utils.key_prefix import mount_prefix_of
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def grep_provision(
|
||||
accessor: DiscordAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
**_extra: FlagValue,
|
||||
) -> ProvisionResult:
|
||||
return await file_read_provision(
|
||||
accessor, paths,
|
||||
"grep " + " ".join(texts + tuple(str(p) for p in paths)))
|
||||
async def grep_provision(accessor: DiscordAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> ProvisionResult:
|
||||
line = "grep " + " ".join(list(texts) + [str(p) for p in paths])
|
||||
return await file_read_provision(accessor, paths, texts,
|
||||
replace(opts, command=line))
|
||||
|
||||
|
||||
@command("grep",
|
||||
resource="discord",
|
||||
spec=SPECS["grep"],
|
||||
provision=grep_provision)
|
||||
async def grep(
|
||||
accessor: DiscordAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["grep"])
|
||||
async def grep(accessor: DiscordAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["grep"])
|
||||
pattern = pattern_arg(texts, fl)
|
||||
max_count = fl.as_int("m")
|
||||
|
||||
pushdown_warnings: list[str] = []
|
||||
if paths and pattern is not None and "\n" not in pattern:
|
||||
scope = await detect_scope(paths[0], index)
|
||||
scope = await detect_scope(paths[0], opts.index)
|
||||
if scope.level in ("messages", "file_blob", "date"):
|
||||
coalesced = await coalesce_scopes(paths, index)
|
||||
coalesced = await coalesce_scopes(paths, opts.index)
|
||||
if coalesced is not None:
|
||||
scope = coalesced
|
||||
|
||||
@@ -123,16 +115,16 @@ async def grep(
|
||||
"falling back to per-file scan", exc)
|
||||
|
||||
resolved = await resolve_glob(accessor, paths,
|
||||
index=index) if paths else []
|
||||
index=opts.index) if paths else []
|
||||
out, io = await generic_grep(
|
||||
resolved,
|
||||
texts,
|
||||
flags,
|
||||
readdir=bound_op(_readdir, accessor, index),
|
||||
stat=bound_op(_stat, accessor, index),
|
||||
read_bytes=bound_op(discord_read, accessor, index),
|
||||
opts.flags,
|
||||
readdir=bound_op(_readdir, accessor, opts.index),
|
||||
stat=bound_op(_stat, accessor, opts.index),
|
||||
read_bytes=bound_op(discord_read, accessor, opts.index),
|
||||
read_stream=None,
|
||||
stdin=stdin,
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
if pushdown_warnings:
|
||||
extra = ("\n".join(pushdown_warnings) + "\n").encode()
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import json
|
||||
from dataclasses import replace
|
||||
|
||||
from mirage.accessor.discord import DiscordAccessor
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.discord._provision import file_read_provision
|
||||
from mirage.commands.builtin.discord.io import IO
|
||||
from mirage.commands.builtin.generic.head import head as generic_head
|
||||
@@ -26,7 +26,6 @@ from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.core.discord._client import discord_get
|
||||
from mirage.core.discord.history import date_to_snowflake
|
||||
from mirage.core.discord.read import read as discord_read
|
||||
@@ -36,37 +35,28 @@ from mirage.provision.types import ProvisionResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def head_provision(
|
||||
accessor: DiscordAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
**_extra: FlagValue,
|
||||
) -> ProvisionResult:
|
||||
return await file_read_provision(
|
||||
accessor, paths,
|
||||
"head " + " ".join(p.virtual if isinstance(p, PathSpec) else p
|
||||
for p in paths))
|
||||
async def head_provision(accessor: DiscordAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> ProvisionResult:
|
||||
line = "head " + " ".join(p.virtual for p in paths)
|
||||
return await file_read_provision(accessor, paths, texts,
|
||||
replace(opts, command=line))
|
||||
|
||||
|
||||
@command("head",
|
||||
resource="discord",
|
||||
spec=SPECS["head"],
|
||||
provision=head_provision)
|
||||
async def head(
|
||||
accessor: DiscordAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def head(accessor: DiscordAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
try:
|
||||
parsed = parse_flags(flags)
|
||||
parsed = parse_flags(opts.flags)
|
||||
except ValueError as exc:
|
||||
return None, IOResult(exit_code=1, stderr=str(exc).encode())
|
||||
lines = parsed.lines if parsed.lines is not None else 10
|
||||
if paths:
|
||||
scope = await detect_scope(paths[0], index)
|
||||
scope = await detect_scope(paths[0], opts.index)
|
||||
|
||||
# Smart head: fetch only first N messages for a single date.
|
||||
if (len(paths) == 1 and scope.level == "file" and scope.channel_id
|
||||
@@ -87,8 +77,7 @@ async def head(
|
||||
json.dumps(m, ensure_ascii=False, separators=(",", ":"))
|
||||
for m in msgs) + "\n"
|
||||
return generic_head(jsonl.encode(), n=lines), IOResult()
|
||||
resolved = await resolve_or_empty(IO, accessor, paths, index)
|
||||
return await head_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(IO.stat, accessor, index),
|
||||
bound_op(discord_read, accessor, index))
|
||||
resolved = await resolve_or_empty(IO, accessor, paths, opts.index)
|
||||
return await head_generic(resolved, list(texts), opts,
|
||||
bound_op(IO.stat, accessor, opts.index),
|
||||
bound_op(discord_read, accessor, opts.index))
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
import logging
|
||||
|
||||
from mirage.accessor.discord import DiscordAccessor
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.discord.io import resolve_glob
|
||||
from mirage.commands.builtin.generic.rg import rg as generic_rg
|
||||
from mirage.commands.builtin.generic_bind.adapter import bound_op
|
||||
from mirage.commands.builtin.grep_helper import pattern_arg
|
||||
from mirage.commands.builtin.utils.output import format_records
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.errors import UsageError
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.discord.channels import list_channels
|
||||
from mirage.core.discord.entry import channel_dirname
|
||||
from mirage.core.discord.formatters import format_grep_results
|
||||
@@ -41,16 +41,10 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@command("rg", resource="discord", spec=SPECS["rg"])
|
||||
async def rg(
|
||||
accessor: DiscordAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["rg"])
|
||||
async def rg(accessor: DiscordAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["rg"])
|
||||
pattern_str = pattern_arg(texts, fl)
|
||||
if pattern_str is None:
|
||||
raise UsageError("rg: usage: rg [flags] pattern [path]")
|
||||
@@ -58,9 +52,9 @@ async def rg(
|
||||
|
||||
pushdown_warnings: list[str] = []
|
||||
if paths and "\n" not in pattern_str:
|
||||
scope = await detect_scope(paths[0], index)
|
||||
scope = await detect_scope(paths[0], opts.index)
|
||||
if scope.level in ("messages", "file_blob", "date"):
|
||||
coalesced = await coalesce_scopes(paths, index)
|
||||
coalesced = await coalesce_scopes(paths, opts.index)
|
||||
if coalesced is not None:
|
||||
scope = coalesced
|
||||
|
||||
@@ -110,16 +104,16 @@ async def rg(
|
||||
"falling back to per-file scan", exc)
|
||||
|
||||
resolved = await resolve_glob(accessor, paths,
|
||||
index=index) if paths else []
|
||||
index=opts.index) if paths else []
|
||||
stdout, io = await generic_rg(
|
||||
resolved,
|
||||
texts,
|
||||
flags,
|
||||
readdir=bound_op(_readdir, accessor, index),
|
||||
stat=bound_op(_stat, accessor, index),
|
||||
read_bytes=bound_op(discord_read, accessor, index),
|
||||
opts.flags,
|
||||
readdir=bound_op(_readdir, accessor, opts.index),
|
||||
stat=bound_op(_stat, accessor, opts.index),
|
||||
read_bytes=bound_op(discord_read, accessor, opts.index),
|
||||
read_stream=None,
|
||||
stdin=stdin,
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
if pushdown_warnings:
|
||||
io.stderr = ("\n".join(pushdown_warnings) + "\n").encode()
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.dropbox import DropboxAccessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.dropbox.narrow import narrow_scope
|
||||
from mirage.commands.builtin.generic.grep import grep as generic_grep
|
||||
from mirage.commands.builtin.generic_bind.adapter import bound_op
|
||||
from mirage.commands.builtin.grep_helper import pattern_arg
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.dropbox.read import read as _read
|
||||
from mirage.core.dropbox.read import stream as _stream
|
||||
from mirage.core.dropbox.readdir import readdir as _readdir
|
||||
@@ -30,16 +30,10 @@ from mirage.types import PathSpec
|
||||
|
||||
|
||||
@command("grep", resource="dropbox", spec=SPECS["grep"])
|
||||
async def grep(
|
||||
accessor: DropboxAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["grep"])
|
||||
async def grep(accessor: DropboxAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["grep"])
|
||||
pattern = pattern_arg(texts, fl)
|
||||
|
||||
resolved: list[PathSpec] = []
|
||||
@@ -50,7 +44,7 @@ async def grep(
|
||||
# visit.
|
||||
resolved, used_search = await narrow_scope(
|
||||
accessor,
|
||||
index,
|
||||
opts.index,
|
||||
paths,
|
||||
pattern,
|
||||
fixed_string=fl.as_bool("F"),
|
||||
@@ -64,10 +58,10 @@ async def grep(
|
||||
return await generic_grep(
|
||||
resolved,
|
||||
texts,
|
||||
flags,
|
||||
readdir=bound_op(_readdir, accessor, index),
|
||||
stat=bound_op(_stat, accessor, index),
|
||||
read_bytes=bound_op(_read, accessor, index),
|
||||
read_stream=bound_op(_stream, accessor, index),
|
||||
stdin=stdin,
|
||||
opts.flags,
|
||||
readdir=bound_op(_readdir, accessor, opts.index),
|
||||
stat=bound_op(_stat, accessor, opts.index),
|
||||
read_bytes=bound_op(_read, accessor, opts.index),
|
||||
read_stream=bound_op(_stream, accessor, opts.index),
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
from collections.abc import Mapping
|
||||
|
||||
from mirage.accessor.dropbox import DropboxAccessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.dropbox.narrow import narrow_scope
|
||||
from mirage.commands.builtin.generic.rg import rg as generic_rg
|
||||
from mirage.commands.builtin.generic_bind.adapter import bound_op
|
||||
from mirage.commands.builtin.grep_helper import pattern_arg
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
@@ -67,26 +67,20 @@ def _keep_visible(
|
||||
|
||||
|
||||
@command("rg", resource="dropbox", spec=SPECS["rg"])
|
||||
async def rg(
|
||||
accessor: DropboxAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["rg"])
|
||||
async def rg(accessor: DropboxAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["rg"])
|
||||
pattern_str = pattern_arg(texts, fl)
|
||||
|
||||
run_flags: Mapping[str, FlagValue] = flags
|
||||
run_flags: Mapping[str, FlagValue] = opts.flags
|
||||
if paths:
|
||||
# -v needs the walk (a narrowed superset hides fully non-matching
|
||||
# files whose every line matches inverted); --type/--glob keep the
|
||||
# walk so their file filtering stays in one place.
|
||||
narrowed, used_search = await narrow_scope(
|
||||
accessor,
|
||||
index,
|
||||
opts.index,
|
||||
paths,
|
||||
pattern_str,
|
||||
fixed_string=fl.as_bool("F"),
|
||||
@@ -103,16 +97,16 @@ async def rg(
|
||||
# arrive as explicit operands, so force the label flag —
|
||||
# unless -I suppresses labels.
|
||||
if not fl.as_bool("args_I"):
|
||||
run_flags = {**flags, "H": True}
|
||||
run_flags = {**opts.flags, "H": True}
|
||||
paths = narrowed
|
||||
|
||||
return await generic_rg(
|
||||
paths,
|
||||
texts,
|
||||
run_flags,
|
||||
readdir=bound_op(_readdir, accessor, index),
|
||||
stat=bound_op(_stat, accessor, index),
|
||||
read_bytes=bound_op(_read, accessor, index),
|
||||
read_stream=bound_op(_stream, accessor, index),
|
||||
stdin=stdin,
|
||||
readdir=bound_op(_readdir, accessor, opts.index),
|
||||
stat=bound_op(_stat, accessor, opts.index),
|
||||
read_bytes=bound_op(_read, accessor, opts.index),
|
||||
read_stream=bound_op(_stream, accessor, opts.index),
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
|
||||
@@ -12,18 +12,19 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from dataclasses import replace
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.email import EmailAccessor
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.email._provision import metadata_provision
|
||||
from mirage.commands.builtin.email.io import resolve_glob
|
||||
from mirage.commands.builtin.generic.find import (is_link, parse_find_args,
|
||||
resolve_start, walk_find)
|
||||
from mirage.commands.builtin.utils.output import format_records
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.email._client import fetch_headers
|
||||
from mirage.core.email.readdir import _date_bucket, _sanitize
|
||||
from mirage.core.email.readdir import readdir as _readdir
|
||||
@@ -31,7 +32,6 @@ from mirage.core.email.scope import extract_folder
|
||||
from mirage.core.email.search import search_messages
|
||||
from mirage.core.email.stat import stat as _stat
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import LinkView, StatPath
|
||||
from mirage.provision.types import ProvisionResult
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.fnmatch import fnmatch
|
||||
@@ -46,14 +46,12 @@ def _is_folder_level(paths: list[PathSpec]) -> bool:
|
||||
return len(parts) <= 1
|
||||
|
||||
|
||||
async def find_provision(
|
||||
accessor: EmailAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
**_extra: FlagValue,
|
||||
) -> ProvisionResult:
|
||||
return await metadata_provision("find " + " ".join(
|
||||
p.virtual if isinstance(p, PathSpec) else p for p in paths))
|
||||
async def find_provision(accessor: EmailAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> ProvisionResult:
|
||||
return await metadata_provision(
|
||||
accessor, paths, texts,
|
||||
replace(opts, command="find " + " ".join(p.virtual for p in paths)))
|
||||
|
||||
|
||||
@command("find",
|
||||
@@ -63,25 +61,20 @@ async def find_provision(
|
||||
async def find(
|
||||
accessor: EmailAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
name: str | None = None,
|
||||
type: str | None = None,
|
||||
maxdepth: str | None = None,
|
||||
size: str | None = None,
|
||||
mtime: str | None = None,
|
||||
iname: str | None = None,
|
||||
path: str | None = None,
|
||||
mindepth: str | None = None,
|
||||
empty: bool = False,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore,
|
||||
L: bool = False,
|
||||
links: LinkView | None = None,
|
||||
stat_path: StatPath | None = None,
|
||||
**_extra: FlagValue,
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
paths = await resolve_glob(accessor, paths, index)
|
||||
fl = FlagView(opts.flags, spec=SPECS["find"])
|
||||
name = fl.as_str("name")
|
||||
type = fl.as_str("type")
|
||||
maxdepth = fl.as_str("maxdepth")
|
||||
size = fl.as_str("size")
|
||||
mtime = fl.as_str("mtime")
|
||||
iname = fl.as_str("iname")
|
||||
path = fl.as_str("path")
|
||||
mindepth = fl.as_str("mindepth")
|
||||
empty = fl.as_bool("empty")
|
||||
paths = await resolve_glob(accessor, paths, opts.index)
|
||||
# A pure -name search at folder level pushes the subject query down to
|
||||
# IMAP search instead of walking every message; any other predicate
|
||||
# falls through to the local walk so nothing is silently dropped.
|
||||
@@ -92,7 +85,7 @@ async def find(
|
||||
search_prefix = mount_prefix_of(p0.virtual, p0.resource_path)
|
||||
return await _find_server_side(accessor, paths, name, search_prefix)
|
||||
|
||||
args = parse_find_args(texts,
|
||||
args = parse_find_args(tuple(texts),
|
||||
name=name,
|
||||
type=type,
|
||||
size=size,
|
||||
@@ -111,18 +104,18 @@ async def find(
|
||||
# directory has a subtree to walk.
|
||||
start = await resolve_start(search,
|
||||
args,
|
||||
stat_path,
|
||||
is_link=is_link(links, search))
|
||||
opts.stat_path,
|
||||
is_link=is_link(opts.links, search))
|
||||
if not start.walk:
|
||||
results.extend(start.results)
|
||||
continue
|
||||
results.extend(await walk_find(search,
|
||||
readdir=partial(_readdir, accessor),
|
||||
stat=partial(_stat, accessor),
|
||||
index=index,
|
||||
index=opts.index,
|
||||
args=args,
|
||||
links=links,
|
||||
follow=L))
|
||||
links=opts.links,
|
||||
follow=fl.as_bool("L")))
|
||||
return format_records(results), IOResult()
|
||||
|
||||
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from dataclasses import replace
|
||||
|
||||
from mirage.accessor.email import EmailAccessor
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.aggregators import prefix_aggregate
|
||||
from mirage.commands.builtin.email._provision import file_read_provision
|
||||
from mirage.commands.builtin.email.io import resolve_glob
|
||||
@@ -23,9 +24,10 @@ from mirage.commands.builtin.grep_helper import (compile_pattern,
|
||||
grep_count_has_matches,
|
||||
grep_lines, pattern_arg)
|
||||
from mirage.commands.builtin.utils.output import format_records
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.email.read import read as email_read
|
||||
from mirage.core.email.readdir import readdir as _readdir
|
||||
from mirage.core.email.scope import EmailScope, detect_scope
|
||||
@@ -37,18 +39,12 @@ from mirage.types import PathSpec
|
||||
from mirage.utils.key_prefix import mount_prefix_of
|
||||
|
||||
|
||||
async def grep_provision(
|
||||
accessor: EmailAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
index: IndexCacheStore,
|
||||
**_extra: FlagValue,
|
||||
) -> ProvisionResult:
|
||||
return await file_read_provision(
|
||||
accessor,
|
||||
paths,
|
||||
"grep " + " ".join(texts + tuple(str(p) for p in paths)),
|
||||
index=index)
|
||||
async def grep_provision(accessor: EmailAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> ProvisionResult:
|
||||
line = "grep " + " ".join(list(texts) + [str(p) for p in paths])
|
||||
return await file_read_provision(accessor, paths, texts,
|
||||
replace(opts, command=line))
|
||||
|
||||
|
||||
@command("grep",
|
||||
@@ -56,16 +52,10 @@ async def grep_provision(
|
||||
spec=SPECS["grep"],
|
||||
provision=grep_provision,
|
||||
aggregate=prefix_aggregate)
|
||||
async def grep(
|
||||
accessor: EmailAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["grep"])
|
||||
async def grep(accessor: EmailAccessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["grep"])
|
||||
pattern = pattern_arg(texts, fl)
|
||||
|
||||
if paths and pattern is not None and "\n" not in pattern and (
|
||||
@@ -86,16 +76,16 @@ async def grep(
|
||||
o=fl.as_bool("o"),
|
||||
max_count=fl.as_int("m"))
|
||||
|
||||
resolved = await resolve_glob(accessor, paths, index) if paths else []
|
||||
resolved = await resolve_glob(accessor, paths, opts.index) if paths else []
|
||||
return await generic_grep(
|
||||
resolved,
|
||||
texts,
|
||||
flags,
|
||||
readdir=bound_op(_readdir, accessor, index),
|
||||
stat=bound_op(_stat, accessor, index),
|
||||
read_bytes=bound_op(email_read, accessor, index),
|
||||
opts.flags,
|
||||
readdir=bound_op(_readdir, accessor, opts.index),
|
||||
stat=bound_op(_stat, accessor, opts.index),
|
||||
read_bytes=bound_op(email_read, accessor, opts.index),
|
||||
read_stream=None,
|
||||
stdin=stdin,
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.email import EmailAccessor
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.email.io import resolve_glob
|
||||
from mirage.commands.builtin.generic.rg import rg as generic_rg
|
||||
from mirage.commands.builtin.generic_bind.adapter import bound_op
|
||||
@@ -21,10 +20,11 @@ from mirage.commands.builtin.grep_helper import (compile_pattern,
|
||||
grep_count_has_matches,
|
||||
grep_lines, pattern_arg)
|
||||
from mirage.commands.builtin.utils.output import format_records
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.errors import UsageError
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.core.email._client import fetch_message
|
||||
from mirage.core.email.read import read as email_read
|
||||
from mirage.core.email.readdir import readdir as _readdir
|
||||
@@ -38,16 +38,9 @@ from mirage.utils.key_prefix import mount_prefix_of
|
||||
|
||||
|
||||
@command("rg", resource="email", spec=SPECS["rg"])
|
||||
async def rg(
|
||||
accessor: EmailAccessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["rg"])
|
||||
async def rg(accessor: EmailAccessor, paths: list[PathSpec], texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["rg"])
|
||||
pattern_str = pattern_arg(texts, fl)
|
||||
if pattern_str is None:
|
||||
raise UsageError("rg: usage: rg [flags] pattern [path]")
|
||||
@@ -112,14 +105,14 @@ async def rg(
|
||||
return b"", IOResult(exit_code=1)
|
||||
return format_records(all_results), IOResult()
|
||||
|
||||
resolved = await resolve_glob(accessor, paths, index) if paths else []
|
||||
resolved = await resolve_glob(accessor, paths, opts.index) if paths else []
|
||||
return await generic_rg(
|
||||
resolved,
|
||||
texts,
|
||||
flags,
|
||||
readdir=bound_op(_readdir, accessor, index),
|
||||
stat=bound_op(_stat, accessor, index),
|
||||
read_bytes=bound_op(email_read, accessor, index),
|
||||
opts.flags,
|
||||
readdir=bound_op(_readdir, accessor, opts.index),
|
||||
stat=bound_op(_stat, accessor, opts.index),
|
||||
read_bytes=bound_op(email_read, accessor, opts.index),
|
||||
read_stream=None,
|
||||
stdin=stdin,
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
import math
|
||||
from typing import Any
|
||||
|
||||
from mirage.accessor.base import Accessor, NOOPAccessor
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.generic_bind.provision import pure_provision
|
||||
from mirage.commands.builtin.utils.stream import _read_stdin_async
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
@@ -52,14 +53,14 @@ def _eval_bc(expression: str, use_math: bool) -> str:
|
||||
|
||||
@command("bc", resource=None, spec=SPECS["bc"], provision=pure_provision)
|
||||
async def bc(
|
||||
accessor: Accessor = NOOPAccessor(),
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
args_l: bool = False,
|
||||
**_extra: FlagValue,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
raw = await _read_stdin_async(stdin)
|
||||
fl = FlagView(opts.flags, spec=SPECS["bc"])
|
||||
use_math = fl.as_bool("args_l")
|
||||
raw = await _read_stdin_async(opts.stdin)
|
||||
if raw is None:
|
||||
raw = b""
|
||||
lines = raw.decode(errors="replace").strip().splitlines()
|
||||
@@ -67,7 +68,7 @@ async def bc(
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line:
|
||||
results.append(_eval_bc(line, args_l))
|
||||
results.append(_eval_bc(line, use_math))
|
||||
if not results:
|
||||
return b"", IOResult()
|
||||
return ("\n".join(results) + "\n").encode(), IOResult()
|
||||
|
||||
@@ -12,16 +12,15 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from typing import Any, Callable
|
||||
|
||||
from mirage.accessor.base import Accessor, NOOPAccessor
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.utils.http import (HttpConnectError,
|
||||
_http_form_request,
|
||||
_http_request)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.errors import UsageError
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.errors import (WALK_ERRORS, OperationNotSupportedError,
|
||||
@@ -36,13 +35,14 @@ EXIT_HTTP_ERROR = 22
|
||||
EXIT_WRITE = 23
|
||||
|
||||
|
||||
def _resolve_target(o: str | PathSpec, cwd: PathSpec | None) -> PathSpec:
|
||||
def _resolve_target(o: str | PathSpec, cwd: PathSpec | str | None) -> PathSpec:
|
||||
if isinstance(o, PathSpec):
|
||||
return o
|
||||
if o.startswith("/"):
|
||||
path = o
|
||||
else:
|
||||
base = cwd.virtual.rstrip("/") if cwd is not None else ""
|
||||
base = (cwd.virtual if isinstance(cwd, PathSpec) else
|
||||
(cwd or "")).rstrip("/")
|
||||
path = f"{base}/{o}" if base else f"/{o}"
|
||||
last_slash = path.rfind("/")
|
||||
directory = path[:last_slash + 1] if last_slash >= 0 else "/"
|
||||
@@ -54,24 +54,19 @@ def _resolve_target(o: str | PathSpec, cwd: PathSpec | None) -> PathSpec:
|
||||
|
||||
@command("curl", resource=None, spec=SPECS["curl"])
|
||||
async def curl(
|
||||
accessor: Accessor = NOOPAccessor(),
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
H: str | None = None,
|
||||
A: str | None = None,
|
||||
X: str | None = None,
|
||||
d: str | None = None,
|
||||
F: str | None = None,
|
||||
o: PathSpec | str | None = None,
|
||||
L: bool = False,
|
||||
fail: bool = False,
|
||||
s: bool = False,
|
||||
S: bool = False,
|
||||
dispatch: Callable[..., Any] | None = None,
|
||||
cwd: PathSpec | None = None,
|
||||
**_extra: FlagValue,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["curl"])
|
||||
H = fl.as_str("H")
|
||||
A = fl.as_str("A")
|
||||
X = fl.as_str("X")
|
||||
d = fl.as_str("d")
|
||||
F = fl.as_str("F")
|
||||
o = fl.raw("o")
|
||||
L = fl.as_bool("L")
|
||||
headers: dict[str, str] = {}
|
||||
if H:
|
||||
k, _, v = H.partition(":")
|
||||
@@ -84,7 +79,7 @@ async def curl(
|
||||
"curl: try 'curl --help' or 'curl --manual' for more information",
|
||||
exit_code=EXIT_NO_URL)
|
||||
# -s silences the message, -S puts it back. Neither changes the exit code.
|
||||
quiet = s and not S
|
||||
quiet = fl.as_bool("s") and not fl.as_bool("S")
|
||||
try:
|
||||
if F:
|
||||
method = X or "POST"
|
||||
@@ -108,18 +103,18 @@ async def curl(
|
||||
f"{exc.port}: Could not connect to server\n").encode()
|
||||
return None, IOResult(exit_code=EXIT_CONNECT, stderr=err)
|
||||
# Only -f makes an error status an error, and then nothing is written.
|
||||
if fail and resp.is_error:
|
||||
if fl.as_bool("fail") and resp.is_error:
|
||||
err = b"" if quiet else (
|
||||
f"curl: ({EXIT_HTTP_ERROR}) The requested URL returned error: "
|
||||
f"{resp.status}\n").encode()
|
||||
return None, IOResult(exit_code=EXIT_HTTP_ERROR, stderr=err)
|
||||
result = resp.body
|
||||
if o is not None:
|
||||
if isinstance(o, (PathSpec, str)):
|
||||
o_str = o.virtual if isinstance(o, PathSpec) else o
|
||||
if dispatch is not None:
|
||||
scope = _resolve_target(o, cwd)
|
||||
if opts.dispatch is not None:
|
||||
scope = _resolve_target(o, opts.cwd)
|
||||
try:
|
||||
await dispatch("write", scope, data=result)
|
||||
await opts.dispatch("write", scope, data=result)
|
||||
# WALK_ERRORS is the shared recoverable set (every filesystem error
|
||||
# plus the ValueError store backends raise for "not a directory"),
|
||||
# so a missing parent cannot escape the way it did when this caught
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
import email.utils
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from mirage.accessor.base import Accessor, NOOPAccessor
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.generic_bind.provision import pure_provision
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import CommandName, FlagValue
|
||||
from mirage.commands.spec.types import CommandName, FlagView
|
||||
from mirage.commands.spec.usage import extra_operand_error
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
@@ -27,16 +28,14 @@ from mirage.types import PathSpec
|
||||
|
||||
@command("date", resource=None, spec=SPECS["date"], provision=pure_provision)
|
||||
async def date(
|
||||
accessor: Accessor = NOOPAccessor(),
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
u: bool = False,
|
||||
d: str | None = None,
|
||||
args_I: bool = False,
|
||||
R: bool = False,
|
||||
**_extra: FlagValue,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["date"])
|
||||
u = fl.as_bool("u")
|
||||
d = fl.as_str("d")
|
||||
if len(texts) > 1:
|
||||
raise extra_operand_error(CommandName.DATE, texts[1])
|
||||
if d is not None:
|
||||
@@ -52,9 +51,9 @@ async def date(
|
||||
if t.startswith("+"):
|
||||
fmt = t[1:]
|
||||
break
|
||||
if args_I:
|
||||
if fl.as_bool("args_I"):
|
||||
result = dt.strftime("%Y-%m-%d")
|
||||
elif R:
|
||||
elif fl.as_bool("R"):
|
||||
result = email.utils.format_datetime(dt)
|
||||
elif fmt is not None:
|
||||
result = dt.strftime(fmt)
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
|
||||
import re
|
||||
|
||||
from mirage.accessor.base import Accessor, NOOPAccessor
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.generic_bind.provision import pure_provision
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
def _expr_eval(args: tuple[str, ...]) -> tuple[str, int]:
|
||||
def _expr_eval(args: list[str]) -> tuple[str, int]:
|
||||
if len(args) == 3 and args[1] == ":":
|
||||
pattern = args[2]
|
||||
m = re.match(pattern, args[0])
|
||||
@@ -86,13 +86,9 @@ def _expr_eval(args: tuple[str, ...]) -> tuple[str, int]:
|
||||
|
||||
|
||||
@command("expr", resource=None, spec=SPECS["expr"], provision=pure_provision)
|
||||
async def expr(
|
||||
accessor: Accessor = NOOPAccessor(),
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
**_extra: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def expr(accessor: Accessor, paths: list[PathSpec] | None,
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not texts:
|
||||
return b"\n", IOResult(exit_code=2)
|
||||
result, exit_code = _expr_eval(texts)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Callable, Literal, TypeAlias
|
||||
from typing import Any, Literal, TypeAlias
|
||||
|
||||
from mirage.commands.builtin.utils.paths import resolve_script
|
||||
from mirage.commands.builtin.utils.stream import _read_stdin_async
|
||||
@@ -21,7 +21,7 @@ from mirage.io.types import ByteSource, CommandOutput, IOResult
|
||||
from mirage.runtime.base import Runtime
|
||||
from mirage.runtime.language import LanguageRuntime
|
||||
from mirage.runtime.python.base import PythonRuntime
|
||||
from mirage.runtime.types import RunArgs, RunResult
|
||||
from mirage.runtime.types import DispatchFn, RunArgs, RunResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
@@ -159,11 +159,11 @@ class Source:
|
||||
async def resolve_source(
|
||||
label: str,
|
||||
paths: list[PathSpec] | None,
|
||||
texts: tuple[str, ...],
|
||||
texts: list[str],
|
||||
payload: str | None,
|
||||
stdin: ByteSource | None,
|
||||
dispatch: Callable[..., Any] | None,
|
||||
cwd: PathSpec | None,
|
||||
dispatch: DispatchFn | None,
|
||||
cwd: PathSpec | str | None,
|
||||
exec_allowed: bool,
|
||||
module: str | None = None,
|
||||
argv0_rules: Argv0Rules = Argv0Rules(),
|
||||
@@ -179,12 +179,13 @@ async def resolve_source(
|
||||
Args:
|
||||
label (str): the command name used in error messages.
|
||||
paths (list[PathSpec] | None): positional path operands.
|
||||
texts (tuple[str, ...]): positional text operands.
|
||||
texts (list[str]): positional text operands.
|
||||
payload (str | None): the -c/-e flag value, if given.
|
||||
stdin (ByteSource | None): piped stdin.
|
||||
dispatch (Callable[..., Any] | None): workspace dispatch for
|
||||
dispatch (DispatchFn | None): workspace dispatch for
|
||||
reading the script operand.
|
||||
cwd (PathSpec | None): the session cwd for script resolution.
|
||||
cwd (PathSpec | str | None): the session cwd for script
|
||||
resolution, as ``CommandOpts.cwd`` carries it.
|
||||
exec_allowed (bool): whether the root mount is in EXEC mode.
|
||||
module (str | None): the -m module name, if given.
|
||||
argv0_rules (Argv0Rules): what this interpreter calls itself in
|
||||
|
||||
@@ -12,43 +12,35 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from typing import Any, Callable
|
||||
|
||||
from mirage.accessor.base import Accessor, NOOPAccessor
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.general.interpreter import (resolve_source,
|
||||
run_code)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, CommandOutput
|
||||
from mirage.runtime.base import Runtime
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import CommandOutput
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def _js(
|
||||
accessor: Accessor = NOOPAccessor(),
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
e: str | None = None,
|
||||
module: bool = False,
|
||||
stdin: ByteSource | None = None,
|
||||
dispatch: Callable[..., Any] | None = None,
|
||||
cwd: PathSpec | None = None,
|
||||
env: dict[str, str] | None = None,
|
||||
exec_allowed: bool = True,
|
||||
runtime: Runtime | None = None,
|
||||
runtime_unavailable: str | None = None,
|
||||
**_extra: FlagValue,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> CommandOutput:
|
||||
error, prepared = await resolve_source("js", paths, texts, e, stdin,
|
||||
dispatch, cwd, exec_allowed)
|
||||
fl = FlagView(opts.flags, spec=SPECS["js"])
|
||||
error, prepared = await resolve_source("js", paths, texts, fl.as_str("e"),
|
||||
opts.stdin, opts.dispatch, opts.cwd,
|
||||
opts.exec_allowed)
|
||||
if error is not None or prepared is None:
|
||||
assert error is not None
|
||||
return error
|
||||
as_module = module or (prepared.script_path is not None
|
||||
and prepared.script_path.virtual.endswith(".mjs"))
|
||||
return await run_code("js", prepared, env, {"module": as_module}, runtime,
|
||||
runtime_unavailable)
|
||||
as_module = fl.as_bool("module") or (
|
||||
prepared.script_path is not None
|
||||
and prepared.script_path.virtual.endswith(".mjs"))
|
||||
return await run_code("js", prepared, opts.env, {"module": as_module},
|
||||
opts.runtime, opts.runtime_unavailable)
|
||||
|
||||
|
||||
js = command("js", resource=None, spec=SPECS["js"])(_js)
|
||||
|
||||
@@ -12,52 +12,33 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from typing import Any, Callable
|
||||
from typing import Any
|
||||
|
||||
from mirage.accessor.base import Accessor, NOOPAccessor
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.general.interpreter import (CPYTHON_ARGV0,
|
||||
resolve_source,
|
||||
run_code)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, CommandOutput
|
||||
from mirage.runtime.base import Runtime
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import CommandOutput
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def _python3(
|
||||
accessor: Accessor = NOOPAccessor(),
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
c: str | None = None,
|
||||
m: str | None = None,
|
||||
u: bool = False,
|
||||
q: bool = False,
|
||||
b: int = 0,
|
||||
B: bool = False,
|
||||
E: bool = False,
|
||||
P: bool = False,
|
||||
s: bool = False,
|
||||
S: bool = False,
|
||||
x: bool = False,
|
||||
args_I: bool = False,
|
||||
args_O: int = 0,
|
||||
W: list[str] | None = None,
|
||||
X: list[str] | None = None,
|
||||
check_hash_based_pycs: str | None = None,
|
||||
stdin: ByteSource | None = None,
|
||||
dispatch: Callable[..., Any] | None = None,
|
||||
cwd: PathSpec | None = None,
|
||||
env: dict[str, str] | None = None,
|
||||
exec_allowed: bool = True,
|
||||
runtime: Runtime | None = None,
|
||||
runtime_unavailable: str | None = None,
|
||||
**_extra: FlagValue,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> CommandOutput:
|
||||
error, prepared = await resolve_source("python3", paths, texts, c, stdin,
|
||||
dispatch, cwd, exec_allowed, m,
|
||||
CPYTHON_ARGV0, x)
|
||||
fl = FlagView(opts.flags, spec=SPECS["python3"])
|
||||
error, prepared = await resolve_source("python3", paths, texts,
|
||||
fl.as_str("c"), opts.stdin,
|
||||
opts.dispatch,
|
||||
opts.cwd, opts.exec_allowed,
|
||||
fl.as_str("m"), CPYTHON_ARGV0,
|
||||
fl.as_bool("x"))
|
||||
if error is not None or prepared is None:
|
||||
assert error is not None
|
||||
return error
|
||||
@@ -69,20 +50,20 @@ async def _python3(
|
||||
# than configuring an interpreter, so resolve_source answered it
|
||||
# above.
|
||||
init_flags: dict[str, Any] = {
|
||||
"b": b,
|
||||
"B": B,
|
||||
"E": E,
|
||||
"I": args_I,
|
||||
"O": args_O,
|
||||
"P": P,
|
||||
"s": s,
|
||||
"S": S,
|
||||
"W": W or [],
|
||||
"X": X or [],
|
||||
"check_hash_based_pycs": check_hash_based_pycs,
|
||||
"b": fl.as_int("b") or 0,
|
||||
"B": fl.as_bool("B"),
|
||||
"E": fl.as_bool("E"),
|
||||
"I": fl.as_bool("args_I"),
|
||||
"O": fl.as_int("args_O") or 0,
|
||||
"P": fl.as_bool("P"),
|
||||
"s": fl.as_bool("s"),
|
||||
"S": fl.as_bool("S"),
|
||||
"W": fl.as_list("W"),
|
||||
"X": fl.as_list("X"),
|
||||
"check_hash_based_pycs": fl.as_str("check_hash_based_pycs"),
|
||||
}
|
||||
return await run_code("python3", prepared, env, init_flags, runtime,
|
||||
runtime_unavailable)
|
||||
return await run_code("python3", prepared, opts.env, init_flags,
|
||||
opts.runtime, opts.runtime_unavailable)
|
||||
|
||||
|
||||
python3 = command("python3", resource=None, spec=SPECS["python3"])(_python3)
|
||||
|
||||
@@ -12,17 +12,18 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor, NOOPAccessor
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.generic_bind.provision import pure_provision
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import CommandName, FlagValue
|
||||
from mirage.commands.spec.types import CommandName, FlagView
|
||||
from mirage.commands.spec.usage import extra_operand_error
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
def _seq_generate(texts: tuple[str, ...], separator: str, width: bool,
|
||||
def _seq_generate(texts: list[str], separator: str, width: bool,
|
||||
fmt: str | None) -> str:
|
||||
nums = [float(t) for t in texts]
|
||||
if len(nums) == 1:
|
||||
@@ -53,17 +54,15 @@ def _seq_generate(texts: tuple[str, ...], separator: str, width: bool,
|
||||
|
||||
@command("seq", resource=None, spec=SPECS["seq"], provision=pure_provision)
|
||||
async def seq(
|
||||
accessor: Accessor = NOOPAccessor(),
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
s: str | None = None,
|
||||
w: bool = False,
|
||||
f: str | None = None,
|
||||
**_extra: FlagValue,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["seq"])
|
||||
if len(texts) > 3:
|
||||
raise extra_operand_error(CommandName.SEQ, texts[3])
|
||||
separator = s if s is not None else "\n"
|
||||
result = _seq_generate(texts, separator, w, f)
|
||||
sep = fl.as_str("s")
|
||||
separator = sep if sep is not None else "\n"
|
||||
result = _seq_generate(texts, separator, fl.as_bool("w"), fl.as_str("f"))
|
||||
return result.encode(), IOResult()
|
||||
|
||||
@@ -12,15 +12,14 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from typing import Any, Callable
|
||||
|
||||
from mirage.accessor.base import Accessor, NOOPAccessor
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.general.curl import _resolve_target
|
||||
from mirage.commands.builtin.utils.http import HttpConnectError, _http_get
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.errors import UsageError
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.errors import WALK_ERRORS
|
||||
@@ -40,17 +39,16 @@ USAGE = ("wget: missing URL\n"
|
||||
|
||||
@command("wget", resource=None, spec=SPECS["wget"])
|
||||
async def wget(
|
||||
accessor: Accessor = NOOPAccessor(),
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
args_O: str | None = None,
|
||||
q: bool = False,
|
||||
spider: bool = False,
|
||||
dispatch: Callable[..., Any] | None = None,
|
||||
cwd: PathSpec | None = None,
|
||||
**_extra: FlagValue,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["wget"])
|
||||
args_O = fl.raw("args_O")
|
||||
q = fl.as_bool("q")
|
||||
spider = fl.as_bool("spider")
|
||||
dispatch = opts.dispatch
|
||||
if not texts:
|
||||
raise UsageError(USAGE, exit_code=EXIT_GENERIC)
|
||||
url = texts[0]
|
||||
@@ -74,7 +72,7 @@ async def wget(
|
||||
return None, IOResult(stderr=err)
|
||||
|
||||
dest_raw: str | PathSpec
|
||||
if args_O:
|
||||
if isinstance(args_O, (str, PathSpec)) and args_O:
|
||||
dest_raw = args_O
|
||||
elif paths:
|
||||
dest_raw = paths[0]
|
||||
@@ -86,7 +84,7 @@ async def wget(
|
||||
# truncates the -O target before it learns the response code.
|
||||
data = b"" if resp.is_error else resp.body
|
||||
if dispatch is not None:
|
||||
scope = _resolve_target(dest_raw, cwd)
|
||||
scope = _resolve_target(dest_raw, opts.cwd)
|
||||
try:
|
||||
await dispatch("write", scope, data=data)
|
||||
# WALK_ERRORS is the shared recoverable set (every filesystem error
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import functools
|
||||
from typing import Any, Callable
|
||||
|
||||
from mirage.commands.builtin.generic.cmp import cmp_cmd as generic_cmp
|
||||
from mirage.commands.builtin.generic.crossmount.types import CrossResult
|
||||
from mirage.commands.builtin.generic.crossmount.utils import flat_scopes, relay
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def run_cmp(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any]) -> CrossResult:
|
||||
dispatch: DispatchFn) -> CrossResult:
|
||||
"""Byte-compare two files on different mounts via the shared generic.
|
||||
|
||||
Pure wiring: both sides are read through dispatch-relayed primitives.
|
||||
@@ -32,7 +32,7 @@ async def run_cmp(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
Args:
|
||||
scopes (list[PathSpec]): The two path operands.
|
||||
flag_kwargs (dict): Flags parsed against the shared cmp spec.
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
"""
|
||||
fl = FlagView(flag_kwargs, spec=SPECS["cmp"])
|
||||
limit = fl.as_str("n")
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import functools
|
||||
from typing import Any, Callable
|
||||
|
||||
from mirage.commands.builtin.generic.comm import comm as generic_comm
|
||||
from mirage.commands.builtin.generic.crossmount.types import CrossResult
|
||||
from mirage.commands.builtin.generic.crossmount.utils import flat_scopes, relay
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def run_comm(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any]) -> CrossResult:
|
||||
dispatch: DispatchFn) -> CrossResult:
|
||||
"""Compare two sorted files on different mounts via the generic comm.
|
||||
|
||||
Pure wiring: both sides are read through dispatch-relayed primitives
|
||||
@@ -33,7 +33,7 @@ async def run_comm(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
Args:
|
||||
scopes (list[PathSpec]): The two path operands.
|
||||
flag_kwargs (dict): Flags parsed against the shared comm spec.
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
"""
|
||||
fl = FlagView(flag_kwargs, spec=SPECS["comm"])
|
||||
return await generic_comm(flat_scopes(scopes),
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from typing import Any, Callable
|
||||
from typing import Callable
|
||||
|
||||
from mirage.commands.builtin.generic.cp import cp as generic_cp
|
||||
from mirage.commands.builtin.generic.cp import parse_cp_flags
|
||||
@@ -21,13 +21,14 @@ from mirage.commands.builtin.generic.crossmount.utils import (
|
||||
flat_scopes, transfer_primitives)
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec, PrimitiveCopy
|
||||
|
||||
|
||||
async def run_cp(
|
||||
scopes: list[PathSpec],
|
||||
flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any],
|
||||
dispatch: DispatchFn,
|
||||
storage_key: Callable[[PathSpec], str] | None = None) -> CrossResult:
|
||||
"""Copy operands that span mounts via the shared generic cp.
|
||||
|
||||
@@ -38,7 +39,7 @@ async def run_cp(
|
||||
Args:
|
||||
scopes (list[PathSpec]): Path operands in command-line order.
|
||||
flag_kwargs (dict): Flags parsed against the shared cp spec.
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
storage_key (Callable | None): Maps an operand to its storage
|
||||
identity so two prefixes over one store compare equal.
|
||||
"""
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import functools
|
||||
from typing import Any, Callable
|
||||
|
||||
from mirage.commands.builtin.generic.crossmount.types import CrossResult
|
||||
from mirage.commands.builtin.generic.crossmount.utils import flat_scopes, relay
|
||||
from mirage.commands.builtin.generic.diff import diff as generic_diff
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def run_diff(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any]) -> CrossResult:
|
||||
dispatch: DispatchFn) -> CrossResult:
|
||||
"""Diff two files on different mounts via the shared generic diff.
|
||||
|
||||
Pure wiring: both sides are read through dispatch-relayed primitives.
|
||||
@@ -32,7 +32,7 @@ async def run_diff(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
Args:
|
||||
scopes (list[PathSpec]): The two path operands.
|
||||
flag_kwargs (dict): Flags parsed against the shared diff spec.
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
"""
|
||||
p = functools.partial
|
||||
fl = FlagView(flag_kwargs, spec=SPECS["diff"])
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import functools
|
||||
from typing import Any, Callable
|
||||
|
||||
from mirage.commands.builtin.generic.crossmount.types import CrossResult
|
||||
from mirage.commands.builtin.generic.crossmount.utils import flat_scopes, relay
|
||||
from mirage.commands.builtin.generic.join import join_cmd as generic_join
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def run_join(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any]) -> CrossResult:
|
||||
dispatch: DispatchFn) -> CrossResult:
|
||||
"""Join two files on different mounts via the shared generic join.
|
||||
|
||||
Pure wiring: both sides are read through dispatch-relayed primitives
|
||||
@@ -33,7 +33,7 @@ async def run_join(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
Args:
|
||||
scopes (list[PathSpec]): The two path operands.
|
||||
flag_kwargs (dict): Flags parsed against the shared join spec.
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
"""
|
||||
fl = FlagView(flag_kwargs, spec=SPECS["join"])
|
||||
field1 = fl.as_str("args_1")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import functools
|
||||
from typing import Any, Callable
|
||||
from typing import Callable
|
||||
|
||||
from mirage.commands.builtin.generic.crossmount.types import CrossResult
|
||||
from mirage.commands.builtin.generic.crossmount.utils import (
|
||||
@@ -22,13 +22,14 @@ from mirage.commands.builtin.generic.mv import mv as generic_mv
|
||||
from mirage.commands.builtin.generic.mv import parse_mv_flags
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec, PrimitiveMove
|
||||
|
||||
|
||||
async def run_mv(
|
||||
scopes: list[PathSpec],
|
||||
flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any],
|
||||
dispatch: DispatchFn,
|
||||
storage_key: Callable[[PathSpec], str] | None = None) -> CrossResult:
|
||||
"""Move operands that span mounts via the shared generic mv.
|
||||
|
||||
@@ -38,7 +39,7 @@ async def run_mv(
|
||||
Args:
|
||||
scopes (list[PathSpec]): Path operands in command-line order.
|
||||
flag_kwargs (dict): Flags parsed against the shared mv spec.
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
storage_key (Callable | None): Maps an operand to its storage
|
||||
identity. Without it a move between two prefixes over one
|
||||
store would copy the object onto itself and then unlink the
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import functools
|
||||
from typing import Any, Callable
|
||||
|
||||
from mirage.commands.builtin.generic.crossmount.types import CrossResult
|
||||
from mirage.commands.builtin.generic.crossmount.utils import flat_scopes, relay
|
||||
from mirage.commands.builtin.generic.paste import paste as generic_paste
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def run_paste(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any]) -> CrossResult:
|
||||
dispatch: DispatchFn) -> CrossResult:
|
||||
"""Paste files on different mounts via the shared generic paste.
|
||||
|
||||
Pure wiring: every operand is read through dispatch-relayed
|
||||
@@ -33,7 +33,7 @@ async def run_paste(scopes: list[PathSpec], flag_kwargs: dict[str, FlagValue],
|
||||
Args:
|
||||
scopes (list[PathSpec]): Path operands in command-line order.
|
||||
flag_kwargs (dict): Flags parsed against the shared paste spec.
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
"""
|
||||
fl = FlagView(flag_kwargs, spec=SPECS["paste"])
|
||||
d = fl.as_str("delimiters")
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from typing import Any, Callable
|
||||
from typing import Callable
|
||||
|
||||
from mirage.commands.builtin.generic.crossmount.relay.cmp import run_cmp
|
||||
from mirage.commands.builtin.generic.crossmount.relay.comm import run_comm
|
||||
@@ -23,6 +23,7 @@ from mirage.commands.builtin.generic.crossmount.relay.mv import run_mv
|
||||
from mirage.commands.builtin.generic.crossmount.relay.paste import run_paste
|
||||
from mirage.commands.builtin.generic.crossmount.types import Cmd, CrossResult
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
@@ -30,7 +31,7 @@ async def run_relay(
|
||||
cmd_name: str,
|
||||
scopes: list[PathSpec],
|
||||
flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any],
|
||||
dispatch: DispatchFn,
|
||||
storage_key: Callable[[PathSpec], str] | None = None) -> CrossResult:
|
||||
"""Run a command whose data must colocate across mounts.
|
||||
|
||||
@@ -42,7 +43,7 @@ async def run_relay(
|
||||
cmd_name (str): One of cp, mv, diff, cmp, paste, comm, join.
|
||||
scopes (list[PathSpec]): Path operands in command-line order.
|
||||
flag_kwargs (dict): Flags parsed against the shared command spec.
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
storage_key (Callable | None): Maps an operand to its storage
|
||||
identity, for the transfer commands that must tell a real
|
||||
move from one whose two prefixes address a single store.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from typing import Any, Callable
|
||||
from typing import Callable
|
||||
|
||||
from mirage.commands.builtin.generic.crossmount.detect import strategy_for
|
||||
from mirage.commands.builtin.generic.crossmount.fanout import run_fanout
|
||||
@@ -24,6 +24,7 @@ from mirage.commands.builtin.generic.crossmount.types import (CrossResult,
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io import IOResult
|
||||
from mirage.io.types import ByteSource
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.errors import FS_ERRORS, format_fs_error
|
||||
|
||||
@@ -33,7 +34,7 @@ async def handle_cross_mount(
|
||||
scopes: list[PathSpec],
|
||||
text_args: list[str],
|
||||
flag_kwargs: dict[str, FlagValue],
|
||||
dispatch: Callable[..., Any],
|
||||
dispatch: DispatchFn,
|
||||
run_single: RunSingle,
|
||||
stdin: ByteSource | None = None,
|
||||
storage_key: Callable[[PathSpec], str] | None = None,
|
||||
@@ -54,7 +55,7 @@ async def handle_cross_mount(
|
||||
text_args (list[str]): Positional text operands (grep pattern,
|
||||
find expression).
|
||||
flag_kwargs (dict): Flags parsed from the shared command spec.
|
||||
dispatch (Callable): Workspace operation dispatcher (RELAY).
|
||||
dispatch (DispatchFn): Workspace operation dispatcher (RELAY).
|
||||
run_single (RunSingle): Executor-injected single-mount runner
|
||||
(STREAM and FANOUT).
|
||||
stdin (ByteSource | None): Original stdin (tee re-feeds it per
|
||||
|
||||
@@ -14,18 +14,19 @@
|
||||
|
||||
import dataclasses
|
||||
import functools
|
||||
from typing import Any, Callable
|
||||
from typing import Any
|
||||
|
||||
from mirage.commands.builtin.generic.crossmount.types import (OperandRun,
|
||||
RunSingle)
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io import IOResult
|
||||
from mirage.io.stream import materialize
|
||||
from mirage.runtime.types import DispatchFn
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.errors import FS_ERRORS, fs_error_line
|
||||
|
||||
|
||||
async def relay(dispatch: Callable[..., Any], name: str, path: PathSpec,
|
||||
async def relay(dispatch: DispatchFn, name: str, path: PathSpec,
|
||||
**kwargs: Any) -> Any:
|
||||
# Relay one op for one path to the mount that owns it. The generics call
|
||||
# ops as (path); dispatch keys off the path.
|
||||
@@ -98,11 +99,11 @@ def flat_scopes(scopes: list[PathSpec]) -> list[PathSpec]:
|
||||
]
|
||||
|
||||
|
||||
def transfer_primitives(dispatch: Callable[..., Any]) -> dict[str, Any]:
|
||||
def transfer_primitives(dispatch: DispatchFn) -> dict[str, Any]:
|
||||
"""Dispatch-relayed primitives shared by the transfer generics (cp/mv).
|
||||
|
||||
Args:
|
||||
dispatch (Callable): Workspace operation dispatcher.
|
||||
dispatch (DispatchFn): Workspace operation dispatcher.
|
||||
"""
|
||||
p = functools.partial
|
||||
return dict(
|
||||
|
||||
@@ -35,7 +35,7 @@ def _split_by_patterns(
|
||||
|
||||
async def csplit(
|
||||
paths: list[PathSpec],
|
||||
patterns: tuple[str, ...],
|
||||
patterns: list[str],
|
||||
*,
|
||||
read_bytes: Callable[..., Awaitable[bytes]],
|
||||
write_bytes: Callable[..., Awaitable[None]],
|
||||
|
||||
@@ -587,8 +587,6 @@ async def du_generic(
|
||||
compute_size: ComputeSize,
|
||||
compute_entries: ComputeEntries,
|
||||
truncated: Callable[[], bool] | None = None,
|
||||
links: LinkView | None = None,
|
||||
mounts: MountView | None = None,
|
||||
) -> tuple[bytes, IOResult]:
|
||||
"""Run du over the given operands; mirrors duGeneric.
|
||||
|
||||
@@ -609,8 +607,6 @@ async def du_generic(
|
||||
compute_size (ComputeSize): Recursive byte size of one operand.
|
||||
compute_entries (ComputeEntries): Per-file breakdown.
|
||||
truncated (Callable[[], bool] | None): Whether the walk was cut.
|
||||
links (LinkView | None): The namespace's symlink facts.
|
||||
mounts (MountView | None): Mounts nested under this one.
|
||||
"""
|
||||
fl = FlagView(opts.flags, spec=SPECS["du"])
|
||||
out = await run_du(
|
||||
@@ -626,7 +622,7 @@ async def du_generic(
|
||||
c=fl.as_bool("c"),
|
||||
max_depth=fl.as_str("max_depth"),
|
||||
truncated=truncated,
|
||||
links=None if fl.as_bool("L") else links,
|
||||
mounts=mounts,
|
||||
links=None if fl.as_bool("L") else opts.links,
|
||||
mounts=opts.mounts,
|
||||
)
|
||||
return out.stdout, IOResult(stderr=out.stderr, exit_code=out.exit_code)
|
||||
|
||||
@@ -107,16 +107,11 @@ def parse_flags(flags: Mapping[str, FlagValue]) -> FileFlags:
|
||||
return FileFlags(brief=fl.as_bool("b"), mime=fl.as_bool("i"))
|
||||
|
||||
|
||||
async def file_generic(paths,
|
||||
texts,
|
||||
opts: CommandOpts,
|
||||
read_bytes,
|
||||
stat_fn,
|
||||
links=None):
|
||||
async def file_generic(paths, texts, opts: CommandOpts, read_bytes, stat_fn):
|
||||
parsed = parse_flags(opts.flags)
|
||||
return await file_cmd(paths,
|
||||
read_bytes=read_bytes,
|
||||
stat_fn=stat_fn,
|
||||
b=parsed.brief,
|
||||
i=parsed.mime,
|
||||
links=links)
|
||||
links=opts.links)
|
||||
|
||||
@@ -809,29 +809,26 @@ async def find_generic(
|
||||
*,
|
||||
find_core: Callable[..., Awaitable[list[str]]],
|
||||
stat: Callable[[PathSpec], Awaitable[FileStat]] | None = None,
|
||||
stat_path: StatPath | None = None,
|
||||
dir_empty: Callable[[PathSpec], Awaitable[bool]] | None = None,
|
||||
links: LinkView | None = None,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
"""Run find through a backend's native op; mirrors findGeneric.
|
||||
|
||||
Args:
|
||||
paths (list[PathSpec]): Glob-resolved start points.
|
||||
texts (list[str]): The raw expression words.
|
||||
opts (CommandOpts): Flags from the dispatcher.
|
||||
opts (CommandOpts): Flags and namespace facts (stat_path, links)
|
||||
from the dispatcher.
|
||||
find_core (Callable): The backend's native find op, bound.
|
||||
stat (Callable | None): Bound overlaid stat, when the backend
|
||||
serves local stats cheaply.
|
||||
stat_path (StatPath | None): Dispatcher-backed stat of one path.
|
||||
dir_empty (Callable | None): Whether a directory start point is
|
||||
empty, for ``-empty``.
|
||||
links (LinkView | None): The namespace's symlink facts.
|
||||
"""
|
||||
parsed = parse_flags(opts.flags)
|
||||
return await find(paths,
|
||||
tuple(texts),
|
||||
find_core=find_core,
|
||||
stat_path=stat_path,
|
||||
stat_path=opts.stat_path,
|
||||
stat=stat,
|
||||
dir_empty=dir_empty,
|
||||
name=parsed.name,
|
||||
@@ -843,7 +840,7 @@ async def find_generic(
|
||||
path=parsed.path,
|
||||
mindepth=parsed.mindepth,
|
||||
empty=parsed.empty,
|
||||
links=links,
|
||||
links=opts.links,
|
||||
follow=parsed.follow)
|
||||
|
||||
|
||||
@@ -854,9 +851,6 @@ async def find_walk_generic(
|
||||
*,
|
||||
readdir: Callable[..., Awaitable[list[str]]],
|
||||
stat: Callable[..., Awaitable[FileStat]],
|
||||
index: IndexCacheStore,
|
||||
stat_path: StatPath | None = None,
|
||||
links: LinkView | None = None,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
"""Run find by walking readdir/stat; the no-native-op twin.
|
||||
|
||||
@@ -867,14 +861,14 @@ async def find_walk_generic(
|
||||
Args:
|
||||
paths (list[PathSpec]): Glob-resolved start points.
|
||||
texts (list[str]): The raw expression words.
|
||||
opts (CommandOpts): Flags from the dispatcher.
|
||||
opts (CommandOpts): Flags, the index for the walk, and namespace
|
||||
facts (stat_path, links) from the dispatcher.
|
||||
readdir (Callable): Bound readdir called as ``readdir(p, index)``.
|
||||
stat (Callable): Bound overlaid stat called as ``stat(p, index)``.
|
||||
index (IndexCacheStore): Index cache store for the walk.
|
||||
stat_path (StatPath | None): Dispatcher-backed stat of one path.
|
||||
links (LinkView | None): The namespace's symlink facts.
|
||||
"""
|
||||
parsed = parse_flags(opts.flags)
|
||||
stat_path = opts.stat_path
|
||||
links = opts.links
|
||||
searches = paths if paths else [
|
||||
PathSpec(virtual="/", directory="/", resource_path="")
|
||||
]
|
||||
@@ -907,7 +901,7 @@ async def find_walk_generic(
|
||||
walked = await walk_find(search,
|
||||
readdir=readdir,
|
||||
stat=stat,
|
||||
index=index,
|
||||
index=opts.index,
|
||||
args=args,
|
||||
links=links,
|
||||
follow=parsed.follow)
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import Any
|
||||
|
||||
import orjson
|
||||
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.errors import UsageError
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
@@ -221,6 +222,26 @@ async def _read_stdin_bytes(stdin: ByteSource | None) -> bytes:
|
||||
return raw
|
||||
|
||||
|
||||
async def jq_generic(
|
||||
paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
read_bytes: Callable[..., Awaitable[bytes]],
|
||||
read_stream: Callable[..., AsyncIterator[bytes]],
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
"""Full-command jq entry; mirrors jqGeneric's (paths, texts, opts).
|
||||
|
||||
The kwargs core below keeps the historical shape; this entry is the
|
||||
dispatcher-facing seam so the builder stays wiring.
|
||||
"""
|
||||
return await jq(paths,
|
||||
*texts,
|
||||
read_bytes=read_bytes,
|
||||
read_stream=read_stream,
|
||||
stdin=opts.stdin,
|
||||
**opts.flags)
|
||||
|
||||
|
||||
async def jq(
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
|
||||
@@ -685,25 +685,21 @@ async def ls_generic(
|
||||
opts: CommandOpts,
|
||||
readdir: Readdir,
|
||||
stat: Stat,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
links: LinkView | None = None,
|
||||
child_mounts: ChildMounts | None = None,
|
||||
) -> tuple[bytes, IOResult]:
|
||||
"""Run ls over resolved operands, GNU semantics; mirrors lsGeneric.
|
||||
|
||||
The wiring resolves globs, defaults the operands from the cwd, and
|
||||
binds the backend ops (including the stat overlay); flag semantics
|
||||
live here.
|
||||
live here, and the namespace facts (links, child mounts) and index
|
||||
ride ``opts``.
|
||||
|
||||
Args:
|
||||
paths (list[PathSpec]): Glob-resolved operands, cwd-defaulted.
|
||||
texts (list[str]): Non-path words, unused by ls.
|
||||
opts (CommandOpts): Flags from the dispatcher.
|
||||
opts (CommandOpts): Flags and namespace facts from the
|
||||
dispatcher.
|
||||
readdir (Readdir): Bound readdir called as ``readdir(p, index)``.
|
||||
stat (Stat): Bound (overlaid) stat called as ``stat(p, index)``.
|
||||
index (IndexCacheStore): Index cache store for the walk.
|
||||
links (LinkView | None): The namespace's symlink facts.
|
||||
child_mounts (ChildMounts | None): Mounts nested under this one.
|
||||
"""
|
||||
parsed = parse_flags(opts.flags)
|
||||
return await ls(paths,
|
||||
@@ -718,10 +714,10 @@ async def ls_generic(
|
||||
recursive=parsed.recursive,
|
||||
list_dir=parsed.list_dir,
|
||||
classify=parsed.classify,
|
||||
index=index,
|
||||
links=links,
|
||||
index=opts.index,
|
||||
links=opts.links,
|
||||
deref=parsed.deref,
|
||||
child_mounts=child_mounts)
|
||||
child_mounts=opts.child_mounts)
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
@@ -16,11 +16,11 @@ from collections.abc import Awaitable, Callable
|
||||
from typing import Any
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.utils.output import format_optional_records
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.registry import command
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.errors import FS_ERRORS, fs_strerror
|
||||
@@ -49,21 +49,21 @@ def make_rm(
|
||||
async def rm(
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
f: bool = False,
|
||||
v: bool = False,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**_extra: FlagValue,
|
||||
texts: list[str],
|
||||
opts: CommandOpts,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
if not paths:
|
||||
raise ValueError("rm: missing operand")
|
||||
paths = await glob_fn(accessor, paths, index)
|
||||
fl = FlagView(opts.flags, spec=SPECS["rm"])
|
||||
f = fl.as_bool("f")
|
||||
v = fl.as_bool("v")
|
||||
paths = await glob_fn(accessor, paths, opts.index)
|
||||
verbose_parts: list[str] = []
|
||||
errors: list[str] = []
|
||||
removed: dict[str, ByteSource] = {}
|
||||
for p in paths:
|
||||
try:
|
||||
await unlink(accessor, p, index)
|
||||
await unlink(accessor, p, opts.index)
|
||||
except FS_ERRORS as exc:
|
||||
if f and isinstance(exc, FileNotFoundError):
|
||||
continue
|
||||
|
||||
@@ -21,7 +21,7 @@ def _sample(items: list[str], count: int | None,
|
||||
|
||||
async def shuf(
|
||||
paths: list[PathSpec],
|
||||
texts: tuple[str, ...],
|
||||
texts: list[str],
|
||||
*,
|
||||
read_bytes: Callable[..., Awaitable[bytes]],
|
||||
stdin: ByteSource | None = None,
|
||||
|
||||
@@ -325,11 +325,11 @@ def parse_flags(flags: Mapping[str, FlagValue]) -> StatFlags:
|
||||
)
|
||||
|
||||
|
||||
async def stat_generic(paths, texts, opts: CommandOpts, stat_fn, links=None):
|
||||
async def stat_generic(paths, texts, opts: CommandOpts, stat_fn):
|
||||
parsed = parse_flags(opts.flags)
|
||||
return await stat(paths,
|
||||
stat_fn=stat_fn,
|
||||
c=parsed.format,
|
||||
f=parsed.file_system,
|
||||
L=parsed.deref,
|
||||
links=links)
|
||||
links=opts.links)
|
||||
|
||||
@@ -246,17 +246,8 @@ def parse_flags(flags: Mapping[str, FlagValue]) -> TarFlags:
|
||||
)
|
||||
|
||||
|
||||
async def tar_generic(paths,
|
||||
texts,
|
||||
opts: CommandOpts,
|
||||
read_bytes,
|
||||
write_bytes,
|
||||
mkdir_fn,
|
||||
stat,
|
||||
walk,
|
||||
is_dir,
|
||||
links=None,
|
||||
mounts=None):
|
||||
async def tar_generic(paths, texts, opts: CommandOpts, read_bytes, write_bytes,
|
||||
mkdir_fn, stat, walk, is_dir):
|
||||
parsed = parse_flags(opts.flags)
|
||||
return await tar(paths,
|
||||
read_bytes=read_bytes,
|
||||
@@ -277,5 +268,5 @@ async def tar_generic(paths,
|
||||
C=list(parsed.directories) or None,
|
||||
strip_components=parsed.strip_components,
|
||||
exclude=parsed.exclude,
|
||||
links=links,
|
||||
mounts=mounts)
|
||||
links=opts.links,
|
||||
mounts=opts.mounts)
|
||||
|
||||
@@ -153,7 +153,7 @@ async def write_output(
|
||||
|
||||
async def tee(
|
||||
paths: list[PathSpec],
|
||||
texts: tuple[str, ...],
|
||||
texts: list[str],
|
||||
*,
|
||||
read_stream: Callable[..., AsyncIterator[bytes]],
|
||||
write_bytes: Callable[..., Awaitable[None]],
|
||||
|
||||
@@ -76,7 +76,7 @@ async def _tr_stream(
|
||||
|
||||
async def tr(
|
||||
paths: list[PathSpec],
|
||||
texts: tuple[str, ...],
|
||||
texts: list[str],
|
||||
*,
|
||||
read_stream: Callable[..., AsyncIterator[bytes]],
|
||||
stdin: ByteSource | None = None,
|
||||
|
||||
@@ -327,16 +327,7 @@ def parse_flags(flags: Mapping[str, FlagValue]) -> TreeFlags:
|
||||
)
|
||||
|
||||
|
||||
async def tree_generic(paths,
|
||||
texts,
|
||||
opts: CommandOpts,
|
||||
readdir,
|
||||
stat,
|
||||
*,
|
||||
index,
|
||||
stat_path=None,
|
||||
readdir_path=None,
|
||||
mounts=None):
|
||||
async def tree_generic(paths, texts, opts: CommandOpts, readdir, stat):
|
||||
parsed = parse_flags(opts.flags)
|
||||
return await tree(paths[0],
|
||||
readdir=readdir,
|
||||
@@ -346,7 +337,7 @@ async def tree_generic(paths,
|
||||
ignore_pattern=parsed.ignore_pattern,
|
||||
dirs_only=parsed.dirs_only,
|
||||
match_pattern=parsed.match_pattern,
|
||||
index=index,
|
||||
stat_path=stat_path,
|
||||
readdir_path=readdir_path,
|
||||
mounts=mounts)
|
||||
index=opts.index,
|
||||
stat_path=opts.stat_path,
|
||||
readdir_path=opts.readdir_path,
|
||||
mounts=opts.mounts)
|
||||
|
||||
@@ -285,15 +285,8 @@ def parse_flags(flags: Mapping[str, FlagValue]) -> ZipFlags:
|
||||
)
|
||||
|
||||
|
||||
async def zip_generic(paths,
|
||||
texts,
|
||||
opts: CommandOpts,
|
||||
read_bytes,
|
||||
write_bytes,
|
||||
stat,
|
||||
walk,
|
||||
links=None,
|
||||
mounts=None):
|
||||
async def zip_generic(paths, texts, opts: CommandOpts, read_bytes, write_bytes,
|
||||
stat, walk):
|
||||
parsed = parse_flags(opts.flags)
|
||||
return await zip_cmd(paths,
|
||||
read_bytes=read_bytes,
|
||||
@@ -305,5 +298,5 @@ async def zip_generic(paths,
|
||||
q=parsed.quiet,
|
||||
y=parsed.store_links,
|
||||
x=list(parsed.exclude) or None,
|
||||
links=links,
|
||||
mounts=mounts)
|
||||
links=opts.links,
|
||||
mounts=opts.mounts)
|
||||
|
||||
@@ -13,14 +13,16 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import functools
|
||||
from collections.abc import AsyncIterator, Callable
|
||||
from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
from typing import Any, overload
|
||||
from typing import Any, Protocol, overload
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.generic.du import DEFAULT_MAX_DU_ENTRIES
|
||||
from mirage.commands.builtin.generic.du import (DEFAULT_MAX_DU_ENTRIES,
|
||||
DuEntries)
|
||||
from mirage.commands.config import CommandFnResult, CommandOpts, ProvisionFn
|
||||
from mirage.ops.types import StatOverlay
|
||||
from mirage.types import FileStat, FileType, PathSpec
|
||||
from mirage.utils.errors import MISS_ERRORS, eisdir
|
||||
@@ -29,6 +31,181 @@ from mirage.utils.path import norm, parent
|
||||
|
||||
OperationFn = Callable[..., Any]
|
||||
|
||||
# Per-slot op shapes, the twins of adapter.ts's ReaddirOp/StatOp/...
|
||||
# generics. The accessor parameter stays Any on purpose: every backend
|
||||
# annotates its own concrete accessor, and a `accessor: Accessor`
|
||||
# protocol parameter would reject all of them under contravariance
|
||||
# (TS solves this with `<A extends Accessor>`; a generic frozen
|
||||
# dataclass plus functools.partial makes that plumbing cost more here
|
||||
# than the accessor check is worth — the slot SHAPE is the guard that
|
||||
# stops readdir being wired where stat belongs). The leading two
|
||||
# parameters are positional-only because backends name the path
|
||||
# parameter both `path` and `path_spec`.
|
||||
|
||||
|
||||
class ReaddirOp(Protocol):
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
path: PathSpec,
|
||||
/,
|
||||
index: IndexCacheStore = ...) -> Awaitable[list[str]]:
|
||||
...
|
||||
|
||||
|
||||
class ReadBytesOp(Protocol):
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
path: PathSpec,
|
||||
/,
|
||||
index: IndexCacheStore = ...) -> Awaitable[bytes]:
|
||||
...
|
||||
|
||||
|
||||
class ReadStreamOp(Protocol):
|
||||
"""Backend streams are async iterators; the polymorphic reader
|
||||
contract (bytes / awaitable) exists only at the generics' bound-
|
||||
reader boundary (``normalized_read``), never on the slot itself:
|
||||
the cache wrapper and the dir-refusing chokepoint both ``async
|
||||
for`` over this directly."""
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
path: PathSpec,
|
||||
/,
|
||||
index: IndexCacheStore = ...) -> AsyncIterator[bytes]:
|
||||
...
|
||||
|
||||
|
||||
class StatOp(Protocol):
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
path: PathSpec,
|
||||
/,
|
||||
index: IndexCacheStore = ...) -> Awaitable[FileStat]:
|
||||
...
|
||||
|
||||
|
||||
class ReadRangeOp(Protocol):
|
||||
"""A byte window without reading the whole object.
|
||||
|
||||
Called as ``(accessor, path, index, offset, size)``; most backends
|
||||
point it at their own ``read_bytes``, which already takes the
|
||||
window.
|
||||
"""
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
path: PathSpec,
|
||||
/,
|
||||
index: IndexCacheStore = ...,
|
||||
offset: int = ...,
|
||||
size: int | None = ...) -> Awaitable[bytes]:
|
||||
...
|
||||
|
||||
|
||||
class WriteOp(Protocol):
|
||||
|
||||
def __call__(self, accessor: Any, path: PathSpec, data: bytes,
|
||||
/) -> Awaitable[None]:
|
||||
...
|
||||
|
||||
|
||||
class ExistsOp(Protocol):
|
||||
|
||||
def __call__(self, accessor: Any, path: PathSpec, /) -> Awaitable[bool]:
|
||||
...
|
||||
|
||||
|
||||
class PathOp(Protocol):
|
||||
|
||||
def __call__(self, accessor: Any, path: PathSpec, /) -> Awaitable[None]:
|
||||
...
|
||||
|
||||
|
||||
class RmTreeOp(Protocol):
|
||||
"""Remove a subtree. The builders ignore any returned value
|
||||
(databricks reports the removed keys for its own rename path), so
|
||||
the return stays loose where unlink/rmdir pin None."""
|
||||
|
||||
def __call__(self, accessor: Any, path: PathSpec, /) -> Awaitable[Any]:
|
||||
...
|
||||
|
||||
|
||||
class MkdirOp(Protocol):
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
path: PathSpec,
|
||||
/,
|
||||
parents: bool = ...) -> Awaitable[None]:
|
||||
...
|
||||
|
||||
|
||||
class PairOp(Protocol):
|
||||
"""Rename/copy/dir-copy: two paths on the same backend."""
|
||||
|
||||
def __call__(self, accessor: Any, src: PathSpec, dst: PathSpec,
|
||||
/) -> Awaitable[None]:
|
||||
...
|
||||
|
||||
|
||||
class TruncateOp(Protocol):
|
||||
|
||||
def __call__(self, accessor: Any, path: PathSpec, length: int,
|
||||
/) -> Awaitable[None]:
|
||||
...
|
||||
|
||||
|
||||
class IsMountedOp(Protocol):
|
||||
|
||||
def __call__(self, accessor: Any, /) -> bool:
|
||||
...
|
||||
|
||||
|
||||
class DuSizeOp(Protocol):
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
path: PathSpec,
|
||||
/,
|
||||
index: IndexCacheStore = ...) -> Awaitable[int]:
|
||||
...
|
||||
|
||||
|
||||
class DuEntriesOp(Protocol):
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
path: PathSpec,
|
||||
/,
|
||||
index: IndexCacheStore = ...) -> Awaitable[DuEntries]:
|
||||
...
|
||||
|
||||
|
||||
class ResolveGlobOp(Protocol):
|
||||
|
||||
def __call__(self,
|
||||
accessor: Any,
|
||||
paths: Sequence[str | PathSpec],
|
||||
/,
|
||||
index: IndexCacheStore = ...) -> Awaitable[list[PathSpec]]:
|
||||
...
|
||||
|
||||
|
||||
class BuilderFn(Protocol):
|
||||
"""Builder body: a CommandFn with the backend's ops bound in front."""
|
||||
|
||||
def __call__(self, ops: "CommandIO", accessor: Any, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> Awaitable[CommandFnResult]:
|
||||
...
|
||||
|
||||
|
||||
AggregateFn = Callable[[list[tuple[str, bytes]]], Awaitable[bytes]]
|
||||
|
||||
|
||||
async def overlaid_stat(stat: OperationFn, overlay: StatOverlay,
|
||||
path: PathSpec, index: IndexCacheStore) -> FileStat:
|
||||
@@ -103,32 +280,32 @@ class DuOps:
|
||||
by omission.
|
||||
|
||||
Args:
|
||||
size (OperationFn): recursive byte total for one path.
|
||||
entries (OperationFn): per-file breakdown, leaf files only.
|
||||
size (DuSizeOp): recursive byte total for one path.
|
||||
entries (DuEntriesOp): per-file breakdown, leaf files only.
|
||||
"""
|
||||
|
||||
size: OperationFn
|
||||
entries: OperationFn
|
||||
size: DuSizeOp
|
||||
entries: DuEntriesOp
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Builder:
|
||||
name: str
|
||||
fn: OperationFn
|
||||
provision: OperationFn | None = None
|
||||
fn: BuilderFn
|
||||
provision: Callable[[StatOp], ProvisionFn] | None = None
|
||||
write: bool = False
|
||||
aggregate: OperationFn | None = None
|
||||
aggregate: AggregateFn | None = None
|
||||
read: bool = False
|
||||
requirements: frozenset[Operation] = frozenset()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CommandIO:
|
||||
readdir: OperationFn
|
||||
read_bytes: OperationFn
|
||||
read_stream: OperationFn
|
||||
stat: OperationFn
|
||||
is_mounted: OperationFn
|
||||
readdir: ReaddirOp
|
||||
read_bytes: ReadBytesOp
|
||||
read_stream: ReadStreamOp
|
||||
stat: StatOp
|
||||
is_mounted: IsMountedOp
|
||||
local: bool = True
|
||||
max_glob_matches: int | None = DEFAULT_MAX_GLOB_MATCHES
|
||||
# Fetch a byte range without pulling the whole object. Absent means
|
||||
@@ -139,26 +316,31 @@ class CommandIO:
|
||||
# Called as (accessor, path, index, offset, size), so most backends
|
||||
# point it at their own read_bytes, which already takes the window;
|
||||
# disk needs a separate function because its read_bytes does not.
|
||||
read_range: OperationFn | None = None
|
||||
write: OperationFn | None = None
|
||||
exists: OperationFn | None = None
|
||||
mkdir: OperationFn | None = None
|
||||
unlink: OperationFn | None = None
|
||||
rmdir: OperationFn | None = None
|
||||
rm_r: OperationFn | None = None
|
||||
rename: OperationFn | None = None
|
||||
copy: OperationFn | None = None
|
||||
dir_copy: OperationFn | None = None
|
||||
create: OperationFn | None = None
|
||||
truncate: OperationFn | None = None
|
||||
read_range: ReadRangeOp | None = None
|
||||
write: WriteOp | None = None
|
||||
exists: ExistsOp | None = None
|
||||
mkdir: MkdirOp | None = None
|
||||
unlink: PathOp | None = None
|
||||
rmdir: PathOp | None = None
|
||||
rm_r: RmTreeOp | None = None
|
||||
rename: PairOp | None = None
|
||||
copy: PairOp | None = None
|
||||
dir_copy: PairOp | None = None
|
||||
create: PathOp | None = None
|
||||
truncate: TruncateOp | None = None
|
||||
# Filter kwargs drift per backend (name/type/size bounds/...), the
|
||||
# repo's kwargs spelling of TS's FindOptions object; a Protocol
|
||||
# naming them would reject every backend, so the slot stays loose.
|
||||
find: OperationFn | None = None
|
||||
du: DuOps | None = None
|
||||
max_du_entries: int | None = DEFAULT_MAX_DU_ENTRIES
|
||||
append: OperationFn | None = None
|
||||
# Typed like `write`, now that the tee generic actually calls it.
|
||||
append: WriteOp | None = None
|
||||
# Kwargs vary per backend (mode/times/owner); loose like TS's any.
|
||||
set_attrs: OperationFn | None = None
|
||||
|
||||
@property
|
||||
def resolve_glob(self) -> OperationFn:
|
||||
def resolve_glob(self) -> ResolveGlobOp:
|
||||
return make_resolve_glob(self.readdir, self.max_glob_matches)
|
||||
|
||||
def operation(self, op: Operation) -> OperationFn | None:
|
||||
|
||||
@@ -13,35 +13,28 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.awk import awk as generic_awk
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def awk(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
paths = await resolve_or_empty(ops, accessor, paths, index)
|
||||
async def awk(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
paths = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await generic_awk(
|
||||
paths,
|
||||
texts,
|
||||
flags,
|
||||
read_bytes=bound_op(ops.read_bytes, accessor, index),
|
||||
read_stream=bound_op(ops.read_stream, accessor, index),
|
||||
stdin=stdin,
|
||||
index=index,
|
||||
opts.flags,
|
||||
read_bytes=bound_op(ops.read_bytes, accessor, opts.index),
|
||||
read_stream=bound_op(ops.read_stream, accessor, opts.index),
|
||||
stdin=opts.stdin,
|
||||
index=opts.index,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -13,31 +13,23 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.base64_cmd import base64_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def base64(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await base64_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_stream, accessor, index))
|
||||
async def base64(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await base64_generic(
|
||||
resolved, list(texts), opts,
|
||||
bound_op(ops.read_stream, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('base64', base64, None, False, None, read=True)
|
||||
|
||||
@@ -16,21 +16,17 @@ from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.generic.basename import \
|
||||
basename as generic_basename
|
||||
from mirage.commands.builtin.generic_bind.adapter import Builder, CommandIO
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def basename(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["basename"])
|
||||
async def basename(ops: CommandIO, accessor: Accessor,
|
||||
paths: list[PathSpec] | None, texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["basename"])
|
||||
suffix = fl.as_str("suffix")
|
||||
return await generic_basename(
|
||||
*texts,
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.aggregators import concat_aggregate
|
||||
from mirage.commands.builtin.generic.cat import cat_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
@@ -22,26 +21,19 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def cat(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
async def cat(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await cat_generic(resolved,
|
||||
list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_stream, accessor, index),
|
||||
opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_stream, accessor, opts.index),
|
||||
local=ops.local)
|
||||
|
||||
|
||||
|
||||
@@ -13,31 +13,22 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.cmp import cmp_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def cmp_cmd(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def cmp_cmd(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor) or len(paths) < 2:
|
||||
raise ValueError('cmp: requires two paths')
|
||||
resolved = await ops.resolve_glob(accessor, paths, index)
|
||||
return await cmp_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
resolved = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
return await cmp_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('cmp', cmp_cmd, None, False, None, read=True)
|
||||
|
||||
@@ -13,31 +13,22 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.column import column_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def column(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await column_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
async def column(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await column_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('column', column, None, False, None, read=True)
|
||||
|
||||
@@ -13,31 +13,22 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.comm import comm_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def comm(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def comm(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor) or len(paths) < 2:
|
||||
raise ValueError("comm: requires two paths")
|
||||
resolved = await ops.resolve_glob(accessor, paths, index)
|
||||
return await comm_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
resolved = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
return await comm_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('comm', comm, None, False, None, read=True)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.generic.cp import cp as generic_cp
|
||||
from mirage.commands.builtin.generic.cp import parse_cp_flags
|
||||
from mirage.commands.builtin.generic.find import parse_find_args, walk_find
|
||||
@@ -24,8 +24,9 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
OperationFn,
|
||||
bound_op,
|
||||
overlaid_stat)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import StatOverlay
|
||||
from mirage.types import NativeCopy, PathSpec
|
||||
@@ -77,33 +78,27 @@ def overlayable_stat(ops: CommandIO, accessor: Accessor,
|
||||
index=index)
|
||||
|
||||
|
||||
async def cp(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
stat_overlay: StatOverlay | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def cp(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor):
|
||||
raise ValueError("cp: no resource")
|
||||
fl = FlagView(flags, spec=SPECS["cp"])
|
||||
fl = FlagView(opts.flags, spec=SPECS["cp"])
|
||||
parsed = parse_cp_flags(fl)
|
||||
paths = await ops.resolve_glob(accessor, paths, index)
|
||||
paths = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
dir_copy = partial(ops.dir_copy, accessor) if ops.dir_copy else None
|
||||
mkdir = partial(ops.mkdir, accessor) if ops.mkdir else None
|
||||
strategy = NativeCopy(copy=partial(ops.require(Operation.COPY), accessor),
|
||||
find=_make_find(ops, accessor, index),
|
||||
find=_make_find(ops, accessor, opts.index),
|
||||
dir_copy=dir_copy,
|
||||
mkdir=mkdir)
|
||||
return await generic_cp(paths,
|
||||
strategy=strategy,
|
||||
stat=overlayable_stat(ops, accessor, index,
|
||||
stat_overlay),
|
||||
stat=overlayable_stat(ops, accessor, opts.index,
|
||||
opts.stat_overlay),
|
||||
flags=parsed,
|
||||
readdir=bound_op(ops.readdir, accessor, index))
|
||||
readdir=bound_op(ops.readdir, accessor,
|
||||
opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('cp',
|
||||
|
||||
@@ -15,37 +15,31 @@
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.csplit import csplit as generic_csplit
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation, bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def csplit(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["csplit"])
|
||||
paths = await resolve_or_empty(ops, accessor, paths, index)
|
||||
async def csplit(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["csplit"])
|
||||
paths = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
prefix_flag = fl.raw("prefix")
|
||||
prefix = prefix_flag if isinstance(prefix_flag, (str, PathSpec)) else "xx"
|
||||
return await generic_csplit(
|
||||
paths,
|
||||
texts,
|
||||
read_bytes=bound_op(ops.read_bytes, accessor, index),
|
||||
read_bytes=bound_op(ops.read_bytes, accessor, opts.index),
|
||||
write_bytes=partial(ops.require(Operation.WRITE), accessor),
|
||||
stdin=stdin,
|
||||
stdin=opts.stdin,
|
||||
prefix=prefix,
|
||||
digits=int(fl.as_str("digits") or "2"),
|
||||
suffix_format=fl.as_str("suffix_format"),
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.cut import cut_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op,
|
||||
@@ -21,25 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def cut(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await cut_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_stream, accessor, index))
|
||||
async def cut(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await cut_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_stream, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('cut', cut, None, False, None, read=True)
|
||||
|
||||
@@ -13,33 +13,24 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.diff import diff_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def diff(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def diff(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor):
|
||||
raise ValueError("diff: no resource")
|
||||
resolved = await ops.resolve_glob(accessor, paths, index)
|
||||
return await diff_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index),
|
||||
bound_op(ops.readdir, accessor, index),
|
||||
bound_op(ops.stat, accessor, index))
|
||||
resolved = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
return await diff_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index),
|
||||
bound_op(ops.readdir, accessor, opts.index),
|
||||
bound_op(ops.stat, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('diff', diff, None, False, None, read=True)
|
||||
|
||||
@@ -15,21 +15,17 @@
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.generic.dirname import dirname as generic_dirname
|
||||
from mirage.commands.builtin.generic_bind.adapter import Builder, CommandIO
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def dirname(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["dirname"])
|
||||
async def dirname(ops: CommandIO, accessor: Accessor,
|
||||
paths: list[PathSpec] | None, texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["dirname"])
|
||||
return await generic_dirname(*texts, zero=fl.as_bool("zero"))
|
||||
|
||||
|
||||
|
||||
@@ -16,15 +16,13 @@ from dataclasses import dataclass
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.generic.du import (ComputeEntries, ComputeSize,
|
||||
DuEntries, du_generic)
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
OperationFn)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import LinkView, MountView
|
||||
from mirage.types import FileType, PathSpec
|
||||
from mirage.utils.key_prefix import mount_key, mount_prefix_of, rekey
|
||||
|
||||
@@ -152,18 +150,9 @@ def _budget_hit(budget: WalkBudget) -> bool:
|
||||
return budget.hit
|
||||
|
||||
|
||||
async def du(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
cwd: PathSpec | str = "/",
|
||||
links: LinkView | None = None,
|
||||
mounts: MountView | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def du(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor):
|
||||
raise ValueError("du: no resource")
|
||||
budget = WalkBudget(ops.max_du_entries)
|
||||
@@ -171,21 +160,21 @@ async def du(
|
||||
compute_size: ComputeSize
|
||||
compute_entries: ComputeEntries
|
||||
if native is None:
|
||||
compute_size = partial(_walk_size, ops, accessor, index, budget)
|
||||
compute_entries = partial(_walk_entries, ops, accessor, index, budget)
|
||||
compute_size = partial(_walk_size, ops, accessor, opts.index, budget)
|
||||
compute_entries = partial(_walk_entries, ops, accessor, opts.index,
|
||||
budget)
|
||||
else:
|
||||
compute_size = partial(_op_size, native.size, accessor, index)
|
||||
compute_entries = partial(_op_entries, native.entries, accessor, index)
|
||||
compute_size = partial(_op_size, native.size, accessor, opts.index)
|
||||
compute_entries = partial(_op_entries, native.entries, accessor,
|
||||
opts.index)
|
||||
return await du_generic(paths,
|
||||
list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags, cwd=cwd),
|
||||
partial(_resolve, ops, accessor, index),
|
||||
partial(_stat, ops, accessor, index),
|
||||
opts,
|
||||
partial(_resolve, ops, accessor, opts.index),
|
||||
partial(_stat, ops, accessor, opts.index),
|
||||
compute_size,
|
||||
compute_entries,
|
||||
truncated=partial(_budget_hit, budget),
|
||||
links=links,
|
||||
mounts=mounts)
|
||||
truncated=partial(_budget_hit, budget))
|
||||
|
||||
|
||||
BUILDER = Builder('du', du, None, False, None)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.expand import expand_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op,
|
||||
@@ -21,25 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def expand(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await expand_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
async def expand(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await expand_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('expand', expand, None, False, None, read=True)
|
||||
|
||||
@@ -13,36 +13,23 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.file import file_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import LinkView
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def file(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
links: LinkView | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def file(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor) or not paths:
|
||||
raise ValueError("file: missing operand")
|
||||
resolved = await ops.resolve_glob(accessor, paths, index)
|
||||
return await file_generic(resolved,
|
||||
list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index),
|
||||
bound_op(ops.stat, accessor, index),
|
||||
links=links)
|
||||
resolved = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
return await file_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index),
|
||||
bound_op(ops.stat, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('file', file, None, False, None, read=True)
|
||||
|
||||
@@ -12,19 +12,18 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.generic.find import (find_generic,
|
||||
find_walk_generic)
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
overlaid_stat)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import LinkView, StatOverlay, StatPath
|
||||
from mirage.types import PathSpec
|
||||
from mirage.types import FileStat, PathSpec
|
||||
|
||||
|
||||
async def _dir_is_empty(ops: CommandIO, accessor: Accessor,
|
||||
@@ -45,51 +44,38 @@ async def _dir_is_empty(ops: CommandIO, accessor: Accessor,
|
||||
return not await ops.readdir(accessor, search, index=index)
|
||||
|
||||
|
||||
async def find(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
stat_overlay: StatOverlay | None = None,
|
||||
links: LinkView | None = None,
|
||||
stat_path: StatPath | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def find(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor):
|
||||
raise ValueError("find: no resource")
|
||||
resolved = await ops.resolve_glob(accessor, paths, index)
|
||||
opts = CommandOpts(stdin=stdin, flags=flags)
|
||||
resolved = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
if ops.find is None:
|
||||
# -mtime must see namespace times (touch results, observed
|
||||
# writes on mtime-less backends), same as ls.
|
||||
walk_stat = partial(ops.stat, accessor)
|
||||
if stat_overlay is not None:
|
||||
walk_stat = partial(overlaid_stat, walk_stat, stat_overlay)
|
||||
walk_stat: Callable[...,
|
||||
Awaitable[FileStat]] = partial(ops.stat, accessor)
|
||||
if opts.stat_overlay is not None:
|
||||
walk_stat = partial(overlaid_stat, walk_stat, opts.stat_overlay)
|
||||
return await find_walk_generic(resolved,
|
||||
list(texts),
|
||||
opts,
|
||||
readdir=partial(ops.readdir, accessor),
|
||||
stat=walk_stat,
|
||||
index=index,
|
||||
stat_path=stat_path,
|
||||
links=links)
|
||||
stat = (partial(ops.stat, accessor, index=index) if ops.local else None)
|
||||
if stat is not None and stat_overlay is not None:
|
||||
stat=walk_stat)
|
||||
stat: Callable[..., Awaitable[FileStat]] | None = (partial(
|
||||
ops.stat, accessor, index=opts.index) if ops.local else None)
|
||||
if stat is not None and opts.stat_overlay is not None:
|
||||
stat = partial(overlaid_stat,
|
||||
partial(ops.stat, accessor),
|
||||
stat_overlay,
|
||||
index=index)
|
||||
opts.stat_overlay,
|
||||
index=opts.index)
|
||||
return await find_generic(resolved,
|
||||
list(texts),
|
||||
opts,
|
||||
find_core=partial(ops.find, accessor),
|
||||
stat=stat,
|
||||
stat_path=stat_path,
|
||||
dir_empty=partial(_dir_is_empty, ops, accessor,
|
||||
index),
|
||||
links=links)
|
||||
opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('find', find, None, False, None)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.fmt import fmt_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op,
|
||||
@@ -21,25 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def fmt(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await fmt_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
async def fmt(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await fmt_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('fmt', fmt, None, False, None, read=True)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.fold import fold_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op,
|
||||
@@ -21,25 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def fold(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await fold_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
async def fold(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await fold_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('fold', fold, None, False, None, read=True)
|
||||
|
||||
@@ -13,36 +13,29 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.aggregators import prefix_aggregate
|
||||
from mirage.commands.builtin.generic.grep import grep as generic_grep
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def grep(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = (await ops.resolve_glob(accessor, paths, index)
|
||||
async def grep(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = (await ops.resolve_glob(accessor, paths, opts.index)
|
||||
if paths and ops.is_mounted(accessor) else [])
|
||||
return await generic_grep(
|
||||
resolved,
|
||||
texts,
|
||||
flags,
|
||||
readdir=bound_op(ops.readdir, accessor, index),
|
||||
stat=bound_op(ops.stat, accessor, index),
|
||||
read_bytes=bound_op(ops.read_bytes, accessor, index),
|
||||
read_stream=bound_op(ops.read_stream, accessor, index),
|
||||
stdin=stdin,
|
||||
opts.flags,
|
||||
readdir=bound_op(ops.readdir, accessor, opts.index),
|
||||
stat=bound_op(ops.stat, accessor, opts.index),
|
||||
read_bytes=bound_op(ops.read_bytes, accessor, opts.index),
|
||||
read_stream=bound_op(ops.read_stream, accessor, opts.index),
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -15,29 +15,22 @@
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.gunzip import gunzip_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation, bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def gunzip(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await ops.resolve_glob(accessor, paths, index) if paths else []
|
||||
async def gunzip(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await ops.resolve_glob(accessor, paths,
|
||||
opts.index) if paths else []
|
||||
return await gunzip_generic(
|
||||
resolved, list(texts), CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index),
|
||||
resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index),
|
||||
partial(ops.require(Operation.WRITE), accessor),
|
||||
partial(ops.require(Operation.UNLINK), accessor))
|
||||
|
||||
|
||||
@@ -15,29 +15,21 @@
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.gzip import gzip_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation, bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def gzip(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await ops.resolve_glob(accessor, paths, index) if paths else []
|
||||
return await gzip_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index),
|
||||
async def gzip(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await ops.resolve_glob(accessor, paths,
|
||||
opts.index) if paths else []
|
||||
return await gzip_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index),
|
||||
partial(ops.require(Operation.WRITE), accessor),
|
||||
partial(ops.require(Operation.UNLINK), accessor))
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.aggregators import header_aggregate
|
||||
from mirage.commands.builtin.generic.head import head_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
@@ -22,25 +21,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def head(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await head_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_stream, accessor, index))
|
||||
async def head(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await head_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_stream, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('head', head, None, False, header_aggregate, read=True)
|
||||
|
||||
@@ -15,31 +15,22 @@
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.iconv import iconv_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation, bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def iconv(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await iconv_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index),
|
||||
async def iconv(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await iconv_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index),
|
||||
partial(ops.require(Operation.WRITE), accessor))
|
||||
|
||||
|
||||
|
||||
@@ -13,31 +13,22 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.join import join_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def join(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def join(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor) or len(paths) < 2:
|
||||
raise ValueError("join: requires two paths")
|
||||
resolved = await ops.resolve_glob(accessor, paths, index)
|
||||
return await join_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
resolved = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
return await join_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('join', join, None, False, None, read=True)
|
||||
|
||||
@@ -13,35 +13,23 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.jq import jq as generic_jq
|
||||
from mirage.commands.builtin.generic.jq import jq_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def jq(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
paths = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await generic_jq(paths,
|
||||
*texts,
|
||||
read_bytes=bound_op(ops.read_bytes, accessor,
|
||||
index),
|
||||
read_stream=bound_op(ops.read_stream, accessor,
|
||||
index),
|
||||
stdin=stdin,
|
||||
**flags)
|
||||
async def jq(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
paths = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await jq_generic(paths, texts, opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index),
|
||||
bound_op(ops.read_stream, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('jq', jq, None, False, None, read=True)
|
||||
|
||||
@@ -13,32 +13,26 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def ln(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["ln"])
|
||||
async def ln(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["ln"])
|
||||
n = fl.as_bool("n")
|
||||
v = fl.as_bool("v")
|
||||
if not ops.is_mounted(accessor) or len(paths) < 2:
|
||||
raise ValueError("ln: usage: ln [-s] [-f] source dest")
|
||||
exists = ops.require(Operation.EXISTS)
|
||||
write = ops.require(Operation.WRITE)
|
||||
paths = await ops.resolve_glob(accessor, paths, index)
|
||||
paths = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
source_path = paths[0]
|
||||
dest_path = paths[1]
|
||||
if n and await exists(accessor, dest_path):
|
||||
|
||||
@@ -13,31 +13,22 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.look import look_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def look(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await look_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
async def look(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await look_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('look', look, None, False, None, read=True)
|
||||
|
||||
@@ -12,57 +12,40 @@
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.ls import ls_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
overlaid_stat)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import ChildMounts, LinkView, StatOverlay
|
||||
from mirage.types import PathSpec
|
||||
from mirage.types import FileStat, PathSpec
|
||||
|
||||
|
||||
async def ls(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
cwd: PathSpec | str = "/",
|
||||
stat_overlay: StatOverlay | None = None,
|
||||
links: LinkView | None = None,
|
||||
child_mounts: ChildMounts | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def ls(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor):
|
||||
raise ValueError("ls: no resource")
|
||||
if not paths:
|
||||
cwd_virtual = cwd.virtual if isinstance(cwd, PathSpec) else cwd
|
||||
cwd_rp = (cwd.resource_path
|
||||
if isinstance(cwd, PathSpec) else cwd.strip("/"))
|
||||
cwd_virtual = opts.cwd.virtual if isinstance(opts.cwd,
|
||||
PathSpec) else opts.cwd
|
||||
cwd_rp = (opts.cwd.resource_path
|
||||
if isinstance(opts.cwd, PathSpec) else opts.cwd.strip("/"))
|
||||
paths = [
|
||||
PathSpec(virtual=cwd_virtual,
|
||||
directory=cwd_virtual,
|
||||
resolved=False,
|
||||
resource_path=cwd_rp)
|
||||
]
|
||||
resolved = await ops.resolve_glob(accessor, paths, index)
|
||||
stat_fn = partial(ops.stat, accessor)
|
||||
if stat_overlay is not None:
|
||||
stat_fn = partial(overlaid_stat, stat_fn, stat_overlay)
|
||||
return await ls_generic(resolved,
|
||||
list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags, cwd=cwd),
|
||||
partial(ops.readdir, accessor),
|
||||
stat_fn,
|
||||
index=index,
|
||||
links=links,
|
||||
child_mounts=child_mounts)
|
||||
resolved = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
stat_fn: Callable[..., Awaitable[FileStat]] = partial(ops.stat, accessor)
|
||||
if opts.stat_overlay is not None:
|
||||
stat_fn = partial(overlaid_stat, stat_fn, opts.stat_overlay)
|
||||
return await ls_generic(resolved, list(texts), opts,
|
||||
partial(ops.readdir, accessor), stat_fn)
|
||||
|
||||
|
||||
BUILDER = Builder('ls', ls, None, False, None)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.md5 import md5_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op,
|
||||
@@ -21,25 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def md5(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await md5_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
async def md5(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await md5_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('md5', md5, None, False, None, read=True)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.md5sum import md5sum_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
dir_aware_stat,
|
||||
@@ -21,26 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def md5sum(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
cwd: PathSpec | str = "/",
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await md5sum_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags, cwd=cwd),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
dir_aware_stream(ops, accessor, index))
|
||||
async def md5sum(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await md5sum_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
dir_aware_stream(ops, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('md5sum', md5sum, None, False, None, read=True)
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.errors import (FS_ERRORS, error_path, fs_strerror,
|
||||
@@ -25,16 +25,10 @@ from mirage.utils.errors import (FS_ERRORS, error_path, fs_strerror,
|
||||
from mirage.utils.mode import DEFAULT_DIR_MODE, parse_chmod
|
||||
|
||||
|
||||
async def mkdir(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["mkdir"])
|
||||
async def mkdir(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["mkdir"])
|
||||
parents = fl.as_bool("parents")
|
||||
verbose = fl.as_bool("verbose")
|
||||
mode_text = fl.as_str("mode")
|
||||
@@ -51,7 +45,7 @@ async def mkdir(
|
||||
raise NotImplementedError(
|
||||
"mkdir: --mode is not supported on this backend")
|
||||
mkdir_fn = ops.require(Operation.MKDIR)
|
||||
paths = await ops.resolve_glob(accessor, paths, index)
|
||||
paths = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
lines: list[str] = []
|
||||
errors: list[str] = []
|
||||
for path in paths:
|
||||
|
||||
@@ -19,21 +19,15 @@ from mirage.commands.builtin.generic.mktemp import mktemp_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def mktemp(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def mktemp(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
return await mktemp_generic(
|
||||
paths, list(texts), CommandOpts(stdin=stdin, flags=flags),
|
||||
paths, list(texts), opts,
|
||||
partial(ops.require(Operation.MKDIR), accessor),
|
||||
partial(ops.require(Operation.WRITE), accessor))
|
||||
|
||||
|
||||
@@ -15,41 +15,33 @@
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.mv import mv as generic_mv
|
||||
from mirage.commands.builtin.generic.mv import parse_mv_flags
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation, bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.cp import overlayable_stat
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.ops.types import StatOverlay
|
||||
from mirage.types import NativeMove, PathSpec
|
||||
|
||||
|
||||
async def mv(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
stat_overlay: StatOverlay | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def mv(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not ops.is_mounted(accessor):
|
||||
raise ValueError("mv: no resource")
|
||||
fl = FlagView(flags, spec=SPECS["mv"])
|
||||
fl = FlagView(opts.flags, spec=SPECS["mv"])
|
||||
parsed = parse_mv_flags(fl)
|
||||
paths = await ops.resolve_glob(accessor, paths, index)
|
||||
paths = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
return await generic_mv(
|
||||
paths,
|
||||
strategy=NativeMove(
|
||||
rename=partial(ops.require(Operation.RENAME), accessor)),
|
||||
stat=overlayable_stat(ops, accessor, index, stat_overlay),
|
||||
stat=overlayable_stat(ops, accessor, opts.index, opts.stat_overlay),
|
||||
flags=parsed,
|
||||
readdir=bound_op(ops.readdir, accessor, index))
|
||||
readdir=bound_op(ops.readdir, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('mv',
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.nl import nl_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op,
|
||||
@@ -21,25 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def nl(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await nl_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_stream, accessor, index))
|
||||
async def nl(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await nl_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_stream, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('nl', nl, None, False, None, read=True)
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.commands.builtin.generic.numfmt import numfmt as generic_numfmt
|
||||
from mirage.commands.builtin.generic_bind.adapter import Builder, CommandIO
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def numfmt(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["numfmt"])
|
||||
async def numfmt(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["numfmt"])
|
||||
return await generic_numfmt(
|
||||
*texts,
|
||||
stdin=stdin,
|
||||
stdin=opts.stdin,
|
||||
to_mode=fl.as_str("to") or "none",
|
||||
from_mode=fl.as_str("from") or "none",
|
||||
suffix=fl.as_str("suffix") or "",
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.od import od as generic_od
|
||||
from mirage.commands.builtin.generic.od import parse_count
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def od(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["od"])
|
||||
paths = await resolve_or_empty(ops, accessor, paths, index)
|
||||
async def od(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["od"])
|
||||
paths = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
formats = fl.as_list("format")
|
||||
# as_str, not `x or y`: the latter would swallow an explicitly empty
|
||||
# value, which GNU rejects loudly (`od -N ''` is an invalid argument,
|
||||
@@ -31,8 +25,8 @@ async def od(
|
||||
limit_value = fl.as_str("read_bytes")
|
||||
return await generic_od(
|
||||
paths,
|
||||
read_stream=bound_op(ops.read_stream, accessor, index),
|
||||
stdin=stdin,
|
||||
read_stream=bound_op(ops.read_stream, accessor, opts.index),
|
||||
stdin=opts.stdin,
|
||||
address_radix=fl.as_str("address_radix") or "o",
|
||||
skip=(parse_count(skip_value, "-j") if skip_value is not None else 0),
|
||||
limit=(parse_count(limit_value, "-N")
|
||||
|
||||
@@ -13,33 +13,27 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.paste import paste as generic_paste
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def paste(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["paste"])
|
||||
paths = await resolve_or_empty(ops, accessor, paths, index)
|
||||
async def paste(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["paste"])
|
||||
paths = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await generic_paste(paths,
|
||||
read_bytes=bound_op(ops.read_bytes, accessor,
|
||||
index),
|
||||
stdin=stdin,
|
||||
opts.index),
|
||||
stdin=opts.stdin,
|
||||
delimiters=fl.as_str("delimiters") or "\t",
|
||||
serial=fl.as_bool("serial"),
|
||||
zero_terminated=fl.as_bool("zero_terminated"))
|
||||
|
||||
@@ -15,28 +15,19 @@
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.patch import patch_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation, bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def patch(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
return await patch_generic(paths, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.read_bytes, accessor, index),
|
||||
async def patch(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
return await patch_generic(paths, list(texts), opts,
|
||||
bound_op(ops.read_bytes, accessor, opts.index),
|
||||
partial(ops.require(Operation.WRITE), accessor),
|
||||
ops.is_mounted(accessor))
|
||||
|
||||
|
||||
@@ -13,29 +13,20 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.readlink import readlink_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import Builder, CommandIO
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def readlink(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def readlink(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if not paths:
|
||||
raise ValueError("readlink: missing operand")
|
||||
resolved = await ops.resolve_glob(accessor, paths, index)
|
||||
return await readlink_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags))
|
||||
resolved = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
return await readlink_generic(resolved, list(texts), opts)
|
||||
|
||||
|
||||
BUILDER = Builder('readlink', readlink, None, False, None)
|
||||
|
||||
@@ -13,29 +13,20 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.realpath import realpath_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def realpath(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec] | None = None,
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await ops.resolve_glob(accessor, paths or [], index)
|
||||
return await realpath_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
bound_op(ops.stat, accessor, index))
|
||||
async def realpath(ops: CommandIO, accessor: Accessor,
|
||||
paths: list[PathSpec] | None, texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await ops.resolve_glob(accessor, paths or [], opts.index)
|
||||
return await realpath_generic(resolved, list(texts), opts,
|
||||
bound_op(ops.stat, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('realpath', realpath, None, False, None)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.rev import rev_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op,
|
||||
@@ -21,25 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def rev(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await rev_generic(resolved, list(texts),
|
||||
CommandOpts(stdin=stdin, flags=flags),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
bound_op(ops.read_bytes, accessor, index))
|
||||
async def rev(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await rev_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
bound_op(ops.read_bytes, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('rev', rev, None, False, None, read=True)
|
||||
|
||||
@@ -13,35 +13,28 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.rg import rg as generic_rg
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def rg(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
prefix: str = "",
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def rg(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
if paths and ops.is_mounted(accessor):
|
||||
paths = await ops.resolve_glob(accessor, paths, index)
|
||||
paths = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
return await generic_rg(
|
||||
paths,
|
||||
texts,
|
||||
flags,
|
||||
readdir=bound_op(ops.readdir, accessor, index),
|
||||
stat=bound_op(ops.stat, accessor, index),
|
||||
read_bytes=bound_op(ops.read_bytes, accessor, index),
|
||||
read_stream=bound_op(ops.read_stream, accessor, index),
|
||||
stdin=stdin,
|
||||
opts.flags,
|
||||
readdir=bound_op(ops.readdir, accessor, opts.index),
|
||||
stat=bound_op(ops.stat, accessor, opts.index),
|
||||
read_bytes=bound_op(ops.read_bytes, accessor, opts.index),
|
||||
read_stream=bound_op(ops.read_stream, accessor, opts.index),
|
||||
stdin=opts.stdin,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -15,34 +15,28 @@
|
||||
import functools
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.cp import walk
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation)
|
||||
from mirage.commands.builtin.utils.output import format_optional_records
|
||||
from mirage.commands.builtin.utils.verbose import removal_lines
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import FileType, PathSpec
|
||||
|
||||
|
||||
async def rm(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(flags, spec=SPECS["rm"])
|
||||
async def rm(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
fl = FlagView(opts.flags, spec=SPECS["rm"])
|
||||
f = fl.as_bool("f")
|
||||
v = fl.as_bool("v")
|
||||
d = fl.as_bool("d")
|
||||
if not ops.is_mounted(accessor) or not paths:
|
||||
raise ValueError("rm: missing operand")
|
||||
paths = await ops.resolve_glob(accessor, paths, index)
|
||||
paths = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
recursive = fl.as_bool("r") or fl.as_bool("R")
|
||||
verbose_parts: list[str] = []
|
||||
errors: list[str] = []
|
||||
@@ -66,7 +60,7 @@ async def rm(
|
||||
if v:
|
||||
readdir = functools.partial(ops.readdir,
|
||||
accessor,
|
||||
index=index)
|
||||
index=opts.index)
|
||||
entry_lines = removal_lines(await walk(
|
||||
readdir, functools.partial(ops.stat, accessor), p))
|
||||
await ops.rm_r(accessor, p)
|
||||
@@ -74,7 +68,7 @@ async def rm(
|
||||
if ops.rmdir is None:
|
||||
raise NotImplementedError(
|
||||
"rm: directory remove not supported on this backend")
|
||||
if await ops.readdir(accessor, p, index=index):
|
||||
if await ops.readdir(accessor, p, index=opts.index):
|
||||
errors.append(f"rm: cannot remove '{p.virtual}': "
|
||||
"Directory not empty")
|
||||
continue
|
||||
|
||||
@@ -13,33 +13,27 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
Operation)
|
||||
from mirage.commands.builtin.utils.output import format_optional_records
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.errors import UsageError
|
||||
from mirage.commands.spec import SPECS
|
||||
from mirage.commands.spec.types import FlagValue, FlagView
|
||||
from mirage.commands.spec.types import FlagView
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import FileType, PathSpec
|
||||
|
||||
|
||||
async def rmdir(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: bytes | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
v = FlagView(flags, spec=SPECS["rmdir"]).as_bool("v")
|
||||
async def rmdir(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
v = FlagView(opts.flags, spec=SPECS["rmdir"]).as_bool("v")
|
||||
if not ops.is_mounted(accessor) or not paths:
|
||||
raise UsageError(
|
||||
"rmdir: missing operand\n"
|
||||
"Try 'rmdir --help' for more information.", 1)
|
||||
rmdir_fn = ops.require(Operation.RMDIR)
|
||||
paths = await ops.resolve_glob(accessor, paths, index)
|
||||
paths = await ops.resolve_glob(accessor, paths, opts.index)
|
||||
verbose_parts: list[str] = []
|
||||
errors: list[str] = []
|
||||
removed: dict[str, ByteSource] = {}
|
||||
@@ -54,7 +48,7 @@ async def rmdir(
|
||||
errors.append(
|
||||
f"rmdir: failed to remove '{p.virtual}': Not a directory")
|
||||
continue
|
||||
if await ops.readdir(accessor, p, index=index):
|
||||
if await ops.readdir(accessor, p, index=opts.index):
|
||||
errors.append(f"rmdir: failed to remove '{p.virtual}': "
|
||||
"Directory not empty")
|
||||
continue
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
from functools import partial
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.cache.index import IndexCacheStore
|
||||
from mirage.commands.builtin.generic.sed import sed_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
bound_op)
|
||||
from mirage.commands.builtin.generic_bind.provision import make_sed_provision
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
@@ -31,20 +30,12 @@ async def _resolve(ops: CommandIO, accessor: Accessor, index: IndexCacheStore,
|
||||
return await ops.resolve_glob(accessor, targets, index)
|
||||
|
||||
|
||||
async def sed(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
cwd: PathSpec | str = "/",
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
async def sed(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
return await sed_generic(
|
||||
paths, list(texts), CommandOpts(stdin=stdin, flags=flags, cwd=cwd),
|
||||
partial(_resolve, ops, accessor, index),
|
||||
bound_op(ops.read_bytes, accessor, index),
|
||||
paths, list(texts), opts, partial(_resolve, ops, accessor, opts.index),
|
||||
bound_op(ops.read_bytes, accessor, opts.index),
|
||||
(partial(ops.write, accessor) if ops.write is not None else None))
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.accessor.base import Accessor
|
||||
from mirage.cache.index import NULL_INDEX, IndexCacheStore
|
||||
from mirage.commands.builtin.generic.sha1sum import sha1sum_generic
|
||||
from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
dir_aware_stat,
|
||||
@@ -21,26 +20,17 @@ from mirage.commands.builtin.generic_bind.adapter import (Builder, CommandIO,
|
||||
from mirage.commands.builtin.generic_bind.builders.common import \
|
||||
resolve_or_empty
|
||||
from mirage.commands.config import CommandOpts
|
||||
from mirage.commands.spec.types import FlagValue
|
||||
from mirage.io.types import ByteSource, IOResult
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
async def sha1sum(
|
||||
ops: CommandIO,
|
||||
accessor: Accessor,
|
||||
paths: list[PathSpec],
|
||||
*texts: str,
|
||||
stdin: ByteSource | None = None,
|
||||
index: IndexCacheStore = NULL_INDEX,
|
||||
cwd: PathSpec | str = "/",
|
||||
**flags: FlagValue,
|
||||
) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, index)
|
||||
return await sha1sum_generic(
|
||||
resolved, list(texts), CommandOpts(stdin=stdin, flags=flags, cwd=cwd),
|
||||
dir_aware_stat(ops, accessor, index),
|
||||
dir_aware_stream(ops, accessor, index))
|
||||
async def sha1sum(ops: CommandIO, accessor: Accessor, paths: list[PathSpec],
|
||||
texts: list[str],
|
||||
opts: CommandOpts) -> tuple[ByteSource | None, IOResult]:
|
||||
resolved = await resolve_or_empty(ops, accessor, paths, opts.index)
|
||||
return await sha1sum_generic(resolved, list(texts), opts,
|
||||
dir_aware_stat(ops, accessor, opts.index),
|
||||
dir_aware_stream(ops, accessor, opts.index))
|
||||
|
||||
|
||||
BUILDER = Builder('sha1sum', sha1sum, None, False, None, read=True)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user