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
// 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 a small metadata
//! predicate language, and runs a command over the result — either once per
//! member (with placeholder substitution) or exactly once for the whole set.
//! It exists to replace hand-rolled for-each-package shell loops with a
//! single cargo-native, cross-platform command.
//!
//! This crate ships **only** the `cargo-each` executable; it exposes no
//! library API (every module below is crate-internal). Consume it as a cargo
//! subcommand, not as a dependency.
//!
//! # 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 <PRED>` keeps only members matching `PRED`; `--exclude-filter
//! <PRED>` drops them. Both are repeatable: `--filter` predicates are
//! AND-combined (kept only if a member matches every one) and
//! `--exclude-filter` predicates are OR-combined (dropped if a member matches
//! any one). Exclusion wins over inclusion. Predicates:
//!
//! - `lib` / `bin` — the member has a target of that kind.
//! - `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.
//!
//! `--keep-going` runs every invocation and exits non-zero if any failed
//! (default is fail-fast); `--chdir` runs each per-package command from that
//! member crate root (its `Cargo.toml` directory) instead of the current
//! directory — per-package mode only, so it cannot be combined with `--once`;
//! `--dry-run` prints the fully-substituted commands without running them.
//!
//! ## Placeholders
//!
//! Substituted inside each command argument:
//!
//! - `{name}` — bare package name (per-package mode).
//! - `{spec}` — `name@version` (per-package mode).
//! - `{version}` — package version (per-package mode).
//! - `{manifest}` — absolute path to the member `Cargo.toml` (per-package).
//! - `{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.
//! 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 predicate, 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
//! ```
use ExitCode;
use Parser;
use crateCargoCli;