1use crate::provider::prelude::*;
10
11#[derive(Debug, Default, PartialEq)]
13#[allow(missing_copy_implementations)]
15pub struct Path {}
16
17impl fmt::Display for Path {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 write!(f, "$PATH")
20 }
21}
22
23impl Path {
24 pub fn new() -> Path {
26 Default::default()
27 }
28}
29
30#[async_trait]
31impl IsProvider for Path {
32 async fn search_internal(
33 &self,
34 command: &str,
35 target_env: Arc<Environment>,
36 ) -> ProviderResult<Vec<Candidate>> {
37 let result_success = |package: String| {
38 Ok(vec![Candidate {
39 package: package.clone(),
40 actions: Actions {
41 install: None,
42 execute: cmd!(package),
43 },
44 ..Candidate::default()
45 }])
46 };
47
48 if &crate::environment::current() == target_env.as_ref() {
49 match which::which(command) {
50 Ok(path) => result_success(path.display().to_string()),
51 Err(_) => Err(ProviderError::NotFound(command.to_string())),
52 }
53 } else {
54 let stdout = target_env
55 .output_of(cmd!("command", "-v", command))
56 .await
57 .map_err(|e| {
58 if let ExecutionError::NonZero { .. } = e {
59 ProviderError::NotFound(command.to_string())
60 } else {
61 ProviderError::from(e)
62 }
63 })?;
64
65 result_success(stdout.trim_end().to_string())
66 }
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use crate::test::prelude::*;
74
75 test::default_tests!(Path::new());
76
77 #[test]
78 fn search_nonexistent() {
79 let query = quick_test!(
80 Path::new(),
81 Err(ExecutionError::NonZero {
82 command: "command".to_string(),
83 output: std::process::Output {
84 stdout: "".into(),
85 stderr: "".into(),
86 status: ExitStatus::from_raw(1),
87 }
88 })
89 );
90
91 assert::is_err!(query);
92 assert::err::not_found!(query);
93 }
94
95 #[test]
96 fn search_existent() {
97 let query = quick_test!(Path::new(), Ok("/usr/bin/top".to_string()));
98
99 let result = query.results.unwrap();
100
101 assert_eq!(result.len(), 1);
102 assert_eq!(result[0].package, "/usr/bin/top".to_string());
103 assert_eq!(result[0].actions.execute, vec!["/usr/bin/top"].into());
104 }
105}