Files
clawstor/claw-store/src/cargo_init.rs
T
Omar SobhandClaude Sonnet 4.6 088b88b225 fix(cargo_init): preserve non-[build] sections on activate
strip_section now strips only the [build] block before rewriting it,
so existing [alias] tables and other custom sections survive repeated
activate calls. Adds strip_leading_marker to prevent the managed-marker
comment from accumulating on each re-activation.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-07-23 06:20:29 +00:00

175 lines
6.1 KiB
Rust

use anyhow::{Context, Result};
use std::path::Path;
/// Write .cargo/config.toml in the project's warm directory pointing
/// CARGO_TARGET_DIR at the hot NVMe path. Preserves any existing non-[build]
/// sections already in the file. Safe to re-run (idempotent).
pub fn write_cargo_config(warm_path: &Path, hot_target_path: &Path) -> Result<()> {
let cargo_dir = warm_path.join(".cargo");
std::fs::create_dir_all(&cargo_dir)
.with_context(|| format!("creating .cargo dir at {}", cargo_dir.display()))?;
let target = hot_target_path.to_str()
.context("hot_target_path is not valid UTF-8")?;
let config_path = cargo_dir.join("config.toml");
// Read existing content; strip any prior [build] section so we can replace it.
let existing = if config_path.exists() {
std::fs::read_to_string(&config_path)?
} else {
String::new()
};
// Drop any leading copies of our own marker comment before stripping the
// [build] section — it sits above the [build] header, outside the range
// strip_section tracks, so without this it would survive every
// regenerate cycle and duplicate one more time.
let existing = strip_leading_marker(&existing);
// Remove old [build] block (from its header to the next section or EOF).
let stripped = strip_section(existing, "build");
let new_content = format!(
"# claw-store managed — do not edit manually\n\
[build]\n\
target-dir = \"{}\"\n\
{}",
target,
stripped.trim_start()
);
std::fs::write(&config_path, new_content)
.with_context(|| format!("writing {}", config_path.display()))
}
const MANAGED_MARKER: &str = "# claw-store managed — do not edit manually";
/// Strip leading copies of `MANAGED_MARKER`, one per line, from the start of `src`.
fn strip_leading_marker(src: &str) -> &str {
let mut rest = src;
while let Some(line_end) = rest.find('\n') {
if rest[..line_end].trim() == MANAGED_MARKER {
rest = &rest[line_end + 1..];
} else {
break;
}
}
rest
}
/// Remove a TOML section `[name]` and all its key=value lines from `src`,
/// stopping at the next `[section]` header or EOF.
fn strip_section(src: &str, name: &str) -> String {
let header = format!("[{}]", name);
let mut out = String::new();
let mut in_section = false;
for line in src.lines() {
let trimmed = line.trim();
if trimmed == header {
in_section = true;
continue;
}
if in_section && trimmed.starts_with('[') {
in_section = false;
}
if !in_section {
out.push_str(line);
out.push('\n');
}
}
out
}
/// Returns true if .cargo/config.toml exists and points to the expected hot path.
pub fn verify_cargo_config(warm_path: &Path, hot_target_path: &Path) -> Result<bool> {
let config_path = warm_path.join(".cargo/config.toml");
if !config_path.exists() { return Ok(false); }
let content = std::fs::read_to_string(&config_path)?;
let target = hot_target_path.to_str().unwrap_or("");
Ok(content.contains(target))
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_write_cargo_config() {
let dir = TempDir::new().unwrap();
let warm = dir.path().join("my-project");
std::fs::create_dir_all(&warm).unwrap();
let hot_target: std::path::PathBuf = "/hot/targets/my-project".into();
write_cargo_config(&warm, &hot_target).unwrap();
let cargo_dir = warm.join(".cargo");
let config_file = cargo_dir.join("config.toml");
assert!(config_file.exists());
let content = std::fs::read_to_string(&config_file).unwrap();
assert!(content.contains("[build]"));
assert!(content.contains("/hot/targets/my-project"));
}
#[test]
fn test_verify_cargo_config_detects_correct() {
let dir = TempDir::new().unwrap();
let warm = dir.path().join("proj");
std::fs::create_dir_all(&warm).unwrap();
let hot: std::path::PathBuf = "/hot/targets/proj".into();
write_cargo_config(&warm, &hot).unwrap();
assert!(verify_cargo_config(&warm, &hot).unwrap());
}
#[test]
fn test_write_cargo_config_idempotent_no_duplicate_marker() {
let dir = TempDir::new().unwrap();
let warm = dir.path().join("proj");
std::fs::create_dir_all(&warm).unwrap();
let hot: std::path::PathBuf = "/hot/targets/proj".into();
write_cargo_config(&warm, &hot).unwrap();
write_cargo_config(&warm, &hot).unwrap();
write_cargo_config(&warm, &hot).unwrap();
let content = std::fs::read_to_string(warm.join(".cargo/config.toml")).unwrap();
assert_eq!(content.matches("claw-store managed").count(), 1);
}
#[test]
fn test_write_cargo_config_heals_existing_duplicate_marker() {
let dir = TempDir::new().unwrap();
let warm = dir.path().join("proj");
let cargo_dir = warm.join(".cargo");
std::fs::create_dir_all(&cargo_dir).unwrap();
std::fs::write(
cargo_dir.join("config.toml"),
"# claw-store managed — do not edit manually\n\
[build]\n\
target-dir = \"/hot/targets/proj\"\n\
# claw-store managed — do not edit manually\n\
[env]\n\
FOO = \"bar\"\n",
)
.unwrap();
let hot: std::path::PathBuf = "/hot/targets/proj".into();
write_cargo_config(&warm, &hot).unwrap();
let content = std::fs::read_to_string(cargo_dir.join("config.toml")).unwrap();
assert_eq!(content.matches("claw-store managed").count(), 1);
assert!(content.contains("FOO = \"bar\""));
}
#[test]
fn test_verify_cargo_config_detects_missing() {
let dir = TempDir::new().unwrap();
let warm = dir.path().join("no-config-proj");
std::fs::create_dir_all(&warm).unwrap();
let hot: std::path::PathBuf = "/hot/targets/no-config-proj".into();
assert!(!verify_cargo_config(&warm, &hot).unwrap());
}
}