rust/chg/src/locator.rs
author Martin von Zweigbergk <martinvonz@google.com>
Thu, 01 Oct 2020 09:09:35 -0700
changeset 45620 426294d06ddc
parent 44756 27fe8cc1338f
permissions -rw-r--r--
rust: move rustfmt.toml to repo root so it can be used by `hg fix` `hg fix` runs the formatters from the repo root so it doesn't pick up the `rustfmt.toml` configs we had in each the `hg-core`, `hg-cpython`, and `rhg` packages, which resulted in warnings about `async fn` not existing in Rust 2015. This patch moves the `rustfmt.toml` file to the root so `hg fix` will use it. By putting the `rustfmt.toml` file in a higher-level directory, it also applies to the `chg` and `hgcli` packages. That makes `test-check-rust-format.t` fail, so this patch also applies the new formatting rules to those packages. Differential Revision: https://phab.mercurial-scm.org/D9142
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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.
45620
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
    74
    pub fn set_early_args(
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
    75
        &mut self,
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
    76
        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
    77
    ) {
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
    78
        self.hg_early_args =
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
    79
            args.into_iter().map(|a| a.as_ref().to_owned()).collect();
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
    80
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
    81
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
    82
    /// Connects to the server.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
    83
    ///
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
    84
    /// 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
    85
    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
    86
        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
    87
            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
    88
            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
    89
            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
    90
            if !reconnect {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
    91
                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
    92
            }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
    93
        }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
    94
44756
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
    95
        let msg = format!(
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
    96
            concat!(
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
    97
                "too many redirections.\n",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
    98
                "Please make sure {:?} is not a wrapper which ",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
    99
                "changes sensitive environment variables ",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   100
                "before executing hg. If you have to use a ",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   101
                "wrapper, wrap chg instead of hg.",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   102
            ),
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   103
            self.hg_command
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   104
        );
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   105
        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
   106
    }
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
    /// 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
   109
    ///
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   110
    /// Returns true if the client should try connecting to the other server.
45620
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   111
    fn run_instructions(
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   112
        &mut self,
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   113
        instructions: &[Instruction],
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   114
    ) -> io::Result<bool> {
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   115
        let mut reconnect = false;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   116
        for inst in instructions {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   117
            debug!("instruction: {:?}", inst);
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   118
            match inst {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   119
                Instruction::Exit(_) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   120
                    // 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
   121
                    // 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
   122
                    return Ok(false);
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   123
                }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   124
                Instruction::Reconnect => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   125
                    reconnect = true;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   126
                }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   127
                Instruction::Redirect(path) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   128
                    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
   129
                        let msg = format!(
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   130
                            "insecure redirect instruction from server: {}",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   131
                            path.display()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   132
                        );
45620
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   133
                        return Err(io::Error::new(
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   134
                            io::ErrorKind::InvalidData,
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   135
                            msg,
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   136
                        ));
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   137
                    }
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   138
                    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
   139
                    reconnect = true;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   140
                }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   141
                Instruction::Unlink(path) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   142
                    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
   143
                        let msg = format!(
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   144
                            "insecure unlink instruction from server: {}",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   145
                            path.display()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   146
                        );
45620
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   147
                        return Err(io::Error::new(
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   148
                            io::ErrorKind::InvalidData,
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   149
                            msg,
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   150
                        ));
44682
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   151
                    }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   152
                    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
   153
                }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   154
            }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   155
        }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   156
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   157
        Ok(reconnect)
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   158
    }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   159
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   160
    /// 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
   161
    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
   162
        let sock_path = self
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   163
            .redirect_sock_path
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   164
            .as_ref()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   165
            .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
   166
            .clone();
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44681
diff changeset
   167
        debug!("try connect to {}", sock_path.display());
44756
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   168
        let mut client = match ChgClient::connect(sock_path).await {
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   169
            Ok(client) => client,
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   170
            Err(_) => {
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   171
                // Prevent us from being re-connected to the outdated
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   172
                // master server: We were told by the server to redirect
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   173
                // to redirect_sock_path, which didn't work. We do not
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   174
                // want to connect to the same master server again
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   175
                // because it would probably tell us the same thing.
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   176
                if self.redirect_sock_path.is_some() {
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   177
                    fs::remove_file(&self.base_sock_path).unwrap_or(());
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   178
                    // may race
44684
80d6e3415636 rust-chg: update name of the server process
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
   179
                }
44756
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   180
                self.spawn_connect().await?
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   181
            }
44756
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   182
        };
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   183
        check_server_capabilities(client.server_spec())?;
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   184
        // It's purely optional, and the server might not support this command.
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   185
        if client.server_spec().capabilities.contains("setprocname") {
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   186
            client
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   187
                .set_process_name(format!("chg[worker/{}]", self.process_id))
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   188
                .await?;
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   189
        }
44756
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   190
        client.set_current_dir(&self.current_dir).await?;
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   191
        client
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   192
            .set_env_vars_os(self.env_vars.iter().cloned())
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   193
            .await?;
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   194
        Ok(client)
44671
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
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   197
    /// 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
   198
    ///
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   199
    /// 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
   200
    /// 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
   201
    /// repository.
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   202
    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
   203
        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
   204
        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
   205
        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
   206
            .arg("serve")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   207
            .arg("--cmdserver")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   208
            .arg("chgunix")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   209
            .arg("--address")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   210
            .arg(&sock_path)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   211
            .arg("--daemon-postexec")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   212
            .arg("chdir:/")
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   213
            .args(&self.hg_early_args)
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   214
            .current_dir(&self.current_dir)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   215
            .env_clear()
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   216
            .envs(self.env_vars.iter().cloned())
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   217
            .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
   218
            .spawn()?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   219
        let client = self.connect_spawned(server, &sock_path).await?;
44756
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   220
        debug!(
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   221
            "rename {} to {}",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   222
            sock_path.display(),
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   223
            self.base_sock_path.display()
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   224
        );
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   225
        fs::rename(&sock_path, &self.base_sock_path)?;
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44753
diff changeset
   226
        Ok(client)
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   227
    }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   228
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   229
    /// 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
   230
    /// exceeded.
44753
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   231
    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
   232
        &mut self,
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   233
        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
   234
        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
   235
    ) -> io::Result<ChgClient> {
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   236
        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
   237
        // 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
   238
        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
   239
        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
   240
            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
   241
                // 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
   242
                // 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
   243
                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
   244
            }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   245
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   246
            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
   247
                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
   248
                    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
   249
                    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
   250
                ));
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   251
            }
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
            // 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
   254
            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
   255
        }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   256
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44737
diff changeset
   257
        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
   258
            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
   259
            "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
   260
        ))
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   261
    }
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
   262
}
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
   263
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   264
/// 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
   265
///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   266
/// 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
   267
/// as necessary.
44671
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44668
diff changeset
   268
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
   269
    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
   270
        Ok(PathBuf::from(s))
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   271
    } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   272
        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
   273
        create_secure_dir(&path)?;
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   274
        path.push("server");
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   275
        Ok(path)
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   276
    }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   277
}
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
/// 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
   280
///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   281
/// 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
   282
/// 2. `$TMPDIR/chg$UID`
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   283
/// 3. `/tmp/chg$UID`
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   284
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
   285
    // 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
   286
    // 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
   287
    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
   288
        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
   289
        path.push("chg");
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   290
        path
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   291
    } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   292
        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
   293
        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
   294
        path
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   295
    }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   296
}
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   297
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
   298
/// 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
   299
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
   300
    // 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
   301
    env::var_os("CHGHG")
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   302
        .or(env::var_os("HG"))
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   303
        .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
   304
}
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
   305
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
   306
fn default_timeout() -> Duration {
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   307
    let secs = env::var("CHGTIMEOUT")
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   308
        .ok()
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   309
        .and_then(|s| s.parse().ok())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   310
        .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
   311
    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
   312
}
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39976
diff changeset
   313
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   314
/// 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
   315
///
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   316
/// 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
   317
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
   318
    DirBuilder::new()
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   319
        .mode(0o700)
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   320
        .create(path.as_ref())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   321
        .or_else(|err| {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   322
            if err.kind() == io::ErrorKind::AlreadyExists {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   323
                check_secure_dir(path).map(|_| ())
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   324
            } else {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   325
                Err(err)
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   326
            }
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   327
        })
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   328
}
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   329
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   330
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
   331
where
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40289
diff changeset
   332
    P: AsRef<Path>,
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   333
{
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   334
    let a = fs::symlink_metadata(path.as_ref())?;
45620
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   335
    if a.is_dir()
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   336
        && a.uid() == procutil::get_effective_uid()
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   337
        && (a.mode() & 0o777) == 0o700
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   338
    {
39976
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   339
        Ok(path)
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   340
    } else {
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   341
        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
   342
    }
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   343
}
44672
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   344
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   345
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
   346
    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
   347
        .iter()
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   348
        .cloned()
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   349
        .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
   350
        .collect();
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   351
    if unsupported.is_empty() {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   352
        Ok(())
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   353
    } else {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   354
        let msg = format!(
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   355
            "insufficient server capabilities: {}",
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   356
            unsupported.join(", ")
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   357
        );
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   358
        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
   359
    }
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44671
diff changeset
   360
}
44681
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
/// Collects arguments which need to be passed to the server at start.
45620
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   363
pub fn collect_early_args(
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   364
    args: impl IntoIterator<Item = impl AsRef<OsStr>>,
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44756
diff changeset
   365
) -> Vec<OsString> {
44681
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   366
    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
   367
    let mut early_args = Vec::new();
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   368
    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
   369
        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
   370
        if argb == b"--" {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   371
            break;
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   372
        } else if argb.starts_with(b"--") {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   373
            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
   374
            match split.next().unwrap() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   375
                b"traceback" => {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   376
                    if split.next().is_none() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   377
                        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
   378
                    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   379
                }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   380
                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
   381
                    if split.next().is_some() {
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
                        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
   384
                    } else {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   385
                        // --<flag> <val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   386
                        args_iter.next().map(|val| {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   387
                            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
   388
                            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
   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
                }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   392
                _ => {}
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   393
            }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   394
        } 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
   395
            if argb.len() > 2 {
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
                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
   398
            } else {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   399
                // -R <val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   400
                args_iter.next().map(|val| {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   401
                    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
   402
                    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
   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
        }
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
    early_args
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   409
}
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   410
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   411
#[cfg(test)]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   412
mod tests {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   413
    use super::*;
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   414
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   415
    #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   416
    fn collect_early_args_some() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   417
        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
   418
        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
   419
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   420
            collect_early_args(&["log", "-Ra", "foo"]),
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   421
            os_string_vec_from(&[b"-Ra"])
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   422
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   423
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   424
            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
   425
            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
   426
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   427
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   428
            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
   429
            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
   430
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   431
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   432
            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
   433
            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
   434
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   435
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   436
            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
   437
            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
   438
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   439
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   440
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   441
    #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   442
    fn collect_early_args_orphaned() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   443
        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
   444
        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
   445
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   446
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   447
    #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   448
    fn collect_early_args_unwanted_value() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   449
        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
   450
    }
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
    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
   453
        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
   454
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44675
diff changeset
   455
}