143 lines
3.3 KiB
Rust
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");
|
|
}
|
|
}
|