// Keep a folder out of the app's git repo: store art pulled from the stores (and renders) is never committed. import { appendFileSync, existsSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; import { spawnSync } from 'node:child_process'; import { join, relative, sep } from 'node:path'; const git = (cwd: string, args: string[]) => spawnSync('git', args, { cwd, encoding: 'utf8', timeout: 15_000 }); /** When `dir` is inside a git repo and not ignored yet, adds `//` to the repo root's * .gitignore. Returns the line added, or null (no repo, no git, already ignored). `dry`: only says what it would add. */ export function ignoreInRepo(dir: string, comment: string, dry = false): string | null { let probe = dir; while (!existsSync(probe)) { const up = join(probe, '..'); if (up === probe) return null; probe = up; } const top = git(probe, ['rev-parse', '--show-toplevel']); if (top.status !== 0) return null; const root = realpathSync(top.stdout.trim()); let real: string; try { real = realpathSync(probe) + dir.slice(probe.length); } catch { return null; } const rel = relative(root, real).split(sep).join('/'); if (!rel || rel.startsWith('..')) return null; if (git(root, ['check-ignore', '-q', `${rel}/`]).status === 0) return null; const line = `/${rel}/`; if (dry) return line; const gi = join(root, '.gitignore'); const cur = existsSync(gi) ? readFileSync(gi, 'utf8') : ''; const add = `# ${comment}\n${line}\n`; if (cur) appendFileSync(gi, `${cur.endsWith('\n') ? '' : '\n'}${add}`); else writeFileSync(gi, add); return line; }