diff --git a/internal/deps/deps.go b/internal/deps/deps.go new file mode 100644 index 0000000..96b75d1 --- /dev/null +++ b/internal/deps/deps.go @@ -0,0 +1,64 @@ +package deps + +import ( + "os/exec" + "strings" +) + +// Status represents the installation status of a dependency +type Status struct { + Installed bool + Path string + Version string +} + +// CheckWhisperCli checks if whisper-cli is installed and returns its status +func CheckWhisperCli() Status { + path, err := exec.LookPath("whisper-cli") + if err != nil { + return Status{Installed: false} + } + + status := Status{ + Installed: true, + Path: path, + } + + // try to get version - whisper-cli --version outputs version info + cmd := exec.Command(path, "--version") + output, err := cmd.Output() + if err == nil { + // parse first line as version + lines := strings.Split(string(output), "\n") + if len(lines) > 0 { + status.Version = strings.TrimSpace(lines[0]) + } + } + + return status +} + +// CheckFFmpeg checks if ffmpeg is installed and returns its status +func CheckFFmpeg() Status { + path, err := exec.LookPath("ffmpeg") + if err != nil { + return Status{Installed: false} + } + + status := Status{ + Installed: true, + Path: path, + } + + // ffmpeg -version outputs version info on first line + cmd := exec.Command(path, "-version") + output, err := cmd.Output() + if err == nil { + lines := strings.Split(string(output), "\n") + if len(lines) > 0 { + status.Version = strings.TrimSpace(lines[0]) + } + } + + return status +} diff --git a/internal/deps/deps_test.go b/internal/deps/deps_test.go new file mode 100644 index 0000000..d99b694 --- /dev/null +++ b/internal/deps/deps_test.go @@ -0,0 +1,71 @@ +package deps + +import ( + "os/exec" + "testing" +) + +func TestCheckWhisperCli(t *testing.T) { + status := CheckWhisperCli() + + // behavior depends on system - just verify no panic and correct structure + if status.Installed { + if status.Path == "" { + t.Error("installed but path empty") + } + } else { + if status.Path != "" { + t.Error("not installed but path non-empty") + } + } +} + +func TestCheckWhisperCli_NotInstalled(t *testing.T) { + // if whisper-cli is not in PATH, should return Installed=false + _, err := exec.LookPath("whisper-cli") + if err != nil { + status := CheckWhisperCli() + if status.Installed { + t.Error("expected Installed=false when whisper-cli not in PATH") + } + if status.Path != "" { + t.Error("expected empty path when not installed") + } + } else { + t.Skip("whisper-cli is installed, can't test not-installed case") + } +} + +func TestCheckFFmpeg(t *testing.T) { + status := CheckFFmpeg() + + if status.Installed { + if status.Path == "" { + t.Error("installed but path empty") + } + } else { + if status.Path != "" { + t.Error("not installed but path non-empty") + } + } +} + +func TestCheckFFmpeg_Installed(t *testing.T) { + // ffmpeg is commonly installed - test if available + _, err := exec.LookPath("ffmpeg") + if err == nil { + status := CheckFFmpeg() + if !status.Installed { + t.Error("ffmpeg in PATH but Installed=false") + } + if status.Path == "" { + t.Error("ffmpeg installed but path empty") + } + // version should be populated + if status.Version == "" { + t.Error("ffmpeg installed but version empty") + } + } else { + t.Skip("ffmpeg not installed, can't test installed case") + } +} diff --git a/progress.txt b/progress.txt index 3260c81..441d608 100644 --- a/progress.txt +++ b/progress.txt @@ -158,4 +158,12 @@ Started: Sun Feb 1 12:22:47 AM CET 2026 - `TestNewTranscriber/unknown_model_returns_error` - returns error for unknown model - `TestNewTranscriber/streaming_model_returns_error` - returns error for streaming model - `go test ./internal/transcriber/...` passes -- Typecheck passes \ No newline at end of file +- Typecheck passes + +### Task 18: Create dependency checker for whisper-cli +- Created `internal/deps/deps.go` +- Status struct: Installed bool, Path string, Version string +- CheckWhisperCli() uses exec.LookPath, tries --version (whisper-cli doesn't support it, but handles gracefully) +- CheckFFmpeg() same pattern, version extraction works +- Both return Installed=false when binary not found, no errors thrown +- All tests passing, typecheck passes \ No newline at end of file diff --git a/tasks/prd.jsonc b/tasks/prd.jsonc index 7f32c78..bbbea6a 100644 --- a/tasks/prd.jsonc +++ b/tasks/prd.jsonc @@ -432,7 +432,7 @@ "No errors thrown, just returns status", "Typecheck passes" ], - "passes": false + "passes": true }, { "title": "Create whisper model info and download management",