ref: 4a17412255e294e99f2d11e9b8458e30bbe58292
parent: c75a034d25ca87f3d209a8e82c743b8a7e96573b
author: Runxi Yu <me@runxiyu.org>
date: Sun Mar 8 10:15:55 EDT 2026
format/pack/ingest: Use progress API
--- a/format/pack/ingest/api.go
+++ b/format/pack/ingest/api.go
@@ -23,6 +23,10 @@
//
// When nil, no progress output is emitted.
Progress io.Writer
+ // ProgressFlush flushes transport output after progress writes.
+ //
+ // When nil, no explicit flush is attempted.
+ ProgressFlush func() error
// RequireTrailingEOF requires the source to hit EOF after the pack trailer.
//
// This is suitable for exact pack-file readers, but should be disabled for
--- a/format/pack/ingest/ingest.go
+++ b/format/pack/ingest/ingest.go
@@ -2,8 +2,6 @@
import (
"fmt"
-
- "codeberg.org/lindenii/furgit/internal/utils"
)
// ingest initializes transaction state and executes the ingest pipeline.
@@ -51,7 +49,7 @@
return Result{}, err}
- utils.BestEffortFprintf(state.opts.Progress, "writing index...\r")
+ writeProgress(state, "writing index...\r")
err = state.packFile.Sync()
if err != nil {@@ -63,10 +61,10 @@
return Result{}, err}
- utils.BestEffortFprintf(state.opts.Progress, "writing index: done.\n")
+ writeProgress(state, "writing index: done.\n")
if state.opts.WriteRev {- utils.BestEffortFprintf(state.opts.Progress, "writing reverse index...\r")
+ writeProgress(state, "writing reverse index...\r")
}
err = writeRev(state)
@@ -75,7 +73,7 @@
}
if state.opts.WriteRev {- utils.BestEffortFprintf(state.opts.Progress, "writing reverse index: done.\n")
+ writeProgress(state, "writing reverse index: done.\n")
}
return finalizeArtifacts(state)
--- a/format/pack/ingest/progress_step.go
+++ /dev/null
@@ -1,9 +1,0 @@
-package ingest
-
-func progressStep(total uint32) uint32 {- if total <= 200 {- return 1
- }
-
- return total / 200
-}
--- /dev/null
+++ b/format/pack/ingest/progress_write.go
@@ -1,0 +1,10 @@
+package ingest
+
+import "codeberg.org/lindenii/furgit/internal/utils"
+
+func writeProgress(state *ingestState, format string, args ...any) {+ utils.BestEffortFprintf(state.opts.Progress, format, args...)
+ if state.opts.ProgressFlush != nil {+ _ = state.opts.ProgressFlush()
+ }
+}
--- a/format/pack/ingest/resolve_all.go
+++ b/format/pack/ingest/resolve_all.go
@@ -3,7 +3,7 @@
import (
"errors"
- "codeberg.org/lindenii/furgit/internal/utils"
+ "codeberg.org/lindenii/furgit/internal/progress"
)
// resolveAll resolves all delta records and finalizes ObjectID/RealType for every record.
@@ -22,11 +22,14 @@
return nil
}
- step := progressStep(pending)
-
var done uint32
- utils.BestEffortFprintf(state.opts.Progress, "resolving deltas: 0%% (0/%d)\r", pending)
+ meter := progress.New(progress.Options{+ Writer: state.opts.Progress,
+ Flush: state.opts.ProgressFlush,
+ Title: "resolving deltas",
+ Total: uint64(pending),
+ })
for idx := range state.records { if state.records[idx].resolved {@@ -34,10 +37,7 @@
}
done++
- if done%step == 0 || done == pending {- percent := done * 100 / pending
- utils.BestEffortFprintf(state.opts.Progress, "resolving deltas: %3d%% (%d/%d)\r", percent, done, pending)
- }
+ meter.Set(uint64(done), 0)
visiting := make(map[int]struct{})@@ -65,7 +65,7 @@
state.baseCache.add(idx, ty, content)
}
- utils.BestEffortFprintf(state.opts.Progress, "resolving deltas: 100%% (%d/%d), done.\n", pending, pending)
+ meter.Stop("done")return nil
}
--- a/format/pack/ingest/scan.go
+++ b/format/pack/ingest/scan.go
@@ -3,7 +3,7 @@
import (
"fmt"
- "codeberg.org/lindenii/furgit/internal/utils"
+ "codeberg.org/lindenii/furgit/internal/progress"
"codeberg.org/lindenii/furgit/objectid"
)
@@ -21,7 +21,7 @@
state.algo.Size(),
)
- utils.BestEffortFprintf(state.opts.Progress, "validating pack header...\r")
+ writeProgress(state, "validating pack header...\r")
err = seedStreamWithPackHeader(state)
if err != nil {@@ -28,7 +28,7 @@
return err
}
- utils.BestEffortFprintf(state.opts.Progress, "validating pack header: done.\n")
+ writeProgress(state, "validating pack header: done.\n")
state.records = make([]objectRecord, 0, state.objectCountHeader)
state.ofsDeltas = make([]ofsDeltaRef, 0, state.objectCountHeader)
@@ -35,8 +35,13 @@
state.refDeltas = make([]refDeltaRef, 0, state.objectCountHeader)
total := state.objectCountHeader
- step := progressStep(total)
- utils.BestEffortFprintf(state.opts.Progress, "receiving objects: 0%% (0/%d)\r", total)
+ meter := progress.New(progress.Options{+ Writer: state.opts.Progress,
+ Flush: state.opts.ProgressFlush,
+ Title: "receiving objects",
+ Total: uint64(total),
+ Throughput: true,
+ })
for i := range total {nextOffset, err := scanOneEntry(state, state.stream.consumed)
@@ -49,13 +54,10 @@
}
done := i + 1
- if done%step == 0 || done == total {- percent := done * 100 / total
- utils.BestEffortFprintf(state.opts.Progress, "receiving objects: %3d%% (%d/%d)\r", percent, done, total)
- }
+ meter.Set(uint64(done), state.stream.consumed)
}
- utils.BestEffortFprintf(state.opts.Progress, "receiving objects: 100%% (%d/%d), done.\n", total, total)
+ meter.Stop("done")err = state.stream.finishAndFlushTrailer(state.opts.RequireTrailingEOF)
if err != nil {--- a/format/pack/ingest/thin_fix.go
+++ b/format/pack/ingest/thin_fix.go
@@ -4,7 +4,7 @@
"fmt"
"codeberg.org/lindenii/furgit/internal/intconv"
- "codeberg.org/lindenii/furgit/internal/utils"
+ "codeberg.org/lindenii/furgit/internal/progress"
)
// maybeFixThin appends missing bases and rewrites pack header/trailer when needed.
@@ -13,8 +13,8 @@
return nil
}
- utils.BestEffortFprintf(
- state.opts.Progress,
+ writeProgress(
+ state,
"fixing thin pack: %d unresolved bases\r",
len(state.unresolvedRefDeltas),
)
@@ -56,9 +56,13 @@
baseIDs := unresolvedThinBaseIDs(state)
total := len(baseIDs)
- if total > 0 {- utils.BestEffortFprintf(state.opts.Progress, "fixing thin pack: 0%% (0/%d)\r", total)
- }
+ meter := progress.New(progress.Options{+ Writer: state.opts.Progress,
+ Flush: state.opts.ProgressFlush,
+ Title: "fixing thin pack",
+ Total: uint64(total),
+ Sparse: true,
+ })
for i, id := range baseIDs {ty, content, err := state.opts.Base.ReadBytesContent(id)
@@ -74,8 +78,7 @@
state.thinFixed = true
done := i + 1
- percent := done * 100 / total
- utils.BestEffortFprintf(state.opts.Progress, "fixing thin pack: %3d%% (%d/%d)\r", percent, done, total)
+ meter.Set(uint64(done), 0)
}
err = rewritePackHeaderAndTrailer(state)
@@ -84,7 +87,7 @@
}
if state.thinFixed {- utils.BestEffortFprintf(state.opts.Progress, "fixing thin pack: 100%% (%d/%d), done.\n", total, total)
+ meter.Stop("done")}
return nil
--
⑨