gix_filter/driver/process/mod.rs
1use std::collections::HashSet;
2
3use gix_packetline::blocking_io::{StreamingPeekableIter, WithSidebands, Writer};
4
5/// A set of capabilities that have been negotiated between client and server.
6pub type Capabilities = HashSet<String>;
7
8/// A handle to a client that allows communicating to a long-running process.
9pub struct Client {
10 /// The child process we are communicating with.
11 child: std::process::Child,
12 /// The names of the obtained capabilities after the handshake.
13 capabilities: Capabilities,
14 /// The negotiated version of the protocol.
15 version: usize,
16 /// A way to send packet-line encoded information to the process.
17 input: Writer<std::process::ChildStdin>,
18 /// A way to read information sent to us by the process.
19 out: StreamingPeekableIter<std::process::ChildStdout>,
20}
21
22/// A handle to facilitate typical server interactions that include the handshake and command-invocations.
23pub struct Server {
24 /// The names of the capabilities we can expect the client to use.
25 capabilities: Capabilities,
26 /// The negotiated version of the protocol, it's the highest supported one.
27 version: usize,
28 /// A way to receive information from the client.
29 input: StreamingPeekableIter<std::io::StdinLock<'static>>,
30 /// A way to send information to the client.
31 out: Writer<std::io::StdoutLock<'static>>,
32}
33
34/// The return status of an [invoked command][Client::invoke()].
35#[derive(Debug, Clone)]
36pub enum Status {
37 /// No new status was set, and nothing was sent, so instead we are to assume the previous status is still in effect.
38 Previous,
39 /// Something was sent, but we couldn't identify it as status.
40 Unset,
41 /// Assume the given named status.
42 Named(String),
43}
44
45/// Initialization
46impl Status {
47 /// Create a new instance that represents a successful operation.
48 pub fn success() -> Self {
49 Status::Named("success".into())
50 }
51
52 /// Create a new instance that represents a delayed operation.
53 pub fn delayed() -> Self {
54 Status::Named("delayed".into())
55 }
56
57 /// Create a status that indicates to the client that the command that caused it will not be run anymore throughout the lifetime
58 /// of the process. However, other commands may still run.
59 pub fn abort() -> Self {
60 Status::Named("abort".into())
61 }
62
63 /// Create a status that makes the client send a kill signal.
64 pub fn exit() -> Self {
65 Status::Named("send-term-signal".into())
66 }
67
68 /// Create a new instance that represents an error with the given `message`.
69 pub fn error(message: impl Into<String>) -> Self {
70 Status::Named(message.into())
71 }
72}
73
74/// Access
75impl Status {
76 /// Note that this is assumed true even if no new status is set, hence we assume that upon error, the caller will not continue
77 /// interacting with the process.
78 pub fn is_success(&self) -> bool {
79 match self {
80 Status::Previous => true,
81 Status::Unset => false,
82 Status::Named(n) => n == "success",
83 }
84 }
85
86 /// Returns true if this is an `abort` status.
87 pub fn is_abort(&self) -> bool {
88 self.message() == Some("abort")
89 }
90
91 /// Return true if the status is explicitly set to indicated delayed output processing
92 pub fn is_delayed(&self) -> bool {
93 match self {
94 Status::Previous | Status::Unset => false,
95 Status::Named(n) => n == "delayed",
96 }
97 }
98
99 /// Return the status message if present.
100 pub fn message(&self) -> Option<&str> {
101 match self {
102 Status::Previous | Status::Unset => None,
103 Status::Named(msg) => msg.as_str().into(),
104 }
105 }
106}
107
108///
109pub mod client;
110
111///
112pub mod server;
113
114type PacketlineReader<'a, T = std::process::ChildStdout> =
115 WithSidebands<'a, T, fn(bool, &[u8]) -> gix_packetline::read::ProgressAction>;