vertigo_cli/build/
cargo_workspace.rs

1use serde::Deserialize;
2use std::path::PathBuf;
3
4use crate::commons::{command::CommandRun, ErrorCode};
5
6#[derive(Clone, Debug, Deserialize)]
7pub struct Workspace {
8    packages: Vec<Package>,
9    target_directory: String,
10    workspace_members: Vec<String>,
11    workspace_root: String,
12}
13
14#[derive(Clone, Debug, Deserialize)]
15pub struct Package {
16    id: String,
17    name: String,
18    manifest_path: String,
19    targets: Vec<Target>,
20}
21
22#[derive(Clone, Debug, Deserialize)]
23pub struct Target {
24    kind: Vec<String>,
25}
26
27impl Workspace {
28    pub fn infer_package_name(&self) -> Option<String> {
29        for member_id in &self.workspace_members {
30            if let Some(package) = self
31                .packages
32                .iter()
33                .find(|package| &package.id == member_id)
34            {
35                if package.is_cdylib() {
36                    return Some(package.name.clone());
37                }
38            }
39        }
40        None
41    }
42
43    pub fn find_package_path(&self, package_name: &str) -> Option<PathBuf> {
44        self.packages
45            .iter()
46            .find(|package| package.name == package_name)
47            .map(|package| package.manifest_path.clone().into())
48            .and_then(|path: PathBuf| path.parent().map(|p| p.to_path_buf()))
49    }
50
51    pub fn get_target_dir(&self) -> PathBuf {
52        self.target_directory.clone().into()
53    }
54
55    pub fn get_root_dir(&self) -> &str {
56        &self.workspace_root
57    }
58}
59
60impl Package {
61    pub fn is_cdylib(&self) -> bool {
62        self.targets
63            .iter()
64            .any(|target| target.kind.iter().any(|kind| kind == "cdylib"))
65    }
66}
67
68pub fn get_workspace() -> Result<Workspace, ErrorCode> {
69    let metadata = CommandRun::new("cargo")
70        .add_param("metadata")
71        .add_param("--format-version=1")
72        .set_error_code(ErrorCode::CantOpenWorkspace)
73        .output()?;
74
75    match serde_json::from_str::<Workspace>(&metadata) {
76        Ok(mut ws) => {
77            // Retain only local packages to keep object thin
78            ws.packages
79                .retain(|package| ws.workspace_members.contains(&package.id));
80            Ok(ws)
81        }
82        Err(err) => {
83            log::error!("Can't parse workspace: {err}");
84            Err(ErrorCode::CantParseWorkspace)
85        }
86    }
87}