Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ to a dated version section.

### Changed

- **Breaking:** `Error` is now an opaque struct wrapping `Box<ErrorKind>`.
`size_of::<Error>()` had grown to over 100 bytes, bloating every `Result<T>`
and triggering clippy lints (see [issue #21](https://github.com/ZelAnton/ProcessKit-rs/issues/21)).
All previous `Error` variants are available in the new, `#[non_exhaustive]`
`ErrorKind` accessible through `err.kind()` or `err.into_kind()`.
The `is_*` classifiers are available on both `Error` and `ErrorKind`.
- Release publishing now uses crates.io Trusted Publishing — a short-lived token
minted over GitHub OIDC per run — instead of a stored long-lived
`CRATES_IO_TOKEN` secret
Expand Down
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ rule allows only for the real hierarchy root — *not* a cgroup-namespace root (
ordinary container EBUSYs too), and *not* under a systemd session/scope/service. The crate
does not migrate your process to work around it, so in practice limits apply only at a
minimal non-systemd init. When a requested limit can't be enforced, `with_options`
returns `Error::ResourceLimit` instead of a silently-unbounded group — an unapplied cap
returns `ErrorKind::ResourceLimit` instead of a silently-unbounded group — an unapplied cap
is no protection.

*Deeper: [Process groups → resource limits](docs/process-groups.md).*
Expand All @@ -278,7 +278,7 @@ async fn main() -> processkit::Result<()> {
```

Signals are POSIX-only: on Windows just `Signal::Kill` is deliverable (it maps to
the Job Object terminate) and anything else returns `Error::Unsupported`.
the Job Object terminate) and anything else returns `ErrorKind::Unsupported`.
`Signal::Kill` always takes the same whole-tree hard-kill path as
`kill_all()`. Suspend/resume work everywhere a container exists — one
`cgroup.freeze` write covering the subtree on Linux, `SIGSTOP`/`SIGCONT` on
Expand Down Expand Up @@ -474,7 +474,7 @@ async fn health_check() -> bool {

A probe that doesn't pass within its deadline — or that can no longer pass
(the child exits; for `wait_for_line`, its stdout closes) — fails with
`Error::NotReady` (distinct from `Error::Timeout`, which is the run's own
`ErrorKind::NotReady` (distinct from `ErrorKind::Timeout`, which is the run's own
`Command::timeout`) and **does not kill the child**: the caller decides what
happens next. `wait_for_line` consumes stdout up to the match
(continue with `finish`); `wait_for_port` / `wait_for` background-drain and
Expand Down Expand Up @@ -552,7 +552,7 @@ async fn main() -> processkit::Result<()> {
`inherit_env` clears the environment and copies only the named parent vars
(explicit `env`/`env_remove` still apply on top); it works everywhere. `uid` /
`gid` (group id is set before user id) and `setsid` are POSIX-only — on other
targets the run fails with `Error::Unsupported` rather than silently skipping
targets the run fails with `ErrorKind::Unsupported` rather than silently skipping
a privilege drop. One Linux caveat: under the **cgroup** mechanism the child
joins its cgroup after the uid has already dropped, and the auto-created
cgroup isn't writable by the target user — the spawn fails with a permission
Expand All @@ -572,7 +572,7 @@ macOS/BSD have no equivalent (documented no-op).

Hand a command a
[`CancellationToken`] (re-exported from `tokio-util`); cancelling the token
kills the process tree, and every consuming path reports `Error::Cancelled`:
kills the process tree, and every consuming path reports `ErrorKind::Cancelled`:

```rust,no_run
use processkit::{CancellationToken, Command};
Expand All @@ -591,7 +591,10 @@ async fn main() -> processkit::Result<()> {
// elsewhere — a shutdown signal, a sibling failure, a UI button:
token.cancel();

assert!(matches!(job.await.unwrap(), Err(processkit::Error::Cancelled { .. })));
assert!(matches!(
job.await.unwrap().map_err(processkit::Error::into_kind),
Err(processkit::ErrorKind::Cancelled { .. })
));
Ok(())
}
```
Expand Down Expand Up @@ -654,7 +657,7 @@ async fn main() -> processkit::Result<()> {
> (own-group handle) or the direct child (shared-group handle) is killed, the
> pipes close, and the stream ends. A `cancel_on` token ends
> the stream the same way, and the following `finish` reports
> `Error::Cancelled`. For an ad-hoc bound, wrapping the loop in
> `ErrorKind::Cancelled`. For an ad-hoc bound, wrapping the loop in
> [`tokio::time::timeout`] and dropping the handle (which kills the tree) still
> works.

Expand All @@ -669,7 +672,8 @@ use processkit::Command;

// `ProcessStdin`'s writer methods return `std::io::Result` (idiomatic for a
// writer), so this example uses `Box<dyn std::error::Error>` to mix them with the
// crate's `Result`; in a `processkit::Result` function, `.map_err(processkit::Error::Io)?`.
// crate's `Result`; in a `processkit::Result` function,
// `.map_err(processkit::ErrorKind::Io)?`.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// `bc` evaluates each stdin line and prints the result on stdout.
Expand Down Expand Up @@ -784,7 +788,7 @@ file is written `0600`. When one invocation was recorded
several times, replay serves the entries in capture order and then repeats the
last one — a recorded sequence of changing outputs replays faithfully, while
retry/probe loops keep getting a stable final answer. An invocation absent from
the cassette is a strict `Error::CassetteMiss` (distinct from a missing program,
the cassette is a strict `ErrorKind::CassetteMiss` (distinct from a missing program,
so `is_not_found()` is `false`; replay never spawns a surprise subprocess), and
the file carries a format `version` so future readers fail loudly instead of
misreading old fixtures.
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ guarantee is unconditional in every configuration.
|---|---|---|---|
| `stats` | off | `ProcessGroup::stats` / `sample_stats`, `RunningProcess::cpu_time` / `peak_memory_bytes` / `profile` | `windows-sys/ProcessStatus` (Windows) |
| `process-control` | **on** | `Signal`, `ProcessGroup::{signal, suspend, resume, members, adopt}` | — |
| `limits` | off | Whole-tree resource caps on `ProcessGroupOptions` (`max_memory` / `max_processes` / `cpu_quota`), `Error::ResourceLimit`; implies `stats` | — |
| `limits` | off | Whole-tree resource caps on `ProcessGroupOptions` (`max_memory` / `max_processes` / `cpu_quota`), `ErrorKind::ResourceLimit`; implies `stats` | — |
| `mock` | off | A `mockall`-generated `MockRunner` for expectation-style tests (test-only; its `expect_*` surface is **semver-exempt**, tracking `mockall` — prefer `ScriptedRunner`/`RecordingRunner` for a stable double) | `mockall` |
| `tracing` | off | Events on the `processkit` target: spawn/exit, timeout & cancel firing, group teardown, retries, supervisor storms, teardown anomalies (never argv/env) | `tracing` |
| `record` | off | `RecordReplayRunner` JSON cassettes over the runner seam | `serde`, `serde_json` |
Expand Down
Loading