···5757}58585959#[tracing::instrument]6060-pub async fn post_hook(hook: &Hook) -> anyhow::Result<()> {6060+pub async fn run_hook(hook: &Hook) -> anyhow::Result<()> {6161 let mut environment_vars: HashMap<_, _> = env::vars().collect();62626363 // Take the environment variables we need to post the hook to the internal API.
+21-29
crates/knot/src/main.rs
···1717use std::{1818 collections::BTreeMap,1919 env,2020- ffi::{OsStr, OsString},2020+ ffi::OsStr,2121 net::ToSocketAddrs,2222- path::PathBuf,2322 sync::{Arc, atomic::AtomicU64},2423 time::Duration,2524};···4041#[global_allocator]4142static GLOBAL: Jemalloc = Jemalloc;42434343-fn main() {4444- use knot::private::Hook;4545-4646- let stderr_layer = tracing_subscriber::fmt::layer().with_writer(std::io::stderr);4444+fn main() -> anyhow::Result<()> {4745 tracing_subscriber::registry()4846 .with(4947 EnvFilter::builder()5048 .with_default_directive(LevelFilter::INFO.into())5149 .from_env_lossy(),5250 )5353- .with(stderr_layer)5454- .try_init()5555- .unwrap();5151+ .with(5252+ tracing_subscriber::fmt::layer()5353+ .with_writer(std::io::stderr)5454+ .with_file(true)5555+ .with_line_number(true),5656+ )5757+ .init();56585759 let runtime = Builder::new_current_thread()5860 .enable_all()5961 .build()6062 .expect("Failed to build runtime");61636262- let name = executable_name().expect("Executable should have a name");6363- match Hook::try_from(name.as_os_str()) {6464- Ok(hook) => runtime.block_on(hooks::post_hook(&hook)).unwrap(),6565- Err(_) => {6666- let arguments = cli::parse();6767- tracing::debug!(?arguments);6868- runtime.block_on(run(arguments)).unwrap();6464+ if let Ok(hook) = ().try_into() {6565+ match runtime.block_on(hooks::run_hook(&hook)) {6666+ Ok(()) => std::process::exit(0),6767+ Err(error) => {6868+ tracing::error!(?error, "failed to run hook");6969+ std::process::exit(1);7070+ }6971 }7072 }7171-}72737373-fn executable_name() -> anyhow::Result<OsString> {7474- Ok(env::args_os()7575- .next()7676- .map(PathBuf::from)7777- .ok_or(anyhow::anyhow!("Expected at least one argument"))?7878- .file_name()7979- .ok_or(anyhow::anyhow!(8080- "Failed to extract file name from executable"8181- ))?8282- .to_os_string())7474+ let arguments = cli::parse();7575+ tracing::debug!(?arguments);7676+ runtime.block_on(knot_main(arguments))8377}84788579const X_REQUEST_ID: HeaderName = HeaderName::from_static("x-request-id");···105113 .and_then(|hv| std::str::from_utf8(hv.as_bytes()).ok())106114}107115108108-pub async fn run(arguments: cli::Arguments) -> anyhow::Result<()> {116116+pub async fn knot_main(arguments: cli::Arguments) -> anyhow::Result<()> {109117 unsafe { env::set_var("GIT_CONFIG_GLOBAL", &arguments.git_config) };110118111119 hooks::setup_global_hooks(&arguments.hooks)?;112120 assert!(git_config_global_set("core.hooksPath", &arguments.hooks)?);113121 assert!(git_config_global_set(114122 "receive.advertisePushOptions",115115- &match arguments.require_signed_push {123123+ match arguments.require_signed_push {116124 true => "true",117125 false => "false",118126 }
+15
crates/knot/src/private.rs
···163163 }164164}165165166166+impl TryFrom<()> for Hook {167167+ type Error = UnknownHook;168168+ /// Extract the hook from the invoked executable name.169169+ fn try_from(_: ()) -> Result<Self, Self::Error> {170170+ fn executable_name() -> Option<std::ffi::OsString> {171171+ use std::path::Path;172172+ std::env::args_os()173173+ .next()174174+ .and_then(|arg| Path::new(&arg).file_name().map(ToOwned::to_owned))175175+ }176176+177177+ Hook::try_from(executable_name().ok_or(UnknownHook)?.as_os_str())178178+ }179179+}180180+166181/// Extracts the 'X-Gordian-User-Did' header from a request.167182pub struct GordianUserDid(pub OwnedDid);168183