Show More
@@ -1,128 +1,121 | |||||
1 | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> |
|
1 | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | |
2 | // |
|
2 | // | |
3 | // This software may be used and distributed according to the terms of the |
|
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. |
|
4 | // GNU General Public License version 2 or any later version. | |
5 |
|
5 | |||
6 | //! cHg extensions to command server client. |
|
6 | //! cHg extensions to command server client. | |
7 |
|
7 | |||
8 |
use bytes::{BufMut, |
|
8 | use bytes::{BufMut, BytesMut}; | |
9 | use std::ffi::OsStr; |
|
9 | use std::ffi::OsStr; | |
10 | use std::io; |
|
10 | use std::io; | |
11 | use std::mem; |
|
11 | use std::mem; | |
12 | use std::os::unix::ffi::OsStrExt; |
|
12 | use std::os::unix::ffi::OsStrExt; | |
13 | use std::os::unix::io::AsRawFd; |
|
13 | use std::os::unix::io::AsRawFd; | |
14 | use std::path::Path; |
|
14 | use std::path::Path; | |
15 | use tokio_hglib::protocol::{OneShotQuery, OneShotRequest}; |
|
15 | use tokio_hglib::UnixClient; | |
16 | use tokio_hglib::{Client, Connection}; |
|
|||
17 |
|
16 | |||
18 |
use crate::attachio |
|
17 | use crate::attachio; | |
19 | use crate::message::{self, Instruction}; |
|
18 | use crate::message::{self, Instruction, ServerSpec}; | |
20 |
use crate::runcommand |
|
19 | use crate::runcommand; | |
21 | use crate::uihandler::SystemHandler; |
|
20 | use crate::uihandler::SystemHandler; | |
22 |
|
21 | |||
23 | pub trait ChgClientExt<C> |
|
22 | /// Command-server client that also supports cHg extensions. | |
24 | where |
|
23 | pub struct ChgClient { | |
25 | C: Connection + AsRawFd, |
|
24 | client: UnixClient, | |
26 | { |
|
25 | } | |
|
26 | ||||
|
27 | impl ChgClient { | |||
|
28 | /// Connects to a command server listening at the specified socket path. | |||
|
29 | pub async fn connect(path: impl AsRef<Path>) -> io::Result<Self> { | |||
|
30 | let client = UnixClient::connect(path).await?; | |||
|
31 | Ok(ChgClient { client }) | |||
|
32 | } | |||
|
33 | ||||
|
34 | /// Server capabilities, encoding, etc. | |||
|
35 | pub fn server_spec(&self) -> &ServerSpec { | |||
|
36 | self.client.server_spec() | |||
|
37 | } | |||
|
38 | ||||
27 | /// Attaches the client file descriptors to the server. |
|
39 | /// Attaches the client file descriptors to the server. | |
28 | fn attach_io<I, O, E>(self, stdin: I, stdout: O, stderr: E) -> AttachIo<C, I, O, E> |
|
40 | pub async fn attach_io( | |
29 | where |
|
41 | &mut self, | |
30 |
|
|
42 | stdin: &impl AsRawFd, | |
31 |
|
|
43 | stdout: &impl AsRawFd, | |
32 |
|
|
44 | stderr: &impl AsRawFd, | |
|
45 | ) -> io::Result<()> { | |||
|
46 | attachio::attach_io(self.client.borrow_protocol_mut(), stdin, stdout, stderr).await | |||
|
47 | } | |||
33 |
|
48 | |||
34 | /// Changes the working directory of the server. |
|
49 | /// Changes the working directory of the server. | |
35 |
fn set_current_dir(self, dir: impl AsRef<Path>) -> |
|
50 | pub async fn set_current_dir(&mut self, dir: impl AsRef<Path>) -> io::Result<()> { | |
|
51 | let dir_bytes = dir.as_ref().as_os_str().as_bytes().to_owned(); | |||
|
52 | self.client | |||
|
53 | .borrow_protocol_mut() | |||
|
54 | .send_command_with_args("chdir", dir_bytes) | |||
|
55 | .await | |||
|
56 | } | |||
36 |
|
57 | |||
37 | /// Updates the environment variables of the server. |
|
58 | /// Updates the environment variables of the server. | |
38 | fn set_env_vars_os( |
|
59 | pub async fn set_env_vars_os( | |
39 | self, |
|
60 | &mut self, | |
40 | vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>, |
|
61 | vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>, | |
41 |
) -> |
|
62 | ) -> io::Result<()> { | |
|
63 | self.client | |||
|
64 | .borrow_protocol_mut() | |||
|
65 | .send_command_with_args("setenv", message::pack_env_vars_os(vars)) | |||
|
66 | .await | |||
|
67 | } | |||
42 |
|
68 | |||
43 | /// Changes the process title of the server. |
|
69 | /// Changes the process title of the server. | |
44 |
fn set_process_name(self, name: impl AsRef<OsStr>) -> |
|
70 | pub async fn set_process_name(&mut self, name: impl AsRef<OsStr>) -> io::Result<()> { | |
|
71 | let name_bytes = name.as_ref().as_bytes().to_owned(); | |||
|
72 | self.client | |||
|
73 | .borrow_protocol_mut() | |||
|
74 | .send_command_with_args("setprocname", name_bytes) | |||
|
75 | .await | |||
|
76 | } | |||
45 |
|
77 | |||
46 | /// Changes the umask of the server process. |
|
78 | /// Changes the umask of the server process. | |
47 |
fn set_umask(self, mask: u32) -> |
|
79 | pub async fn set_umask(&mut self, mask: u32) -> io::Result<()> { | |
|
80 | let mut mask_bytes = BytesMut::with_capacity(mem::size_of_val(&mask)); | |||
|
81 | mask_bytes.put_u32(mask); | |||
|
82 | self.client | |||
|
83 | .borrow_protocol_mut() | |||
|
84 | .send_command_with_args("setumask2", mask_bytes) | |||
|
85 | .await | |||
|
86 | } | |||
48 |
|
87 | |||
49 | /// Runs the specified Mercurial command with cHg extension. |
|
88 | /// Runs the specified Mercurial command with cHg extension. | |
50 |
fn run_command_chg |
|
89 | pub async fn run_command_chg( | |
51 | self, |
|
90 | &mut self, | |
52 | handler: H, |
|
91 | handler: &mut impl SystemHandler, | |
53 | args: impl IntoIterator<Item = impl AsRef<OsStr>>, |
|
92 | args: impl IntoIterator<Item = impl AsRef<OsStr>>, | |
54 | ) -> ChgRunCommand<C, H> |
|
93 | ) -> io::Result<i32> { | |
55 | where |
|
94 | runcommand::run_command( | |
56 | H: SystemHandler; |
|
95 | self.client.borrow_protocol_mut(), | |
|
96 | handler, | |||
|
97 | message::pack_args_os(args), | |||
|
98 | ) | |||
|
99 | .await | |||
|
100 | } | |||
57 |
|
101 | |||
58 | /// Validates if the server can run Mercurial commands with the expected |
|
102 | /// Validates if the server can run Mercurial commands with the expected | |
59 | /// configuration. |
|
103 | /// configuration. | |
60 | /// |
|
104 | /// | |
61 | /// The `args` should contain early command arguments such as `--config` |
|
105 | /// The `args` should contain early command arguments such as `--config` | |
62 | /// and `-R`. |
|
106 | /// and `-R`. | |
63 | /// |
|
107 | /// | |
64 | /// Client-side environment must be sent prior to this request, by |
|
108 | /// Client-side environment must be sent prior to this request, by | |
65 | /// `set_current_dir()` and `set_env_vars_os()`. |
|
109 | /// `set_current_dir()` and `set_env_vars_os()`. | |
66 | fn validate( |
|
110 | pub async fn validate( | |
67 | self, |
|
111 | &mut self, | |
68 | args: impl IntoIterator<Item = impl AsRef<OsStr>>, |
|
112 | args: impl IntoIterator<Item = impl AsRef<OsStr>>, | |
69 |
|
|
113 | ) -> io::Result<Vec<Instruction>> { | |
70 | } |
|
114 | let data = self | |
71 |
|
115 | .client | ||
72 | impl<C> ChgClientExt<C> for Client<C> |
|
116 | .borrow_protocol_mut() | |
73 | where |
|
117 | .query_with_args("validate", message::pack_args_os(args)) | |
74 | C: Connection + AsRawFd, |
|
118 | .await?; | |
75 | { |
|
119 | message::parse_instructions(data) | |
76 | fn attach_io<I, O, E>(self, stdin: I, stdout: O, stderr: E) -> AttachIo<C, I, O, E> |
|
|||
77 | where |
|
|||
78 | I: AsRawFd, |
|
|||
79 | O: AsRawFd, |
|
|||
80 | E: AsRawFd, |
|
|||
81 | { |
|
|||
82 | AttachIo::with_client(self, stdin, stdout, Some(stderr)) |
|
|||
83 | } |
|
|||
84 |
|
||||
85 | fn set_current_dir(self, dir: impl AsRef<Path>) -> OneShotRequest<C> { |
|
|||
86 | OneShotRequest::start_with_args(self, b"chdir", dir.as_ref().as_os_str().as_bytes()) |
|
|||
87 | } |
|
|||
88 |
|
||||
89 | fn set_env_vars_os( |
|
|||
90 | self, |
|
|||
91 | vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>, |
|
|||
92 | ) -> OneShotRequest<C> { |
|
|||
93 | OneShotRequest::start_with_args(self, b"setenv", message::pack_env_vars_os(vars)) |
|
|||
94 | } |
|
|||
95 |
|
||||
96 | fn set_process_name(self, name: impl AsRef<OsStr>) -> OneShotRequest<C> { |
|
|||
97 | OneShotRequest::start_with_args(self, b"setprocname", name.as_ref().as_bytes()) |
|
|||
98 | } |
|
|||
99 |
|
||||
100 | fn set_umask(self, mask: u32) -> OneShotRequest<C> { |
|
|||
101 | let mut args = BytesMut::with_capacity(mem::size_of_val(&mask)); |
|
|||
102 | args.put_u32(mask); |
|
|||
103 | OneShotRequest::start_with_args(self, b"setumask2", args) |
|
|||
104 | } |
|
|||
105 |
|
||||
106 | fn run_command_chg<H>( |
|
|||
107 | self, |
|
|||
108 | handler: H, |
|
|||
109 | args: impl IntoIterator<Item = impl AsRef<OsStr>>, |
|
|||
110 | ) -> ChgRunCommand<C, H> |
|
|||
111 | where |
|
|||
112 | H: SystemHandler, |
|
|||
113 | { |
|
|||
114 | ChgRunCommand::with_client(self, handler, message::pack_args_os(args)) |
|
|||
115 | } |
|
|||
116 |
|
||||
117 | fn validate( |
|
|||
118 | self, |
|
|||
119 | args: impl IntoIterator<Item = impl AsRef<OsStr>>, |
|
|||
120 | ) -> OneShotQuery<C, fn(Bytes) -> io::Result<Vec<Instruction>>> { |
|
|||
121 | OneShotQuery::start_with_args( |
|
|||
122 | self, |
|
|||
123 | b"validate", |
|
|||
124 | message::pack_args_os(args), |
|
|||
125 | message::parse_instructions, |
|
|||
126 | ) |
|
|||
127 | } |
|
120 | } | |
128 | } |
|
121 | } |
@@ -1,15 +1,15 | |||||
1 | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> |
|
1 | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | |
2 | // |
|
2 | // | |
3 | // This software may be used and distributed according to the terms of the |
|
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. |
|
4 | // GNU General Public License version 2 or any later version. | |
5 |
|
5 | |||
6 | mod attachio; |
|
6 | mod attachio; | |
7 |
|
|
7 | mod clientext; | |
8 | //pub mod locator; |
|
8 | //pub mod locator; | |
9 | pub mod message; |
|
9 | pub mod message; | |
10 | pub mod procutil; |
|
10 | pub mod procutil; | |
11 | mod runcommand; |
|
11 | mod runcommand; | |
12 | mod uihandler; |
|
12 | mod uihandler; | |
13 |
|
13 | |||
14 |
|
|
14 | pub use clientext::ChgClient; | |
15 | pub use uihandler::{ChgUiHandler, SystemHandler}; |
|
15 | pub use uihandler::{ChgUiHandler, SystemHandler}; |
General Comments 0
You need to be logged in to leave comments.
Login now