// Copyright 2018 Yuya Nishihara // // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. //! Functions to run Mercurial command in cHg-aware command server. use bytes::Bytes; use std::io; use std::os::unix::io::AsRawFd; use tokio_hglib::codec::ChannelMessage; use tokio_hglib::{Connection, Protocol}; use crate::attachio; use crate::message::{self, CommandType}; use crate::uihandler::SystemHandler; /// Runs the given Mercurial command in cHg-aware command server, and /// fetches the result code. /// /// This is a subset of tokio-hglib's `run_command()` with the additional /// SystemRequest support. pub async fn run_command( proto: &mut Protocol, handler: &mut impl SystemHandler, packed_args: impl Into, ) -> io::Result { proto .send_command_with_args("runcommand", packed_args) .await?; loop { match proto.fetch_response().await? { ChannelMessage::Data(b'r', data) => { return message::parse_result_code(data); } ChannelMessage::Data(..) => { // just ignores data sent to optional channel } ChannelMessage::InputRequest(..) | ChannelMessage::LineRequest(..) => { return Err(io::Error::new( io::ErrorKind::InvalidData, "unsupported request", )); } ChannelMessage::SystemRequest(data) => { let (cmd_type, cmd_spec) = message::parse_command_spec(data)?; match cmd_type { CommandType::Pager => { // server spins new command loop while pager request is // in progress, which can be terminated by "" command. let pin = handler.spawn_pager(&cmd_spec).await?; attachio::attach_io(proto, &io::stdin(), &pin, &pin) .await?; proto.send_command("").await?; // terminator } CommandType::System => { let code = handler.run_system(&cmd_spec).await?; let data = message::pack_result_code(code); proto.send_data(data).await?; } } } } } }