aboutsummaryrefslogtreecommitdiff
path: root/network/receivepack/service/run_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/service/run_hook.go
parentobject/id: Empty tree (diff)
signatureNo signature
network/receivepack: Rename from receivepack
Diffstat (limited to 'network/receivepack/service/run_hook.go')
-rw-r--r--network/receivepack/service/run_hook.go168
1 files changed, 168 insertions, 0 deletions
diff --git a/network/receivepack/service/run_hook.go b/network/receivepack/service/run_hook.go
new file mode 100644
index 00000000..94467078
--- /dev/null
+++ b/network/receivepack/service/run_hook.go
@@ -0,0 +1,168 @@
+package service
+
+import (
+ "context"
+ "os"
+
+ "codeberg.org/lindenii/furgit/internal/utils"
+ objectstorer "codeberg.org/lindenii/furgit/object/storer"
+ "codeberg.org/lindenii/furgit/object/storer/loose"
+ objectmix "codeberg.org/lindenii/furgit/object/storer/mix"
+ "codeberg.org/lindenii/furgit/object/storer/packed"
+)
+
+func (service *Service) runHook(
+ ctx context.Context,
+ req *Request,
+ commands []Command,
+ quarantineName string,
+) (
+ allowedCommands []Command,
+ allowedIndices []int,
+ rejected map[int]string,
+ ok bool,
+ errText string,
+) {
+ allowedCommands = append([]Command(nil), commands...)
+
+ allowedIndices = make([]int, 0, len(commands))
+ for index := range commands {
+ allowedIndices = append(allowedIndices, index)
+ }
+
+ rejected = make(map[int]string)
+ if service.opts.Hook == nil {
+ return allowedCommands, allowedIndices, rejected, true, ""
+ }
+
+ utils.BestEffortFprintf(service.opts.Progress, "running hooks...\r")
+
+ quarantinedObjects := service.opts.ExistingObjects
+
+ var (
+ quarantineObjectsStore objectstorer.Store
+ quarantineLooseStore *loose.Store
+ quarantinePackedStore *packed.Store
+ quarantineLooseRoot *os.Root
+ quarantinePackRoot *os.Root
+ err error
+ )
+
+ //nolint:nestif
+ if quarantineName != "" {
+ quarantineLooseRoot, err = service.opts.ObjectsRoot.OpenRoot(quarantineName)
+ if err != nil {
+ utils.BestEffortFprintf(service.opts.Progress, "running hooks: failed: %v.\n", err)
+
+ return nil, nil, nil, false, err.Error()
+ }
+
+ quarantineLooseStore, err = loose.New(quarantineLooseRoot, service.opts.Algorithm)
+ if err != nil {
+ _ = quarantineLooseRoot.Close()
+
+ utils.BestEffortFprintf(service.opts.Progress, "running hooks: failed: %v.\n", err)
+
+ return nil, nil, nil, false, err.Error()
+ }
+
+ quarantineObjectsStore = quarantineLooseStore
+ quarantinedObjects = quarantineLooseStore
+
+ quarantinePackRoot, err = quarantineLooseRoot.OpenRoot("pack")
+ if err == nil {
+ var packedErr error
+
+ quarantinePackedStore, packedErr = packed.New(quarantinePackRoot, service.opts.Algorithm, packed.Options{})
+ if packedErr != nil {
+ _ = quarantineLooseStore.Close()
+ _ = quarantinePackRoot.Close()
+ _ = quarantineLooseRoot.Close()
+
+ utils.BestEffortFprintf(service.opts.Progress, "running hooks: failed: %v.\n", packedErr)
+
+ return nil, nil, nil, false, packedErr.Error()
+ }
+
+ quarantineObjectsStore = objectmix.New(quarantineLooseStore, quarantinePackedStore)
+ quarantinedObjects = quarantineObjectsStore
+ } else if !os.IsNotExist(err) {
+ _ = quarantineLooseStore.Close()
+ _ = quarantineLooseRoot.Close()
+
+ utils.BestEffortFprintf(service.opts.Progress, "running hooks: failed: %v.\n", err)
+
+ return nil, nil, nil, false, err.Error()
+ }
+
+ defer func() {
+ if quarantineObjectsStore != nil {
+ _ = quarantineObjectsStore.Close()
+ }
+
+ if quarantinePackedStore != nil {
+ _ = quarantinePackedStore.Close()
+ }
+
+ if quarantineLooseStore != nil {
+ _ = quarantineLooseStore.Close()
+ }
+
+ if quarantinePackRoot != nil {
+ _ = quarantinePackRoot.Close()
+ }
+
+ if quarantineLooseRoot != nil {
+ _ = quarantineLooseRoot.Close()
+ }
+ }()
+ }
+
+ decisions, err := service.opts.Hook(ctx, HookRequest{
+ Refs: service.opts.Refs,
+ ExistingObjects: service.opts.ExistingObjects,
+ QuarantinedObjects: quarantinedObjects,
+ Updates: buildHookUpdates(commands),
+ PushOptions: append([]string(nil), req.PushOptions...),
+ IO: service.opts.HookIO,
+ })
+ if err != nil {
+ utils.BestEffortFprintf(service.opts.Progress, "running hooks: failed: %v.\n", err)
+
+ return nil, nil, nil, false, err.Error()
+ }
+
+ if len(decisions) != len(commands) {
+ utils.BestEffortFprintf(service.opts.Progress, "running hooks: failed: wrong decision count.\n")
+
+ return nil, nil, nil, false, "hook returned wrong number of update decisions"
+ }
+
+ allowedCommands = allowedCommands[:0]
+ allowedIndices = allowedIndices[:0]
+
+ for index, decision := range decisions {
+ if decision.Accept {
+ allowedCommands = append(allowedCommands, commands[index])
+ allowedIndices = append(allowedIndices, index)
+
+ continue
+ }
+
+ message := decision.Message
+ if message == "" {
+ message = "rejected by hook"
+ }
+
+ rejected[index] = message
+ }
+
+ utils.BestEffortFprintf(
+ service.opts.Progress,
+ "running hooks: done (%d/%d accepted).\n",
+ len(allowedCommands),
+ len(commands),
+ )
+
+ return allowedCommands, allowedIndices, rejected, true, ""
+}