comparison rust/chg/src/locator.rs @ 44681:00ac60658654

rust-chg: collect server flags from command arguments This is the reimplementation of testsensitiveflag() and setcmdserverargs() of chg.c. Differential Revision: https://phab.mercurial-scm.org/D8380
author Yuya Nishihara <yuya@tcha.org>
date Sun, 07 Oct 2018 16:46:30 +0900
parents 97e6d435ff7e
children 9ce613d648de
comparison
equal deleted inserted replaced
44680:43513444bb88 44681:00ac60658654
28 28
29 /// Helper to connect to and spawn a server process. 29 /// Helper to connect to and spawn a server process.
30 #[derive(Clone, Debug)] 30 #[derive(Clone, Debug)]
31 pub struct Locator { 31 pub struct Locator {
32 hg_command: OsString, 32 hg_command: OsString,
33 hg_early_args: Vec<OsString>,
33 current_dir: PathBuf, 34 current_dir: PathBuf,
34 env_vars: Vec<(OsString, OsString)>, 35 env_vars: Vec<(OsString, OsString)>,
35 process_id: u32, 36 process_id: u32,
36 base_sock_path: PathBuf, 37 base_sock_path: PathBuf,
37 timeout: Duration, 38 timeout: Duration,
43 /// If no `$CHGSOCKNAME` is specified, the socket directory will be 44 /// If no `$CHGSOCKNAME` is specified, the socket directory will be
44 /// created as necessary. 45 /// created as necessary.
45 pub fn prepare_from_env() -> io::Result<Locator> { 46 pub fn prepare_from_env() -> io::Result<Locator> {
46 Ok(Locator { 47 Ok(Locator {
47 hg_command: default_hg_command(), 48 hg_command: default_hg_command(),
49 hg_early_args: Vec::new(),
48 current_dir: env::current_dir()?, 50 current_dir: env::current_dir()?,
49 env_vars: env::vars_os().collect(), 51 env_vars: env::vars_os().collect(),
50 process_id: process::id(), 52 process_id: process::id(),
51 base_sock_path: prepare_server_socket_path()?, 53 base_sock_path: prepare_server_socket_path()?,
52 timeout: default_timeout(), 54 timeout: default_timeout(),
58 let src = self.base_sock_path.as_os_str().as_bytes(); 60 let src = self.base_sock_path.as_os_str().as_bytes();
59 let mut buf = Vec::with_capacity(src.len() + 6); // "{src}.{pid}".len() 61 let mut buf = Vec::with_capacity(src.len() + 6); // "{src}.{pid}".len()
60 buf.extend_from_slice(src); 62 buf.extend_from_slice(src);
61 buf.extend_from_slice(format!(".{}", self.process_id).as_bytes()); 63 buf.extend_from_slice(format!(".{}", self.process_id).as_bytes());
62 OsString::from_vec(buf).into() 64 OsString::from_vec(buf).into()
65 }
66
67 /// Specifies the arguments to be passed to the server at start.
68 pub fn set_early_args<I, P>(&mut self, args: I)
69 where
70 I: IntoIterator<Item = P>,
71 P: AsRef<OsStr>,
72 {
73 self.hg_early_args = args.into_iter().map(|a| a.as_ref().to_owned()).collect();
63 } 74 }
64 75
65 /// Connects to the server. 76 /// Connects to the server.
66 /// 77 ///
67 /// The server process will be spawned if not running. 78 /// The server process will be spawned if not running.
107 .arg("chgunix") 118 .arg("chgunix")
108 .arg("--address") 119 .arg("--address")
109 .arg(&sock_path) 120 .arg(&sock_path)
110 .arg("--daemon-postexec") 121 .arg("--daemon-postexec")
111 .arg("chdir:/") 122 .arg("chdir:/")
123 .args(&self.hg_early_args)
112 .current_dir(&self.current_dir) 124 .current_dir(&self.current_dir)
113 .env_clear() 125 .env_clear()
114 .envs(self.env_vars.iter().cloned()) 126 .envs(self.env_vars.iter().cloned())
115 .env("CHGINTERNALMARK", "") 127 .env("CHGINTERNALMARK", "")
116 .spawn_async() 128 .spawn_async()
273 unsupported.join(", ") 285 unsupported.join(", ")
274 ); 286 );
275 Err(io::Error::new(io::ErrorKind::Other, msg)) 287 Err(io::Error::new(io::ErrorKind::Other, msg))
276 } 288 }
277 } 289 }
290
291 /// Collects arguments which need to be passed to the server at start.
292 pub fn collect_early_args<I, P>(args: I) -> Vec<OsString>
293 where
294 I: IntoIterator<Item = P>,
295 P: AsRef<OsStr>,
296 {
297 let mut args_iter = args.into_iter();
298 let mut early_args = Vec::new();
299 while let Some(arg) = args_iter.next() {
300 let argb = arg.as_ref().as_bytes();
301 if argb == b"--" {
302 break;
303 } else if argb.starts_with(b"--") {
304 let mut split = argb[2..].splitn(2, |&c| c == b'=');
305 match split.next().unwrap() {
306 b"traceback" => {
307 if split.next().is_none() {
308 early_args.push(arg.as_ref().to_owned());
309 }
310 }
311 b"config" | b"cwd" | b"repo" | b"repository" => {
312 if split.next().is_some() {
313 // --<flag>=<val>
314 early_args.push(arg.as_ref().to_owned());
315 } else {
316 // --<flag> <val>
317 args_iter.next().map(|val| {
318 early_args.push(arg.as_ref().to_owned());
319 early_args.push(val.as_ref().to_owned());
320 });
321 }
322 }
323 _ => {}
324 }
325 } else if argb.starts_with(b"-R") {
326 if argb.len() > 2 {
327 // -R<val>
328 early_args.push(arg.as_ref().to_owned());
329 } else {
330 // -R <val>
331 args_iter.next().map(|val| {
332 early_args.push(arg.as_ref().to_owned());
333 early_args.push(val.as_ref().to_owned());
334 });
335 }
336 }
337 }
338
339 early_args
340 }
341
342 #[cfg(test)]
343 mod tests {
344 use super::*;
345
346 #[test]
347 fn collect_early_args_some() {
348 assert!(collect_early_args(&[] as &[&OsStr]).is_empty());
349 assert!(collect_early_args(&["log"]).is_empty());
350 assert_eq!(
351 collect_early_args(&["log", "-Ra", "foo"]),
352 os_string_vec_from(&[b"-Ra"])
353 );
354 assert_eq!(
355 collect_early_args(&["log", "-R", "repo", "", "--traceback", "a"]),
356 os_string_vec_from(&[b"-R", b"repo", b"--traceback"])
357 );
358 assert_eq!(
359 collect_early_args(&["log", "--config", "diff.git=1", "-q"]),
360 os_string_vec_from(&[b"--config", b"diff.git=1"])
361 );
362 assert_eq!(
363 collect_early_args(&["--cwd=..", "--repository", "r", "log"]),
364 os_string_vec_from(&[b"--cwd=..", b"--repository", b"r"])
365 );
366 assert_eq!(
367 collect_early_args(&["log", "--repo=r", "--repos", "a"]),
368 os_string_vec_from(&[b"--repo=r"])
369 );
370 }
371
372 #[test]
373 fn collect_early_args_orphaned() {
374 assert!(collect_early_args(&["log", "-R"]).is_empty());
375 assert!(collect_early_args(&["log", "--config"]).is_empty());
376 }
377
378 #[test]
379 fn collect_early_args_unwanted_value() {
380 assert!(collect_early_args(&["log", "--traceback="]).is_empty());
381 }
382
383 fn os_string_vec_from(v: &[&[u8]]) -> Vec<OsString> {
384 v.iter().map(|s| OsStr::from_bytes(s).to_owned()).collect()
385 }
386 }