OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-sync commits / 837ed0c

repos: count real on-disk footprint, not just packs
Previously summed bytes of objects/pack/*.pack only. That misses loose objects (any freshly-fetched repo before gc), refs/, packed-refs, info/, hooks/. Many real repos rendered as 0 bytes on /repos and the template's truthy check left the size column blank. Walk the whole repoPath via a sync dirSize() best-effort recursion (skips entries it can't stat so one permission/race issue doesn't break the whole scan). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
837ed0c38aad31c2aa5dd9a113811e355cd34ed4
by plankatron <fleeky@gmail.com> · 2026-04-28T01:39:13.000Z

Changed files (1) +35 -10

lib/repos.js +35 -10
……@@ -1,6 +1,34 @@
11const fs = require('fs');
22const path = require('path');
33
4/**
5 * Recursive byte-size of a directory tree. Synchronous (matches the
6 * rest of repos.js which is sync). Best-effort — silently skips any
7 * file/dir it can't read so a single permission/race issue doesn't
8 * break the whole scan.
9 *
10 * For bare repos this counts loose objects, packs, idx/bitmap/rev,
11 * refs/, packed-refs, hooks/, info/ — the actual on-disk footprint.
12 */
13function dirSize (p) {
14 let total = 0;
15 let entries;
16 try {
17 entries = fs.readdirSync(p, { withFileTypes: true });
18 } catch {
19 return 0;
20 }
21 for (const entry of entries) {
22 const full = path.join(p, entry.name);
23 if (entry.isDirectory()) {
24 total += dirSize(full);
25 } else if (entry.isFile()) {
26 try { total += fs.statSync(full).size; } catch {}
27 }
28 }
29 return total;
30}
31
432/**
533 * Scan a directory for bare git repos.
634 * Returns a Map of repo name → info.
……@@ -55,16 +83,13 @@ function repoInfo (repoPath, name) {
5583 const head = headBranch ? refs[headBranch] : null;
5684 if (headBranch) repointHeadIfDangling(repoPath, refs, headBranch);
5785
58 let size = 0;
59 try {
60 const packDir = path.join(repoPath, 'objects', 'pack');
61 const packs = fs.readdirSync(packDir);
62 for (const p of packs) {
63 if (p.endsWith('.pack')) {
64 size += fs.statSync(path.join(packDir, p)).size;
65 }
66 }
67 } catch {}
86 // Real bare-repo footprint: walk the whole dir. Counts loose objects
87 // under objects/xx/, packs + idx + bitmap + rev, refs/, packed-refs,
88 // info/, hooks/, etc. Previously only `objects/pack/*.pack` bytes were
89 // counted — that misses freshly-fetched repos where content is still
90 // loose, and produces 0 for many real repos (which then renders blank
91 // on /repos because of `truthy ?` template check).
92 const size = dirSize(repoPath);
6893
6994 let lastUpdated = null;
7095 try {