qlty_analysis/workspace_entries/
args_source.rs1use crate::{walker::WalkerBuilder, WorkspaceEntry, WorkspaceEntryKind, WorkspaceEntrySource};
2use core::fmt;
3use path_absolutize::Absolutize;
4use rayon::prelude::*;
5use std::{path::PathBuf, sync::Arc};
6
7pub struct ArgsSource {
9 pub root: PathBuf,
10 pub paths: Vec<PathBuf>,
11 pub entries: Arc<Vec<WorkspaceEntry>>,
12}
13
14impl fmt::Debug for ArgsSource {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 write!(f, "ArgsSource[{:?}, {:?}]", self.root, self.paths)
17 }
18}
19
20impl ArgsSource {
21 pub fn new(root: PathBuf, paths: Vec<PathBuf>) -> Self {
22 Self {
23 entries: Arc::new(Self::build(&root, &paths)),
24 root,
25 paths,
26 }
27 }
28
29 fn build(root: &PathBuf, paths: &Vec<PathBuf>) -> Vec<WorkspaceEntry> {
30 WalkerBuilder::new()
31 .build(paths)
32 .par_bridge()
33 .map(|entry| {
34 let entry = entry.unwrap();
35 let path = entry.path();
36
37 let workspace_entry_kind = if path.is_dir() {
38 WorkspaceEntryKind::Directory
39 } else {
40 WorkspaceEntryKind::File
41 };
42
43 let clean_path = path
44 .absolutize()
45 .ok()
46 .unwrap()
47 .strip_prefix(root)
48 .ok()
49 .unwrap()
50 .to_path_buf();
51 let metadata = entry.metadata().ok().unwrap();
52
53 WorkspaceEntry {
54 path: clean_path,
55 content_modified: metadata.modified().ok().unwrap(),
56 contents_size: metadata.len(),
57 kind: workspace_entry_kind,
58 language_name: None,
59 }
60 })
61 .collect::<Vec<_>>()
62 }
63}
64
65impl WorkspaceEntrySource for ArgsSource {
66 fn entries(&self) -> Arc<Vec<WorkspaceEntry>> {
67 self.entries.clone()
68 }
69}
70
71#[cfg(test)]
72mod test {
73 use super::*;
74 use itertools::Itertools;
75 use qlty_test_utilities::git::build_sample_project;
76
77 #[test]
78 fn test_args_source_next() {
79 let root = build_sample_project();
80 let args = vec![
81 root.path().to_path_buf().join("lib/tasks/ops"),
82 root.path().to_path_buf().join("greetings.rb"),
83 ];
84 let source = ArgsSource::new(root.path().to_path_buf(), args);
85
86 let mut paths = vec![];
87
88 for workspace_entry in source.entries().iter() {
89 let workspace_entry = workspace_entry.clone();
90 paths.push((workspace_entry.path, workspace_entry.kind));
91 }
92
93 let expected_paths = build_expected_workspace_entries(vec![
94 ("lib/tasks/ops", WorkspaceEntryKind::Directory),
95 ("lib/tasks/ops/deploy.rb", WorkspaceEntryKind::File),
96 ("lib/tasks/ops/setup.rb", WorkspaceEntryKind::File),
97 ("greetings.rb", WorkspaceEntryKind::File),
98 ]);
99
100 assert_eq!(
101 paths
102 .iter()
103 .cloned()
104 .sorted()
105 .collect::<Vec<(PathBuf, WorkspaceEntryKind)>>(),
106 expected_paths
107 );
108 }
109
110 #[test]
111 fn test_args_source_includes_hidden_files() {
112 let root = build_sample_project();
113 std::fs::write(
114 root.path().join("lib/tasks/ops/.hidden"),
115 "This is a hidden file.",
116 )
117 .unwrap();
118 let args = vec![root.path().to_path_buf().join("lib/tasks/ops")];
119 let source = ArgsSource::new(root.path().to_path_buf(), args);
120
121 let mut paths = vec![];
122
123 for workspace_entry in source.entries().iter() {
124 paths.push(workspace_entry.clone().path);
125 }
126
127 assert!(
128 paths.contains(&PathBuf::from("lib/tasks/ops/.hidden")),
129 "Expected .hidden file to be included in the paths, but it wasn't."
130 );
131 }
132
133 fn build_expected_workspace_entries(
134 workspace_entries: Vec<(&str, WorkspaceEntryKind)>,
135 ) -> Vec<(PathBuf, WorkspaceEntryKind)> {
136 workspace_entries
137 .into_iter()
138 .map(|(s, tt)| (PathBuf::from(s), tt))
139 .sorted()
140 .collect()
141 }
142}