Skip to main content

ready_set_rust/
workspace.rs

1//! Cargo workspace resolution.
2
3use std::path::{Path, PathBuf};
4
5use ready_set_sdk::{Error, Result};
6use toml_edit::DocumentMut;
7
8/// Resolved Cargo manifest hosting the workspace.
9#[derive(Debug, Clone)]
10pub struct Workspace {
11    /// Project root containing `Cargo.toml`.
12    pub root: PathBuf,
13    /// Path to that `Cargo.toml`.
14    pub manifest_path: PathBuf,
15    /// Whether the manifest already has a `[workspace]` table.
16    pub has_workspace_table: bool,
17    /// Whether the manifest has a `[package]` table.
18    pub has_package_table: bool,
19}
20
21/// Walk up from `cwd` to find the nearest Cargo project.
22///
23/// # Errors
24///
25/// Returns [`Error::Io`] if a manifest cannot be read or
26/// [`Error::TomlParse`] if it does not parse.
27pub fn resolve(cwd: &Path) -> Result<Option<Workspace>> {
28    let mut nearest_manifest: Option<PathBuf> = None;
29    let mut cur: Option<&Path> = Some(cwd);
30
31    while let Some(dir) = cur {
32        let manifest = dir.join("Cargo.toml");
33        if manifest.is_file() && nearest_manifest.is_none() {
34            nearest_manifest = Some(manifest);
35        }
36        if dir.join(".git").exists() {
37            break;
38        }
39        cur = dir.parent();
40    }
41
42    let Some(manifest_path) = nearest_manifest else {
43        return Ok(None);
44    };
45
46    let raw = std::fs::read_to_string(&manifest_path)?;
47    let doc: DocumentMut = raw.parse().map_err(|e: toml_edit::TomlError| {
48        Error::TomlParse(format!("{}: {e}", manifest_path.display()))
49    })?;
50
51    let has_workspace_table = doc.get("workspace").is_some();
52    let has_package_table = doc.get("package").is_some();
53
54    if !has_workspace_table && !has_package_table {
55        return Ok(None);
56    }
57
58    let root = manifest_path
59        .parent()
60        .ok_or_else(|| Error::Other(format!("{} has no parent", manifest_path.display())))?
61        .to_path_buf();
62
63    Ok(Some(Workspace {
64        root,
65        manifest_path,
66        has_workspace_table,
67        has_package_table,
68    }))
69}