aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--format/pack/ingest/api.go4
-rw-r--r--format/pack/ingest/ingest.go14
-rw-r--r--format/pack/ingest/progress_step.go9
-rw-r--r--format/pack/ingest/resolve_all.go29
-rw-r--r--format/pack/ingest/scan.go15
-rw-r--r--format/pack/ingest/thin_fix.go16
-rw-r--r--receivepack/service/ingest_quarantine.go1
7 files changed, 84 insertions, 4 deletions
diff --git a/format/pack/ingest/api.go b/format/pack/ingest/api.go
index f24bf83d..eb00ded3 100644
--- a/format/pack/ingest/api.go
+++ b/format/pack/ingest/api.go
@@ -16,6 +16,10 @@ type Options struct {
WriteRev bool
// Base supplies existing objects for thin-pack fixup.
Base objectstore.Store
+ // Progress receives human-readable progress messages.
+ //
+ // When nil, no progress output is emitted.
+ Progress io.Writer
// RequireTrailingEOF requires the source to hit EOF after the pack trailer.
//
// This is suitable for exact pack-file readers, but should be disabled for
diff --git a/format/pack/ingest/ingest.go b/format/pack/ingest/ingest.go
index 22007d27..5f204c2b 100644
--- a/format/pack/ingest/ingest.go
+++ b/format/pack/ingest/ingest.go
@@ -1,6 +1,10 @@
package ingest
-import "fmt"
+import (
+ "fmt"
+
+ "codeberg.org/lindenii/furgit/internal/utils"
+)
// ingest initializes transaction state and executes the ingest pipeline.
func ingest(state *ingestState) (out Result, err error) {
@@ -47,6 +51,7 @@ func ingest(state *ingestState) (out Result, err error) {
return Result{}, err
}
+ utils.WriteProgressf(state.opts.Progress, "writing index: start\n")
err = state.packFile.Sync()
if err != nil {
return Result{}, &DestinationWriteError{Op: fmt.Sprintf("sync pack: %v", err)}
@@ -56,11 +61,18 @@ func ingest(state *ingestState) (out Result, err error) {
if err != nil {
return Result{}, err
}
+ utils.WriteProgressf(state.opts.Progress, "writing index: done\n")
+ if state.opts.WriteRev {
+ utils.WriteProgressf(state.opts.Progress, "writing reverse index: start\n")
+ }
err = writeRev(state)
if err != nil {
return Result{}, err
}
+ if state.opts.WriteRev {
+ utils.WriteProgressf(state.opts.Progress, "writing reverse index: done\n")
+ }
return finalizeArtifacts(state)
}
diff --git a/format/pack/ingest/progress_step.go b/format/pack/ingest/progress_step.go
new file mode 100644
index 00000000..cdfc2322
--- /dev/null
+++ b/format/pack/ingest/progress_step.go
@@ -0,0 +1,9 @@
+package ingest
+
+func progressStep(total uint32) uint32 {
+ if total <= 200 {
+ return 1
+ }
+
+ return total / 200
+}
diff --git a/format/pack/ingest/resolve_all.go b/format/pack/ingest/resolve_all.go
index 992d87ae..e71d38d1 100644
--- a/format/pack/ingest/resolve_all.go
+++ b/format/pack/ingest/resolve_all.go
@@ -1,16 +1,41 @@
package ingest
-import "errors"
+import (
+ "errors"
+
+ "codeberg.org/lindenii/furgit/internal/utils"
+)
// resolveAll resolves all delta records and finalizes ObjectID/RealType for every record.
func resolveAll(state *ingestState) error {
state.unresolvedRefDeltas = state.unresolvedRefDeltas[:0]
+ var pending uint32
+ for idx := range state.records {
+ if !state.records[idx].resolved {
+ pending++
+ }
+ }
+
+ if pending == 0 {
+ return nil
+ }
+
+ step := progressStep(pending)
+ var done uint32
+ utils.WriteProgressf(state.opts.Progress, "resolving deltas: 0%% (0/%d)\r", pending)
+
for idx := range state.records {
if state.records[idx].resolved {
continue
}
+ done++
+ if done%step == 0 || done == pending {
+ percent := done * 100 / pending
+ utils.WriteProgressf(state.opts.Progress, "resolving deltas: %3d%% (%d/%d)\r", percent, done, pending)
+ }
+
visiting := make(map[int]struct{})
ty, content, err := resolveRecord(state, idx, visiting)
@@ -37,5 +62,7 @@ func resolveAll(state *ingestState) error {
state.baseCache.add(idx, ty, content)
}
+ utils.WriteProgressf(state.opts.Progress, "resolving deltas: 100%% (%d/%d), done.\n", pending, pending)
+
return nil
}
diff --git a/format/pack/ingest/scan.go b/format/pack/ingest/scan.go
index d1252d00..a0d06dac 100644
--- a/format/pack/ingest/scan.go
+++ b/format/pack/ingest/scan.go
@@ -3,6 +3,7 @@ package ingest
import (
"fmt"
+ "codeberg.org/lindenii/furgit/internal/utils"
"codeberg.org/lindenii/furgit/objectid"
)
@@ -29,7 +30,11 @@ func streamPackAndScan(state *ingestState) error {
state.ofsDeltas = make([]ofsDeltaRef, 0, state.objectCountHeader)
state.refDeltas = make([]refDeltaRef, 0, state.objectCountHeader)
- for range state.objectCountHeader {
+ total := state.objectCountHeader
+ step := progressStep(total)
+ utils.WriteProgressf(state.opts.Progress, "receiving objects: 0%% (0/%d)\r", total)
+
+ for i := uint32(0); i < total; i++ {
nextOffset, err := scanOneEntry(state, state.stream.consumed)
if err != nil {
return err
@@ -38,8 +43,16 @@ func streamPackAndScan(state *ingestState) error {
if nextOffset != state.stream.consumed {
return fmt.Errorf("format/pack/ingest: internal stream offset mismatch")
}
+
+ done := i + 1
+ if done%step == 0 || done == total {
+ percent := done * 100 / total
+ utils.WriteProgressf(state.opts.Progress, "receiving objects: %3d%% (%d/%d)\r", percent, done, total)
+ }
}
+ utils.WriteProgressf(state.opts.Progress, "receiving objects: 100%% (%d/%d), done.\n", total, total)
+
err = state.stream.finishAndFlushTrailer(state.opts.RequireTrailingEOF)
if err != nil {
return err
diff --git a/format/pack/ingest/thin_fix.go b/format/pack/ingest/thin_fix.go
index cdee8748..42e356b6 100644
--- a/format/pack/ingest/thin_fix.go
+++ b/format/pack/ingest/thin_fix.go
@@ -4,6 +4,7 @@ import (
"fmt"
"codeberg.org/lindenii/furgit/internal/intconv"
+ "codeberg.org/lindenii/furgit/internal/utils"
)
// maybeFixThin appends missing bases and rewrites pack header/trailer when needed.
@@ -12,6 +13,12 @@ func maybeFixThin(state *ingestState) error {
return nil
}
+ utils.WriteProgressf(
+ state.opts.Progress,
+ "fixing thin pack: %d unresolved bases\r",
+ len(state.unresolvedRefDeltas),
+ )
+
if !state.opts.FixThin {
return &ThinPackUnresolvedError{Count: len(state.unresolvedRefDeltas)}
}
@@ -47,7 +54,8 @@ func maybeFixThin(state *ingestState) error {
state.stream.consumed = consumed
baseIDs := unresolvedThinBaseIDs(state)
- for _, id := range baseIDs {
+ total := len(baseIDs)
+ for i, id := range baseIDs {
ty, content, err := state.opts.Base.ReadBytesContent(id)
if err != nil {
continue
@@ -59,6 +67,8 @@ func maybeFixThin(state *ingestState) error {
}
state.thinFixed = true
+
+ utils.WriteProgressf(state.opts.Progress, "fixing thin pack: %d/%d\r", i+1, total)
}
err = rewritePackHeaderAndTrailer(state)
@@ -66,5 +76,9 @@ func maybeFixThin(state *ingestState) error {
return err
}
+ if state.thinFixed {
+ utils.WriteProgressf(state.opts.Progress, "fixing thin pack: done.\n")
+ }
+
return nil
}
diff --git a/receivepack/service/ingest_quarantine.go b/receivepack/service/ingest_quarantine.go
index 921ce217..8e592bb9 100644
--- a/receivepack/service/ingest_quarantine.go
+++ b/receivepack/service/ingest_quarantine.go
@@ -86,6 +86,7 @@ func (service *Service) ingestQuarantine(
}
utils.WriteProgressf(
+ service.opts.Progress,
"receiving objects: unpack ok, %d objects (%s)\n",
ingested.ObjectCount,
ingested.PackHash,