weavatrix_scan/selection/
queries.rs1use super::{
2 Error, IgnoreSourceEvidence, Path, RepositoryMatch, Result, ScanOptions, ScanWarning,
3 SelectionDecision, SelectionMatcher, SkipKind, WalkEntry, fs, relative_depth,
4};
5
6impl SelectionMatcher {
7 pub fn matched(&mut self, path: impl AsRef<Path>) -> Result<SelectionDecision> {
18 let relative = self.repository.normalize(path)?;
19 let absolute = self.repository.root().join(&relative);
20 let depth = relative_depth(&relative);
21 if let Some(decision) = self.match_ancestors(&relative)? {
22 return Ok(decision);
23 }
24 let link_metadata =
25 fs::symlink_metadata(&absolute).map_err(|source| Error::io(&absolute, source))?;
26 let is_symlink = link_metadata.file_type().is_symlink();
27 if is_symlink && !self.options.walk.follow_links {
28 return Ok(SelectionDecision::skipped(
29 SkipKind::Symlink,
30 RepositoryMatch::None,
31 ));
32 }
33 let metadata = if is_symlink {
34 let canonical = absolute
35 .canonicalize()
36 .map_err(|source| Error::io(&absolute, source))?;
37 if !canonical.starts_with(self.repository.root()) {
38 return Ok(SelectionDecision::skipped(
39 SkipKind::PathEscape,
40 RepositoryMatch::None,
41 ));
42 }
43 fs::metadata(&absolute).map_err(|source| Error::io(&absolute, source))?
44 } else {
45 link_metadata
46 };
47 if metadata.is_dir()
48 && let Some(decision) = self.file_system_decision(&absolute, &metadata)?
49 {
50 return Ok(decision);
51 }
52 self.classify(
53 &absolute,
54 &relative,
55 depth,
56 metadata.is_file(),
57 metadata.is_dir(),
58 false,
59 metadata.len(),
60 None,
61 )
62 }
63
64 pub fn matched_entry(&mut self, entry: &WalkEntry) -> Result<SelectionDecision> {
71 let relative = self.repository.normalize(entry.relative_path())?;
72 let absolute = self.repository.root().join(&relative);
73 let bytes = if entry.is_file() {
74 match entry.bytes() {
75 Some(bytes) => bytes,
76 None => fs::metadata(&absolute)
77 .map_err(|source| Error::io(&absolute, source))?
78 .len(),
79 }
80 } else {
81 0
82 };
83 self.classify(
84 &absolute,
85 &relative,
86 entry.depth(),
87 entry.is_file(),
88 entry.is_dir(),
89 entry.is_symlink(),
90 bytes,
91 entry.skip_reason(),
92 )
93 }
94
95 pub fn refresh(&mut self) -> Result<bool> {
102 self.repository.refresh()
103 }
104
105 #[must_use]
107 pub fn root(&self) -> &Path {
108 self.repository.root()
109 }
110
111 #[must_use]
113 pub const fn options(&self) -> &ScanOptions {
114 &self.options
115 }
116
117 #[must_use]
119 pub fn sources(&self) -> &[IgnoreSourceEvidence] {
120 self.repository.sources()
121 }
122
123 #[must_use]
125 pub fn warnings(&self) -> &[ScanWarning] {
126 self.repository.warnings()
127 }
128
129 #[must_use]
131 pub fn portable(&self) -> bool {
132 self.repository.portable()
133 }
134}