1use std::vec;
2
3use error;
4use p4;
5
6#[derive(Debug, Clone)]
31pub struct DirsCommand<'p, 'f, 's> {
32 connection: &'p p4::P4,
33 dir: Vec<&'f str>,
34
35 client_only: bool,
36 stream: Option<&'s str>,
37 include_deleted: bool,
38 include_synced: bool,
39 ignore_case: bool,
40}
41
42impl<'p, 'f, 's> DirsCommand<'p, 'f, 's> {
43 pub fn new(connection: &'p p4::P4, dir: &'f str) -> Self {
44 Self {
45 connection,
46 dir: vec![dir],
47 client_only: false,
48 stream: None,
49 include_deleted: false,
50 include_synced: false,
51 ignore_case: false,
52 }
53 }
54
55 pub fn dir(mut self, dir: &'f str) -> Self {
56 self.dir.push(dir);
57 self
58 }
59
60 pub fn client_only(mut self, client_only: bool) -> Self {
63 self.client_only = client_only;
64 self
65 }
66
67 pub fn set_stream(mut self, stream: &'s str) -> Self {
70 self.stream = Some(stream);
71 self
72 }
73
74 pub fn include_deleted(mut self, include_deleted: bool) -> Self {
76 self.include_deleted = include_deleted;
77 self
78 }
79
80 pub fn include_synced(mut self, include_synced: bool) -> Self {
83 self.include_synced = include_synced;
84 self
85 }
86
87 pub fn ignore_case(mut self, ignore_case: bool) -> Self {
91 self.ignore_case = ignore_case;
92 self
93 }
94
95 pub fn run(self) -> Result<Dirs, error::P4Error> {
97 let mut cmd = self.connection.connect_with_retries(None);
98 cmd.arg("dirs");
99 if self.client_only {
100 cmd.arg("-C");
101 }
102 if let Some(stream) = self.stream {
103 cmd.args(&["-S", stream]);
104 }
105 if self.include_deleted {
106 cmd.arg("-D");
107 }
108 if self.include_synced {
109 cmd.arg("-H");
110 }
111 if self.ignore_case {
112 cmd.arg("-i");
113 }
114 for dir in self.dir {
115 cmd.arg(dir);
116 }
117 let data = cmd.output().map_err(|e| {
118 error::ErrorKind::SpawnFailed
119 .error()
120 .set_cause(e)
121 .set_context(format!("Command: {:?}", cmd))
122 })?;
123 let (_remains, (mut items, exit)) = dirs_parser::dirs(&data.stdout).map_err(|_| {
124 error::ErrorKind::ParseFailed
125 .error()
126 .set_context(format!("Command: {:?}", cmd))
127 })?;
128 items.push(exit);
129 Ok(Dirs(items))
130 }
131}
132
133pub type DirItem = error::Item<Dir>;
134
135pub struct Dirs(Vec<DirItem>);
136
137impl IntoIterator for Dirs {
138 type Item = DirItem;
139 type IntoIter = DirsIntoIter;
140
141 fn into_iter(self) -> DirsIntoIter {
142 DirsIntoIter(self.0.into_iter())
143 }
144}
145
146#[derive(Debug)]
147pub struct DirsIntoIter(vec::IntoIter<DirItem>);
148
149impl Iterator for DirsIntoIter {
150 type Item = DirItem;
151
152 #[inline]
153 fn next(&mut self) -> Option<DirItem> {
154 self.0.next()
155 }
156
157 #[inline]
158 fn size_hint(&self) -> (usize, Option<usize>) {
159 self.0.size_hint()
160 }
161
162 #[inline]
163 fn count(self) -> usize {
164 self.0.count()
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq)]
169pub struct Dir {
170 pub dir: String,
171 non_exhaustive: (),
172}
173
174mod dirs_parser {
175 use super::super::parser::*;
176
177 named!(dir_<&[u8], super::Dir>,
178 do_parse!(
179 dir: dir >>
180 (
181 super::Dir {
182 dir: dir.dir.to_owned(),
183 non_exhaustive: (),
184 }
185 )
186 )
187 );
188
189 named!(item<&[u8], super::DirItem>,
190 alt!(
191 map!(dir_, data_to_item) |
192 map!(error, error_to_item) |
193 map!(info, info_to_item)
194 )
195 );
196
197 named!(pub dirs<&[u8], (Vec<super::DirItem>, super::DirItem)>,
198 pair!(
199 many0!(item),
200 map!(exit, exit_to_item)
201 )
202 );
203}