shithub: furgit

Download patch

ref: b90caf8f6606cdecd8529dc365b53584ee402d8c
parent: b6221066b17bfc019202fc68bdeede4a4f41307e
author: Runxi Yu <me@runxiyu.org>
date: Sun Mar 8 10:25:33 EDT 2026

format/pack/ingest: Write index progress too

--- a/format/pack/ingest/idx_write.go
+++ b/format/pack/ingest/idx_write.go
@@ -9,6 +9,7 @@
 	"slices"
 
 	"codeberg.org/lindenii/furgit/internal/intconv"
+	"codeberg.org/lindenii/furgit/internal/progress"
 )
 
 const (
@@ -26,14 +27,14 @@
 	}
 
 	write := func(src []byte) error {
-		_, err := state.idxFile.Write(src)
-		if err != nil {
-			return err
+		_, writeErr := state.idxFile.Write(src)
+		if writeErr != nil {
+			return writeErr
 		}
 
-		_, err = hashImpl.Write(src)
-		if err != nil {
-			return err
+		_, writeErr = hashImpl.Write(src)
+		if writeErr != nil {
+			return writeErr
 		}
 
 		return nil
@@ -40,15 +41,8 @@
 	}
 
 	var scratch [8]byte
-	binary.BigEndian.PutUint32(scratch[:4], idxMagicV2)
-	binary.BigEndian.PutUint32(scratch[4:8], idxVersionV2)
-
-	err = write(scratch[:8])
-	if err != nil {
-		return err
-	}
-
 	var fanout [256]uint32
+	writeProgress(state, "writing index fanout...\r")
 
 	for _, recordIdx := range order {
 		idRaw := state.records[recordIdx].objectID.Bytes()
@@ -55,6 +49,13 @@
 		fanout[idRaw[0]]++
 	}
 
+	binary.BigEndian.PutUint32(scratch[:4], idxMagicV2)
+	binary.BigEndian.PutUint32(scratch[4:8], idxVersionV2)
+	err = write(scratch[:8])
+	if err != nil {
+		return err
+	}
+
 	var cumulative uint32
 	for i := range fanout {
 		cumulative += fanout[i]
@@ -65,7 +66,23 @@
 			return err
 		}
 	}
+	writeProgress(state, "writing index fanout: done.\n")
 
+	largeOffsetCount := 0
+	for idx := range state.records {
+		if state.records[idx].offset >= 0x80000000 {
+			largeOffsetCount++
+		}
+	}
+
+	oidMeter := progress.New(progress.Options{
+		Writer: state.opts.Progress,
+		Flush:  state.opts.ProgressFlush,
+		Title:  "writing index object ids",
+		Total:  uint64(len(order)),
+	})
+	var oidDone uint64
+
 	for _, recordIdx := range order {
 		idRaw := state.records[recordIdx].objectID.Bytes()
 
@@ -73,8 +90,22 @@
 		if err != nil {
 			return err
 		}
+
+		oidDone++
+		oidMeter.Set(oidDone, 0)
 	}
+	if oidDone > 0 {
+		oidMeter.Stop("done")
+	}
 
+	crcMeter := progress.New(progress.Options{
+		Writer: state.opts.Progress,
+		Flush:  state.opts.ProgressFlush,
+		Title:  "writing index crc32",
+		Total:  uint64(len(order)),
+	})
+	var crcDone uint64
+
 	for _, recordIdx := range order {
 		binary.BigEndian.PutUint32(scratch[:4], state.records[recordIdx].crc32)
 
@@ -82,9 +113,22 @@
 		if err != nil {
 			return err
 		}
+
+		crcDone++
+		crcMeter.Set(crcDone, 0)
 	}
+	if crcDone > 0 {
+		crcMeter.Stop("done")
+	}
 
 	largeOffsets := make([]uint64, 0)
+	offsetMeter := progress.New(progress.Options{
+		Writer: state.opts.Progress,
+		Flush:  state.opts.ProgressFlush,
+		Title:  "writing index offsets",
+		Total:  uint64(len(order)),
+	})
+	var offsetDone uint64
 
 	for _, recordIdx := range order {
 		offset := state.records[recordIdx].offset
@@ -107,8 +151,21 @@
 		if err != nil {
 			return err
 		}
+
+		offsetDone++
+		offsetMeter.Set(offsetDone, 0)
 	}
+	if offsetDone > 0 {
+		offsetMeter.Stop("done")
+	}
 
+	largeOffsetMeter := progress.New(progress.Options{
+		Writer: state.opts.Progress,
+		Flush:  state.opts.ProgressFlush,
+		Title:  "writing index large offsets",
+		Total:  uint64(largeOffsetCount),
+	})
+	var largeOffsetDone uint64
 	for _, off := range largeOffsets {
 		binary.BigEndian.PutUint64(scratch[:8], off)
 
@@ -116,8 +173,16 @@
 		if err != nil {
 			return err
 		}
+
+		largeOffsetDone++
+		largeOffsetMeter.Set(largeOffsetDone, 0)
 	}
+	if largeOffsetDone > 0 {
+		largeOffsetMeter.Stop("done")
+	}
 
+	writeProgress(state, "writing index trailer...\r")
+
 	err = write(state.packHash.Bytes())
 	if err != nil {
 		return err
@@ -130,7 +195,13 @@
 		return err
 	}
 
-	return state.idxFile.Sync()
+	err = state.idxFile.Sync()
+	if err != nil {
+		return err
+	}
+	writeProgress(state, "writing index trailer: done.\n")
+
+	return nil
 }
 
 // buildIdxOrder returns record indexes sorted by ObjectID.
--- a/format/pack/ingest/ingest.go
+++ b/format/pack/ingest/ingest.go
@@ -34,7 +34,7 @@
 	}
 
 	if state.thinFixed {
-		err := resolveAll(state)
+		err = resolveAll(state)
 		if err != nil {
 			return Result{}, err
 		}
@@ -49,8 +49,6 @@
 		return Result{}, err
 	}
 
-	writeProgress(state, "writing index...\r")
-
 	err = state.packFile.Sync()
 	if err != nil {
 		return Result{}, &DestinationWriteError{Op: fmt.Sprintf("sync pack: %v", err)}
@@ -61,19 +59,9 @@
 		return Result{}, err
 	}
 
-	writeProgress(state, "writing index: done.\n")
-
-	if state.opts.WriteRev {
-		writeProgress(state, "writing reverse index...\r")
-	}
-
 	err = writeRev(state)
 	if err != nil {
 		return Result{}, err
-	}
-
-	if state.opts.WriteRev {
-		writeProgress(state, "writing reverse index: done.\n")
 	}
 
 	return finalizeArtifacts(state)
--- a/format/pack/ingest/rev_write.go
+++ b/format/pack/ingest/rev_write.go
@@ -5,6 +5,7 @@
 	"slices"
 
 	"codeberg.org/lindenii/furgit/internal/intconv"
+	"codeberg.org/lindenii/furgit/internal/progress"
 )
 
 const (
@@ -33,6 +34,7 @@
 	}
 
 	var scratch [8]byte
+	writeProgress(state, "writing reverse index header...\r")
 	binary.BigEndian.PutUint32(scratch[:4], revMagic)
 
 	err = writeAndHash(state.revFile, hashImpl, scratch[:4])
@@ -53,7 +55,16 @@
 	if err != nil {
 		return err
 	}
+	writeProgress(state, "writing reverse index header: done.\n")
 
+	entriesMeter := progress.New(progress.Options{
+		Writer: state.opts.Progress,
+		Flush:  state.opts.ProgressFlush,
+		Title:  "writing reverse index entries",
+		Total:  uint64(len(packOrder)),
+	})
+	var entriesDone uint64
+
 	for _, recordIdx := range packOrder {
 		recordPos, err := intconv.IntToUint32(recordToIdxPos[recordIdx])
 		if err != nil {
@@ -66,8 +77,15 @@
 		if err != nil {
 			return err
 		}
+		entriesDone++
+		entriesMeter.Set(entriesDone, 0)
 	}
+	if entriesDone > 0 {
+		entriesMeter.Stop("done")
+	}
 
+	writeProgress(state, "writing reverse index trailer...\r")
+
 	err = writeAndHash(state.revFile, hashImpl, state.packHash.Bytes())
 	if err != nil {
 		return err
@@ -80,7 +98,13 @@
 		return err
 	}
 
-	return state.revFile.Sync()
+	err = state.revFile.Sync()
+	if err != nil {
+		return err
+	}
+	writeProgress(state, "writing reverse index trailer: done.\n")
+
+	return nil
 }
 
 // buildPackOrder returns record indexes sorted by pack offset.
--