ref: 85f1212724e037e6934203f04a3f6231ac609503
dir: /refstore/files/transaction_prepare.go/
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
}