check / scan: project walks skip dot folders, worktrees and git-ignored output, no stat per entry (244 s -> 46 s on a big game repo)
This commit is contained in:
parent
f2d7beb7ce
commit
164ba390dd
6 changed files with 106 additions and 30 deletions
|
|
@ -3,9 +3,10 @@
|
|||
// Xcode INFOPLIST_KEY_* build settings, Expo app.json, Unity ProjectSettings and Godot export presets), entitlements,
|
||||
// privacy manifests, the Android manifest (permissions, services, target SDK) and the app's own source files.
|
||||
// Tolerant on purpose: an unreadable or odd file is skipped, never an exception.
|
||||
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
||||
import { type Dirent, readdirSync, readFileSync, statSync } from 'node:fs';
|
||||
import { basename, dirname, extname, join, relative, sep } from 'node:path';
|
||||
import { resolvePackage } from '../node-packages';
|
||||
import { skipDir } from '../walk-skip';
|
||||
import { isBuildCopyPath, type Manifest, parseManifest } from '../privacy-manifest';
|
||||
import { type DepRef, type Eco, matchesSdk, SDKS, type SdkDef } from './sdks';
|
||||
import { exportedIpas, ipaInfo } from '../xcode';
|
||||
|
|
@ -104,33 +105,32 @@ const SRC_EXT = new Set(['.swift', '.m', '.mm', '.h', '.kt', '.java', '.dart', '
|
|||
const MAX_FILES = 25_000;
|
||||
const MAX_TEXT = 1_500_000;
|
||||
|
||||
/** A linked git worktree: its .git is a file pointing into <repo>/.git/worktrees/ (a submodule's points into modules/). */
|
||||
function isWorktree(dir: string): boolean {
|
||||
try { return /^gitdir:.*[\\/]worktrees[\\/]/m.test(readFileSync(join(dir, '.git'), 'utf8')); } catch { return false; }
|
||||
}
|
||||
|
||||
/** Every file under root (relative paths), skipping build output, dependency folders and VCS data. Native libraries
|
||||
* (.so) of any size also go into `bins` when given (they are not read, only listed). */
|
||||
export function listFiles(root: string, bins?: string[]): string[] {
|
||||
const out: string[] = [];
|
||||
const walk = (dir: string, depth: number) => {
|
||||
if (depth > 14 || out.length >= MAX_FILES) return;
|
||||
let names: string[];
|
||||
try { names = readdirSync(dir); } catch { return; }
|
||||
for (const n of names.sort()) {
|
||||
let ents: Dirent[];
|
||||
try { ents = readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
||||
for (const e of ents.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))) {
|
||||
const n = e.name;
|
||||
if (SKIP_DIRS.has(n) || n === '.DS_Store') continue;
|
||||
const p = join(dir, n);
|
||||
let st;
|
||||
try { st = statSync(p); } catch { continue; }
|
||||
if (st.isDirectory()) {
|
||||
// the entry type comes with the listing; only files (for their size) and links get a stat
|
||||
let isDir = e.isDirectory();
|
||||
if (e.isSymbolicLink()) { try { isDir = statSync(p).isDirectory(); } catch { continue; } }
|
||||
if (isDir) {
|
||||
// compiled frameworks are SDK binaries, not app code
|
||||
if (/\.(xc)?framework$|\.xcassets$|\.bundle$|\.app$|\.dSYM$/.test(n)) continue;
|
||||
// a git worktree inside the project (another checkout of the same repo; submodules stay in)
|
||||
if (isWorktree(p)) continue;
|
||||
// dot folders, git worktrees (other checkouts of the same repo; submodules stay in), git-ignored output
|
||||
if (skipDir(root, p, n)) continue;
|
||||
walk(p, depth + 1);
|
||||
} else {
|
||||
if (bins && n.endsWith('.so')) bins.push(relative(root, p).split(sep).join('/'));
|
||||
if (st.size <= MAX_TEXT) out.push(relative(root, p).split(sep).join('/'));
|
||||
let size = 0;
|
||||
try { size = statSync(p).size; } catch { continue; }
|
||||
if (size <= MAX_TEXT) out.push(relative(root, p).split(sep).join('/'));
|
||||
}
|
||||
if (out.length >= MAX_FILES) return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue