workspacer_metadata/
metadata.rs

1// ---------------- [ File: workspacer-metadata/src/metadata.rs ]
2crate::ix!();
3
4/// 1) Extend `GetCargoMetadata` to also handle a single crate (e.g., `CrateHandle`).
5#[async_trait]
6pub trait GetCargoMetadata {
7    type Error;
8    async fn get_cargo_metadata(&self) -> Result<Metadata, Self::Error>;
9}
10
11/// 2) Implement `GetCargoMetadata` for your `Workspace` (already done):
12#[async_trait]
13impl<P,H> GetCargoMetadata for Workspace<P,H>
14where
15    H: CrateHandleInterface<P>,
16    for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait,
17{
18    type Error = WorkspaceError;
19
20    /// We run `cargo metadata` from the workspace root directory
21    async fn get_cargo_metadata(&self) -> Result<Metadata, Self::Error> {
22        let path = self.as_ref().to_path_buf();
23
24        // We spawn a blocking task because cargo_metadata is a blocking I/O operation
25        let metadata = tokio::task::spawn_blocking(move || {
26            MetadataCommand::new()
27                .current_dir(&path)
28                .exec()
29                .map_err(|e| CargoMetadataError::MetadataError { error: e.into() })
30        })
31        .await
32        .map_err(|e| WorkspaceError::TokioError(TokioError::JoinError { join_error: e.into() }))??;
33
34        Ok(metadata)
35    }
36}
37
38/// 3) For single crates (`CrateHandle`), we do a similar approach, but we run
39///    `cargo metadata` from that crate’s directory (the parent of Cargo.toml),
40///    or pass `--manifest-path` if you prefer. 
41///
42#[async_trait]
43impl GetCargoMetadata for CrateHandle {
44    type Error = CrateError;
45
46    async fn get_cargo_metadata(&self) -> Result<Metadata, Self::Error> {
47        // 1) We'll lock the cargo_toml to locate the exact path to Cargo.toml
48        let cargo_toml_arc = self.cargo_toml_direct();
49        let cargo_toml_guard = cargo_toml_arc.lock().await;
50        let cargo_toml_path = cargo_toml_guard.as_ref().to_path_buf(); // e.g. /some/dir/Cargo.toml
51
52        // 2) We can pass `--manifest-path` to cargo metadata, or `current_dir()`.
53        //    We'll use `--manifest-path` for clarity:
54        let cargo_toml_path2 = cargo_toml_path.clone();
55
56        // 3) Spawn blocking to run cargo_metadata
57        let metadata = tokio::task::spawn_blocking(move || {
58            let mut cmd = MetadataCommand::new();
59            cmd.manifest_path(cargo_toml_path2);
60            cmd.exec().map_err(|e| CargoMetadataError::MetadataError { error: e.into() })
61        })
62        .await??; // Double question marks to unwrap spawn error and the map_err
63
64        Ok(metadata)
65    }
66}