1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
package service
import (
"context"
"codeberg.org/lindenii/furgit/internal/utils"
objectstore "codeberg.org/lindenii/furgit/object/store"
)
// Execute validates one receive-pack request, optionally ingests its pack into
// quarantine, runs the optional hook, and applies allowed ref updates.
//
// Labels: Deps-Borrowed.
func (service *Service) Execute(ctx context.Context, req *Request) (*Result, error) {
result := &Result{
Commands: make([]CommandResult, 0, len(req.Commands)),
}
var err error
quarantine, ok := service.ingestQuarantine(result, req.Commands, req)
if !ok {
return result, nil
}
if quarantine != nil {
defer func(q objectstore.Quarantine) {
_ = q.Discard()
}(quarantine)
}
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,
quarantine,
)
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 && quarantine != nil {
// Git migrates quarantined objects into permanent storage immediately
// before starting ref updates.
utils.BestEffortFprintf(service.opts.Progress, "promoting quarantine...\r")
err := quarantine.Promote()
if err != nil {
utils.BestEffortFprintf(service.opts.Progress, "promoting quarantine: failed: %v.\n", err)
result.UnpackError = err.Error()
fillCommandErrors(result, req.Commands, err.Error())
return result, nil
}
utils.BestEffortFprintf(service.opts.Progress, "promoting quarantine: done.\n")
}
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
}
|