##// END OF EJS Templates
merge default into stable for 5.4 release
merge default into stable for 5.4 release

File last commit:

r45185:f8780482 default
r45223:26ce8e75 merge 5.4rc0 stable
Show More
runcommand.rs
172 lines | 5.9 KiB | application/rls-services+xml | RustLexer
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 // 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.
//! Functions to run Mercurial command in cHg-aware command server.
use bytes::Bytes;
use futures::future::IntoFuture;
use futures::{Async, Future, Poll};
use std::io;
use std::mem;
use std::os::unix::io::AsRawFd;
use tokio_hglib::codec::ChannelMessage;
use tokio_hglib::protocol::MessageLoop;
Gregory Szorc
rust: run rustfmt...
r44270 use tokio_hglib::{Client, Connection};
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011
Yuya Nishihara
rust-chg: use "crate::" to import local modules...
r45180 use crate::attachio::AttachIo;
use crate::message::{self, CommandType};
use crate::uihandler::SystemHandler;
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011
enum AsyncS<R, S> {
Ready(R),
NotReady(S),
PollAgain(S),
}
enum CommandState<C, H>
Gregory Szorc
rust: run rustfmt...
r44270 where
C: Connection,
H: SystemHandler,
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 {
Running(MessageLoop<C>, H),
SpawningPager(Client<C>, <H::SpawnPagerResult as IntoFuture>::Future),
AttachingPager(AttachIo<C, io::Stdin, H::PagerStdin, H::PagerStdin>, H),
WaitingSystem(Client<C>, <H::RunSystemResult as IntoFuture>::Future),
Finished,
}
Yuya Nishihara
rust-chg: silence warning about dated coding style...
r45176 type CommandPoll<C, H> = io::Result<AsyncS<(Client<C>, H, i32), CommandState<C, H>>>;
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011
/// Future resolves to `(exit_code, client)`.
#[must_use = "futures do nothing unless polled"]
pub struct ChgRunCommand<C, H>
Gregory Szorc
rust: run rustfmt...
r44270 where
C: Connection,
H: SystemHandler,
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 {
state: CommandState<C, H>,
}
impl<C, H> ChgRunCommand<C, H>
Gregory Szorc
rust: run rustfmt...
r44270 where
C: Connection + AsRawFd,
H: SystemHandler,
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 {
Gregory Szorc
rust: run rustfmt...
r44270 pub fn with_client(client: Client<C>, handler: H, packed_args: Bytes) -> ChgRunCommand<C, H> {
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 let msg_loop = MessageLoop::start_with_args(client, b"runcommand", packed_args);
ChgRunCommand {
state: CommandState::Running(msg_loop, handler),
}
}
}
impl<C, H> Future for ChgRunCommand<C, H>
Gregory Szorc
rust: run rustfmt...
r44270 where
C: Connection + AsRawFd,
H: SystemHandler,
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 {
type Item = (Client<C>, H, i32);
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
let state = mem::replace(&mut self.state, CommandState::Finished);
match state.poll()? {
AsyncS::Ready((client, handler, code)) => {
return Ok(Async::Ready((client, handler, code)));
}
AsyncS::NotReady(newstate) => {
self.state = newstate;
return Ok(Async::NotReady);
}
AsyncS::PollAgain(newstate) => {
self.state = newstate;
}
}
}
}
}
impl<C, H> CommandState<C, H>
Gregory Szorc
rust: run rustfmt...
r44270 where
C: Connection + AsRawFd,
H: SystemHandler,
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 {
fn poll(self) -> CommandPoll<C, H> {
match self {
CommandState::Running(mut msg_loop, handler) => {
if let Async::Ready((client, msg)) = msg_loop.poll()? {
process_message(client, handler, msg)
} else {
Ok(AsyncS::NotReady(CommandState::Running(msg_loop, handler)))
}
}
CommandState::SpawningPager(client, mut fut) => {
if let Async::Ready((handler, pin)) = fut.poll()? {
let fut = AttachIo::with_client(client, io::stdin(), pin, None);
Gregory Szorc
rust: run rustfmt...
r44270 Ok(AsyncS::PollAgain(CommandState::AttachingPager(
fut, handler,
)))
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 } else {
Ok(AsyncS::NotReady(CommandState::SpawningPager(client, fut)))
}
}
CommandState::AttachingPager(mut fut, handler) => {
if let Async::Ready(client) = fut.poll()? {
Gregory Szorc
rust: run rustfmt...
r44270 let msg_loop = MessageLoop::start(client, b""); // terminator
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 Ok(AsyncS::PollAgain(CommandState::Running(msg_loop, handler)))
} else {
Ok(AsyncS::NotReady(CommandState::AttachingPager(fut, handler)))
}
}
CommandState::WaitingSystem(client, mut fut) => {
if let Async::Ready((handler, code)) = fut.poll()? {
let data = message::pack_result_code(code);
let msg_loop = MessageLoop::resume_with_data(client, data);
Ok(AsyncS::PollAgain(CommandState::Running(msg_loop, handler)))
} else {
Ok(AsyncS::NotReady(CommandState::WaitingSystem(client, fut)))
}
}
Gregory Szorc
rust: run rustfmt...
r44270 CommandState::Finished => panic!("poll ChgRunCommand after it's done"),
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 }
}
}
fn process_message<C, H>(client: Client<C>, handler: H, msg: ChannelMessage) -> CommandPoll<C, H>
Gregory Szorc
rust: run rustfmt...
r44270 where
C: Connection,
H: SystemHandler,
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 {
Yuya Nishihara
rust-chg: indent process_message() to prepare mass rewrite to futures-0.3...
r45185 {
match msg {
ChannelMessage::Data(b'r', data) => {
let code = message::parse_result_code(data)?;
Ok(AsyncS::Ready((client, handler, code)))
}
ChannelMessage::Data(..) => {
// just ignores data sent to optional channel
let msg_loop = MessageLoop::resume(client);
Ok(AsyncS::PollAgain(CommandState::Running(msg_loop, handler)))
}
ChannelMessage::InputRequest(..) | ChannelMessage::LineRequest(..) => 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 => {
let fut = handler.spawn_pager(cmd_spec).into_future();
Ok(AsyncS::PollAgain(CommandState::SpawningPager(client, fut)))
}
CommandType::System => {
let fut = handler.run_system(cmd_spec).into_future();
Ok(AsyncS::PollAgain(CommandState::WaitingSystem(client, fut)))
}
Yuya Nishihara
rust-chg: add state machine to handle "runcommand" request with cHg extension...
r40011 }
}
}
}
}