mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-10-05 12:13:05 +08:00
refactor: rebuild desktop app with Tauri
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
//! Adapter lifecycle for benchmarking an installed CodeGraph distribution.
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::case::Suite;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CodeGraphRun {
|
||||
pub version: String,
|
||||
pub cold_index_ms: f64,
|
||||
pub persisted_index_bytes: u64,
|
||||
pub adapter: AdapterOutput,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AdapterOutput {
|
||||
pub load_ms: f64,
|
||||
pub stats: AdapterStats,
|
||||
pub tracks: Vec<AdapterTrack>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AdapterStats {
|
||||
pub node_count: usize,
|
||||
pub edge_count: usize,
|
||||
pub file_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AdapterTrack {
|
||||
pub name: String,
|
||||
pub queries: Vec<AdapterQuery>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AdapterQuery {
|
||||
pub id: String,
|
||||
pub query: String,
|
||||
pub durations_ms: Vec<f64>,
|
||||
pub results: Vec<AdapterResult>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AdapterResult {
|
||||
pub path: String,
|
||||
pub start_line: usize,
|
||||
pub end_line: usize,
|
||||
pub score: f32,
|
||||
pub lines: Option<Vec<usize>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct AdapterInput<'a> {
|
||||
tracks: [AdapterInputTrack<'a>; 3],
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct AdapterInputTrack<'a> {
|
||||
name: &'static str,
|
||||
queries: Vec<AdapterInputQuery<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct AdapterInputQuery<'a> {
|
||||
id: &'a str,
|
||||
query: &'a str,
|
||||
}
|
||||
|
||||
pub fn benchmark(
|
||||
executable: &str,
|
||||
adapter_path: &Path,
|
||||
source: &Path,
|
||||
suite: &Suite,
|
||||
repetitions: usize,
|
||||
top_k: usize,
|
||||
) -> Result<CodeGraphRun, String> {
|
||||
let executable = locate_executable(executable)?;
|
||||
let distribution = distribution_root(&executable)?;
|
||||
let node = distribution.join("node");
|
||||
let library = distribution.join("lib");
|
||||
if !node.is_file() || !library.is_dir() {
|
||||
return Err(format!(
|
||||
"unsupported CodeGraph installation layout below {}",
|
||||
distribution.display()
|
||||
));
|
||||
}
|
||||
if source.join(".codegraph").exists() {
|
||||
command_status(
|
||||
Command::new(&executable)
|
||||
.args(["uninit", "--force"])
|
||||
.arg(source),
|
||||
"reset CodeGraph index",
|
||||
)?;
|
||||
}
|
||||
let started = Instant::now();
|
||||
command_status(
|
||||
Command::new(&executable).arg("init").arg(source),
|
||||
"build CodeGraph index",
|
||||
)?;
|
||||
let cold_index_ms = started.elapsed().as_secs_f64() * 1_000.0;
|
||||
let persisted_index_bytes = directory_size(&source.join(".codegraph"))?;
|
||||
let version = command_output(
|
||||
Command::new(&executable).arg("version"),
|
||||
"read CodeGraph version",
|
||||
)?;
|
||||
let input = AdapterInput {
|
||||
tracks: [
|
||||
AdapterInputTrack {
|
||||
name: "natural_language",
|
||||
queries: suite
|
||||
.queries
|
||||
.iter()
|
||||
.map(|query| AdapterInputQuery {
|
||||
id: &query.id,
|
||||
query: &query.query,
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
AdapterInputTrack {
|
||||
name: "literal",
|
||||
queries: suite
|
||||
.queries
|
||||
.iter()
|
||||
.map(|query| AdapterInputQuery {
|
||||
id: &query.id,
|
||||
query: &query.literal_query,
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
AdapterInputTrack {
|
||||
name: "symbol",
|
||||
queries: suite
|
||||
.queries
|
||||
.iter()
|
||||
.map(|query| AdapterInputQuery {
|
||||
id: &query.id,
|
||||
query: &query.symbol_query,
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
],
|
||||
};
|
||||
let encoded = serde_json::to_vec(&input)
|
||||
.map_err(|error| format!("serialize CodeGraph benchmark input: {error}"))?;
|
||||
let mut child = Command::new(node)
|
||||
.arg("--liftoff-only")
|
||||
.arg(adapter_path)
|
||||
.arg(library)
|
||||
.arg(source)
|
||||
.arg(repetitions.to_string())
|
||||
.arg(top_k.to_string())
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.map_err(|error| format!("start CodeGraph benchmark adapter: {error}"))?;
|
||||
child
|
||||
.stdin
|
||||
.take()
|
||||
.ok_or_else(|| "CodeGraph adapter stdin is unavailable".to_owned())?
|
||||
.write_all(&encoded)
|
||||
.map_err(|error| format!("write CodeGraph benchmark input: {error}"))?;
|
||||
let output = child
|
||||
.wait_with_output()
|
||||
.map_err(|error| format!("wait for CodeGraph benchmark adapter: {error}"))?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"CodeGraph benchmark adapter failed: {}",
|
||||
String::from_utf8_lossy(&output.stderr).trim()
|
||||
));
|
||||
}
|
||||
let adapter = serde_json::from_slice(&output.stdout)
|
||||
.map_err(|error| format!("parse CodeGraph benchmark output: {error}"))?;
|
||||
Ok(CodeGraphRun {
|
||||
version,
|
||||
cold_index_ms,
|
||||
persisted_index_bytes,
|
||||
adapter,
|
||||
})
|
||||
}
|
||||
|
||||
fn locate_executable(name: &str) -> Result<PathBuf, String> {
|
||||
let output = command_output(
|
||||
Command::new("which").arg(name),
|
||||
"locate CodeGraph executable",
|
||||
)?;
|
||||
fs::canonicalize(output)
|
||||
.map_err(|error| format!("resolve CodeGraph executable symlink: {error}"))
|
||||
}
|
||||
|
||||
fn distribution_root(executable: &Path) -> Result<PathBuf, String> {
|
||||
executable
|
||||
.parent()
|
||||
.and_then(Path::parent)
|
||||
.map(Path::to_path_buf)
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"cannot locate distribution root for {}",
|
||||
executable.display()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn command_status(command: &mut Command, action: &str) -> Result<(), String> {
|
||||
let status = command
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.status()
|
||||
.map_err(|error| format!("{action}: {error}"))?;
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("{action} failed with {status}"))
|
||||
}
|
||||
}
|
||||
|
||||
fn command_output(command: &mut Command, action: &str) -> Result<String, String> {
|
||||
let output = command
|
||||
.output()
|
||||
.map_err(|error| format!("{action}: {error}"))?;
|
||||
if !output.status.success() {
|
||||
return Err(format!("{action} failed with {}", output.status));
|
||||
}
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_owned())
|
||||
}
|
||||
|
||||
fn directory_size(path: &Path) -> Result<u64, String> {
|
||||
let mut total = 0_u64;
|
||||
let mut pending = vec![path.to_path_buf()];
|
||||
while let Some(directory) = pending.pop() {
|
||||
for entry in fs::read_dir(&directory)
|
||||
.map_err(|error| format!("read {}: {error}", directory.display()))?
|
||||
{
|
||||
let entry = entry.map_err(|error| format!("read directory entry: {error}"))?;
|
||||
let metadata = entry
|
||||
.metadata()
|
||||
.map_err(|error| format!("inspect {}: {error}", entry.path().display()))?;
|
||||
if metadata.is_dir() {
|
||||
pending.push(entry.path());
|
||||
} else if metadata.is_file() {
|
||||
total = total.saturating_add(metadata.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(total)
|
||||
}
|
||||
Reference in New Issue
Block a user