##// END OF EJS Templates
rust-chg: add callback to handle pager and shell command requests...
Yuya Nishihara -
r40010:a9c5fc43 default
parent child Browse files
Show More
@@ -0,0 +1,83 b''
1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
2 //
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
5
6 use futures::Future;
7 use futures::future::IntoFuture;
8 use std::io;
9 use std::os::unix::io::AsRawFd;
10 use std::os::unix::process::ExitStatusExt;
11 use std::process::{Command, Stdio};
12 use tokio;
13 use tokio_process::{ChildStdin, CommandExt};
14
15 use super::message::CommandSpec;
16 use super::procutil;
17
18 /// Callback to process shell command requests received from server.
19 pub trait SystemHandler: Sized {
20 type PagerStdin: AsRawFd;
21 type SpawnPagerResult: IntoFuture<Item = (Self, Self::PagerStdin), Error = io::Error>;
22 type RunSystemResult: IntoFuture<Item = (Self, i32), Error = io::Error>;
23
24 /// Handles pager command request.
25 ///
26 /// Returns the pipe to be attached to the server if the pager is spawned.
27 fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult;
28
29 /// Handles system command request.
30 ///
31 /// Returns command exit code (positive) or signal number (negative).
32 fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult;
33 }
34
35 /// Default cHg implementation to process requests received from server.
36 pub struct ChgUiHandler {
37 }
38
39 impl ChgUiHandler {
40 pub fn new() -> ChgUiHandler {
41 ChgUiHandler {}
42 }
43 }
44
45 impl SystemHandler for ChgUiHandler {
46 type PagerStdin = ChildStdin;
47 type SpawnPagerResult = io::Result<(Self, Self::PagerStdin)>;
48 type RunSystemResult = Box<dyn Future<Item = (Self, i32), Error = io::Error> + Send>;
49
50 fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult {
51 let mut pager = new_shell_command(&spec)
52 .stdin(Stdio::piped())
53 .spawn_async()?;
54 let pin = pager.stdin().take().unwrap();
55 procutil::set_blocking_fd(pin.as_raw_fd())?;
56 tokio::spawn(pager.map(|_| ()).map_err(|_| ())); // just ignore errors
57 Ok((self, pin))
58 }
59
60 fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult {
61 let fut = new_shell_command(&spec)
62 .spawn_async()
63 .into_future()
64 .flatten()
65 .map(|status| {
66 let code = status.code().or_else(|| status.signal().map(|n| -n))
67 .expect("either exit code or signal should be set");
68 (self, code)
69 });
70 Box::new(fut)
71 }
72 }
73
74 fn new_shell_command(spec: &CommandSpec) -> Command {
75 let mut builder = Command::new("/bin/sh");
76 builder
77 .arg("-c")
78 .arg(&spec.command)
79 .current_dir(&spec.current_dir)
80 .env_clear()
81 .envs(spec.envs.iter().cloned());
82 builder
83 }
@@ -9,7 +9,11 b' extern crate futures;'
9 extern crate libc;
9 extern crate libc;
10 extern crate tokio;
10 extern crate tokio;
11 extern crate tokio_hglib;
11 extern crate tokio_hglib;
12 extern crate tokio_process;
12
13
13 pub mod attachio;
14 pub mod attachio;
14 pub mod message;
15 pub mod message;
15 pub mod procutil;
16 pub mod procutil;
17 mod uihandler;
18
19 pub use uihandler::{ChgUiHandler, SystemHandler};
General Comments 0
You need to be logged in to leave comments. Login now