annotate 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
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
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
8 use futures::future::{self, Either, Loop};
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};
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
16 use std::process::{self, Command};
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
17 use std::time::Duration;
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
18 use tokio::prelude::*;
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
19 use tokio_hglib::UnixClient;
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
20 use tokio_process::{Child, CommandExt};
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
21 use tokio_timer;
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
22
44673
0a2516efc463 rust-chg: move set_current_dir() to Locator
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
23 use super::clientext::ChgClientExt;
44672
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
24 use super::message::ServerSpec;
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
25 use super::procutil;
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
26
44675
97e6d435ff7e rust-chg: send client-side environment variables to server
Yuya Nishihara <yuya@tcha.org>
parents: 44673
diff changeset
27 const REQUIRED_SERVER_CAPABILITIES: &[&str] = &["attachio", "chdir", "runcommand", "setenv"];
44672
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
28
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
29 /// 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
30 #[derive(Clone, Debug)]
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
31 pub struct Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
32 hg_command: OsString,
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
33 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
34 current_dir: PathBuf,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
35 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
36 process_id: u32,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
37 base_sock_path: PathBuf,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
38 timeout: Duration,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
39 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
40
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
41 impl Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
42 /// 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
43 ///
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
44 /// 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
45 /// created as necessary.
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
46 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
47 Ok(Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
48 hg_command: default_hg_command(),
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
49 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
50 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
51 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
52 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
53 base_sock_path: prepare_server_socket_path()?,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
54 timeout: default_timeout(),
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
55 })
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
56 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
57
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
58 /// 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
59 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
60 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
61 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
62 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
63 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
64 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
65 }
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
66
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
67 /// Specifies the arguments to be passed to the server at start.
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
68 pub fn set_early_args<I, P>(&mut self, args: I)
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
69 where
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
70 I: IntoIterator<Item = P>,
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
71 P: AsRef<OsStr>,
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
72 {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
73 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
74 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
75
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
76 /// Connects to the server.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
77 ///
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
78 /// The server process will be spawned if not running.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
79 pub fn connect(self) -> impl Future<Item = (Self, UnixClient), Error = io::Error> {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
80 self.try_connect()
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
81 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
82
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
83 /// Tries to connect to the existing server, or spawns new if not running.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
84 fn try_connect(self) -> impl Future<Item = (Self, UnixClient), Error = io::Error> {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
85 debug!("try connect to {}", self.base_sock_path.display());
44672
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
86 UnixClient::connect(self.base_sock_path.clone())
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
87 .then(|res| match res {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
88 Ok(client) => Either::A(future::ok((self, client))),
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
89 Err(_) => Either::B(self.spawn_connect()),
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
90 })
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
91 .and_then(|(loc, client)| {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
92 check_server_capabilities(client.server_spec())?;
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
93 Ok((loc, client))
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
94 })
44673
0a2516efc463 rust-chg: move set_current_dir() to Locator
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
95 .and_then(|(loc, client)| {
0a2516efc463 rust-chg: move set_current_dir() to Locator
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
96 client
0a2516efc463 rust-chg: move set_current_dir() to Locator
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
97 .set_current_dir(&loc.current_dir)
0a2516efc463 rust-chg: move set_current_dir() to Locator
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
98 .map(|client| (loc, client))
0a2516efc463 rust-chg: move set_current_dir() to Locator
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
99 })
44675
97e6d435ff7e rust-chg: send client-side environment variables to server
Yuya Nishihara <yuya@tcha.org>
parents: 44673
diff changeset
100 .and_then(|(loc, client)| {
97e6d435ff7e rust-chg: send client-side environment variables to server
Yuya Nishihara <yuya@tcha.org>
parents: 44673
diff changeset
101 client
97e6d435ff7e rust-chg: send client-side environment variables to server
Yuya Nishihara <yuya@tcha.org>
parents: 44673
diff changeset
102 .set_env_vars_os(loc.env_vars.iter().cloned())
97e6d435ff7e rust-chg: send client-side environment variables to server
Yuya Nishihara <yuya@tcha.org>
parents: 44673
diff changeset
103 .map(|client| (loc, client))
97e6d435ff7e rust-chg: send client-side environment variables to server
Yuya Nishihara <yuya@tcha.org>
parents: 44673
diff changeset
104 })
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
105 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
106
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
107 /// 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
108 ///
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
109 /// 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
110 /// 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
111 /// repository.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
112 fn spawn_connect(self) -> impl Future<Item = (Self, UnixClient), Error = io::Error> {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
113 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
114 debug!("start cmdserver at {}", sock_path.display());
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
115 Command::new(&self.hg_command)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
116 .arg("serve")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
117 .arg("--cmdserver")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
118 .arg("chgunix")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
119 .arg("--address")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
120 .arg(&sock_path)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
121 .arg("--daemon-postexec")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
122 .arg("chdir:/")
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
123 .args(&self.hg_early_args)
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
124 .current_dir(&self.current_dir)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
125 .env_clear()
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
126 .envs(self.env_vars.iter().cloned())
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
127 .env("CHGINTERNALMARK", "")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
128 .spawn_async()
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
129 .into_future()
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
130 .and_then(|server| self.connect_spawned(server, sock_path))
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
131 .and_then(|(loc, client, sock_path)| {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
132 debug!(
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
133 "rename {} to {}",
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
134 sock_path.display(),
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
135 loc.base_sock_path.display()
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
136 );
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
137 fs::rename(&sock_path, &loc.base_sock_path)?;
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
138 Ok((loc, client))
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
139 })
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
140 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
141
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
142 /// 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
143 /// exceeded.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
144 fn connect_spawned(
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
145 self,
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
146 server: Child,
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
147 sock_path: PathBuf,
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
148 ) -> impl Future<Item = (Self, UnixClient, PathBuf), Error = io::Error> {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
149 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
150 let connect = future::loop_fn(sock_path, |sock_path| {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
151 UnixClient::connect(sock_path.clone()).then(|res| {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
152 match res {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
153 Ok(client) => Either::A(future::ok(Loop::Break((client, sock_path)))),
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
154 Err(_) => {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
155 // try again with slight delay
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
156 let fut = tokio_timer::sleep(Duration::from_millis(10))
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
157 .map(|()| Loop::Continue(sock_path))
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
158 .map_err(|err| io::Error::new(io::ErrorKind::Other, err));
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
159 Either::B(fut)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
160 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
161 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
162 })
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
163 });
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
164
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
165 // waits for either connection established or server failed to start
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
166 connect
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
167 .select2(server)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
168 .map_err(|res| res.split().0)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
169 .timeout(self.timeout)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
170 .map_err(|err| {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
171 err.into_inner().unwrap_or_else(|| {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
172 io::Error::new(
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
173 io::ErrorKind::TimedOut,
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
174 "timed out while connecting to server",
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
175 )
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
176 })
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
177 })
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
178 .and_then(|res| {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
179 match res {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
180 Either::A(((client, sock_path), server)) => {
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
181 server.forget(); // continue to run in background
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
182 Ok((self, client, sock_path))
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
183 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
184 Either::B((st, _)) => Err(io::Error::new(
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
185 io::ErrorKind::Other,
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
186 format!("server exited too early: {}", st),
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
187 )),
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
188 }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
189 })
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
190 }
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
191 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
192
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
193 /// 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
194 ///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
195 /// 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
196 /// as necessary.
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
197 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
198 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
199 Ok(PathBuf::from(s))
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
200 } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
201 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
202 create_secure_dir(&path)?;
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
203 path.push("server");
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
204 Ok(path)
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
205 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
206 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
207
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
208 /// 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
209 ///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
210 /// 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
211 /// 2. `$TMPDIR/chg$UID`
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
212 /// 3. `/tmp/chg$UID`
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
213 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
214 // 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
215 // 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
216 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
217 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
218 path.push("chg");
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
219 path
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
220 } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
221 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
222 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
223 path
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
224 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
225 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
226
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
227 /// 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
228 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
229 // 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
230 env::var_os("CHGHG")
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
231 .or(env::var_os("HG"))
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
232 .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
233 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
234
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
235 fn default_timeout() -> Duration {
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
236 let secs = env::var("CHGTIMEOUT")
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
237 .ok()
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
238 .and_then(|s| s.parse().ok())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
239 .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
240 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
241 }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
242
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
243 /// 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
244 ///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
245 /// If the directory already exists, tests its permission.
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
246 fn create_secure_dir<P>(path: P) -> io::Result<()>
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
247 where
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
248 P: AsRef<Path>,
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
249 {
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
250 DirBuilder::new()
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
251 .mode(0o700)
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
252 .create(path.as_ref())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
253 .or_else(|err| {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
254 if err.kind() == io::ErrorKind::AlreadyExists {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
255 check_secure_dir(path).map(|_| ())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
256 } else {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
257 Err(err)
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
258 }
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
259 })
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
260 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
261
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
262 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
263 where
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
264 P: AsRef<Path>,
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
265 {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
266 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
267 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
268 Ok(path)
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
269 } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
270 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
271 }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
272 }
44672
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
273
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
274 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
275 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
276 .iter()
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
277 .cloned()
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
278 .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
279 .collect();
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
280 if unsupported.is_empty() {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
281 Ok(())
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
282 } else {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
283 let msg = format!(
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
284 "insufficient server capabilities: {}",
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
285 unsupported.join(", ")
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
286 );
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
287 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
288 }
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
289 }
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
290
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
291 /// Collects arguments which need to be passed to the server at start.
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
292 pub fn collect_early_args<I, P>(args: I) -> Vec<OsString>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
293 where
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
294 I: IntoIterator<Item = P>,
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
295 P: AsRef<OsStr>,
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
296 {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
297 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
298 let mut early_args = Vec::new();
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
299 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
300 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
301 if argb == b"--" {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
302 break;
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
303 } else if argb.starts_with(b"--") {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
304 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
305 match split.next().unwrap() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
306 b"traceback" => {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
307 if split.next().is_none() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
308 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
309 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
310 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
311 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
312 if split.next().is_some() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
313 // --<flag>=<val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
314 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
315 } else {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
316 // --<flag> <val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
317 args_iter.next().map(|val| {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
318 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
319 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
320 });
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
321 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
322 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
323 _ => {}
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
324 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
325 } 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
326 if argb.len() > 2 {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
327 // -R<val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
328 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
329 } else {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
330 // -R <val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
331 args_iter.next().map(|val| {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
332 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
333 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
334 });
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
335 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
336 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
337 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
338
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
339 early_args
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
340 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
341
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
342 #[cfg(test)]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
343 mod tests {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
344 use super::*;
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
345
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
346 #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
347 fn collect_early_args_some() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
348 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
349 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
350 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
351 collect_early_args(&["log", "-Ra", "foo"]),
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
352 os_string_vec_from(&[b"-Ra"])
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
353 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
354 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
355 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
356 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
357 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
358 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
359 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
360 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
361 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
362 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
363 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
364 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
365 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
366 assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
367 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
368 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
369 );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
370 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
371
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
372 #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
373 fn collect_early_args_orphaned() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
374 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
375 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
376 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
377
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
378 #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
379 fn collect_early_args_unwanted_value() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
380 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
381 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
382
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
383 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
384 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
385 }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
386 }