p4_cmd/
where_.rs

1use std::path;
2use std::vec;
3
4use error;
5use p4;
6
7/// Show how file names are mapped by the client view
8///
9/// Where shows how the specified files are mapped by the client view.
10/// For each argument, three names are produced: the name in the depot,
11/// the name on the client in Perforce syntax, and the name on the client
12/// in local syntax.
13///
14/// If the file parameter is omitted, the mapping for all files in the
15/// current directory and below) is returned.
16///
17/// Note that 'p4 where' does not determine where any real files reside.
18/// It only displays the locations that are mapped by the client view.
19///
20/// # Examples
21///
22/// ```rust,no_run
23/// let p4 = p4_cmd::P4::new();
24/// let files = p4.where_().file("//depot/dir/*").run().unwrap();
25/// for file in files {
26///     println!("{:?}", file);
27/// }
28/// ```
29#[derive(Debug, Clone)]
30pub struct WhereCommand<'p, 'f> {
31    connection: &'p p4::P4,
32    file: Vec<&'f str>,
33}
34
35impl<'p, 'f> WhereCommand<'p, 'f> {
36    pub fn new(connection: &'p p4::P4) -> Self {
37        Self {
38            connection,
39            file: vec![],
40        }
41    }
42
43    /// Restrict the operation to the specified path.
44    pub fn file(mut self, file: &'f str) -> Self {
45        self.file.push(file);
46        self
47    }
48
49    /// Run the `where` command.
50    pub fn run(self) -> Result<Files, error::P4Error> {
51        let mut cmd = self.connection.connect_with_retries(None);
52        cmd.arg("where");
53        for file in self.file {
54            cmd.arg(file);
55        }
56        let data = cmd.output().map_err(|e| {
57            error::ErrorKind::SpawnFailed
58                .error()
59                .set_cause(e)
60                .set_context(format!("Command: {:?}", cmd))
61        })?;
62        let (_remains, (mut items, exit)) = where_parser::where_(&data.stdout).map_err(|_| {
63            error::ErrorKind::ParseFailed
64                .error()
65                .set_context(format!("Command: {:?}", cmd))
66        })?;
67        items.push(exit);
68        Ok(Files(items))
69    }
70}
71
72pub type FileItem = error::Item<File>;
73
74pub struct Files(Vec<FileItem>);
75
76impl IntoIterator for Files {
77    type Item = FileItem;
78    type IntoIter = FilesIntoIter;
79
80    fn into_iter(self) -> FilesIntoIter {
81        FilesIntoIter(self.0.into_iter())
82    }
83}
84
85#[derive(Debug)]
86pub struct FilesIntoIter(vec::IntoIter<FileItem>);
87
88impl Iterator for FilesIntoIter {
89    type Item = FileItem;
90
91    #[inline]
92    fn next(&mut self) -> Option<FileItem> {
93        self.0.next()
94    }
95
96    #[inline]
97    fn size_hint(&self) -> (usize, Option<usize>) {
98        self.0.size_hint()
99    }
100
101    #[inline]
102    fn count(self) -> usize {
103        self.0.count()
104    }
105}
106
107#[derive(Debug, Clone, PartialEq, Eq)]
108pub struct File {
109    pub depot_file: String,
110    pub client_file: String,
111    pub path: path::PathBuf,
112    non_exhaustive: (),
113}
114
115mod where_parser {
116    use super::*;
117
118    use super::super::parser::*;
119
120    named!(file<&[u8], File>,
121        do_parse!(
122            depot_file: depot_file >>
123            client_file: client_file >>
124            path: path >>
125            (
126                File {
127                    depot_file: depot_file.path.to_owned(),
128                    client_file: client_file.path.to_owned(),
129                    path: path::PathBuf::from(path.path),
130                    non_exhaustive: (),
131                }
132            )
133        )
134    );
135
136    named!(item<&[u8], FileItem>,
137        alt!(
138            map!(file, data_to_item) |
139            map!(error, error_to_item) |
140            map!(info, info_to_item)
141        )
142    );
143
144    named!(pub where_<&[u8], (Vec<FileItem>, FileItem)>,
145        pair!(
146            many0!(item),
147            map!(exit, exit_to_item)
148        )
149    );
150}