use std::ffi::OsString;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use cargo_metadata::MetadataCommand;
pub struct RatchetPaths {
pub lockfile: PathBuf,
pub ratchet_file: PathBuf,
}
impl RatchetPaths {
pub fn discover(
manifest_path: Option<&Path>,
lockfile: Option<PathBuf>,
ratchet_file: Option<PathBuf>,
) -> Result<Self> {
let lockfile = match lockfile {
Some(lockfile) => lockfile,
None => workspace_root(manifest_path)?.join("Cargo.lock"),
};
let ratchet_file = match ratchet_file {
Some(ratchet_file) => ratchet_file,
None => default_ratchet_path(&lockfile)?,
};
Ok(Self {
lockfile,
ratchet_file,
})
}
}
fn workspace_root(manifest_path: Option<&Path>) -> Result<PathBuf> {
let mut command = MetadataCommand::new();
if let Some(path) = manifest_path {
command.manifest_path(path);
}
let metadata = command
.no_deps()
.exec()
.context("failed to locate workspace root via `cargo metadata`")?;
Ok(metadata.workspace_root.into_std_path_buf())
}
fn default_ratchet_path(lockfile: &Path) -> Result<PathBuf> {
let lockfile_name = lockfile
.file_name()
.with_context(|| format!("lockfile path has no file name: {}", lockfile.display()))?;
let mut ratchet_name = OsString::from(".");
ratchet_name.push(lockfile_name);
ratchet_name.push(".ratchet");
Ok(lockfile.with_file_name(ratchet_name))
}