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
121
122
123
124
|
package service
import (
"codeberg.org/lindenii/furgit/internal/utils"
"codeberg.org/lindenii/furgit/objectid"
"codeberg.org/lindenii/furgit/refstore"
)
func (service *Service) applyAtomic(result *Result, commands []Command) error {
total := len(commands)
utils.WriteProgressf(service.opts.Progress, "updating refs: 0/%d\r", total)
tx, err := service.opts.Refs.BeginTransaction()
if err != nil {
return err
}
for i, command := range commands {
err = queueWriteTransaction(tx, command)
if err != nil {
_ = tx.Abort()
fillCommandErrors(result, commands, err.Error())
utils.WriteProgressf(service.opts.Progress, "updating refs: failed at %d/%d\n", i+1, total)
return nil
}
utils.WriteProgressf(service.opts.Progress, "updating refs: %d/%d\r", i+1, total)
}
err = tx.Commit()
if err != nil {
fillCommandErrors(result, commands, err.Error())
utils.WriteProgressf(service.opts.Progress, "updating refs: failed at commit\n")
return nil
}
result.Applied = true
for _, command := range commands {
result.Commands = append(result.Commands, successCommandResult(command))
}
utils.WriteProgressf(service.opts.Progress, "updating refs: done.\n")
return nil
}
func (service *Service) applyBatch(result *Result, commands []Command) error {
total := len(commands)
utils.WriteProgressf(service.opts.Progress, "updating refs...\r")
batch, err := service.opts.Refs.BeginBatch()
if err != nil {
return err
}
for _, command := range commands {
queueWriteBatch(batch, command)
}
batchResults, err := batch.Apply()
if err != nil && len(batchResults) == 0 {
utils.WriteProgressf(service.opts.Progress, "updating refs: failed at apply\n")
return err
}
appliedAny := false
for i, command := range commands {
item := successCommandResult(command)
if i < len(batchResults) && batchResults[i].Error != nil {
item.Error = batchResults[i].Error.Error()
} else {
appliedAny = true
}
result.Commands = append(result.Commands, item)
utils.WriteProgressf(service.opts.Progress, "updating refs: %d/%d\r", i+1, total)
}
result.Applied = appliedAny
utils.WriteProgressf(service.opts.Progress, "updating refs: done.\n")
return nil
}
func queueWriteTransaction(tx refstore.Transaction, command Command) error {
if isDelete(command) {
return tx.Delete(command.Name, command.OldID)
}
if command.OldID == objectid.Zero(command.OldID.Algorithm()) {
return tx.Create(command.Name, command.NewID)
}
return tx.Update(command.Name, command.NewID, command.OldID)
}
func queueWriteBatch(batch refstore.Batch, command Command) {
if isDelete(command) {
batch.Delete(command.Name, command.OldID)
return
}
if command.OldID == objectid.Zero(command.OldID.Algorithm()) {
batch.Create(command.Name, command.NewID)
return
}
batch.Update(command.Name, command.NewID, command.OldID)
}
func successCommandResult(command Command) CommandResult {
return CommandResult{
Name: command.Name,
RefName: command.Name,
OldID: objectIDPointer(command.OldID),
NewID: objectIDPointer(command.NewID),
}
}
|