use super::locus::{classify_locus, read_locus, write_locus};
use crate::engine::facet::*;
pub(super) fn reads_to_model(paths: &[&str], scale: Scale) -> Vec<Capability> {
if paths.is_empty() {
return vec![reads_content(LocalLocus::Process, scale, "reads stdin")];
}
paths
.iter()
.map(|p| {
if *p == "-" {
reads_content(LocalLocus::Process, scale, "reads stdin (-)")
} else {
reads_content(read_locus(p), scale, "reads file content to the model")
}
})
.collect()
}
pub(super) fn reads_content(locus: LocalLocus, scale: Scale, because: &str) -> Capability {
let mut c = Capability::new(Operation::Observe);
c.locus.local = locus;
c.scale = scale;
c.disclosure.audience = DisclosureAudience::LocalProcess; c.because = because.to_string();
c
}
pub(super) fn destroys(locus: LocalLocus, scale: Scale) -> Capability {
let reversibility = if locus >= LocalLocus::User && scale == Scale::Unbounded {
Reversibility::Irreversible
} else {
Reversibility::Effortful
};
writes(
Operation::Destroy,
locus,
scale,
reversibility,
PersistenceLevel::Transient, "rm deletes files (recoverable only from out-of-band backups; irreversible when it mass-deletes home/system)",
)
}
fn writes(
op: Operation,
locus: LocalLocus,
scale: Scale,
reversibility: Reversibility,
persistence: PersistenceLevel,
because: &str,
) -> Capability {
let mut c = Capability::new(op);
c.locus.local = locus;
c.scale = scale;
c.reversibility = reversibility;
c.persistence.level = persistence;
c.because = because.to_string();
c
}
pub(super) fn creates(locus: LocalLocus, scale: Scale) -> Capability {
writes(Operation::Create, locus, scale, Reversibility::Trivial, PersistenceLevel::Data, "creates a file or directory")
}
pub(super) fn overwrites(locus: LocalLocus, scale: Scale, no_clobber: bool) -> Capability {
let reversibility = if no_clobber { Reversibility::Trivial } else { Reversibility::Recoverable };
writes(Operation::Create, locus, scale, reversibility, PersistenceLevel::Data, "writes the destination; may overwrite existing content unless --no-clobber")
}
pub(super) fn writes_export_file(locus: LocalLocus) -> Capability {
writes(Operation::Create, locus, Scale::Single, Reversibility::Recoverable, PersistenceLevel::Data, "writes the export/dump output file (may overwrite existing content)")
}
pub(super) fn mutates(locus: LocalLocus, scale: Scale, because: &str) -> Capability {
writes(Operation::Mutate, locus, scale, Reversibility::Recoverable, PersistenceLevel::Data, because)
}
pub(super) fn relocates(locus: LocalLocus, scale: Scale) -> Capability {
writes(Operation::Mutate, locus, scale, Reversibility::Trivial, PersistenceLevel::Transient, "mv removes the source from its old location (trivially reversible: mv back)")
}
pub(super) fn executes(locus: LocalLocus, trust: ExecutionTrust, because: &str) -> Capability {
let mut c = Capability::new(Operation::Execute);
c.locus.local = locus;
c.execution.trust = trust;
c.because = because.to_string();
c
}
pub(super) fn worst(because: &str) -> Profile {
Profile::of(vec![Capability::worst(because)])
}
pub(super) fn breadth_scale(operands: &[&str], recursive: bool) -> Scale {
if recursive {
Scale::Unbounded
} else if operands.len() > 1 || operands.iter().any(|p| p.contains(['*', '?', '['])) {
Scale::Bounded
} else {
Scale::Single
}
}
pub(super) fn observes(locus: LocalLocus, scale: Scale, because: &str) -> Capability {
let mut c = Capability::new(Operation::Observe);
c.locus.local = locus;
c.scale = scale;
c.because = because.to_string();
c
}
pub(super) fn transfer_profile(
sources: &[&str],
dest: &str,
scale: Scale,
source_writes: bool,
per_source: impl Fn(LocalLocus, Scale) -> Capability,
per_dest: impl Fn(LocalLocus, Scale) -> Capability,
) -> Profile {
let source_locus = if source_writes { write_locus } else { read_locus };
let mut caps: Vec<Capability> =
sources.iter().map(|s| per_source(source_locus(s), scale)).collect();
caps.push(per_dest(classify_locus(dest), scale));
Profile::of(caps)
}