refactor(parsers): single shared FFmpeg/FFprobe binary resolver

The cli, engine, and lint packages each carried their own copy of the
ffmpeg/ffprobe lookup, annotated fallow-ignore code-duplication, and the
copies had drifted: the engine copy handled Windows PATHEXT and executed
which/where without a shell but lacked the Homebrew-dirs fallback for
GUI-spawned processes; the cli copy had the opposite. One resolver in
@hyperframes/parsers (the dependency-graph bottom) now carries the union
of both hardenings, and all three packages delegate to it. Every
consumer gets strictly more robust resolution; env-override semantics
per call site are preserved via configuredMustExist.
This commit is contained in:
Miguel Angel Simon Sierra
2026-07-16 18:36:40 -04:00
parent 247743fcdf
commit 88c049f525
12 changed files with 342 additions and 318 deletions
@@ -1,7 +1,4 @@
// fallow-ignore-file code-duplication
import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
import { resolve } from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
assertConfiguredFfmpegBinariesExist,
@@ -48,39 +45,6 @@ describe("ffmpeg binary env resolution", () => {
expect(() => assertConfiguredFfmpegBinariesExist()).not.toThrow();
});
it("prefers the real Windows exe when PATH lookup lists a cmd shim first", async () => {
vi.resetModules();
vi.doMock("child_process", () => ({
execFileSync: () => "C:\\tools\\ffmpeg.cmd\r\nC:\\tools\\ffmpeg.exe\r\n",
}));
const { getFfmpegBinary: getMockedFfmpegBinary } = await import("./ffmpegBinaries.js");
expect(getMockedFfmpegBinary()).toBe(resolve("C:\\tools\\ffmpeg.exe"));
});
it("falls back to scanning PATH when which/where fails", async () => {
const binDir = mkdtempSync(join(tmpdir(), "hyperframes-ffmpeg-path-"));
const ffmpegPath = join(binDir, process.platform === "win32" ? "ffmpeg.exe" : "ffmpeg");
const execFileSync = vi.fn(() => {
throw new Error("lookup command failed");
});
writeFileSync(ffmpegPath, "#!/bin/sh\n");
chmodSync(ffmpegPath, 0o755);
process.env.PATH = binDir;
vi.resetModules();
vi.doMock("child_process", () => ({ execFileSync }));
try {
const { getFfmpegBinary: getMockedFfmpegBinary } = await import("./ffmpegBinaries.js");
expect(getMockedFfmpegBinary()).toBe(resolve(ffmpegPath));
expect(execFileSync).toHaveBeenCalledOnce();
} finally {
rmSync(binDir, { force: true, recursive: true });
}
});
it("calls out a mangled replacement character in configured binary paths", () => {
process.env.HYPERFRAMES_FFMPEG_PATH = "/missing/ffmpeg.exe";