[PATCH 4 of 8] rust-hglib: extract object managing command-server process
Yuya Nishihara
yuya at tcha.org
Sun Apr 1 11:14:20 UTC 2018
# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1522481035 -32400
# Sat Mar 31 16:23:55 2018 +0900
# Node ID a3c01fe6cf0a036859f76d8c222c4ca9aa32116c
# Parent 0502f8498e8da8f0608181619d49d4a8f7ce9637
rust-hglib: extract object managing command-server process
A stub for supporting domain sockets. We could design it as a Read/Write
wrapper like UnixStream, but that would make borrowing thingy difficult
when we want to wrap IOs by BufReader/Writer.
diff --git a/rust/hglib/src/connection.rs b/rust/hglib/src/connection.rs
--- a/rust/hglib/src/connection.rs
+++ b/rust/hglib/src/connection.rs
@@ -22,7 +22,7 @@ use std::error::Error;
use std::fmt::{self, Display};
use std::io;
use std::io::prelude::*;
-use std::process::{Command, Stdio, Child, ChildStdout, ExitStatus};
+use std::process::{Command, Stdio, Child, ChildStdin, ChildStdout, ExitStatus};
use std::str;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
@@ -121,32 +121,53 @@ impl<'a> Iterator for CommandRun<'a> {
}
}
+/// A connection to new command server over stdin/stdout pipe
+#[derive(Debug)]
+pub struct PipeBackend {
+ child: Child,
+}
+
+impl PipeBackend {
+ pub fn spawn() -> io::Result<PipeBackend> {
+ let child = try!(
+ Command::new("hg")
+ .args(&["serve", "--cmdserver", "pipe", "--config", "ui.interactive=True"])
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn());
+ Ok(PipeBackend { child: child })
+ }
+
+ // We just unwrap the Option<ChildStd*> because we know that
+ // we set up the pipe in Connection::new(). We have to call
+ // .as_mut() because .unwrap()'s signature moves the `self`
+ // value out.
+
+ fn get_reader(&mut self) -> &mut ChildStdout {
+ self.child.stdout.as_mut().unwrap()
+ }
+
+ fn get_writer(&mut self) -> &mut ChildStdin {
+ self.child.stdin.as_mut().unwrap()
+ }
+
+ fn close(&mut self) -> io::Result<ExitStatus> {
+ // This will close the command server's stdin, which signals
+ // that it should exit. Returns the command server's exit code.
+ self.child.wait()
+ }
+}
+
/// A handle to a running command server instance.
pub struct Connection {
- child: Child,
+ backend: PipeBackend,
}
impl Connection {
/// Spawns a new command server process.
pub fn new() -> io::Result<Connection> {
- let cmdserver = try!(
- Command::new("hg")
- .args(&["serve", "--cmdserver", "pipe", "--config", "ui.interactive=True"])
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .spawn());
-
- Ok(Connection {
- child: cmdserver,
- })
- }
-
- fn child_stdout(&mut self) -> &mut ChildStdout {
- // We just unwrap the Option<ChildStdout> because we know that
- // we set up the pipe in Connection::new(). We have to call
- // .as_mut() because .unwrap()'s signature moves the `self`
- // value out.
- self.child.stdout.as_mut().unwrap()
+ let backend = try!(PipeBackend::spawn());
+ Ok(Connection { backend: backend })
}
/// Reads and parses the server hello message. Returns a tuple of
@@ -207,7 +228,7 @@ impl Connection {
}
fn read_header(&mut self) -> io::Result<(Channel, i32)> {
- let pout = self.child_stdout();
+ let pout = self.backend.get_reader();
let chan = try!(pout.read_u8());
let chan = try!(Channel::from_u8(chan));
let length = try!(pout.read_i32::<BigEndian>());
@@ -215,14 +236,14 @@ impl Connection {
}
fn read_body(&mut self, length: i32) -> io::Result<Vec<u8>> {
- let pout = self.child_stdout();
+ let pout = self.backend.get_reader();
let mut buf = Vec::with_capacity(length as usize);
try!(pout.take(length as u64).read_to_end(&mut buf));
Ok(buf)
}
fn read_result(&mut self) -> io::Result<i32> {
- let pout = self.child_stdout();
+ let pout = self.backend.get_reader();
let result = try!(pout.read_i32::<BigEndian>());
Ok(result)
}
@@ -235,7 +256,7 @@ impl Connection {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "message too long"));
}
- let pin = self.child.stdin.as_mut().unwrap();
+ let pin = self.backend.get_writer();
try!(pin.write(b"runcommand\n"));
try!(pin.write_i32::<BigEndian>(len as i32));
try!(pin.write(command[0]));
@@ -258,8 +279,6 @@ impl Connection {
/// Shuts down the command server process.
pub fn close(&mut self) -> io::Result<ExitStatus> {
- // This will close the command server's stdin, which signals
- // that it should exit. Returns the command server's exit code.
- self.child.wait()
+ self.backend.close()
}
}
More information about the Mercurial-devel
mailing list