package fetch import ( "fmt" "sync/atomic" ) // counters accumulates transfer activity for one repository's summary log // line. Counters are atomic because download workers run concurrently. type counters struct { Fetched atomic.Int64 FetchedBytes atomic.Int64 Unchanged atomic.Int64 Pruned atomic.Int64 Planned atomic.Int64 PlannedBytes atomic.Int64 } // Stats collects transfer activity for the repository currently // synchronizing. The CLI synchronizes repositories sequentially, so one // package-level collector suffices there. The server's concurrent crawls // interleave into these counters, so their values are only meaningful in // the sequential path; the server must not report them. var Stats = &counters{} // Reset clears the collector for the next repository. func (s *counters) Reset() { s.Fetched.Store(0) s.FetchedBytes.Store(0) s.Unchanged.Store(0) s.Pruned.Store(0) s.Planned.Store(0) s.PlannedBytes.Store(0) } // FormatBytes renders a byte count in a human readable unit. func FormatBytes(n int64) string { const unit = 1024 const prefixes = "KMGTPE" if n < unit { return fmt.Sprintf("%d B", n) } div, exp := int64(unit), 0 // Cap the exponent at the last available prefix so an unexpectedly // large count can never index past the prefix table. for m := n / unit; m >= unit && exp < len(prefixes)-1; m /= unit { div *= unit exp++ } return fmt.Sprintf("%.1f %ciB", float64(n)/float64(div), prefixes[exp]) }