workspacer_workspace/
find_items.rs

1// ---------------- [ File: workspacer-workspace/src/find_items.rs ]
2crate::ix!();
3
4#[async_trait]
5impl<P, H> AsyncFindItems for Workspace<P, H>
6where
7    // Make sure P can be constructed from a PathBuf
8    for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait,
9    H: CrateHandleInterface<P> + Send + Sync,
10{
11    type Item = Arc<AsyncMutex<H>>;
12    type Error = WorkspaceError;
13
14    /// Asynchronously finds all the crates in the workspace
15    async fn find_items(path: &Path) -> Result<Vec<Self::Item>, Self::Error> {
16        let mut crates = vec![];
17
18        let mut entries = fs::read_dir(path)
19            .await
20            .map_err(|e| DirectoryError::ReadDirError { io: e.into() })?;
21
22        while let Some(entry) = entries
23            .next_entry()
24            .await
25            .map_err(|e| DirectoryError::GetNextEntryError { io: e.into() })?
26        {
27            let crate_path = entry.path();
28
29            // If there's a Cargo.toml here, we consider it a crate:
30            if fs::metadata(crate_path.join("Cargo.toml"))
31                .await
32                .is_ok()
33            {
34                // Convert crate_path (PathBuf) into your generic P:
35                let converted: P = crate_path.into();
36                crates.push(Arc::new(AsyncMutex::new(H::new(&converted).await?)));
37            }
38        }
39
40        Ok(crates)
41    }
42}
43
44#[cfg(test)]
45mod test_async_find_items {
46    use super::*;
47    
48    /// We'll define a type alias for convenience
49    type MyWorkspace = Workspace<PathBuf, CrateHandle>;
50    
51    ///
52    /// Creates a minimal directory with one or more sub-crates, then calls
53    /// the real `Workspace::<PathBuf,CrateHandle>::find_items(...)`.
54    ///
55    #[traced_test]
56    async fn test_find_items_in_directory() {
57        info!("Starting test_find_items_in_directory");
58        let tmp = tempdir().expect("Failed to create temp dir");
59        let root = tmp.path().to_path_buf();
60        
61        // We'll create two subdirs, each with a Cargo.toml, representing 2 crates
62        let crate_a = root.join("crateA");
63        fs::create_dir(&crate_a).await.unwrap();
64        fs::write(crate_a.join("Cargo.toml"), b"[package]\nname=\"crateA\"").await.unwrap();
65
66        let crate_b = root.join("crateB");
67        fs::create_dir(&crate_b).await.unwrap();
68        fs::write(crate_b.join("Cargo.toml"), b"[package]\nname=\"crateB\"").await.unwrap();
69
70        // Now call the real find_items:
71        let crates_found = MyWorkspace::find_items(&root).await
72            .expect("Should find both crates in subdirectories");
73
74        // We expect 2 crates
75        assert_eq!(crates_found.len(), 2, "Should find exactly 2 crates");
76        let mut paths = Vec::new();
77        for c in crates_found.iter() {
78            paths.push(c.lock().await.root_dir_path_buf());
79        }
80        assert!(paths.contains(&crate_a));
81        assert!(paths.contains(&crate_b));
82        
83        info!("test_find_items_in_directory passed");
84    }
85
86    ///
87    /// Tests that a directory with no sub-crates yields an empty result
88    ///
89    #[traced_test]
90    async fn test_find_items_in_empty_directory() {
91        let tmp = tempdir().unwrap();
92        let root = tmp.path().to_path_buf();
93
94        let crates_found = MyWorkspace::find_items(&root).await
95            .expect("Reading an empty dir should not error");
96        assert_eq!(crates_found.len(), 0, "No subdirs => no crates found");
97    }
98
99    ///
100    /// Tests that if reading the directory fails entirely, we get a `DirectoryError::ReadDirError`.
101    /// We rely on a path that likely doesn't exist or is forbidden.
102    ///
103    #[traced_test]
104    async fn test_find_items_directory_not_found() {
105        let bad_path = PathBuf::from("/this/path/should/not/exist-12345");
106        let result = MyWorkspace::find_items(&bad_path).await;
107        assert!(result.is_err(), "Should fail on non-existent directory");
108        
109        match result.err().unwrap() {
110            WorkspaceError::DirectoryError(DirectoryError::ReadDirError { .. }) => {
111                info!("Got expected DirectoryError::ReadDirError for missing directory");
112            }
113            other => {
114                panic!("Expected DirectoryError::ReadDirError, got: {:?}", other);
115            }
116        }
117    }
118}