Build git 2.54 from source and add hook subcommand
Debian bookworm ships git 2.39 but we need 2.54+ for
hook.<name>.command config support, which lets quire register
hooks via git config instead of writing shim scripts to disk.
The hook subcommand is a no-op that logs invocations — enough to
verify the dispatch path works end-to-end.
Assisted-by: GLM-5.1 via pi
diff --git a/Dockerfile b/Dockerfile
index fc74769..7923e3b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,32 @@
-# Build stage.
+# Git build stage.
+#
+# Debian bookworm ships git 2.39, but we need 2.54+ for hook.<name>.command
+# config support. This lets quire register hooks via git config instead of
+# writing shim scripts to disk — the hook dispatches directly into the
+# quire binary as `quire hook <name>`.
+ARG GIT_VERSION=2.54.0
+FROM debian:bookworm-slim AS git-builder
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ ca-certificates \
+ curl \
+ gcc \
+ gettext \
+ libcurl4-openssl-dev \
+ libexpat1-dev \
+ libssl-dev \
+ libz-dev \
+ make \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN curl -fsSL https://github.com/git/git/archive/refs/tags/v${GIT_VERSION}.tar.gz \
+ | tar xz \
+ && cd git-${GIT_VERSION} \
+ && make -j$(nproc) prefix=/usr/local NO_TCLTK=1 NO_GETTEXT= \
+ && make prefix=/usr/local install
+
+# Quire build stage.
FROM rust:1.88-bookworm AS builder
WORKDIR /usr/src/quire
@@ -12,10 +40,13 @@ FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
- git \
ca-certificates \
+ libcurl4 \
+ libexpat1 \
&& rm -rf /var/lib/apt/lists/*
+COPY --from=git-builder /usr/local/bin/git /usr/local/bin/git
+COPY --from=git-builder /usr/local/libexec/git-core/ /usr/local/libexec/git-core/
COPY --from=builder /usr/local/cargo/bin/quire /usr/local/bin/quire
# Volume layout per PLAN.md. Ownership is set on the host; the container
diff --git a/src/bin/quire/commands/hook.rs b/src/bin/quire/commands/hook.rs
new file mode 100644
index 0000000..17c5fb2
--- /dev/null
+++ b/src/bin/quire/commands/hook.rs
@@ -0,0 +1,6 @@
+use miette::Result;
+
+pub async fn run(hook_name: &str) -> Result<()> {
+ tracing::info!(hook = %hook_name, "hook invoked");
+ Ok(())
+}
diff --git a/src/bin/quire/commands/mod.rs b/src/bin/quire/commands/mod.rs
index 003cac0..68ed5a0 100644
--- a/src/bin/quire/commands/mod.rs
+++ b/src/bin/quire/commands/mod.rs
@@ -1,2 +1,3 @@
pub mod exec;
+pub mod hook;
pub mod serve;
diff --git a/src/bin/quire/main.rs b/src/bin/quire/main.rs
index 6842589..5ab7114 100644
--- a/src/bin/quire/main.rs
+++ b/src/bin/quire/main.rs
@@ -37,6 +37,12 @@ enum Commands {
/// Pass as a single argument: quire exec "git-receive-pack '/foo.git'"
command: Vec<String>,
},
+
+ /// Invoked by git hooks configured via hook.<name>.command.
+ Hook {
+ /// The hook name (e.g. pre-receive, post-receive).
+ hook_name: String,
+ },
}
#[tokio::main]
@@ -63,6 +69,7 @@ async fn main() -> Result<()> {
match command {
Commands::Serve => commands::serve::run(&config).await?,
Commands::Exec { command } => commands::exec::run(&config, command).await?,
+ Commands::Hook { hook_name } => commands::hook::run(&hook_name).await?,
}
Ok(())