diff options
Diffstat (limited to 'receivepack/service/execute.go')
| -rw-r--r-- | receivepack/service/execute.go | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/receivepack/service/execute.go b/receivepack/service/execute.go new file mode 100644 index 00000000..14468799 --- /dev/null +++ b/receivepack/service/execute.go @@ -0,0 +1,115 @@ +package service + +import ( + "context" + "os" +) + +// Execute validates one receive-pack request, optionally ingests its pack into +// quarantine, runs the optional hook, and applies allowed ref updates. +func (service *Service) Execute(ctx context.Context, req *Request) (*Result, error) { + result := &Result{ + Commands: make([]CommandResult, 0, len(req.Commands)), + } + + var ( + quarantineName string + quarantineRoot *os.Root + err error + ) + + quarantineName, quarantineRoot, ok := service.ingestQuarantine(result, req.Commands, req) + if !ok { + return result, nil + } + + if quarantineRoot != nil { + defer func() { + _ = quarantineRoot.Close() + _ = service.opts.ObjectsRoot.RemoveAll(quarantineName) + }() + } + + for _, command := range req.Commands { + result.Planned = append(result.Planned, PlannedUpdate{ + Name: command.Name, + OldID: command.OldID, + NewID: command.NewID, + Delete: isDelete(command), + }) + } + + if len(req.Commands) == 0 { + return result, nil + } + + allowedCommands, allowedIndices, rejected, ok, errText := service.runHook( + ctx, + req, + req.Commands, + quarantineName, + ) + if !ok { + fillCommandErrors(result, req.Commands, errText) + + return result, nil + } + + if req.Atomic && len(rejected) != 0 { + result.Commands = make([]CommandResult, 0, len(req.Commands)) + for index, command := range req.Commands { + message := rejected[index] + if message == "" { + message = "atomic push rejected by hook" + } + + result.Commands = append(result.Commands, resultForHookRejection(command, message)) + } + + return result, nil + } + + if len(allowedCommands) == 0 { + result.Commands = mergeCommandResults(req.Commands, rejected, nil, nil) + + return result, nil + } + + if req.PackExpected { + // Git migrates quarantined objects into permanent storage immediately + // before starting ref updates. + err = service.promoteQuarantine(quarantineName, quarantineRoot) + if err != nil { + result.UnpackError = err.Error() + fillCommandErrors(result, req.Commands, err.Error()) + + return result, nil + } + } + + if req.Atomic { + subresult := &Result{} + + err := service.applyAtomic(subresult, allowedCommands) + if err != nil { + return result, err + } + + result.Commands = mergeCommandResults(req.Commands, rejected, subresult.Commands, allowedIndices) + result.Applied = subresult.Applied + + return result, nil + } + + subresult := &Result{} + + err = service.applyBatch(subresult, allowedCommands) + if err != nil { + return result, err + } + + result.Commands = mergeCommandResults(req.Commands, rejected, subresult.Commands, allowedIndices) + result.Applied = subresult.Applied + + return result, nil +} |
