1use std::{
2 ffi::OsStr,
3 path::PathBuf,
4 process::{Child, Command, Stdio},
5};
6
7use super::SubCommand;
8
9use crate::global::GlobalOpts;
10use crate::spawn::ParameterizedSpawn;
11
12#[cfg_attr(feature = "lt2015_1", doc = "`p4 [g-opts] where [file ...]`")]
13#[cfg_attr(
14 all(feature = "lt2016_1", not(feature = "lt2015_1")),
15 doc = "`p4 [g-opts] where [file …]`"
16)]
17#[cfg_attr(not(feature = "lt2016_1"), doc = "`p4 [g-opts] where [file ...]`")]
18#[cfg_attr(
20 feature = "lt2023_2",
21 doc = "Show where a particular file is located, as determined by the client view.",
22 doc = "",
23 doc = "`p4 where` uses the client view and root (as set in `p4 client`) to print files'",
24 doc = "locations relative to the top of the depot, relative to the top of the client",
25 doc = "workspace, and relative to the top of the local OS directory tree. The command",
26 doc = "does not check to see if the file exists; it merely reports where the file",
27 doc = "*would be* located if it *did* exist.",
28 doc = "",
29 doc = "For each file provided as a parameter, a set of mappings is output. Each set",
30 doc = "of mappings is composed of lines consisting of three parts: the first part",
31 doc = "is the filename expressed in depot syntax, the second part is the filename",
32 doc = "expressed in client syntax, and the third is the local OS path of the file."
33)]
34#[cfg_attr(
35 not(feature = "lt2023_2"),
36 doc = "Show how the specified files are mapped by the client view.",
37 doc = "",
38 doc = "`p4 where` uses the client view and root to print files locations relative to",
39 doc = "the top of the depot, relative to the top of the client workspace, and",
40 doc = "relative to the top of the local OS directory tree. The client mappings are",
41 doc = "set by the `p4 client` command. The `p4 where` command does not check to see",
42 doc = "whether the file exists. Instead, it reports where the file *would be*",
43 doc = "located if it *did* exist.",
44 doc = "",
45 doc = "The command accepts wildcards, such as `p4 where *.html`",
46 doc = "",
47 doc = "For each file provided as a parameter, a set of mappings is output. Each set",
48 doc = "of mappings consists of:",
49 doc = "",
50 doc = "- the filename in depot syntax. such as `//depot/project1/my-file.html`",
51 doc = "- the filename in client syntax, such as `//maria/depot/project1/my-file.html`",
52 doc = "- the filename in local syntax, which is the local operating system path,",
53 doc = "such as `C:\\Users\\maria\\project1\\my-file.html`"
54)]
55#[derive(Debug, Clone, Default)]
56pub struct Where {
57 bin: PathBuf,
58
59 global_opts: GlobalOpts,
60}
61
62impl SubCommand for Where {
63 fn name(&self) -> &str {
64 "where"
65 }
66
67 fn inject_local_args(&self, _: &mut Command) {}
68
69 fn global_opts(&self) -> Option<&GlobalOpts> {
70 Some(&self.global_opts)
71 }
72}
73
74impl ParameterizedSpawn for Where {
75 type Input<'a> = &'a [&'a OsStr];
76 type Output<'a> = Child;
77 type Error = std::io::Error;
78
79 fn spawn_with<'a>(&mut self, files: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
85 self.setup_command(&self.bin)
86 .args(files)
87 .stdout(Stdio::piped())
88 .stderr(Stdio::piped())
89 .spawn()
90 }
91}
92
93impl Where {
94 pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts) -> Self {
98 Self {
99 bin: bin.into(),
100 global_opts,
101 }
102 }
103
104 #[cfg_attr(
109 feature = "lt2014_2",
110 doc = "See the [Global Options](GlobalOpts) section."
111 )]
112 #[cfg_attr(
113 all(feature = "lt2015_1", not(feature = "lt2014_2")),
114 doc = "See the [“Global Options”](GlobalOpts) section."
115 )]
116 #[cfg_attr(
117 all(feature = "lt2017_1", not(feature = "lt2015_1")),
118 doc = "See [“Global Options”](GlobalOpts)."
119 )]
120 #[cfg_attr(
121 all(feature = "lt2018_2", not(feature = "lt2017_1")),
122 doc = "See [Global Options](GlobalOpts)."
123 )]
124 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
125 pub fn get_global_opts(&self) -> &GlobalOpts {
126 &self.global_opts
127 }
128
129 #[cfg_attr(
134 feature = "lt2014_2",
135 doc = "See the [Global Options](GlobalOpts) section."
136 )]
137 #[cfg_attr(
138 all(feature = "lt2015_1", not(feature = "lt2014_2")),
139 doc = "See the [“Global Options”](GlobalOpts) section."
140 )]
141 #[cfg_attr(
142 all(feature = "lt2017_1", not(feature = "lt2015_1")),
143 doc = "See [“Global Options”](GlobalOpts)."
144 )]
145 #[cfg_attr(
146 all(feature = "lt2018_2", not(feature = "lt2017_1")),
147 doc = "See [Global Options](GlobalOpts)."
148 )]
149 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
150 pub fn set_global_opts(&mut self, v: GlobalOpts) -> &mut Self {
151 self.global_opts = v;
152 self
153 }
154
155 #[cfg_attr(
160 feature = "lt2014_2",
161 doc = "See the [Global Options](GlobalOpts) section."
162 )]
163 #[cfg_attr(
164 all(feature = "lt2015_1", not(feature = "lt2014_2")),
165 doc = "See the [“Global Options”](GlobalOpts) section."
166 )]
167 #[cfg_attr(
168 all(feature = "lt2017_1", not(feature = "lt2015_1")),
169 doc = "See [“Global Options”](GlobalOpts)."
170 )]
171 #[cfg_attr(
172 all(feature = "lt2018_2", not(feature = "lt2017_1")),
173 doc = "See [Global Options](GlobalOpts)."
174 )]
175 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
176 pub fn global_opts(mut self, v: GlobalOpts) -> Self {
177 self.global_opts = v;
178 self
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use crate::cmd::args_of;
186
187 #[test]
190 fn without_options() {
191 let r#where = Where::new("p4", GlobalOpts::new());
192
193 assert_eq!(args_of(&r#where.setup_command("p4")), ["where"]);
194 }
195
196 #[test]
197 fn with_global_opts() {
198 let r#where = Where::new(
199 "p4",
200 GlobalOpts::new().port("localhost:1666").quiet_mode(true),
201 );
202
203 assert_eq!(
204 args_of(&r#where.setup_command("p4")),
205 ["-p", "localhost:1666", "-q", "where"]
206 );
207 }
208
209 #[test]
210 fn with_files() {
211 let r#where = Where::new("p4", GlobalOpts::new());
212
213 assert_eq!(
214 args_of(r#where.setup_command("p4").args(["file.c"])),
215 ["where", "file.c"]
216 );
217 }
218}