| … | … | @@ -1,6 +1,34 @@ |
| 1 | 1 | const fs = require('fs'); |
| 2 | 2 | const path = require('path'); |
| 3 | 3 | |
| 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 | */ |
| 13 | function 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 | |
| 4 | 32 | /** |
| 5 | 33 | * Scan a directory for bare git repos. |
| 6 | 34 | * Returns a Map of repo name → info. |
| … | … | @@ -55,16 +83,13 @@ function repoInfo (repoPath, name) { |
| 55 | 83 | const head = headBranch ? refs[headBranch] : null; |
| 56 | 84 | if (headBranch) repointHeadIfDangling(repoPath, refs, headBranch); |
| 57 | 85 | |
| 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); |
| 68 | 93 | |
| 69 | 94 | let lastUpdated = null; |
| 70 | 95 | try { |