aboutsummaryrefslogtreecommitdiff
path: root/format/pack/ingest/finalize.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-05 18:24:40 +0800
committerGravatar Runxi Yu2026-03-05 19:05:47 +0800
commit57f1818d547f2f1dca38033b4e29f62d89ef80f9 (patch)
tree88d55ac38e2427860bf380c8cce42fcb3bb1e9ee /format/pack/ingest/finalize.go
parentinternal/compress/zlib: Use flate's compression consumed counter (diff)
signatureNo signature
format/pack/ingest: Init
Diffstat (limited to 'format/pack/ingest/finalize.go')
-rw-r--r--format/pack/ingest/finalize.go77
1 files changed, 77 insertions, 0 deletions
diff --git a/format/pack/ingest/finalize.go b/format/pack/ingest/finalize.go
new file mode 100644
index 00000000..06b30102
--- /dev/null
+++ b/format/pack/ingest/finalize.go
@@ -0,0 +1,77 @@
+package ingest
+
+import (
+ "errors"
+ "fmt"
+ "io/fs"
+ "strings"
+)
+
+// 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.writeRev {
+ revFinal = base + ".rev"
+ }
+
+ if err := linkTempToFinal(state, state.packTmpName, packFinal); err != nil {
+ return Result{}, err
+ }
+ if err := linkTempToFinal(state, state.idxTmpName, idxFinal); err != nil {
+ return Result{}, err
+ }
+ if state.writeRev {
+ if err := linkTempToFinal(state, state.revTmpName, revFinal); err != nil {
+ return Result{}, err
+ }
+ }
+
+ return Result{
+ PackName: packFinal,
+ IdxName: idxFinal,
+ RevName: revFinal,
+ PackHash: state.packHash,
+ ObjectCount: uint32(len(state.records)),
+ 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("format/pack/ingest: invalid finalize names tmp=%q final=%q", tmp, final)
+ }
+ if strings.Contains(final, "/") {
+ return fmt.Errorf("format/pack/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
+}