#![forbid(unsafe_code)]
use std::env;
use std::ffi::OsString;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process;
const EMBEDDED: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/embedded_binary"));
const PLACEHOLDER_PREAMBLE: &[u8] = b"CG_STUB_PLACEHOLDER\n";
const BIN_NAME: &str = "code_graph-mcp";
const CACHE_STAMP_VERSION: &str = "code-graph-cache-v2";
fn main() {
if EMBEDDED.starts_with(PLACEHOLDER_PREAMBLE) {
eprintln!(
"error: this `{BIN_NAME}` build is a development placeholder.\n\
\n\
Install a real release via one of:\n \
cargo install renso-code-graph renso-code-graph-mcp\n \
curl -fsSL https://cg.renso.ai/install.sh | sh\n \
brew tap renso-ai/code-graph https://github.com/renso-ai/code-graph-homebrew && brew install renso-ai/code-graph/code-graph\n \
npm install -g @rensoai/code-graph\n \
pipx install rensoai-code-graph"
);
process::exit(126);
}
if embedded_binary_looks_like_launcher() {
eprintln!(
"error: this `{BIN_NAME}` build embedded another launcher instead of the product binary.\n\
\n\
Reinstall from a current release, then retry `{BIN_NAME} --register`."
);
process::exit(126);
}
let cache_dir = resolve_cache_dir().unwrap_or_else(|err| {
eprintln!("error: cannot resolve cache directory: {err}");
process::exit(127);
});
let bin_path = cache_dir.join(bin_file_name());
let exec_path = ensure_extracted(&cache_dir, &bin_path).unwrap_or_else(|err| {
eprintln!(
"error: failed to extract {BIN_NAME} to {}: {err}",
bin_path.display()
);
process::exit(127);
});
let args: Vec<OsString> = env::args_os().skip(1).collect();
exec(&exec_path, &args);
}
fn bin_file_name() -> &'static str {
if cfg!(windows) {
"code_graph-mcp.exe"
} else {
"code_graph-mcp"
}
}
fn resolve_cache_dir() -> io::Result<PathBuf> {
let version = env!("CARGO_PKG_VERSION");
#[cfg(windows)]
let base = env::var_os("LOCALAPPDATA")
.map(PathBuf::from)
.or_else(|| {
env::var_os("USERPROFILE").map(|p| PathBuf::from(p).join("AppData").join("Local"))
})
.ok_or_else(|| io::Error::other("LOCALAPPDATA and USERPROFILE both unset"))?;
#[cfg(not(windows))]
let base = env::var_os("XDG_CACHE_HOME")
.map(PathBuf::from)
.or_else(|| env::var_os("HOME").map(|p| PathBuf::from(p).join(".cache")))
.ok_or_else(|| io::Error::other("XDG_CACHE_HOME and HOME both unset"))?;
Ok(base.join("code-graph").join(version))
}
fn ensure_extracted(cache_dir: &Path, bin_path: &Path) -> io::Result<PathBuf> {
if cache_is_current(bin_path) && !current_exe_is(bin_path) {
return Ok(bin_path.to_path_buf());
}
match extract(cache_dir, bin_path) {
Ok(()) => Ok(bin_path.to_path_buf()),
Err(primary_err) => {
let fallback = cache_dir.join(fallback_bin_file_name());
if fallback != bin_path && extract(cache_dir, &fallback).is_ok() {
return Ok(fallback);
}
Err(primary_err)
}
}
}
fn extract(cache_dir: &Path, bin_path: &Path) -> io::Result<()> {
fs::create_dir_all(cache_dir)?;
let tmp_path = bin_path.with_extension("partial");
fs::write(&tmp_path, EMBEDDED)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&tmp_path)?.permissions();
perms.set_mode(0o755);
fs::set_permissions(&tmp_path, perms)?;
}
replace_file(&tmp_path, bin_path)?;
fs::write(cache_stamp_path(bin_path), cache_stamp())?;
Ok(())
}
fn replace_file(tmp_path: &Path, bin_path: &Path) -> io::Result<()> {
#[cfg(windows)]
{
match fs::rename(tmp_path, bin_path) {
Ok(()) => Ok(()),
Err(first_err) if bin_path.exists() => {
if let Err(remove_err) = fs::remove_file(bin_path) {
let _ = fs::remove_file(tmp_path);
return Err(remove_err);
}
fs::rename(tmp_path, bin_path).map_err(|rename_err| {
let _ = fs::remove_file(tmp_path);
io::Error::new(
rename_err.kind(),
format!(
"replace {} after initial rename failed ({first_err}): {rename_err}",
bin_path.display()
),
)
})
}
Err(err) => {
let _ = fs::remove_file(tmp_path);
Err(err)
}
}
}
#[cfg(not(windows))]
{
fs::rename(tmp_path, bin_path)
}
}
fn cache_is_current(bin_path: &Path) -> bool {
bin_path.is_file()
&& fs::read_to_string(cache_stamp_path(bin_path))
.map(|stamp| stamp == cache_stamp())
.unwrap_or(false)
}
fn cache_stamp_path(bin_path: &Path) -> PathBuf {
let mut path = bin_path.as_os_str().to_os_string();
path.push(".stamp");
PathBuf::from(path)
}
fn cache_stamp() -> String {
format!(
"{CACHE_STAMP_VERSION}\nbin={BIN_NAME}\nlen={}\n",
EMBEDDED.len()
)
}
fn fallback_bin_file_name() -> String {
if cfg!(windows) {
format!("{BIN_NAME}.real.exe")
} else {
format!("{BIN_NAME}.real")
}
}
fn current_exe_is(path: &Path) -> bool {
let Ok(current) = env::current_exe() else {
return false;
};
let Ok(current) = current.canonicalize() else {
return false;
};
let Ok(path) = path.canonicalize() else {
return false;
};
current == path
}
fn embedded_binary_looks_like_launcher() -> bool {
contains_bytes(EMBEDDED, PLACEHOLDER_PREAMBLE)
}
fn contains_bytes(haystack: &[u8], needle: &[u8]) -> bool {
!needle.is_empty() && haystack.windows(needle.len()).any(|w| w == needle)
}
#[cfg(unix)]
fn exec(bin_path: &Path, args: &[OsString]) -> ! {
use std::os::unix::process::CommandExt;
let err = process::Command::new(bin_path).args(args).exec();
eprintln!("error: exec {} failed: {err}", bin_path.display());
process::exit(127);
}
#[cfg(windows)]
fn exec(bin_path: &Path, args: &[OsString]) -> ! {
let status = match process::Command::new(bin_path).args(args).status() {
Ok(s) => s,
Err(err) => {
eprintln!("error: spawn {} failed: {err}", bin_path.display());
process::exit(127);
}
};
process::exit(status.code().unwrap_or(127));
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::{SystemTime, UNIX_EPOCH};
fn temp_dir(name: &str) -> PathBuf {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let dir = env::temp_dir().join(format!("{BIN_NAME}-{name}-{}-{nanos}", process::id()));
fs::create_dir_all(&dir).unwrap();
dir
}
#[test]
fn refreshes_cache_without_stamp() {
let dir = temp_dir("refreshes-cache-without-stamp");
let bin_path = dir.join(bin_file_name());
fs::write(&bin_path, b"stale launcher").unwrap();
let exec_path = ensure_extracted(&dir, &bin_path).unwrap();
assert_eq!(exec_path, bin_path);
assert_eq!(fs::read(&bin_path).unwrap(), EMBEDDED);
assert_eq!(
fs::read_to_string(cache_stamp_path(&bin_path)).unwrap(),
cache_stamp()
);
fs::remove_dir_all(dir).unwrap();
}
#[test]
fn reuses_cache_with_current_stamp() {
let dir = temp_dir("reuses-cache-with-current-stamp");
let bin_path = dir.join(bin_file_name());
fs::write(&bin_path, b"already cached").unwrap();
fs::write(cache_stamp_path(&bin_path), cache_stamp()).unwrap();
let exec_path = ensure_extracted(&dir, &bin_path).unwrap();
assert_eq!(exec_path, bin_path);
assert_eq!(fs::read(&bin_path).unwrap(), b"already cached");
fs::remove_dir_all(dir).unwrap();
}
#[test]
fn detects_embedded_launcher_marker() {
assert!(contains_bytes(
b"prefix CG_STUB_PLACEHOLDER\n suffix",
PLACEHOLDER_PREAMBLE
));
assert!(!contains_bytes(b"prefix suffix", PLACEHOLDER_PREAMBLE));
}
}