use crate::compsys::ported::_message::_message;
use crate::compsys::ported::shared::zstyle_t;
use crate::ported::modules::zutil::lookupstyle;
use crate::ported::params::{getaparam, getsparam};
use std::fs;
use std::path::Path;
pub fn _store_cache(args: &[String]) -> i32 {
crate::compsys::ported::shared::call_compfn("_store_cache", args, || _store_cache_impl(args))
}
pub fn _store_cache_impl(args: &[String]) -> i32 {
let _fn_scope = crate::compsys::ported::shared::FnScope::enter("_store_cache");
let cache_ident = args.first().cloned().unwrap_or_default();
let curcontext = getsparam("curcontext").unwrap_or_default();
let ctx = format!(":completion:{}:", curcontext);
if zstyle_t(&ctx, "use-cache") != 0 {
return 1;
}
let cache_dir = lookupstyle(&ctx, "cache-path")
.first()
.cloned()
.unwrap_or_else(|| {
let home = getsparam("ZDOTDIR")
.filter(|s| !s.is_empty())
.or_else(|| getsparam("HOME"))
.unwrap_or_default();
format!("{}/.zcompcache", home)
});
let dir_path = Path::new(&cache_dir);
if !dir_path.is_dir() {
if dir_path.exists() {
let _ = _message(&["cache-dir style points to a non-directory!".to_string()]);
return 1;
}
if fs::create_dir_all(dir_path).is_err() {
let _ = _message(&[format!("couldn't create cache-dir {}", cache_dir)]);
return 1;
}
}
let cache_path = format!("{}/{}", cache_dir, cache_ident);
let ident_dir = Path::new(&cache_path).parent().map(|p| p.to_path_buf());
if let Some(p) = ident_dir.as_ref() {
if !p.exists() {
if fs::create_dir_all(p).is_err() {
let _ = _message(&[format!("couldn't create cache-ident_dir {}", p.display())]);
return 1;
}
}
}
let var_names: &[String] = if args.is_empty() { &[] } else { &args[1..] };
let mut serialized = String::new();
for var in var_names {
if let Some(arr) = getaparam(var) {
serialized.push_str(&format!("{}=( ", var));
for v in &arr {
serialized.push('\'');
serialized.push_str(&v.replace('\'', "'\\''"));
serialized.push_str("' ");
}
serialized.push_str(")\n");
} else if let Some(s) = getsparam(var) {
serialized.push_str(&format!("{}='{}'\n", var, s.replace('\'', "'\\''")));
}
}
if fs::write(&cache_path, serialized).is_err() {
return 1;
}
0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_one_when_use_cache_disabled() {
let _g = crate::test_util::global_state_lock();
assert_eq!(_store_cache_impl(&["test-cache".to_string()]), 1);
}
#[test]
fn use_cache_zero_writes_nothing() {
let _g = crate::test_util::global_state_lock();
let ops = crate::ported::zsh_h::options {
ind: [0u8; crate::ported::zsh_h::MAX_OPS],
args: Vec::new(),
argscount: 0,
argsalloc: 0,
};
let dir = std::env::temp_dir().join(format!("zshrs-store-cache-{}", std::process::id()));
let _ = fs::remove_dir_all(&dir);
let ctx = ":completion:sczero:sczero:sczero:";
let _ = crate::ported::params::setsparam("curcontext", "sczero:sczero:sczero");
for (style, val) in [
("use-cache", "0"),
("cache-path", dir.to_string_lossy().as_ref()),
] {
crate::ported::modules::zutil::bin_zstyle(
"zstyle",
&[ctx.to_string(), style.to_string(), val.to_string()],
&ops,
0,
);
}
let rc = _store_cache_impl(&["scz-ident".to_string()]);
let landed = dir.join("scz-ident").exists();
for style in ["use-cache", "cache-path"] {
crate::ported::modules::zutil::bin_zstyle(
"zstyle",
&["-d".to_string(), ctx.to_string(), style.to_string()],
&ops,
0,
);
}
crate::ported::params::unsetparam("curcontext");
let _ = fs::remove_dir_all(&dir);
assert_eq!(rc, 1, "sh:61 — `use-cache 0` returns 1");
assert!(
!landed,
"sh:59 — the cache file must not be written when use-cache is off"
);
}
}