2026-03-31 17:29:08 -04:00
|
|
|
use anyhow::{Context, Result};
|
|
|
|
|
use std::path::Path;
|
|
|
|
|
use std::process::Command;
|
|
|
|
|
|
|
|
|
|
pub fn clone_if_missing(url: &str, dest: &Path) -> Result<bool> {
|
|
|
|
|
if dest.exists() {
|
|
|
|
|
return Ok(false);
|
|
|
|
|
}
|
2026-04-11 23:52:40 -04:00
|
|
|
// SAFETY: `url` comes from the notstrap.toml config and `dest` is a `Path` derived from
|
|
|
|
|
// the resolved dotfiles directory. Both are passed as discrete `.arg()` calls with no
|
|
|
|
|
// shell involved, so argument injection is not possible.
|
2026-03-31 17:29:08 -04:00
|
|
|
let status = Command::new("git")
|
2026-04-01 05:00:26 -04:00
|
|
|
.arg("clone")
|
|
|
|
|
.arg(url)
|
|
|
|
|
.arg(dest)
|
2026-03-31 17:29:08 -04:00
|
|
|
.status()
|
|
|
|
|
.context("failed to run git clone")?;
|
|
|
|
|
if !status.success() {
|
|
|
|
|
anyhow::bail!("git clone {} failed", url);
|
|
|
|
|
}
|
|
|
|
|
Ok(true)
|
|
|
|
|
}
|