annotate rust/chg/src/locator.rs @ 44753:a347a329e48d

rust-chg: reimplement locator by using async/await and tokio-0.2 connect_spawned() is rewritten from scratch by using std::process. Before, it would select completion of either connection or server process. New code could be implemented as such, but it's much simpler to occasionally run try_wait() to detect server death. Differential Revision: https://phab.mercurial-scm.org/D8447
author Yuya Nishihara <yuya@tcha.org>
date Sat, 11 Apr 2020 00:47:32 +0900
parents e9e44e61042b
children 27fe8cc1338f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
1 // Copyright 2011, 2018 Yuya Nishihara <yuya@tcha.org>
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
2 //
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
3 // This software may be used and distributed according to the terms of the
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
4 // GNU General Public License version 2 or any later version.
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
5
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
6 //! Utility for locating command-server process.
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
7
44688
1f5ab1a9363d rust-chg: upgrade to 2018 edition and remove useless extern crates
Yuya Nishihara <yuya@tcha.org>
parents: 44684
diff changeset
8 use log::debug;
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
9 use std::env;
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
10 use std::ffi::{OsStr, OsString};
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
11 use std::fs::{self, DirBuilder};
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
12 use std::io;
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
13 use std::os::unix::ffi::{OsStrExt, OsStringExt};
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
14 use std::os::unix::fs::{DirBuilderExt, MetadataExt};
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
15 use std::path::{Path, PathBuf};
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
16 use std::process::{self, Child, Command};
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
17 use std::time::{Duration, Instant};
44737
e9e44e61042b rust-chg: upgrade to futures-0.3 based libraries
Yuya Nishihara <yuya@tcha.org>
parents: 44693
diff changeset
18 use tokio::time;
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
19
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
20 use crate::clientext::ChgClient;
44689
6bef9d43cc55 rust-chg: use "crate::" to import local modules
Yuya Nishihara <yuya@tcha.org>
parents: 44688
diff changeset
21 use crate::message::{Instruction, ServerSpec};
6bef9d43cc55 rust-chg: use "crate::" to import local modules
Yuya Nishihara <yuya@tcha.org>
parents: 44688
diff changeset
22 use crate::procutil;
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
23
44683
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
24 const REQUIRED_SERVER_CAPABILITIES: &[&str] = &[
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
25 "attachio",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
26 "chdir",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
27 "runcommand",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
28 "setenv",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
29 "setumask2",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
30 "validate",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
31 ];
44672
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
32
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
33 /// Helper to connect to and spawn a server process.
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
34 #[derive(Clone, Debug)]
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
35 pub struct Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
36 hg_command: OsString,
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
37 hg_early_args: Vec<OsString>,
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
38 current_dir: PathBuf,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
39 env_vars: Vec<(OsString, OsString)>,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
40 process_id: u32,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
41 base_sock_path: PathBuf,
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
42 redirect_sock_path: Option<PathBuf>,
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
43 timeout: Duration,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
44 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
45
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
46 impl Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
47 /// Creates locator capturing the current process environment.
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
48 ///
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
49 /// If no `$CHGSOCKNAME` is specified, the socket directory will be
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
50 /// created as necessary.
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
51 pub fn prepare_from_env() -> io::Result<Locator> {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
52 Ok(Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
53 hg_command: default_hg_command(),
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
54 hg_early_args: Vec::new(),
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
55 current_dir: env::current_dir()?,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
56 env_vars: env::vars_os().collect(),
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
57 process_id: process::id(),
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
58 base_sock_path: prepare_server_socket_path()?,
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
59 redirect_sock_path: None,
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
60 timeout: default_timeout(),
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
61 })
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
62 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
63
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
64 /// Temporary socket path for this client process.
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
65 fn temp_sock_path(&self) -> PathBuf {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
66 let src = self.base_sock_path.as_os_str().as_bytes();
44668
c11d98cff883 rust-chg: add brief comment about initial capacity of temp_sock_path()
Yuya Nishihara <yuya@tcha.org>
parents: 43818
diff changeset
67 let mut buf = Vec::with_capacity(src.len() + 6); // "{src}.{pid}".len()
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
68 buf.extend_from_slice(src);
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
69 buf.extend_from_slice(format!(".{}", self.process_id).as_bytes());
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
70 OsString::from_vec(buf).into()
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
71 }
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
72
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
73 /// Specifies the arguments to be passed to the server at start.
44693
61fda2dbc522 rust-chg: leverage impl trait at argument position
Yuya Nishihara <yuya@tcha.org>
parents: 44689
diff changeset
74 pub fn set_early_args(&mut self, args: impl IntoIterator<Item = impl AsRef<OsStr>>) {
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
75 self.hg_early_args = args.into_iter().map(|a| a.as_ref().to_owned()).collect();
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
76 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
77
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
78 /// Connects to the server.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
79 ///
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
80 /// The server process will be spawned if not running.
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
81 pub async fn connect(&mut self) -> io::Result<ChgClient> {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
82 for _cnt in 0..10 {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
83 let mut client = self.try_connect().await?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
84 let instructions = client.validate(&self.hg_early_args).await?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
85 let reconnect = self.run_instructions(&instructions)?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
86 if !reconnect {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
87 return Ok(client);
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
88 }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
89 }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
90
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
91 // TODO: unindent
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
92 {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
93 {
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
94 let msg = format!(
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
95 concat!(
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
96 "too many redirections.\n",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
97 "Please make sure {:?} is not a wrapper which ",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
98 "changes sensitive environment variables ",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
99 "before executing hg. If you have to use a ",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
100 "wrapper, wrap chg instead of hg.",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
101 ),
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
102 self.hg_command
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
103 );
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
104 Err(io::Error::new(io::ErrorKind::Other, msg))
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
105 }
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
106 }
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
107 }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
108
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
109 /// Runs instructions received from the server.
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
110 ///
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
111 /// Returns true if the client should try connecting to the other server.
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
112 fn run_instructions(&mut self, instructions: &[Instruction]) -> io::Result<bool> {
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
113 let mut reconnect = false;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
114 for inst in instructions {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
115 debug!("instruction: {:?}", inst);
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
116 match inst {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
117 Instruction::Exit(_) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
118 // Just returns the current connection to run the
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
119 // unparsable command and report the error
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
120 return Ok(false);
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
121 }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
122 Instruction::Reconnect => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
123 reconnect = true;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
124 }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
125 Instruction::Redirect(path) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
126 if path.parent() != self.base_sock_path.parent() {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
127 let msg = format!(
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
128 "insecure redirect instruction from server: {}",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
129 path.display()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
130 );
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
131 return Err(io::Error::new(io::ErrorKind::InvalidData, msg));
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
132 }
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
133 self.redirect_sock_path = Some(path.to_owned());
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
134 reconnect = true;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
135 }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
136 Instruction::Unlink(path) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
137 if path.parent() != self.base_sock_path.parent() {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
138 let msg = format!(
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
139 "insecure unlink instruction from server: {}",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
140 path.display()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
141 );
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
142 return Err(io::Error::new(io::ErrorKind::InvalidData, msg));
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
143 }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
144 fs::remove_file(path).unwrap_or(()); // may race
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
145 }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
146 }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
147 }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
148
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
149 Ok(reconnect)
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
150 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
151
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
152 /// Tries to connect to the existing server, or spawns new if not running.
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
153 async fn try_connect(&mut self) -> io::Result<ChgClient> {
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
154 let sock_path = self
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
155 .redirect_sock_path
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
156 .as_ref()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
157 .unwrap_or(&self.base_sock_path)
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
158 .clone();
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
159 debug!("try connect to {}", sock_path.display());
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
160 // TODO: unindent
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
161 {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
162 {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
163 let mut client = match ChgClient::connect(sock_path).await {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
164 Ok(client) => client,
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
165 Err(_) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
166 // Prevent us from being re-connected to the outdated
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
167 // master server: We were told by the server to redirect
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
168 // to redirect_sock_path, which didn't work. We do not
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
169 // want to connect to the same master server again
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
170 // because it would probably tell us the same thing.
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
171 if self.redirect_sock_path.is_some() {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
172 fs::remove_file(&self.base_sock_path).unwrap_or(());
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
173 // may race
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
174 }
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
175 self.spawn_connect().await?
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
176 }
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
177 };
44672
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
178 check_server_capabilities(client.server_spec())?;
44684
80d6e3415636 rust-chg: update name of the server process
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
179 // It's purely optional, and the server might not support this command.
80d6e3415636 rust-chg: update name of the server process
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
180 if client.server_spec().capabilities.contains("setprocname") {
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
181 client
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
182 .set_process_name(format!("chg[worker/{}]", self.process_id))
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
183 .await?;
44684
80d6e3415636 rust-chg: update name of the server process
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
184 }
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
185 client.set_current_dir(&self.current_dir).await?;
44673
0a2516efc463 rust-chg: move set_current_dir() to Locator
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
186 client
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
187 .set_env_vars_os(self.env_vars.iter().cloned())
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
188 .await?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
189 Ok(client)
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
190 }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
191 }
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
192 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
193
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
194 /// Spawns new server process and connects to it.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
195 ///
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
196 /// The server will be spawned at the current working directory, then
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
197 /// chdir to "/", so that the server will load configs from the target
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
198 /// repository.
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
199 async fn spawn_connect(&mut self) -> io::Result<ChgClient> {
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
200 let sock_path = self.temp_sock_path();
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
201 debug!("start cmdserver at {}", sock_path.display());
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
202 let server = Command::new(&self.hg_command)
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
203 .arg("serve")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
204 .arg("--cmdserver")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
205 .arg("chgunix")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
206 .arg("--address")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
207 .arg(&sock_path)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
208 .arg("--daemon-postexec")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
209 .arg("chdir:/")
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
210 .args(&self.hg_early_args)
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
211 .current_dir(&self.current_dir)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
212 .env_clear()
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
213 .envs(self.env_vars.iter().cloned())
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
214 .env("CHGINTERNALMARK", "")
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
215 .spawn()?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
216 let client = self.connect_spawned(server, &sock_path).await?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
217 // TODO: unindent
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
218 {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
219 {
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
220 debug!(
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
221 "rename {} to {}",
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
222 sock_path.display(),
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
223 self.base_sock_path.display()
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
224 );
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
225 fs::rename(&sock_path, &self.base_sock_path)?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
226 Ok(client)
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
227 }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
228 }
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
229 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
230
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
231 /// Tries to connect to the just spawned server repeatedly until timeout
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
232 /// exceeded.
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
233 async fn connect_spawned(
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
234 &mut self,
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
235 mut server: Child,
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
236 sock_path: &Path,
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
237 ) -> io::Result<ChgClient> {
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
238 debug!("try connect to {} repeatedly", sock_path.display());
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
239 // waits for either connection established or server failed to start
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
240 let start_time = Instant::now();
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
241 while start_time.elapsed() < self.timeout {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
242 if let Ok(client) = ChgClient::connect(&sock_path).await {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
243 // server handle is dropped here, but the detached process
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
244 // will continue running in background
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
245 return Ok(client);
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
246 }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
247
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
248 if let Some(st) = server.try_wait()? {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
249 return Err(io::Error::new(
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
250 io::ErrorKind::Other,
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
251 format!("server exited too early: {}", st),
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
252 ));
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
253 }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
254
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
255 // try again with slight delay
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
256 time::delay_for(Duration::from_millis(10)).await;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
257 }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
258
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
259 Err(io::Error::new(
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
260 io::ErrorKind::TimedOut,
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
261 "timed out while connecting to server",
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
262 ))
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
263 }
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
264 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
265
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
266 /// Determines the server socket to connect to.
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
267 ///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
268 /// If no `$CHGSOCKNAME` is specified, the socket directory will be created
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
269 /// as necessary.
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
270 fn prepare_server_socket_path() -> io::Result<PathBuf> {
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
271 if let Some(s) = env::var_os("CHGSOCKNAME") {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
272 Ok(PathBuf::from(s))
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
273 } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
274 let mut path = default_server_socket_dir();
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
275 create_secure_dir(&path)?;
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
276 path.push("server");
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
277 Ok(path)
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
278 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
279 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
280
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
281 /// Determines the default server socket path as follows.
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
282 ///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
283 /// 1. `$XDG_RUNTIME_DIR/chg`
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
284 /// 2. `$TMPDIR/chg$UID`
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
285 /// 3. `/tmp/chg$UID`
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
286 pub fn default_server_socket_dir() -> PathBuf {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
287 // XDG_RUNTIME_DIR should be ignored if it has an insufficient permission.
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
288 // https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
289 if let Some(Ok(s)) = env::var_os("XDG_RUNTIME_DIR").map(check_secure_dir) {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
290 let mut path = PathBuf::from(s);
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
291 path.push("chg");
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
292 path
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
293 } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
294 let mut path = env::temp_dir();
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
295 path.push(format!("chg{}", procutil::get_effective_uid()));
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
296 path
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
297 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
298 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
299
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
300 /// Determines the default hg command.
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
301 pub fn default_hg_command() -> OsString {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
302 // TODO: maybe allow embedding the path at compile time (or load from hgrc)
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
303 env::var_os("CHGHG")
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
304 .or(env::var_os("HG"))
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
305 .unwrap_or(OsStr::new("hg").to_owned())
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
306 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
307
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
308 fn default_timeout() -> Duration {
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
309 let secs = env::var("CHGTIMEOUT")
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
310 .ok()
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
311 .and_then(|s| s.parse().ok())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
312 .unwrap_or(60);
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
313 Duration::from_secs(secs)
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
314 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
315
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
316 /// Creates a directory which the other users cannot access to.
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
317 ///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
318 /// If the directory already exists, tests its permission.
44693
61fda2dbc522 rust-chg: leverage impl trait at argument position
Yuya Nishihara <yuya@tcha.org>
parents: 44689
diff changeset
319 fn create_secure_dir(path: impl AsRef<Path>) -> io::Result<()> {
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
320 DirBuilder::new()
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
321 .mode(0o700)
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
322 .create(path.as_ref())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
323 .or_else(|err| {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
324 if err.kind() == io::ErrorKind::AlreadyExists {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
325 check_secure_dir(path).map(|_| ())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
326 } else {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
327 Err(err)
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
328 }
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
329 })
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
330 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
331
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
332 fn check_secure_dir<P>(path: P) -> io::Result<P>
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
333 where
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
334 P: AsRef<Path>,
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
335 {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
336 let a = fs::symlink_metadata(path.as_ref())?;
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
337 if a.is_dir() && a.uid() == procutil::get_effective_uid() && (a.mode() & 0o777) == 0o700 {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
338 Ok(path)
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
339 } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
340 Err(io::Error::new(io::ErrorKind::Other, "insecure directory"))
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
341 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
342 }
44672
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
343
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
344 fn check_server_capabilities(spec: &ServerSpec) -> io::Result<()> {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
345 let unsupported: Vec<_> = REQUIRED_SERVER_CAPABILITIES
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
346 .iter()
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
347 .cloned()
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
348 .filter(|&s| !spec.capabilities.contains(s))
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
349 .collect();
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
350 if unsupported.is_empty() {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
351 Ok(())
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
352 } else {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
353 let msg = format!(
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
354 "insufficient server capabilities: {}",
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
355 unsupported.join(", ")
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
356 );
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
357 Err(io::Error::new(io::ErrorKind::Other, msg))
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
358 }
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
359 }
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
360
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
361 /// Collects arguments which need to be passed to the server at start.
44693
61fda2dbc522 rust-chg: leverage impl trait at argument position
Yuya Nishihara <yuya@tcha.org>
parents: 44689
diff changeset
362 pub fn collect_early_args(args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> Vec<OsString> {
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
363 let mut args_iter = args.into_iter();
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
364 let mut early_args = Vec::new();
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
365 while let Some(arg) = args_iter.next() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
366 let argb = arg.as_ref().as_bytes();
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
367 if argb == b"--" {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
368 break;
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
369 } else if argb.starts_with(b"--") {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
370 let mut split = argb[2..].splitn(2, |&c| c == b'=');
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
371 match split.next().unwrap() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
372 b"traceback" => {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
373 if split.next().is_none() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
374 early_args.push(arg.as_ref().to_owned());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
375 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
376 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
377 b"config" | b"cwd" | b"repo" | b"repository" => {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
378 if split.next().is_some() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
379 // --<flag>=<val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
380 early_args.push(arg.as_ref().to_owned());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
381 } else {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
382 // --<flag> <val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
383 args_iter.next().map(|val| {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
384 early_args.push(arg.as_ref().to_owned());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
385 early_args.push(val.as_ref().to_owned());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
386 });
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
387 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
388 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
389 _ => {}
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
390 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
391 } else if argb.starts_with(b"-R") {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
392 if argb.len() > 2 {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
393 // -R<val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
394 early_args.push(arg.as_ref().to_owned());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
395 } else {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
396 // -R <val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
397 args_iter.next().map(|val| {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
398 early_args.push(arg.as_ref().to_owned());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
399 early_args.push(val.as_ref().to_owned());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
400 });
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
401 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
402 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
403 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
404
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
405 early_args
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
406 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
407
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
408 #[cfg(test)]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
409 mod tests {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
410 use super::*;
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
411
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
412 #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
413 fn collect_early_args_some() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
414 assert!(collect_early_args(&[] as &[&OsStr]).is_empty());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
415 assert!(collect_early_args(&["log"]).is_empty());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
416 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
417 collect_early_args(&["log", "-Ra", "foo"]),
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
418 os_string_vec_from(&[b"-Ra"])
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
419 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
420 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
421 collect_early_args(&["log", "-R", "repo", "", "--traceback", "a"]),
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
422 os_string_vec_from(&[b"-R", b"repo", b"--traceback"])
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
423 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
424 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
425 collect_early_args(&["log", "--config", "diff.git=1", "-q"]),
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
426 os_string_vec_from(&[b"--config", b"diff.git=1"])
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
427 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
428 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
429 collect_early_args(&["--cwd=..", "--repository", "r", "log"]),
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
430 os_string_vec_from(&[b"--cwd=..", b"--repository", b"r"])
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
431 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
432 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
433 collect_early_args(&["log", "--repo=r", "--repos", "a"]),
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
434 os_string_vec_from(&[b"--repo=r"])
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
435 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
436 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
437
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
438 #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
439 fn collect_early_args_orphaned() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
440 assert!(collect_early_args(&["log", "-R"]).is_empty());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
441 assert!(collect_early_args(&["log", "--config"]).is_empty());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
442 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
443
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
444 #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
445 fn collect_early_args_unwanted_value() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
446 assert!(collect_early_args(&["log", "--traceback="]).is_empty());
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
447 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
448
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
449 fn os_string_vec_from(v: &[&[u8]]) -> Vec<OsString> {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
450 v.iter().map(|s| OsStr::from_bytes(s).to_owned()).collect()
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
451 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
452 }