view rust/chg/src/clientext.rs @ 44805:02bf61bb4a70

copy: to find copy source, walk parent of revision we're marking copies in As shown in the previous patch, `hg cp --after --at-rev . src dst` fails if `src` is not in `.`. It seems obvious that you should always walk the *parent* of the revision you're marking copies in, but that's not how it was done for the working copy, and I didn't think to change it when marking copies in a non-working-copy commit. This patch fixes that by walking the parent commit instead, but only if we're marking copies for a non-working-copy commit. We need to leave the working-copy code unchanged because it depends on the weird behavior of `workingctx.walk()`. With these changes, there's very little overlap between the working-copy version and the non-working-copy version of `walkpats()`, but I've refrained from cleaning that up on the stable branch. Differential Revision: https://phab.mercurial-scm.org/D8494
author Martin von Zweigbergk <martinvonz@google.com>
date Wed, 06 May 2020 10:33:56 -0700
parents d6f706929120
children 426294d06ddc
line wrap: on
line source

// Copyright 2018 Yuya Nishihara <yuya@tcha.org>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.

//! cHg extensions to command server client.

use bytes::{BufMut, BytesMut};
use std::ffi::OsStr;
use std::io;
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::AsRawFd;
use std::path::Path;
use tokio_hglib::UnixClient;

use crate::attachio;
use crate::message::{self, Instruction, ServerSpec};
use crate::runcommand;
use crate::uihandler::SystemHandler;

/// Command-server client that also supports cHg extensions.
pub struct ChgClient {
    client: UnixClient,
}

impl ChgClient {
    /// Connects to a command server listening at the specified socket path.
    pub async fn connect(path: impl AsRef<Path>) -> io::Result<Self> {
        let client = UnixClient::connect(path).await?;
        Ok(ChgClient { client })
    }

    /// Server capabilities, encoding, etc.
    pub fn server_spec(&self) -> &ServerSpec {
        self.client.server_spec()
    }

    /// Attaches the client file descriptors to the server.
    pub async fn attach_io(
        &mut self,
        stdin: &impl AsRawFd,
        stdout: &impl AsRawFd,
        stderr: &impl AsRawFd,
    ) -> io::Result<()> {
        attachio::attach_io(self.client.borrow_protocol_mut(), stdin, stdout, stderr).await
    }

    /// Changes the working directory of the server.
    pub async fn set_current_dir(&mut self, dir: impl AsRef<Path>) -> io::Result<()> {
        let dir_bytes = dir.as_ref().as_os_str().as_bytes().to_owned();
        self.client
            .borrow_protocol_mut()
            .send_command_with_args("chdir", dir_bytes)
            .await
    }

    /// Updates the environment variables of the server.
    pub async fn set_env_vars_os(
        &mut self,
        vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>,
    ) -> io::Result<()> {
        self.client
            .borrow_protocol_mut()
            .send_command_with_args("setenv", message::pack_env_vars_os(vars))
            .await
    }

    /// Changes the process title of the server.
    pub async fn set_process_name(&mut self, name: impl AsRef<OsStr>) -> io::Result<()> {
        let name_bytes = name.as_ref().as_bytes().to_owned();
        self.client
            .borrow_protocol_mut()
            .send_command_with_args("setprocname", name_bytes)
            .await
    }

    /// Changes the umask of the server process.
    pub async fn set_umask(&mut self, mask: u32) -> io::Result<()> {
        let mut mask_bytes = BytesMut::with_capacity(mem::size_of_val(&mask));
        mask_bytes.put_u32(mask);
        self.client
            .borrow_protocol_mut()
            .send_command_with_args("setumask2", mask_bytes)
            .await
    }

    /// Runs the specified Mercurial command with cHg extension.
    pub async fn run_command_chg(
        &mut self,
        handler: &mut impl SystemHandler,
        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
    ) -> io::Result<i32> {
        runcommand::run_command(
            self.client.borrow_protocol_mut(),
            handler,
            message::pack_args_os(args),
        )
        .await
    }

    /// Validates if the server can run Mercurial commands with the expected
    /// configuration.
    ///
    /// The `args` should contain early command arguments such as `--config`
    /// and `-R`.
    ///
    /// Client-side environment must be sent prior to this request, by
    /// `set_current_dir()` and `set_env_vars_os()`.
    pub async fn validate(
        &mut self,
        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
    ) -> io::Result<Vec<Instruction>> {
        let data = self
            .client
            .borrow_protocol_mut()
            .query_with_args("validate", message::pack_args_os(args))
            .await?;
        message::parse_instructions(data)
    }
}