vertigo_cli/build/
cargo_workspace.rs

1use serde::Deserialize;
2use std::path::PathBuf;
3
4use crate::commons::{ErrorCode, command::CommandRun};
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                && package.is_cdylib()
35            {
36                return Some(package.name.clone());
37            }
38        }
39        None
40    }
41
42    pub fn find_package_path(&self, package_name: &str) -> Option<PathBuf> {
43        self.packages
44            .iter()
45            .find(|package| package.name == package_name)
46            .map(|package| package.manifest_path.clone().into())
47            .and_then(|path: PathBuf| path.parent().map(|p| p.to_path_buf()))
48    }
49
50    pub fn get_target_dir(&self) -> PathBuf {
51        self.target_directory.clone().into()
52    }
53
54    pub fn get_root_dir(&self) -> &str {
55        &self.workspace_root
56    }
57}
58
59impl Package {
60    pub fn is_cdylib(&self) -> bool {
61        self.targets
62            .iter()
63            .any(|target| target.kind.iter().any(|kind| kind == "cdylib"))
64    }
65}
66
67pub fn get_workspace() -> Result<Workspace, ErrorCode> {
68    let metadata = CommandRun::new("cargo")
69        .add_param("metadata")
70        .add_param("--format-version=1")
71        .set_error_code(ErrorCode::CantOpenWorkspace)
72        .output()?;
73
74    match serde_json::from_str::<Workspace>(&metadata) {
75        Ok(mut ws) => {
76            // Retain only local packages to keep object thin
77            ws.packages
78                .retain(|package| ws.workspace_members.contains(&package.id));
79            Ok(ws)
80        }
81        Err(err) => {
82            log::error!("Can't parse workspace: {err}");
83            Err(ErrorCode::CantParseWorkspace)
84        }
85    }
86}