##// END OF EJS Templates
rust-chg: add helper to parse instructions sent from server...
Yuya Nishihara -
r45170:82adc720 default
parent child Browse files
Show More
@@ -10,6 +10,7 b' use std::error;'
10 use std::ffi::{OsStr, OsString};
10 use std::ffi::{OsStr, OsString};
11 use std::io;
11 use std::io;
12 use std::os::unix::ffi::OsStrExt;
12 use std::os::unix::ffi::OsStrExt;
13 use std::path::PathBuf;
13
14
14 pub use tokio_hglib::message::*; // re-exports
15 pub use tokio_hglib::message::*; // re-exports
15
16
@@ -67,6 +68,42 b' fn parse_command_type(value: &[u8]) -> i'
67 }
68 }
68 }
69 }
69
70
71 /// Client-side instruction requested by the server.
72 #[derive(Clone, Debug, Eq, PartialEq)]
73 pub enum Instruction {
74 Exit(i32),
75 Reconnect,
76 Redirect(PathBuf),
77 Unlink(PathBuf),
78 }
79
80 /// Parses validation result into instructions.
81 pub fn parse_instructions(data: Bytes) -> io::Result<Vec<Instruction>> {
82 let mut instructions = Vec::new();
83 for l in data.split(|&c| c == b'\0') {
84 if l.is_empty() {
85 continue;
86 }
87 let mut s = l.splitn(2, |&c| c == b' ');
88 let inst = match (s.next().unwrap(), s.next()) {
89 (b"exit", Some(arg)) => decode_latin1(arg)
90 .parse()
91 .map(Instruction::Exit)
92 .map_err(|_| new_parse_error(format!("invalid exit code: {:?}", arg)))?,
93 (b"reconnect", None) => Instruction::Reconnect,
94 (b"redirect", Some(arg)) => {
95 Instruction::Redirect(OsStr::from_bytes(arg).to_owned().into())
96 }
97 (b"unlink", Some(arg)) => Instruction::Unlink(OsStr::from_bytes(arg).to_owned().into()),
98 _ => {
99 return Err(new_parse_error(format!("unknown command: {:?}", l)));
100 }
101 };
102 instructions.push(inst);
103 }
104 Ok(instructions)
105 }
106
70 // allocate large buffer as environment variables can be quite long
107 // allocate large buffer as environment variables can be quite long
71 const INITIAL_PACKED_ENV_VARS_CAPACITY: usize = 4096;
108 const INITIAL_PACKED_ENV_VARS_CAPACITY: usize = 4096;
72
109
@@ -168,6 +205,50 b' mod tests {'
168 }
205 }
169
206
170 #[test]
207 #[test]
208 fn parse_instructions_good() {
209 let src = [
210 b"exit 123".as_ref(),
211 b"reconnect".as_ref(),
212 b"redirect /whatever".as_ref(),
213 b"unlink /someother".as_ref(),
214 ]
215 .join(&0);
216 let insts = vec![
217 Instruction::Exit(123),
218 Instruction::Reconnect,
219 Instruction::Redirect(path_buf_from(b"/whatever")),
220 Instruction::Unlink(path_buf_from(b"/someother")),
221 ];
222 assert_eq!(parse_instructions(Bytes::from(src)).unwrap(), insts);
223 }
224
225 #[test]
226 fn parse_instructions_empty() {
227 assert_eq!(parse_instructions(Bytes::new()).unwrap(), vec![]);
228 assert_eq!(
229 parse_instructions(Bytes::from_static(b"\0")).unwrap(),
230 vec![]
231 );
232 }
233
234 #[test]
235 fn parse_instructions_malformed_exit_code() {
236 assert!(parse_instructions(Bytes::from_static(b"exit foo")).is_err());
237 }
238
239 #[test]
240 fn parse_instructions_missing_argument() {
241 assert!(parse_instructions(Bytes::from_static(b"exit")).is_err());
242 assert!(parse_instructions(Bytes::from_static(b"redirect")).is_err());
243 assert!(parse_instructions(Bytes::from_static(b"unlink")).is_err());
244 }
245
246 #[test]
247 fn parse_instructions_unknown_command() {
248 assert!(parse_instructions(Bytes::from_static(b"quit 0")).is_err());
249 }
250
251 #[test]
171 fn pack_env_vars_os_good() {
252 fn pack_env_vars_os_good() {
172 assert_eq!(
253 assert_eq!(
173 pack_env_vars_os(vec![] as Vec<(OsString, OsString)>),
254 pack_env_vars_os(vec![] as Vec<(OsString, OsString)>),
@@ -229,4 +310,8 b' mod tests {'
229 fn os_string_pair_from(k: &[u8], v: &[u8]) -> (OsString, OsString) {
310 fn os_string_pair_from(k: &[u8], v: &[u8]) -> (OsString, OsString) {
230 (os_string_from(k), os_string_from(v))
311 (os_string_from(k), os_string_from(v))
231 }
312 }
313
314 fn path_buf_from(s: &[u8]) -> PathBuf {
315 os_string_from(s).into()
316 }
232 }
317 }
General Comments 0
You need to be logged in to leave comments. Login now