1use std::vec;
2
3use error;
4use p4;
5
6#[derive(Debug, Clone)]
30pub struct FilesCommand<'p, 'f> {
31 connection: &'p p4::P4,
32 file: Vec<&'f str>,
33
34 list_revisions: bool,
35 syncable_only: bool,
36 ignore_case: bool,
37 max: Option<usize>,
38}
39
40impl<'p, 'f> FilesCommand<'p, 'f> {
41 pub fn new(connection: &'p p4::P4, file: &'f str) -> Self {
42 Self {
43 connection,
44 file: vec![file],
45 list_revisions: false,
46 syncable_only: false,
47 ignore_case: false,
48 max: None,
49 }
50 }
51
52 pub fn file(mut self, file: &'f str) -> Self {
53 self.file.push(file);
54 self
55 }
56
57 pub fn list_revisions(mut self, list_revisions: bool) -> Self {
60 self.list_revisions = list_revisions;
61 self
62 }
63
64 pub fn syncable_only(mut self, syncable_only: bool) -> Self {
68 self.syncable_only = syncable_only;
69 self
70 }
71
72 pub fn ignore_case(mut self, ignore_case: bool) -> Self {
75 self.ignore_case = ignore_case;
76 self
77 }
78
79 pub fn set_max(mut self, max: Option<usize>) -> Self {
81 self.max = max;
82 self
83 }
84
85 pub fn run(self) -> Result<Files, error::P4Error> {
87 let mut cmd = self.connection.connect_with_retries(None);
88 cmd.arg("files");
89 if self.list_revisions {
90 cmd.arg("-a");
91 }
92 if self.syncable_only {
93 cmd.arg("-e");
94 }
95 if self.ignore_case {
96 cmd.arg("-i");
97 }
98 if let Some(max) = self.max {
99 cmd.arg(format!("-m {}", max));
100 }
101 for file in self.file {
102 cmd.arg(file);
103 }
104 let data = cmd.output().map_err(|e| {
105 error::ErrorKind::SpawnFailed
106 .error()
107 .set_cause(e)
108 .set_context(format!("Command: {:?}", cmd))
109 })?;
110 let (_remains, (mut items, exit)) = files_parser::files(&data.stdout).map_err(|_| {
111 error::ErrorKind::ParseFailed
112 .error()
113 .set_context(format!("Command: {:?}", cmd))
114 })?;
115 items.push(exit);
116 Ok(Files(items))
117 }
118}
119
120pub type FileItem = error::Item<File>;
121
122pub struct Files(Vec<FileItem>);
123
124impl IntoIterator for Files {
125 type Item = FileItem;
126 type IntoIter = FilesIntoIter;
127
128 fn into_iter(self) -> FilesIntoIter {
129 FilesIntoIter(self.0.into_iter())
130 }
131}
132
133#[derive(Debug)]
134pub struct FilesIntoIter(vec::IntoIter<FileItem>);
135
136impl Iterator for FilesIntoIter {
137 type Item = FileItem;
138
139 #[inline]
140 fn next(&mut self) -> Option<FileItem> {
141 self.0.next()
142 }
143
144 #[inline]
145 fn size_hint(&self) -> (usize, Option<usize>) {
146 self.0.size_hint()
147 }
148
149 #[inline]
150 fn count(self) -> usize {
151 self.0.count()
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct File {
157 pub depot_file: String,
158 pub rev: usize,
159 pub change: usize,
160 pub action: p4::Action,
161 pub file_type: p4::FileType,
162 pub time: p4::Time,
163 non_exhaustive: (),
164}
165
166mod files_parser {
167 use super::*;
168
169 use super::super::parser::*;
170
171 named!(file<&[u8], File>,
172 do_parse!(
173 depot_file: depot_file >>
174 rev: rev >>
175 change: change >>
176 action: action >>
177 file_type: file_type >>
178 time: time >>
179 (
180 File {
181 depot_file: depot_file.path.to_owned(),
182 rev: rev.rev,
183 change: change.change,
184 action: action.action.parse().expect("Unknown to capture all"),
185 file_type: file_type.ft.parse().expect("Unknown to capture all"),
186 time: p4::from_timestamp(time.time),
187 non_exhaustive: (),
188 }
189 )
190 )
191 );
192
193 named!(item<&[u8], FileItem>,
194 alt!(
195 map!(file, data_to_item) |
196 map!(error, error_to_item) |
197 map!(info, info_to_item)
198 )
199 );
200
201 named!(pub files<&[u8], (Vec<FileItem>, FileItem)>,
202 pair!(
203 many0!(item),
204 map!(exit, exit_to_item)
205 )
206 );
207}