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
|
package files
import (
"fmt"
"slices"
)
func (tx *Transaction) prepare() (prepared []preparedTxOp, err error) {
prepared = make([]preparedTxOp, 0, len(tx.ops))
defer func() {
if err != nil {
_ = tx.cleanup(prepared)
}
}()
targets := make(map[string]struct{}, len(tx.ops))
for _, op := range tx.ops {
target, err := tx.resolveTarget(op)
if err != nil {
return prepared, err
}
targetKey := tx.targetKey(target.loc)
if _, exists := targets[targetKey]; exists {
return prepared, fmt.Errorf("refstore/files: duplicate transaction operation for %q", target.name)
}
targets[targetKey] = struct{}{}
prepared = append(prepared, preparedTxOp{
op: op,
target: target,
})
}
deleted := make(map[string]struct{})
written := make([]string, 0, len(prepared))
for _, item := range prepared {
switch item.op.kind {
case txDelete, txDeleteSymbolic:
deleted[item.target.name] = struct{}{}
case txCreate, txUpdate, txCreateSymbolic, txUpdateSymbolic:
written = append(written, item.target.name)
case txVerify, txVerifySymbolic:
}
}
existing, err := tx.visibleNames()
if err != nil {
return prepared, err
}
for _, name := range written {
err = verifyRefnameAvailable(name, existing, written, deleted)
if err != nil {
return prepared, err
}
}
lockNames := make([]string, 0, len(prepared))
for _, item := range prepared {
lockNames = append(lockNames, tx.targetKey(item.target.loc))
}
slices.Sort(lockNames)
for _, lockKey := range lockNames {
err = tx.createLock(refPathFromKey(lockKey))
if err != nil {
return prepared, err
}
}
hasDeletes := len(deleted) > 0
if hasDeletes {
err = tx.createPackedLock(tx.store.packedRefsTimeout)
if err != nil {
return prepared, err
}
}
for i := range prepared {
item := &prepared[i]
refState, err := tx.directRead(item.target.name)
if err != nil {
return prepared, err
}
item.target.ref = refState
err = tx.verifyCurrent(*item)
if err != nil {
return prepared, err
}
}
return prepared, nil
}
|