Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
5b7aa5c
feat(rust-sdk/py): add shared cargo argument assembler
markovejnovic Jun 11, 2026
e8f363f
fix(rust-sdk/py): exclude= pairs with workspace, not packages (cargo …
markovejnovic Jun 11, 2026
cdfbc9d
feat(rust-sdk/py): full cargo options + nextest/doctest on RustToolchain
markovejnovic Jun 11, 2026
2ecdfa4
fix(rust-sdk/py): expose all_targets on test, target/exclude on doctest
markovejnovic Jun 11, 2026
5e9b13b
feat(rust-sdk/py): RustProject build/doc/doctest/ci + packages on eve…
markovejnovic Jun 11, 2026
f5bf426
polish(rust-sdk/py): accurate ci() docstring + exclude= on doc()
markovejnovic Jun 11, 2026
52b528a
feat(rust-sdk/py): cargo-hack feature_powerset helper
markovejnovic Jun 11, 2026
3ad745e
fix(rust-sdk/py): path-independent cargo-hack install for cache sharing
markovejnovic Jun 11, 2026
6cdd669
test(rust-sdk/py): shell-injection regression coverage
markovejnovic Jun 11, 2026
0a85f7a
feat(rust-sdk/ts): add shared cargo argument assembler
markovejnovic Jun 11, 2026
be139bd
feat(rust-sdk/ts): full cargo options, nextest/doctest, ci(), cargo-h…
markovejnovic Jun 11, 2026
3f6e6fc
test(rust-sdk): cross-language golden command parity
markovejnovic Jun 11, 2026
2f3273e
docs(rust-sdk): examples use project().ci(nextest=True); regen rust-r…
markovejnovic Jun 11, 2026
bf515d4
fix(rust-sdk/ts): shell-quote cargo-hack skip/include values (parity …
markovejnovic Jun 11, 2026
801e67a
fix(rust-sdk/example): commit Cargo.lock for --locked; ci() without n…
markovejnovic Jun 11, 2026
3565c1c
Merge remote-tracking branch 'origin/main' into feat/better-rust-sdk
markovejnovic Jun 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions crates/hm-dsl-engine/harmont-py/harmont/_cargo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""Shared cargo-argument assembly for the Rust toolchain helper.

Turns structured options (features, packages, target, …) into a
canonically-ordered, shell-safe cargo argument string. Every user-supplied
*value* (package/exclude names, the joined feature list, target triple,
profile name) is shell-quoted; the raw escape-hatch ``flags`` pass through
verbatim because they are meant to be literal cargo arguments.
"""

from __future__ import annotations

import shlex
from dataclasses import dataclass


@dataclass(frozen=True)
class CargoOpts:
"""Structured cargo invocation options. See the SDK design reference for
the canonical token order each field lowers to."""

workspace: bool = False
packages: tuple[str, ...] = ()
exclude: tuple[str, ...] = ()
all_features: bool = False
no_default_features: bool = False
features: tuple[str, ...] = ()
target: str | None = None
all_targets: bool = False
release: bool = False
profile: str | None = None
locked: bool = True
flags: tuple[str, ...] = ()


def _validate(opts: CargoOpts) -> None:
if opts.all_features and (opts.features or opts.no_default_features):
msg = (
"hm.rust: --all-features conflicts with features=/no_default_features=\n"
f" observed: all_features=True, features={list(opts.features)!r}, "
f"no_default_features={opts.no_default_features!r}\n"
" → pass all_features=True alone, or list explicit features= "
"without all_features"
)
raise ValueError(msg)
if opts.release and opts.profile is not None:
msg = (
"hm.rust: release=True conflicts with profile=\n"
f" observed: release=True, profile={opts.profile!r}\n"
' → use profile="release" (identical effect) or drop one'
)
raise ValueError(msg)
if opts.exclude:
if opts.packages:
msg = (
"hm.rust: exclude= cannot combine with packages=\n"
f" observed: packages={list(opts.packages)!r}, "
f"exclude={list(opts.exclude)!r}\n"
" → --exclude pairs with --workspace; packages= already selects "
"explicitly, so drop one"
)
raise ValueError(msg)
if not opts.workspace:
msg = (
"hm.rust: exclude= requires workspace=True\n"
f" observed: exclude={list(opts.exclude)!r} without workspace=True\n"
" → cargo --exclude only applies to --workspace; pass workspace=True"
)
raise ValueError(msg)


def cargo_flags(opts: CargoOpts) -> str:
"""Assemble the cargo argument middle (after the subcommand, before any
``--`` passthrough). Returns a leading-space string, or ``""`` when empty.
"""
_validate(opts)
toks: list[str] = []

# scope
if opts.packages:
toks += [f"-p {shlex.quote(p)}" for p in opts.packages]
elif opts.workspace:
toks.append("--workspace")
toks += [f"--exclude {shlex.quote(e)}" for e in opts.exclude]

# target selection
if opts.all_targets:
toks.append("--all-targets")

# features
if opts.all_features:
toks.append("--all-features")
else:
if opts.no_default_features:
toks.append("--no-default-features")
if opts.features:
toks.append("--features " + shlex.quote(",".join(opts.features)))

# target triple
if opts.target is not None:
toks.append(f"--target {shlex.quote(opts.target)}")

# profile / release
if opts.profile is not None:
toks.append(f"--profile {shlex.quote(opts.profile)}")
elif opts.release:
toks.append("--release")

# lockfile
if opts.locked:
toks.append("--locked")

# escape hatch — verbatim
toks += list(opts.flags)

return (" " + " ".join(toks)) if toks else ""
Loading
Loading