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