Layers/src/paths.rs

143 lines
3.3 KiB
Rust

use std::fs;
use std::path::{Path, PathBuf};
use sha2::{Digest, Sha256};
const PLUGIN_ID: &str = "com.jesshunter.layers";
const KICAD_MAJOR_DIR: &str = "KiCad/10.0/plugins";
pub fn plugin_data_dir() -> PathBuf {
plugin_root()
}
pub fn plugin_dir() -> PathBuf {
plugin_root()
}
pub fn data_dir() -> PathBuf {
plugin_root()
}
pub fn state_dir() -> PathBuf {
data_dir().join("state")
}
pub fn cache_root() -> PathBuf {
data_dir().join("cache")
}
pub fn cache_dir(project_hash: &str) -> PathBuf {
cache_root().join(project_hash)
}
pub fn preview_dir(project_hash: &str) -> PathBuf {
cache_dir(project_hash).join("previews")
}
pub fn log_dir() -> PathBuf {
data_dir().join("logs")
}
pub fn runtime_dir() -> PathBuf {
data_dir().join("runtime")
}
pub fn settings_path() -> PathBuf {
data_dir().join("settings.json")
}
pub fn state_path(project_hash: &str) -> PathBuf {
state_dir().join(format!("{project_hash}.json"))
}
pub fn log_path() -> PathBuf {
log_dir().join("layers.log")
}
pub fn project_hash(kicad_pro_path: &Path) -> String {
let abs = match kicad_pro_path.canonicalize() {
Ok(p) => p,
Err(_) => kicad_pro_path.to_path_buf(),
};
hash_bytes_hex16(abs.to_string_lossy().as_bytes())
}
pub fn create_dirs_if_missing() -> std::io::Result<()> {
for d in [
data_dir(),
state_dir(),
cache_root(),
log_dir(),
runtime_dir(),
] {
fs::create_dir_all(d)?;
}
Ok(())
}
#[cfg(target_os = "linux")]
fn plugin_root() -> PathBuf {
dirs::data_local_dir()
.expect("XDG data-local dir unavailable; cannot resolve plugin data directory")
.join(KICAD_MAJOR_DIR)
.join(PLUGIN_ID)
}
#[cfg(any(target_os = "macos", target_os = "windows"))]
fn plugin_root() -> PathBuf {
dirs::document_dir()
.expect("user Documents dir unavailable; cannot resolve plugin data directory")
.join(KICAD_MAJOR_DIR)
.join(PLUGIN_ID)
}
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
fn plugin_root() -> PathBuf {
dirs::data_local_dir()
.expect("data-local dir unavailable; cannot resolve plugin data directory")
.join(KICAD_MAJOR_DIR)
.join(PLUGIN_ID)
}
fn hash_bytes_hex16(bytes: &[u8]) -> String {
let digest = Sha256::digest(bytes);
let mut s = String::with_capacity(16);
for byte in &digest[..8] {
use std::fmt::Write;
let _ = write!(&mut s, "{byte:02x}");
}
s
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn project_hash_is_16_hex_chars() {
let h = project_hash(Path::new("/tmp/example.kicad_pro"));
assert_eq!(h.len(), 16);
assert!(h.chars().all(|c| c.is_ascii_hexdigit()));
}
#[test]
fn project_hash_is_deterministic() {
let a = project_hash(Path::new("/tmp/a.kicad_pro"));
let b = project_hash(Path::new("/tmp/a.kicad_pro"));
assert_eq!(a, b);
}
#[test]
fn subdirs_under_data_dir() {
assert!(state_dir().starts_with(data_dir()));
assert!(log_dir().starts_with(data_dir()));
assert!(runtime_dir().starts_with(data_dir()));
assert!(cache_root().starts_with(data_dir()));
}
#[test]
fn log_path_is_layers_log() {
assert_eq!(log_path().file_name().unwrap(), "layers.log");
}
}