//! Client for sorceryd's control socket (see `daemon/control.rs` there). use std::io::{BufRead, BufReader, Write}; use std::os::unix::net::UnixStream; use std::path::Path; use anyhow::{Context, Result, bail}; /// Ask sorceryd to rebuild the site for the repository at `repo` now. pub fn send(socket: &Path, repo: &Path) -> Result<()> { let mut stream = UnixStream::connect(socket) .with_context(|| format!("connecting to sorcery control socket {}", socket.display()))?; writeln!(stream, "{}", repo.display())?; let mut reply = String::new(); BufReader::new(stream).read_line(&mut reply)?; if reply.split_whitespace().next() != Some("ok") { bail!("sorcery replied {:?}", reply.trim_end()); } Ok(()) } #[cfg(test)] mod tests { use std::os::unix::net::UnixListener; use std::thread; use super::*; fn serve_once(socket: &Path, reply: &'static str) -> thread::JoinHandle { let listener = UnixListener::bind(socket).unwrap(); thread::spawn(move || { let (mut connection, _) = listener.accept().unwrap(); let mut request = String::new(); BufReader::new(connection.try_clone().unwrap()) .read_line(&mut request) .unwrap(); connection.write_all(reply.as_bytes()).unwrap(); request }) } #[test] fn sends_repository_path_and_interprets_reply() { let temp = tempfile::tempdir().unwrap(); let repo = Path::new("/home/git/public/alice/a repo"); let server = serve_once( &temp.path().join("ok"), "ok https://git.example/alice/a%20repo\n", ); send(&temp.path().join("ok"), repo).unwrap(); assert_eq!(server.join().unwrap(), "/home/git/public/alice/a repo\n"); let server = serve_once(&temp.path().join("bare"), "ok\n"); send(&temp.path().join("bare"), repo).unwrap(); server.join().unwrap(); let server = serve_once(&temp.path().join("error"), "error nope\n"); let error = send(&temp.path().join("error"), repo).unwrap_err(); server.join().unwrap(); assert!(error.to_string().contains("nope")); } }