rust/chg/src/locator.rs
author Matt Harbison <matt_harbison@yahoo.com>
Mon, 05 Dec 2022 11:46:00 -0500
branchstable
changeset 49616 d5b722ce9864
parent 45623 426294d06ddc
permissions -rw-r--r--
make: add a target for building pyoxidizer tests on macOS The resources seem to be embedded inside the binary, but for some reasons they aren't read there. And since they are embedded, they aren't staged by the build in the `lib` directory like on Windows. So copy them from the repo. We can figure out what's going wrong later.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
39977
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
44689
1f5ab1a9363d rust-chg: upgrade to 2018 edition and remove useless extern crates
Yuya Nishihara <yuya@tcha.org>
parents: 44685
diff changeset
     8
use log::debug;
39977
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: 39977
diff changeset
    10
use std::ffi::{OsStr, OsString};
39977
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: 39977
diff changeset
    13
use std::os::unix::ffi::{OsStrExt, OsStringExt};
39977
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};
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
diff changeset
    17
use std::time::{Duration, Instant};
44847
e9e44e61042b rust-chg: upgrade to futures-0.3 based libraries
Yuya Nishihara <yuya@tcha.org>
parents: 44693
diff changeset
    18
use tokio::time;
39977
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    19
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
    20
use crate::clientext::ChgClient;
44690
6bef9d43cc55 rust-chg: use "crate::" to import local modules
Yuya Nishihara <yuya@tcha.org>
parents: 44689
diff changeset
    21
use crate::message::{Instruction, ServerSpec};
6bef9d43cc55 rust-chg: use "crate::" to import local modules
Yuya Nishihara <yuya@tcha.org>
parents: 44689
diff changeset
    22
use crate::procutil;
39977
44840bcc411a rust-chg: port basic socket path handling from cHg of C
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    23
44684
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
    24
const REQUIRED_SERVER_CAPABILITIES: &[&str] = &[
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
    25
    "attachio",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
    26
    "chdir",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
    27
    "runcommand",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
    28
    "setenv",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
    29
    "setumask2",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
    30
    "validate",
065048e66f32 rust-chg: send client side umask to server
Yuya Nishihara <yuya@tcha.org>
parents: 44683
diff changeset
    31
];
44673
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
    32
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
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: 39977
diff changeset
    34
#[derive(Clone, Debug)]
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    35
pub struct Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    36
    hg_command: OsString,
44682
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 39977
diff changeset
    38
    current_dir: PathBuf,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
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: 39977
diff changeset
    40
    process_id: u32,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    41
    base_sock_path: PathBuf,
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
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: 39977
diff changeset
    43
    timeout: Duration,
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    44
}
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    45
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    46
impl Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
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: 39977
diff changeset
    48
    ///
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
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: 39977
diff changeset
    50
    /// created as necessary.
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
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: 39977
diff changeset
    52
        Ok(Locator {
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    53
            hg_command: default_hg_command(),
44682
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 39977
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: 39977
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: 39977
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: 39977
diff changeset
    58
            base_sock_path: prepare_server_socket_path()?,
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
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: 39977
diff changeset
    60
            timeout: default_timeout(),
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    61
        })
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    62
    }
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
    63
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
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: 39977
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: 39977
diff changeset
    66
        let src = self.base_sock_path.as_os_str().as_bytes();
44669
c11d98cff883 rust-chg: add brief comment about initial capacity of temp_sock_path()
Yuya Nishihara <yuya@tcha.org>
parents: 43836
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: 39977
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: 39977
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: 39977
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: 39977
diff changeset
    71
    }
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
    72
44682
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
    73
    /// Specifies the arguments to be passed to the server at start.
45623
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44856
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: 44856
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: 44856
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: 44856
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: 44856
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: 44856
diff changeset
    79
            args.into_iter().map(|a| a.as_ref().to_owned()).collect();
44682
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
    80
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
    81
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
    82
    /// Connects to the server.
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
    83
    ///
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
    84
    /// The server process will be spawned if not running.
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
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: 44847
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: 44847
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: 44847
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: 44847
diff changeset
    90
            if !reconnect {
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
diff changeset
    92
            }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
    93
        }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
    94
44856
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
    95
        let msg = format!(
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
    96
            concat!(
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
    97
                "too many redirections.\n",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
    98
                "Please make sure {:?} is not a wrapper which ",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
    99
                "changes sensitive environment variables ",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
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: 44853
diff changeset
   101
                "wrapper, wrap chg instead of hg.",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   102
            ),
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   103
            self.hg_command
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   104
        );
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   105
        Err(io::Error::new(io::ErrorKind::Other, msg))
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   106
    }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   107
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   108
    /// Runs instructions received from the server.
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   109
    ///
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   110
    /// Returns true if the client should try connecting to the other server.
45623
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44856
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: 44856
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: 44856
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: 44856
diff changeset
   114
    ) -> io::Result<bool> {
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   115
        let mut reconnect = false;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   116
        for inst in instructions {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   117
            debug!("instruction: {:?}", inst);
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   118
            match inst {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   119
                Instruction::Exit(_) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
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: 44682
diff changeset
   121
                    // unparsable command and report the error
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   122
                    return Ok(false);
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   123
                }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   124
                Instruction::Reconnect => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   125
                    reconnect = true;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   126
                }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   127
                Instruction::Redirect(path) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
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: 44682
diff changeset
   129
                        let msg = format!(
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   130
                            "insecure redirect instruction from server: {}",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   131
                            path.display()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   132
                        );
45623
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44856
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: 44856
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: 44856
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: 44856
diff changeset
   136
                        ));
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   137
                    }
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   138
                    self.redirect_sock_path = Some(path.to_owned());
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   139
                    reconnect = true;
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   140
                }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   141
                Instruction::Unlink(path) => {
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
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: 44682
diff changeset
   143
                        let msg = format!(
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   144
                            "insecure unlink instruction from server: {}",
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   145
                            path.display()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   146
                        );
45623
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44856
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: 44856
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: 44856
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: 44856
diff changeset
   150
                        ));
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   151
                    }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
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: 44682
diff changeset
   153
                }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   154
            }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   155
        }
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   156
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   157
        Ok(reconnect)
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   158
    }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   159
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   160
    /// Tries to connect to the existing server, or spawns new if not running.
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   161
    async fn try_connect(&mut self) -> io::Result<ChgClient> {
44683
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   162
        let sock_path = self
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   163
            .redirect_sock_path
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   164
            .as_ref()
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
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: 44682
diff changeset
   166
            .clone();
9ce613d648de rust-chg: add config validation and process returned instructions
Yuya Nishihara <yuya@tcha.org>
parents: 44682
diff changeset
   167
        debug!("try connect to {}", sock_path.display());
44856
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
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: 44853
diff changeset
   169
            Ok(client) => client,
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   170
            Err(_) => {
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
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: 44853
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: 44853
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: 44853
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: 44853
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: 44853
diff changeset
   176
                if self.redirect_sock_path.is_some() {
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
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: 44853
diff changeset
   178
                    // may race
44685
80d6e3415636 rust-chg: update name of the server process
Yuya Nishihara <yuya@tcha.org>
parents: 44684
diff changeset
   179
                }
44856
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   180
                self.spawn_connect().await?
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   181
            }
44856
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   182
        };
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   183
        check_server_capabilities(client.server_spec())?;
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
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: 44853
diff changeset
   185
        if client.server_spec().capabilities.contains("setprocname") {
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   186
            client
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
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: 44853
diff changeset
   188
                .await?;
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   189
        }
44856
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   190
        client.set_current_dir(&self.current_dir).await?;
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   191
        client
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
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: 44853
diff changeset
   193
            .await?;
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   194
        Ok(client)
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   195
    }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   196
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
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: 44669
diff changeset
   198
    ///
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
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: 44669
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: 44669
diff changeset
   201
    /// repository.
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   202
    async fn spawn_connect(&mut self) -> io::Result<ChgClient> {
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
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: 44669
diff changeset
   204
        debug!("start cmdserver at {}", sock_path.display());
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   205
        let server = Command::new(&self.hg_command)
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   206
            .arg("serve")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   207
            .arg("--cmdserver")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   208
            .arg("chgunix")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   209
            .arg("--address")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   210
            .arg(&sock_path)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   211
            .arg("--daemon-postexec")
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   212
            .arg("chdir:/")
44682
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   213
            .args(&self.hg_early_args)
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   214
            .current_dir(&self.current_dir)
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   215
            .env_clear()
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   216
            .envs(self.env_vars.iter().cloned())
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   217
            .env("CHGINTERNALMARK", "")
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   218
            .spawn()?;
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   219
        let client = self.connect_spawned(server, &sock_path).await?;
44856
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   220
        debug!(
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   221
            "rename {} to {}",
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   222
            sock_path.display(),
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   223
            self.base_sock_path.display()
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   224
        );
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   225
        fs::rename(&sock_path, &self.base_sock_path)?;
27fe8cc1338f rust-chg: clean up excessive indents
Yuya Nishihara <yuya@tcha.org>
parents: 44853
diff changeset
   226
        Ok(client)
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   227
    }
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   228
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
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: 44669
diff changeset
   230
    /// exceeded.
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
diff changeset
   232
        &mut self,
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
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: 44847
diff changeset
   235
    ) -> io::Result<ChgClient> {
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
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: 44669
diff changeset
   237
        // waits for either connection established or server failed to start
44853
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
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: 44847
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: 44847
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: 44847
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: 44847
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: 44847
diff changeset
   244
            }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   245
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
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: 44847
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: 44847
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: 44847
diff changeset
   250
                ));
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   251
            }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   252
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
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: 44847
diff changeset
   255
        }
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
diff changeset
   256
a347a329e48d rust-chg: reimplement locator by using async/await and tokio-0.2
Yuya Nishihara <yuya@tcha.org>
parents: 44847
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: 44847
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: 44847
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: 44847
diff changeset
   260
        ))
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   261
    }
40289
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
   262
}
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
   263
39977
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.
44672
bb936e25a84a rust-chg: spawn server process if not running
Yuya Nishihara <yuya@tcha.org>
parents: 44669
diff changeset
   268
fn prepare_server_socket_path() -> io::Result<PathBuf> {
39977
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: 39977
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: 39977
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: 39977
diff changeset
   300
    // TODO: maybe allow embedding the path at compile time (or load from hgrc)
43836
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: 39977
diff changeset
   304
}
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
   305
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
   306
fn default_timeout() -> Duration {
43836
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: 39977
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: 39977
diff changeset
   312
}
7d3285f799cc rust-chg: add struct holding information needed to spawn server process
Yuya Nishihara <yuya@tcha.org>
parents: 39977
diff changeset
   313
39977
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: 44690
diff changeset
   317
fn create_secure_dir(path: impl AsRef<Path>) -> io::Result<()> {
43836
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
        })
39977
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>
43836
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>,
39977
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())?;
45623
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44856
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: 44856
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: 44856
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: 44856
diff changeset
   338
    {
39977
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
}
44673
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   344
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
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: 44672
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: 44672
diff changeset
   347
        .iter()
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   348
        .cloned()
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
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: 44672
diff changeset
   350
        .collect();
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   351
    if unsupported.is_empty() {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   352
        Ok(())
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   353
    } else {
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   354
        let msg = format!(
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   355
            "insufficient server capabilities: {}",
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   356
            unsupported.join(", ")
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   357
        );
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
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: 44672
diff changeset
   359
    }
7bf45ed9e25e rust-chg: abort if server doesn't have required capabilities
Yuya Nishihara <yuya@tcha.org>
parents: 44672
diff changeset
   360
}
44682
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   361
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   362
/// Collects arguments which need to be passed to the server at start.
45623
426294d06ddc rust: move rustfmt.toml to repo root so it can be used by `hg fix`
Martin von Zweigbergk <martinvonz@google.com>
parents: 44856
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: 44856
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: 44856
diff changeset
   365
) -> Vec<OsString> {
44682
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
diff changeset
   367
    let mut early_args = Vec::new();
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   370
        if argb == b"--" {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   371
            break;
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   372
        } else if argb.starts_with(b"--") {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
diff changeset
   374
            match split.next().unwrap() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   375
                b"traceback" => {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   376
                    if split.next().is_none() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
diff changeset
   378
                    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   379
                }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
diff changeset
   381
                    if split.next().is_some() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   382
                        // --<flag>=<val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
diff changeset
   384
                    } else {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   385
                        // --<flag> <val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   386
                        args_iter.next().map(|val| {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   389
                        });
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   390
                    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   391
                }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   392
                _ => {}
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   393
            }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
diff changeset
   395
            if argb.len() > 2 {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   396
                // -R<val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
diff changeset
   398
            } else {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   399
                // -R <val>
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   400
                args_iter.next().map(|val| {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   403
                });
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   404
            }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   405
        }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   406
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   407
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   408
    early_args
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   409
}
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   410
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   411
#[cfg(test)]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   412
mod tests {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   413
    use super::*;
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   414
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   415
    #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   416
    fn collect_early_args_some() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   419
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   420
            collect_early_args(&["log", "-Ra", "foo"]),
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   421
            os_string_vec_from(&[b"-Ra"])
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   422
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   423
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   426
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   427
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   430
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   431
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   434
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   435
        assert_eq!(
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   438
        );
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   439
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   440
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   441
    #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   442
    fn collect_early_args_orphaned() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   445
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   446
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   447
    #[test]
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   448
    fn collect_early_args_unwanted_value() {
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
diff changeset
   450
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   451
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
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: 44676
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: 44676
diff changeset
   454
    }
00ac60658654 rust-chg: collect server flags from command arguments
Yuya Nishihara <yuya@tcha.org>
parents: 44676
diff changeset
   455
}