use std::collections::BTreeSet;
use std::fs;
use std::path::Path;
use crate::error::{Error, Result};
use crate::provenance::Provenance;
use crate::manifest::{StrictPolicy, default_cache_dir, default_gitignore, default_probe_shell};
use super::{Document, POLICY_KEYS, parse_text};
pub(super) struct Resolved {
pub gitignore: bool,
pub cache_dir: String,
pub strict: StrictPolicy,
pub on_hit: Option<String>,
pub probe_shell: Vec<String>,
}
pub(super) fn resolve(document: &Document, path: &Path, root: &Path) -> Result<Resolved> {
Ok(Resolved {
gitignore: require_or_default(
document.gitignore,
"gitignore",
path,
root,
default_gitignore,
)?,
cache_dir: require_or_default(
document.cache_dir.clone(),
"cache_dir",
path,
root,
default_cache_dir,
)?,
strict: require_or_default(
document.strict.clone(),
"strict",
path,
root,
StrictPolicy::all,
)?,
on_hit: document.on_hit.clone().flatten(),
probe_shell: require_or_default(
document.probe_shell.clone(),
"probe_shell",
path,
root,
default_probe_shell,
)?,
})
}
fn require_or_default<T>(
value: Option<Option<T>>,
key: &str,
path: &Path,
root: &Path,
default: impl FnOnce() -> T,
) -> Result<T> {
match value {
None => Ok(default()),
Some(None) => Err(Error::NullPolicyKey {
key: key.to_owned(),
path: Provenance::shorten(path, root),
}),
Some(Some(resolved)) => Ok(resolved),
}
}
pub(super) fn check_no_policy_keys(document: &Document, path: &Path, root: &Path) -> Result<()> {
let [cache_dir, gitignore, strict, on_hit, probe_shell] = POLICY_KEYS;
let present = [
(cache_dir, document.cache_dir.is_some()),
(gitignore, document.gitignore.is_some()),
(strict, document.strict.is_some()),
(on_hit, document.on_hit.is_some()),
(probe_shell, document.probe_shell.is_some()),
];
if let Some((key, _)) = present.into_iter().find(|(_, set)| *set) {
return Err(Error::FragmentPolicyKey {
key: key.to_owned(),
path: Provenance::shorten(path, root),
});
}
Ok(())
}
pub(crate) fn declared_policy_keys(path: &Path, root: &Path) -> Result<BTreeSet<&'static str>> {
let text = fs::read_to_string(path).map_err(|source| super::unreadable(path, root, source))?;
let document = parse_text(&text, path, root)?;
let [cache_dir, gitignore, strict, on_hit, probe_shell] = POLICY_KEYS;
Ok([
(cache_dir, document.cache_dir.is_some()),
(gitignore, document.gitignore.is_some()),
(strict, document.strict.is_some()),
(on_hit, document.on_hit.is_some()),
(probe_shell, document.probe_shell.is_some()),
]
.into_iter()
.filter(|(_, set)| *set)
.map(|(key, _)| key)
.collect())
}