From d780391408b9e6d443e5e4f907748cae484b79fb Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Sat, 1 Feb 2025 22:42:11 +0100 Subject: Use workspace instead of features Having to include --feature=build-server in basically all commands that wasn't building eyeballs-githook got tiring quickly. Instead, use workspaces, with a separate project for building the githook. It means I also had to add a library common with code shared by both githook and server. --- server/hook/Cargo.toml | 14 ++++++ server/hook/src/githook.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 server/hook/Cargo.toml create mode 100644 server/hook/src/githook.rs (limited to 'server/hook') diff --git a/server/hook/Cargo.toml b/server/hook/Cargo.toml new file mode 100644 index 0000000..2a298b7 --- /dev/null +++ b/server/hook/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "eyeballs-githook" +version = "0.1.0" +edition = "2021" + +[dependencies] +eyeballs-common = { path = "../common" } +rmp-serde.workspace = true +serde.workspace = true +tokio = { workspace = true, features = ["full"] } + +[[bin]] +name = "eyeballs-githook" +path = "src/githook.rs" diff --git a/server/hook/src/githook.rs b/server/hook/src/githook.rs new file mode 100644 index 0000000..a9cb898 --- /dev/null +++ b/server/hook/src/githook.rs @@ -0,0 +1,105 @@ +use rmp_serde::{decode, Serializer}; +use serde::ser::Serialize; +use std::error::Error; +use std::fmt; +use std::os::unix::net::UnixStream; +use std::path::PathBuf; +use tokio::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader}; +use tokio::task; + +use eyeballs_common::git; +use eyeballs_common::git_socket; + +#[derive(Debug)] +struct IoError { + message: String, +} + +impl IoError { + fn new(message: impl Into) -> Self { + Self { + message: message.into(), + } + } +} + +impl fmt::Display for IoError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } +} + +impl Error for IoError {} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let pre = match std::env::current_exe()? + .file_name() + .and_then(|x| x.to_str()) + { + Some("pre-receive") => true, + Some("post-receive") => false, + _ => return Err(Box::::from("Invalid hook executable name")), + }; + + let input = io::stdin(); + let reader = BufReader::new(input); + let mut lines = reader.lines(); + + let mut request = git_socket::GitHookRequest { + pre, + receive: Vec::new(), + }; + + let repo = git::Repository::new( + PathBuf::from("."), + true, + None::, + None::, + None::, + ); + + while let Some(line) = lines.next_line().await? { + let data: Vec<&str> = line.split(' ').collect(); + + if data.len() == 3 { + let mut commiter: Option = None; + if pre && data[1] != git::EMPTY { + if let Ok(user) = repo.get_commiter(data[1]).await { + commiter = Some(user.username); + } + } + + request.receive.push(git_socket::GitReceive { + old_value: data[0].to_string(), + new_value: data[1].to_string(), + reference: data[2].to_string(), + commiter, + }) + } + } + + let socket = PathBuf::from(repo.config_get("eyeballs.socket").await?); + + let response = task::spawn_blocking(move || { + let stream = UnixStream::connect(socket).map_err(|e| IoError::new(e.to_string()))?; + let mut serializer = Serializer::new(&stream); + request + .serialize(&mut serializer) + .map_err(|e| IoError::new(e.to_string()))?; + let result: Result = + decode::from_read(stream).map_err(|e| IoError::new(e.to_string())); + result + }) + .await? + .map_err(Box::::from)?; + + let mut output = io::stdout(); + output.write_all(response.message.as_bytes()).await?; + + if response.ok { + Ok(()) + } else { + Err(Box::::from("Hook failed")) + } +} -- cgit v1.2.3-70-g09d2