Mercurial > public > mercurial-scm > hg
annotate rust/chg/src/message.rs @ 39974:a9c5fc436fd5
rust-chg: add callback to handle pager and shell command requests
This could be inlined into the ChgRunCommand state to be introduced by
the next patch, but it seemed good to separate any user interactions from
the IPC code.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Mon, 24 Sep 2018 18:18:35 +0900 |
parents | b1d8acd82d60 |
children | ce088b38f92b |
rev | line source |
---|---|
39971
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org> |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
2 // |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
3 // This software may be used and distributed according to the terms of the |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
4 // GNU General Public License version 2 or any later version. |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
5 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
6 //! Utility for parsing and building command-server messages. |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
7 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
8 use bytes::Bytes; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
9 use std::error; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
10 use std::ffi::{OsStr, OsString}; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
11 use std::io; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
12 use std::os::unix::ffi::OsStrExt; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
13 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
14 pub use tokio_hglib::message::*; // re-exports |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
15 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
16 /// Shell command type requested by the server. |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
17 #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
18 pub enum CommandType { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
19 /// Pager should be spawned. |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
20 Pager, |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
21 /// Shell command should be executed to send back the result code. |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
22 System, |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
23 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
24 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
25 /// Shell command requested by the server. |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
26 #[derive(Clone, Debug, Eq, PartialEq)] |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
27 pub struct CommandSpec { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
28 pub command: OsString, |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
29 pub current_dir: OsString, |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
30 pub envs: Vec<(OsString, OsString)>, |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
31 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
32 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
33 /// Parses "S" channel request into command type and spec. |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
34 pub fn parse_command_spec(data: Bytes) -> io::Result<(CommandType, CommandSpec)> { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
35 let mut split = data.split(|&c| c == b'\0'); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
36 let ctype = parse_command_type(split.next().ok_or(new_parse_error("missing type"))?)?; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
37 let command = split.next().ok_or(new_parse_error("missing command"))?; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
38 let current_dir = split.next().ok_or(new_parse_error("missing current dir"))?; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
39 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
40 let mut envs = Vec::new(); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
41 for l in split { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
42 let mut s = l.splitn(2, |&c| c == b'='); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
43 let k = s.next().unwrap(); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
44 let v = s.next().ok_or(new_parse_error("malformed env"))?; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
45 envs.push((OsStr::from_bytes(k).to_owned(), OsStr::from_bytes(v).to_owned())); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
46 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
47 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
48 let spec = CommandSpec { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
49 command: OsStr::from_bytes(command).to_owned(), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
50 current_dir: OsStr::from_bytes(current_dir).to_owned(), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
51 envs: envs, |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
52 }; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
53 Ok((ctype, spec)) |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
54 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
55 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
56 fn parse_command_type(value: &[u8]) -> io::Result<CommandType> { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
57 match value { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
58 b"pager" => Ok(CommandType::Pager), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
59 b"system" => Ok(CommandType::System), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
60 _ => Err(new_parse_error(format!("unknown command type: {}", decode_latin1(value)))), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
61 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
62 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
63 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
64 fn decode_latin1<S>(s: S) -> String |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
65 where S: AsRef<[u8]>, |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
66 { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
67 s.as_ref().iter().map(|&c| c as char).collect() |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
68 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
69 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
70 fn new_parse_error<E>(error: E) -> io::Error |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
71 where E: Into<Box<error::Error + Send + Sync>>, |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
72 { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
73 io::Error::new(io::ErrorKind::InvalidData, error) |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
74 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
75 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
76 #[cfg(test)] |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
77 mod tests { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
78 use std::os::unix::ffi::OsStringExt; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
79 use super::*; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
80 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
81 #[test] |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
82 fn parse_command_spec_good() { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
83 let src = [b"pager".as_ref(), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
84 b"less -FRX".as_ref(), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
85 b"/tmp".as_ref(), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
86 b"LANG=C".as_ref(), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
87 b"HGPLAIN=".as_ref()].join(&0); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
88 let spec = CommandSpec { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
89 command: os_string_from(b"less -FRX"), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
90 current_dir: os_string_from(b"/tmp"), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
91 envs: vec![(os_string_from(b"LANG"), os_string_from(b"C")), |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
92 (os_string_from(b"HGPLAIN"), os_string_from(b""))], |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
93 }; |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
94 assert_eq!(parse_command_spec(Bytes::from(src)).unwrap(), (CommandType::Pager, spec)); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
95 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
96 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
97 #[test] |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
98 fn parse_command_spec_too_short() { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
99 assert!(parse_command_spec(Bytes::from_static(b"")).is_err()); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
100 assert!(parse_command_spec(Bytes::from_static(b"pager")).is_err()); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
101 assert!(parse_command_spec(Bytes::from_static(b"pager\0less")).is_err()); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
102 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
103 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
104 #[test] |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
105 fn parse_command_spec_malformed_env() { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
106 assert!(parse_command_spec(Bytes::from_static(b"pager\0less\0/tmp\0HOME")).is_err()); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
107 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
108 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
109 #[test] |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
110 fn parse_command_spec_unknown_type() { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
111 assert!(parse_command_spec(Bytes::from_static(b"paper\0less")).is_err()); |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
112 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
113 |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
114 fn os_string_from(s: &[u8]) -> OsString { |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
115 OsString::from_vec(s.to_vec()) |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
116 } |
b1d8acd82d60
rust-chg: add parser for request messages sent to "S" channel
Yuya Nishihara <yuya@tcha.org>
parents:
diff
changeset
|
117 } |