use std::path::PathBuf;
const STATE_FILE_NAME: &str = ".installed_apps";
const STATE_SUBDIR: &str = "reinhardt";
fn compose_state_dir_path(manifest_dir: &str, crate_name: &str) -> PathBuf {
PathBuf::from(manifest_dir)
.join("target")
.join(STATE_SUBDIR)
.join(crate_name)
}
fn state_dir_path() -> Result<PathBuf, String> {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").map_err(|_| {
"CARGO_MANIFEST_DIR not set. Cannot locate installed apps state file".to_string()
})?;
let crate_name = std::env::var("CARGO_CRATE_NAME").map_err(|_| {
"CARGO_CRATE_NAME not set. Cannot namespace installed apps state file (Issue #4592)"
.to_string()
})?;
Ok(compose_state_dir_path(&manifest_dir, &crate_name))
}
pub(crate) fn write_installed_apps(labels: &[String]) -> Result<(), String> {
let dir = state_dir_path()?;
std::fs::create_dir_all(&dir)
.map_err(|e| format!("Cannot create state directory {}: {e}", dir.display()))?;
let path = dir.join(STATE_FILE_NAME);
let content = labels.join("\n");
std::fs::write(&path, content).map_err(|e| format!("Cannot write {}: {e}", path.display()))
}
pub(crate) fn read_installed_apps() -> Result<Vec<String>, String> {
let dir = state_dir_path()?;
let path = dir.join(STATE_FILE_NAME);
let content = match std::fs::read_to_string(&path) {
Ok(c) => c,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()),
Err(e) => return Err(format!("Cannot read {}: {e}", path.display())),
};
Ok(content
.lines()
.filter(|line| !line.is_empty())
.map(|line| line.to_string())
.collect())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compose_appends_crate_name_as_final_segment() {
let path = compose_state_dir_path("/tmp/manifest", "widget_test");
assert_eq!(
path,
PathBuf::from("/tmp/manifest")
.join("target")
.join("reinhardt")
.join("widget_test"),
);
}
#[test]
fn compose_produces_distinct_paths_for_distinct_crate_names() {
let a = compose_state_dir_path("/tmp/manifest", "test_a");
let b = compose_state_dir_path("/tmp/manifest", "test_b");
assert_ne!(a, b);
}
}