ref: 65a6439638a18e4317e144a0117db7604a2f2940
dir: /packfile/ingest/finalize.go/
package ingest
import (
"errors"
"fmt"
"io/fs"
"strings"
"codeberg.org/lindenii/furgit/internal/intconv"
)
// finalizeArtifacts links temporary files to final names and returns Result.
func finalizeArtifacts(state *ingestState) (Result, error) {
base := "pack-" + state.packHash.String()
packFinal := base + ".pack"
idxFinal := base + ".idx"
revFinal := ""
if state.opts.WriteRev {
revFinal = base + ".rev"
}
err := linkTempToFinal(state, state.packTmpName, packFinal)
if err != nil {
return Result{}, err
}
err = linkTempToFinal(state, state.idxTmpName, idxFinal)
if err != nil {
return Result{}, err
}
if state.opts.WriteRev {
err := linkTempToFinal(state, state.revTmpName, revFinal)
if err != nil {
return Result{}, err
}
}
objectCount, err := intconv.IntToUint32(len(state.records))
if err != nil {
return Result{}, err
}
return Result{
PackName: packFinal,
IdxName: idxFinal,
RevName: revFinal,
PackHash: state.packHash,
ObjectCount: objectCount,
ThinFixed: state.thinFixed,
}, nil
}
// rollbackTemporaryArtifacts removes temporary files after failure.
func rollbackTemporaryArtifacts(state *ingestState) {
if state.packTmpName != "" {
_ = state.destination.Remove(state.packTmpName)
}
if state.idxTmpName != "" {
_ = state.destination.Remove(state.idxTmpName)
}
if state.revTmpName != "" {
_ = state.destination.Remove(state.revTmpName)
}
}
// linkTempToFinal hard-links tmp to final, tolerating existing final paths.
func linkTempToFinal(state *ingestState, tmp, final string) error {
if tmp == "" || final == "" {
return fmt.Errorf("packfile/ingest: invalid finalize names tmp=%q final=%q", tmp, final)
}
if strings.Contains(final, "/") {
return fmt.Errorf("packfile/ingest: final name must be leaf: %q", final)
}
err := state.destination.Link(tmp, final)
if err == nil {
_ = state.destination.Remove(tmp)
return nil
}
if errors.Is(err, fs.ErrExist) {
_ = state.destination.Remove(tmp)
return nil
}
return err
}