aboutsummaryrefslogtreecommitdiff
path: root/network/receivepack/hook.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-26 09:14:59 +0000
committerGravatar Runxi Yu2026-03-26 09:14:59 +0000
commit3d25bda9d5da6814661828adabe8a09f9d01aefb (patch)
treed034e28079333f85e5d7b96d921282eddd4798d6 /network/receivepack/hook.go
parentobject/id: Empty tree (diff)
signatureNo signature
network/receivepack: Rename from receivepack
Diffstat (limited to 'network/receivepack/hook.go')
-rw-r--r--network/receivepack/hook.go93
1 files changed, 93 insertions, 0 deletions
diff --git a/network/receivepack/hook.go b/network/receivepack/hook.go
new file mode 100644
index 00000000..81286bea
--- /dev/null
+++ b/network/receivepack/hook.go
@@ -0,0 +1,93 @@
+package receivepack
+
+import (
+ "context"
+ "io"
+
+ objectid "codeberg.org/lindenii/furgit/object/id"
+ objectstorer "codeberg.org/lindenii/furgit/object/storer"
+ "codeberg.org/lindenii/furgit/network/receivepack/service"
+ refstore "codeberg.org/lindenii/furgit/ref/store"
+)
+
+type HookIO struct {
+ Progress io.Writer
+ Error io.Writer
+}
+
+// RefUpdate is one requested reference update presented to a receive-pack hook.
+type RefUpdate struct {
+ Name string
+ OldID objectid.ObjectID
+ NewID objectid.ObjectID
+}
+
+// UpdateDecision is one hook decision for a requested reference update.
+type UpdateDecision struct {
+ Accept bool
+ Message string
+}
+
+// HookRequest is the input presented to a receive-pack hook before quarantine
+// promotion and ref updates.
+//
+// Refs, ExistingObjects, and QuarantinedObjects are borrowed and are only
+// valid for the duration of the hook call.
+type HookRequest struct {
+ Refs refstore.ReadingStore
+ ExistingObjects objectstorer.Store
+ QuarantinedObjects objectstorer.Store
+ Updates []RefUpdate
+ PushOptions []string
+ IO HookIO
+}
+
+// Hook decides whether each requested update should proceed.
+//
+// The hook runs after pack ingestion into quarantine and before quarantine
+// promotion or ref updates. The returned decisions must have the same length as
+// HookRequest.Updates. Hook borrows the data and stores in HookRequest only for
+// the duration of the call.
+type Hook func(context.Context, HookRequest) ([]UpdateDecision, error)
+
+func translateHook(hook Hook) service.Hook {
+ if hook == nil {
+ return nil
+ }
+
+ return func(ctx context.Context, req service.HookRequest) ([]service.UpdateDecision, error) {
+ translatedUpdates := make([]RefUpdate, 0, len(req.Updates))
+ for _, update := range req.Updates {
+ translatedUpdates = append(translatedUpdates, RefUpdate{
+ Name: update.Name,
+ OldID: update.OldID,
+ NewID: update.NewID,
+ })
+ }
+
+ decisions, err := hook(ctx, HookRequest{
+ Refs: req.Refs,
+ ExistingObjects: req.ExistingObjects,
+ QuarantinedObjects: req.QuarantinedObjects,
+ Updates: translatedUpdates,
+ PushOptions: append([]string(nil), req.PushOptions...),
+ IO: HookIO{
+ Progress: req.IO.Progress,
+ Error: req.IO.Error,
+ },
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ out := make([]service.UpdateDecision, 0, len(decisions))
+ for _, decision := range decisions {
+ out = append(out, service.UpdateDecision{
+ Accept: decision.Accept,
+ Message: decision.Message,
+ })
+ }
+
+ return out, nil
+ }
+}