pmpx_plugin/spec.rs
1//! What a plugin answers with: one command, still unexecuted.
2
3use std::ffi::OsString;
4use std::path::PathBuf;
5
6/// One command waiting to be executed, pure data -- a plugin only describes "what to run" and the
7/// actual spawn is done by the host, so stdio, environment, and exit-code handling have exactly
8/// one implementation. Construction is a consuming chain (`self` -> `Self`), so it can produce a
9/// value directly:
10/// ```ignore
11/// let spec = CommandSpec::new("cargo").arg("add").args(args.iter()).cwd("/somewhere");
12/// ```
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct CommandSpec {
15 /// Executable. It may be a bare name (resolved on `PATH`), an absolute path, or a path
16 /// relative to this spec's [`cwd`](CommandSpec::cwd) -- which is the project root when the
17 /// spec does not name one. On Windows a bare name resolves through `PATHEXT`, so `pnpm` finds
18 /// `pnpm.cmd`, and the host starts a batch file the way the platform requires.
19 pub program: OsString,
20
21 /// Arguments, in order.
22 pub args: Vec<OsString>,
23
24 /// Working-directory override. `None` = use the project root given by the host.
25 pub cwd: Option<PathBuf>,
26}
27
28impl CommandSpec {
29 /// Specify the executable.
30 pub fn new(program: impl Into<OsString>) -> Self {
31 Self {
32 program: program.into(),
33 args: Vec::new(),
34 cwd: None,
35 }
36 }
37
38 /// Append one argument.
39 pub fn arg(mut self, arg: impl Into<OsString>) -> Self {
40 self.args.push(arg.into());
41 self
42 }
43
44 /// Append a batch of arguments; `args.iter()` can be passed straight in and stays lossless
45 /// (`&OsString: Into<OsString>`), unlike `String`, which would corrupt non-UTF-8 arguments on
46 /// Unix.
47 pub fn args<I, S>(mut self, args: I) -> Self
48 where
49 I: IntoIterator<Item = S>,
50 S: Into<OsString>,
51 {
52 self.args.extend(args.into_iter().map(Into::into));
53 self
54 }
55
56 /// Override the working directory.
57 pub fn cwd(mut self, dir: impl Into<PathBuf>) -> Self {
58 self.cwd = Some(dir.into());
59 self
60 }
61}