Skip to content

Commit d2a27fe

Browse files
authored
refactor: optimize the file finder code (#50)
1 parent df39fac commit d2a27fe

File tree

4 files changed

+90
-54
lines changed

4 files changed

+90
-54
lines changed

.changeset/clean-drinks-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"mucho": patch
3+
---
4+
5+
optimize the file finder code

src/lib/cli.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { OutputConfiguration } from "@commander-js/extra-typings";
77
import {
88
directoryExists,
99
doesFileExist,
10-
findFileInRepo,
10+
findClosestFile,
1111
isInCurrentDir,
1212
loadTomlFile,
1313
loadYamlFile,
@@ -77,13 +77,15 @@ export function loadConfigToml(
7777

7878
// attempt to locate the closest config file
7979
if (configPath === DEFAULT_CONFIG_FILE) {
80-
// accept both `Solana.toml` and `solana.toml` (case insensitive)
81-
const newPath = findFileInRepo(DEFAULT_CONFIG_FILE);
80+
// accepts both `Solana.toml` and `solana.toml` (case insensitive)
81+
const newPath = findClosestFile({
82+
fileName: DEFAULT_CONFIG_FILE,
83+
});
8284
if (newPath) {
8385
configPath = newPath;
8486
if (!isInCurrentDir(newPath)) {
8587
// todo: should we prompt the user if they want to use this one?
86-
warnMessage(`Using closest Solana.toml located at: ${newPath}`);
88+
warnMessage(`Using Solana.toml located at: ${newPath}`);
8789
}
8890
}
8991
}
@@ -95,7 +97,8 @@ export function loadConfigToml(
9597
} else {
9698
if (isConfigRequired) {
9799
warningOutro(`No Solana.toml config file found. Operation canceled.`);
98-
} else warnMessage(`No Solana.toml config file found. Skipping.`);
100+
process.exit();
101+
}
99102
}
100103

101104
const defaultSettings: SolanaToml["settings"] = {

src/lib/programs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function listLocalPrograms({
4040
}
4141

4242
if (!directoryExists(buildDir)) {
43-
warnMessage(`Unable to locate build output directory: ${buildDir}`);
43+
// warnMessage(`Unable to locate build output directory: ${buildDir}`);
4444
return { locatedPrograms, buildDirListing, allFound };
4545
}
4646

src/lib/utils.ts

Lines changed: 76 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -241,68 +241,96 @@ export function updateGitignore(
241241
}
242242
}
243243

244-
export function findFileInRepo(
245-
targetFilename: string,
246-
startDir: string = process.cwd(),
247-
maxDepth: number = 5 /* depth=5 should be good enough to handle most repos? */,
248-
skipDirs: string[] = ["node_modules", ".cache"],
249-
): string | null {
250-
let currentDir = startDir;
251-
let depth = 0;
252-
253-
while (depth < maxDepth) {
254-
const filePath = findFileInDirectory(
255-
currentDir,
256-
targetFilename.toLowerCase(),
257-
skipDirs,
244+
export function findClosestFile({
245+
fileName,
246+
maxDepth = 5,
247+
maxLevelsUp = 5,
248+
stopMarkers = [".git", "package.json", "cargo.toml"],
249+
startDir = process.cwd(),
250+
skipDirs = ["node_modules"],
251+
}: {
252+
fileName: string;
253+
maxDepth?: number;
254+
maxLevelsUp?: number;
255+
stopMarkers?: string[];
256+
skipDirs?: string[];
257+
startDir?: string;
258+
}): string | null {
259+
const visited = new Set<string>();
260+
261+
// check if we're already in what looks like a repo
262+
const isLikelyRepo = stopMarkers.some((marker) =>
263+
fs.existsSync(path.join(startDir, marker)),
264+
);
265+
266+
// if we are not in what looks like a repo, limit the search more aggressively
267+
if (!isLikelyRepo) {
268+
maxDepth = 2;
269+
maxLevelsUp = 2;
270+
}
271+
272+
function crawlUp(currentDir: string, levelsUp: number): string | null {
273+
if (levelsUp > maxLevelsUp) return null;
274+
275+
let targetPath = path.join(currentDir, fileName);
276+
if (fs.existsSync(targetPath)) return targetPath;
277+
targetPath = path.join(currentDir, fileName.toLowerCase());
278+
if (fs.existsSync(targetPath)) return targetPath;
279+
280+
const hasMarker = stopMarkers.some((marker) =>
281+
fs.existsSync(path.join(currentDir, marker)),
258282
);
259-
if (filePath) return filePath;
260283

261-
// stop searching once we hit the repository root
262-
const gitDir = path.join(currentDir, ".git");
263-
if (fs.existsSync(gitDir) && fs.statSync(gitDir).isDirectory()) {
264-
return null;
265-
}
284+
if (hasMarker && levelsUp > 0) return null;
266285

267-
// Move up one directory
268286
const parentDir = path.dirname(currentDir);
269-
if (parentDir === currentDir) {
270-
return null;
271-
}
287+
if (parentDir === currentDir) return null;
272288

273-
currentDir = parentDir;
274-
depth++;
289+
return crawlUp(parentDir, levelsUp + 1);
275290
}
276291

277-
return null;
278-
}
292+
function crawlDown(dir: string, depth: number): string | null {
293+
if (depth > maxDepth) return null;
294+
if (visited.has(dir)) return null;
295+
visited.add(dir);
279296

280-
export function findFileInDirectory(
281-
dir: string,
282-
targetFilename: string,
283-
skipDirs: string[],
284-
): string | null {
285-
const files = fs.readdirSync(dir);
286-
287-
for (const file of files) {
288-
const absolutePath = path.join(dir, file);
289297
try {
290-
if (fs.statSync(absolutePath).isDirectory()) {
291-
if (skipDirs.includes(file)) {
298+
let targetPath = path.join(dir, fileName);
299+
if (fs.existsSync(targetPath)) return targetPath;
300+
targetPath = path.join(dir, fileName.toLowerCase());
301+
if (fs.existsSync(targetPath)) return targetPath;
302+
303+
const entries = fs.readdirSync(dir, { withFileTypes: true });
304+
305+
for (const entry of entries) {
306+
// skip hidden directories and node_modules
307+
if (entry.name.startsWith(".") || skipDirs.includes(entry.name))
292308
continue;
309+
310+
if (entry.isDirectory()) {
311+
const fullPath = path.join(dir, entry.name);
312+
313+
const hasMarker = stopMarkers.some((marker) =>
314+
fs.existsSync(path.join(fullPath, marker)),
315+
);
316+
if (hasMarker) continue;
317+
318+
const result = crawlDown(fullPath, depth + 1);
319+
if (result) return result;
293320
}
294-
const result = findFileInDirectory(
295-
absolutePath,
296-
targetFilename,
297-
skipDirs,
298-
);
299-
if (result) return result; // Found in a subdirectory
300-
} else if (file.toLowerCase() === targetFilename) {
301-
return absolutePath;
302321
}
303-
} catch (err) {}
322+
} catch (error) {
323+
// honey badger don't care about errors
324+
return null;
325+
}
326+
327+
return null;
304328
}
305329

330+
const upResult = crawlUp(startDir, 0);
331+
if (upResult) return upResult;
332+
if (isLikelyRepo) return crawlDown(startDir, 0);
333+
306334
return null;
307335
}
308336

0 commit comments

Comments
 (0)