1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! `cargo-each`: run a command over a cargo-style selection of workspace
//! members.
//!
//! `cargo-each` resolves a package selection expressed with the same
//! selectors as `cargo build`, optionally narrows it with package predicates,
//! and runs a command over the result — once per member, once per matching
//! Cargo target, or exactly once for the whole set. It replaces hand-rolled
//! shell loops with one cargo-native, cross-platform command.
//!
//! `cargo-each` ships as an executable only; it is a cargo subcommand, not a
//! library dependency.
//!
//! # Installation
//!
//! ```text
//! cargo install cargo-each
//! ```
//!
//! # Usage
//!
//! ```text
//! cargo each [SELECTION] [FILTERS] [EXECUTION] -- <COMMAND> [ARG...]
//! ```
//!
//! Everything after `--` is the command template; `cargo-each` spawns it
//! directly (argv, not a shell string) after substituting placeholders.
//!
//! ## Selection (mirrors `cargo build`)
//!
//! - `-p` / `--package <SPEC>` — select a member. Repeatable. `SPEC` is a
//! package name, a `name@version` spec, or a Unix glob (`tokio-*`).
//! - `--workspace` / `--all` — select every workspace member.
//! - `--exclude <SPEC>` — drop a member (with `--workspace`). Repeatable.
//! - `--none` — explicitly select zero members (a no-op that exits 0).
//!
//! When nothing is named the default is cargo `default-members`, exactly
//! like `cargo build`; pass `--workspace` for every member. A selector that
//! matches no member is an error, so typos fail loudly. A computed selection
//! (for example a CI affected-packages set) is fed in as ordinary flags via
//! shell expansion — `cargo-each` has no file or environment-variable source
//! of its own.
//!
//! ## Filters
//!
//! `--filter` accepts Boolean expressions using `not`, `and`, `or`, and
//! parentheses, with conventional precedence. Repeated `--filter` expressions
//! are AND-combined. Repeated `--exclude-filter` expressions are OR-combined,
//! and exclusion wins. Metadata values containing whitespace or Boolean syntax
//! can be double-quoted. Expression atoms:
//!
//! - `lib` / `bin` / `target-kind:<kind>` — target-kind membership.
//! - `publishable` — Cargo permits publishing the package.
//! - `feature:<name>` — the package declares the feature.
//! - `dep:<name>` — the member declares `<name>` as a dependency.
//! - `metadata:<dotted.key>` — `package.metadata.<dotted.key>` is present.
//! - `metadata:<dotted.key>=<value>` — that key equals `<value>` (numeric
//! compare when both sides parse as a number, else string compare).
//!
//! ## Execution modes
//!
//! - *per-package* (default): run the command once per selected member, in
//! name order, substituting the per-package placeholders below.
//! - `--once`: run the command exactly once when the set is non-empty (skip
//! when empty), using the `{packages}` placeholder to inject the selection.
//! - `--each-target <KIND>`: run once per matching Cargo target, using
//! `{target}` plus the package placeholders. Repeated kinds are OR-combined;
//! `--target-required-feature` further narrows targets.
//!
//! `--keep-going` runs every invocation and exits non-zero if any failed
//! (default is fail-fast); `--chdir` runs each per-package or per-target
//! command from that member crate root; `--dry-run` prints commands without
//! running them.
//!
//! ## Placeholders
//!
//! Substituted inside each command argument:
//!
//! - `{name}` — bare package name (per-package and per-target).
//! - `{spec}` — `name@version` (per-package and per-target).
//! - `{version}` — package version (per-package and per-target).
//! - `{manifest}` — absolute member `Cargo.toml` path (per-package and
//! per-target).
//! - `{target}` — Cargo target name (per-target).
//! - `{packages}` — the cargo selection flags for the resolved set
//! (`--workspace` for the whole workspace, else `--package name@version …`);
//! valid only in `--once` mode and only as a standalone argument.
//!
//! Using a placeholder in the wrong mode is a usage error. Only the tokens
//! above are interpreted; any other `{…}` sequence (a typo, or a literal brace
//! an argument needs) passes through verbatim to the spawned command — there is
//! no brace-escape, so this passthrough is part of the contract.
//!
//! # Behavior
//!
//! An empty resolved selection (via `--none`, or a filter that removes every
//! member) is a **successful no-op**: `cargo-each` prints a one-line note and
//! exits 0. This is what lets callers drop bespoke nothing-to-do guards.
//! Child commands inherit `PATH` explicitly. On Windows this makes relative
//! program lookup honor the inherited `PATH` order instead of preferring an
//! unrelated executable beside `cargo-each`.
//! Otherwise the exit code is the first failing command code (fail-fast),
//! `1` under `--keep-going` if any command failed, or `2` for a `cargo-each`
//! usage error (unknown selector, bad filter expression, misused placeholder).
//!
//! # Examples
//!
//! Run a per-manifest tool over every library crate:
//!
//! ```text
//! cargo each --workspace --filter lib -- \
//! cargo check-external-types --manifest-path {manifest}
//! ```
//!
//! Run one clippy invocation over a computed subset, skipping when it is empty:
//!
//! ```text
//! cargo each -p crate-a -p crate-b --once -- \
//! cargo clippy {packages} --all-targets -- -D warnings
//! ```
//!
//! Run every Cargo test target that requires the `loom` feature:
//!
//! ```text
//! cargo each --workspace --each-target test --target-required-feature loom -- \
//! cargo test -p {name} --test {target} --features loom
//! ```
use ExitCode;
use Parser;
use crateCargoCli;