Merge pull request #3016 from code-yeongyu/fix/issue-3003-ripgrep-autodownload
fix(grep): enable ripgrep auto-download when not found in PATH
This commit is contained in:
+15
-8
@@ -1,6 +1,7 @@
|
||||
import { spawn } from "bun"
|
||||
import {
|
||||
resolveGrepCli,
|
||||
type ResolvedCli,
|
||||
type GrepBackend,
|
||||
DEFAULT_MAX_DEPTH,
|
||||
DEFAULT_MAX_FILESIZE,
|
||||
@@ -148,17 +149,17 @@ function parseCountOutput(output: string): CountResult[] {
|
||||
return results
|
||||
}
|
||||
|
||||
export async function runRg(options: GrepOptions): Promise<GrepResult> {
|
||||
export async function runRg(options: GrepOptions, resolvedCli?: ResolvedCli): Promise<GrepResult> {
|
||||
await rgSemaphore.acquire()
|
||||
try {
|
||||
return await runRgInternal(options)
|
||||
return await runRgInternal(options, resolvedCli)
|
||||
} finally {
|
||||
rgSemaphore.release()
|
||||
}
|
||||
}
|
||||
|
||||
async function runRgInternal(options: GrepOptions): Promise<GrepResult> {
|
||||
const cli = resolveGrepCli()
|
||||
async function runRgInternal(options: GrepOptions, resolvedCli?: ResolvedCli): Promise<GrepResult> {
|
||||
const cli = resolvedCli ?? resolveGrepCli()
|
||||
const args = buildArgs(options, cli.backend)
|
||||
const timeout = Math.min(options.timeout ?? DEFAULT_TIMEOUT_MS, DEFAULT_TIMEOUT_MS)
|
||||
|
||||
@@ -224,17 +225,23 @@ async function runRgInternal(options: GrepOptions): Promise<GrepResult> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function runRgCount(options: Omit<GrepOptions, "context">): Promise<CountResult[]> {
|
||||
export async function runRgCount(
|
||||
options: Omit<GrepOptions, "context">,
|
||||
resolvedCli?: ResolvedCli
|
||||
): Promise<CountResult[]> {
|
||||
await rgSemaphore.acquire()
|
||||
try {
|
||||
return await runRgCountInternal(options)
|
||||
return await runRgCountInternal(options, resolvedCli)
|
||||
} finally {
|
||||
rgSemaphore.release()
|
||||
}
|
||||
}
|
||||
|
||||
async function runRgCountInternal(options: Omit<GrepOptions, "context">): Promise<CountResult[]> {
|
||||
const cli = resolveGrepCli()
|
||||
async function runRgCountInternal(
|
||||
options: Omit<GrepOptions, "context">,
|
||||
resolvedCli?: ResolvedCli
|
||||
): Promise<CountResult[]> {
|
||||
const cli = resolvedCli ?? resolveGrepCli()
|
||||
const args = buildArgs({ ...options, context: 0 }, cli.backend)
|
||||
|
||||
if (cli.backend === "rg") {
|
||||
|
||||
@@ -3,10 +3,11 @@ import { join, dirname } from "node:path"
|
||||
import { spawnSync } from "node:child_process"
|
||||
import { getInstalledRipgrepPath, downloadAndInstallRipgrep } from "./downloader"
|
||||
import { getDataDir } from "../../shared/data-path"
|
||||
import { log } from "../../shared/logger"
|
||||
|
||||
export type GrepBackend = "rg" | "grep"
|
||||
|
||||
interface ResolvedCli {
|
||||
export interface ResolvedCli {
|
||||
path: string
|
||||
backend: GrepBackend
|
||||
}
|
||||
@@ -89,7 +90,7 @@ export function resolveGrepCli(): ResolvedCli {
|
||||
export async function resolveGrepCliWithAutoInstall(): Promise<ResolvedCli> {
|
||||
const current = resolveGrepCli()
|
||||
|
||||
if (current.backend === "rg") {
|
||||
if (current.backend === "rg" && current.path !== "rg") {
|
||||
return current
|
||||
}
|
||||
|
||||
@@ -103,7 +104,18 @@ export async function resolveGrepCliWithAutoInstall(): Promise<ResolvedCli> {
|
||||
const rgPath = await downloadAndInstallRipgrep()
|
||||
cachedCli = { path: rgPath, backend: "rg" }
|
||||
return cachedCli
|
||||
} catch {
|
||||
} catch (error) {
|
||||
if (current.backend === "grep") {
|
||||
log("[oh-my-opencode] Failed to auto-install ripgrep. Falling back to GNU grep.", {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
grep_path: current.path,
|
||||
})
|
||||
} else {
|
||||
log("[oh-my-opencode] Failed to auto-install ripgrep and GNU grep was not found.", {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
})
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { resolve } from "node:path"
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
||||
import { runRg, runRgCount } from "./cli"
|
||||
import { resolveGrepCliWithAutoInstall } from "./constants"
|
||||
import { formatGrepResult, formatCountResult } from "./result-formatter"
|
||||
|
||||
export function createGrepTools(ctx: PluginInput): Record<string, ToolDefinition> {
|
||||
@@ -42,13 +43,14 @@ export function createGrepTools(ctx: PluginInput): Record<string, ToolDefinition
|
||||
const paths = [searchPath]
|
||||
const outputMode = args.output_mode ?? "files_with_matches"
|
||||
const headLimit = args.head_limit ?? 0
|
||||
const cli = await resolveGrepCliWithAutoInstall()
|
||||
|
||||
if (outputMode === "count") {
|
||||
const results = await runRgCount({
|
||||
pattern: args.pattern,
|
||||
paths,
|
||||
globs,
|
||||
})
|
||||
}, cli)
|
||||
const limited = headLimit > 0 ? results.slice(0, headLimit) : results
|
||||
return formatCountResult(limited)
|
||||
}
|
||||
@@ -60,7 +62,7 @@ export function createGrepTools(ctx: PluginInput): Record<string, ToolDefinition
|
||||
context: 0,
|
||||
outputMode,
|
||||
headLimit,
|
||||
})
|
||||
}, cli)
|
||||
|
||||
return formatGrepResult(result)
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user